@ -15,9 +15,11 @@ import { untrack } from '../../runtime.js';
import {
block ,
branch ,
destroy _effect ,
effect ,
run _out _transitions ,
pause _children ,
pause _effect ,
pause _effects ,
resume _effect
} from '../../reactivity/effects.js' ;
import { source , mutable _source , set } from '../../reactivity/sources.js' ;
@ -39,6 +41,39 @@ export function set_current_each_item(item) {
current _each _item = item ;
}
/ * *
* Pause multiple effects simultaneously , and coordinate their
* subsequent destruction . Used in each blocks
* @ param { import ( '#client' ) . Effect [ ] } effects
* @ param { null | Node } controlled _anchor
* @ param { ( ) => void } [ callback ]
* /
function pause _effects ( effects , controlled _anchor , callback ) {
/** @type {import('#client').TransitionManager[]} */
var transitions = [ ] ;
var length = effects . length ;
for ( var i = 0 ; i < length ; i ++ ) {
pause _children ( effects [ i ] , transitions , true ) ;
}
// If we have a controlled anchor, it means that the each block is inside a single
// DOM element, so we can apply a fast-path for clearing the contents of the element.
if ( effects . length > 0 && transitions . length === 0 && controlled _anchor !== null ) {
var parent _node = /** @type {Element} */ ( controlled _anchor . parentNode ) ;
parent _node . textContent = '' ;
parent _node . append ( controlled _anchor ) ;
}
run _out _transitions ( transitions , ( ) => {
for ( var i = 0 ; i < length ; i ++ ) {
destroy _effect ( effects [ i ] ) ;
}
if ( callback !== undefined ) callback ( ) ;
} ) ;
}
/ * *
* @ template V
* @ param { Element | Comment } anchor The next sibling node , or the parent node if this is a 'controlled' block
@ -145,7 +180,6 @@ function each(anchor, flags, get_collection, get_key, render_fn, fallback_fn, re
}
if ( ! hydrating ) {
// TODO add 'empty controlled block' optimisation here
reconcile _fn ( array , state , anchor , render _fn , flags , keys ) ;
}
@ -244,7 +278,9 @@ function reconcile_indexed_array(array, state, anchor, render_fn, flags) {
effects . push ( a _items [ i ] . e ) ;
}
pause _effects ( effects , ( ) => {
var controlled _anchor = ( flags & EACH _IS _CONTROLLED ) !== 0 && b === 0 ? anchor : null ;
pause _effects ( effects , controlled _anchor , ( ) => {
state . items . length = b ;
} ) ;
}
@ -274,6 +310,7 @@ function reconcile_tracked_array(array, state, anchor, render_fn, flags, keys) {
var is _animated = ( flags & EACH _IS _ANIMATED ) !== 0 ;
var should _update = ( flags & ( EACH _ITEM _REACTIVE | EACH _INDEX _REACTIVE ) ) !== 0 ;
var is _controlled = ( flags & EACH _IS _CONTROLLED ) !== 0 ;
var start = 0 ;
var item ;
@ -381,6 +418,11 @@ function reconcile_tracked_array(array, state, anchor, render_fn, flags, keys) {
// I fully understand this part)
if ( moved ) {
mark _lis ( sources ) ;
} else if ( is _controlled && to _destroy . length === a _items . length ) {
// We can optimize the case in which all items are replaced —
// destroy everything first, then append new items
pause _effects ( to _destroy , anchor ) ;
to _destroy = [ ] ;
}
// working from the back, insert new or moved items
@ -421,9 +463,9 @@ function reconcile_tracked_array(array, state, anchor, render_fn, flags, keys) {
} ) ;
}
// TODO: would be good to avoid this closure in the case where we have no
// transitions at all. It would make it far more JIT friendly in the hot cases.
pause _effects ( to _destroy , ( ) => {
var controlled _anchor = is _controlled && b === 0 ? anchor : null ;
pause _effects ( to _destroy , controlled _anchor , ( ) => {
state . items = b _items ;
} ) ;
}