diff --git a/packages/svelte/src/internal/client/reactivity/computations.js b/packages/svelte/src/internal/client/reactivity/computations.js index cec1ce6799..316a660191 100644 --- a/packages/svelte/src/internal/client/reactivity/computations.js +++ b/packages/svelte/src/internal/client/reactivity/computations.js @@ -265,26 +265,73 @@ export function derived_safe_equal(fn) { * @param {() => void} done */ export function pause_effect(effect, done) { - if (effect.r) { - for (const child of effect.r) { - pause_effect(child, noop); + const transitions = []; + + pause_children(effect, transitions); + + let remaining = transitions.length; + + if (remaining > 0) { + const check = () => { + if (!--remaining) { + destroy_effect(effect); + done(); + } + }; + + for (const transition of transitions) { + transition.to(0, check); } + } else { + destroy_effect(effect); + done(); } +} +/** + * @param {import('../types.js').ComputationSignal} effect + * @param {TODO[]} transitions + */ +function pause_children(effect, transitions) { effect.f |= INERT; + if (effect.out) { + transitions.push(...effect.out); // TODO differentiate between global and local + } + + if (effect.r) { + for (const child of effect.r) { + pause_children(child, transitions); + } + } +} + +/** + * @param {import('../types.js').ComputationSignal} effect + */ +function destroy_effect(effect) { // TODO distinguish between 'block effects' (?) which own their own DOM // and other render effects if (effect.dom) { remove(effect.dom); } - done(); // TODO defer until transitions have completed + if (effect.r) { + for (const child of effect.r) { + destroy_effect(child); + } + } } /** - * @param {import('../types.js').ComputationSignal} signal + * @param {import('../types.js').ComputationSignal} effect */ -export function resume_effect(signal) { - // TODO +export function resume_effect(effect) { + if (effect.r) { + for (const child of effect.r) { + resume_effect(child); + } + } + + effect.f ^= INERT; } diff --git a/packages/svelte/src/internal/client/transitions.js b/packages/svelte/src/internal/client/transitions.js index 59eb3ad60d..938618ae89 100644 --- a/packages/svelte/src/internal/client/transitions.js +++ b/packages/svelte/src/internal/client/transitions.js @@ -495,133 +495,68 @@ function is_transition_block(block) { /** * @template P - * @param {HTMLElement} dom - * @param {() => import('./types.js').TransitionFn
| import('./types.js').AnimateFn
} get_transition_fn - * @param {(() => P) | null} props_fn - * @param {'in' | 'out' | 'both' | 'key'} direction + * @param {HTMLElement} element + * @param {() => import('./types.js').TransitionFn
} get_fn
+ * @param {(() => P) | null} get_params
+ * @param {'in' | 'out' | 'both'} direction
* @param {boolean} global
* @returns {void}
*/
-export function bind_transition(dom, get_transition_fn, props_fn, direction, global) {
- const transition_effect = /** @type {import('./types.js').EffectSignal} */ (current_effect);
- const block = current_block;
- const is_keyed_transition = direction === 'key';
+export function bind_transition(element, get_fn, get_params, direction, global) {
+ const effect = /** @type {import('./types.js').EffectSignal} */ (current_effect);
- let can_show_intro_on_mount = true;
- let can_apply_lazy_transitions = false;
+ let p = direction === 'out' ? 1 : 0;
- if (is_keyed_transition) {
- // @ts-ignore
- dom.__animate = true;
- }
- /** @type {import('./types.js').Block | null} */
- let transition_block = block;
- main: while (transition_block !== null) {
- if (is_transition_block(transition_block)) {
- if (transition_block.t === EACH_ITEM_BLOCK) {
- // Lazily apply the each block transition
- transition_block.r = each_item_transition;
- transition_block.a = each_item_animate;
- transition_block = transition_block.p;
- } else if (transition_block.t === AWAIT_BLOCK && transition_block.n /* pending */) {
- can_show_intro_on_mount = true;
- } else if (transition_block.t === IF_BLOCK) {
- transition_block.r = if_block_transition;
- if (can_show_intro_on_mount) {
- /** @type {import('./types.js').Block | null} */
- let if_block = transition_block;
- while (if_block.t === IF_BLOCK) {
- // If we have an if block parent that is currently falsy then
- // we can show the intro on mount as long as that block is mounted
- if (if_block.e !== null && !if_block.v) {
- can_show_intro_on_mount = true;
- break main;
- }
- if_block = if_block.p;
- }
- }
- }
- if (!can_apply_lazy_transitions && can_show_intro_on_mount) {
- can_show_intro_on_mount = transition_block.e !== null;
- }
- if (can_show_intro_on_mount || !global) {
- can_apply_lazy_transitions = true;
+ /** @type {Animation | null} */
+ let current_animation;
+
+ /** @type {TODO} */
+ let current_options;
+
+ const transition = {
+ global,
+ to(target, callback) {
+ if (current_animation) {
+ // TODO get `p` from current_animation?
+ current_animation.cancel();
}
- } else if (transition_block.t === ROOT_BLOCK && !can_apply_lazy_transitions) {
- can_show_intro_on_mount = transition_block.e !== null || transition_block.i;
- }
- transition_block = transition_block.p;
- }
- /** @type {import('./types.js').Transition} */
- let transition;
-
- effect(() => {
- let already_mounted = false;
- if (transition !== undefined) {
- already_mounted = true;
- // Destroy any existing transitions first
- transition.x();
- }
- const transition_fn = get_transition_fn();
- /** @param {DOMRect} [from] */
- const init = (from) =>
- untrack(() => {
- const props = props_fn === null ? {} : props_fn();
- return is_keyed_transition
- ? /** @type {import('./types.js').AnimateFn