Comparing version 5.0.0-next.239 to 5.0.0-next.240
@@ -5,3 +5,3 @@ { | ||
"license": "MIT", | ||
"version": "5.0.0-next.239", | ||
"version": "5.0.0-next.240", | ||
"type": "module", | ||
@@ -8,0 +8,0 @@ "types": "./types/index.d.ts", |
@@ -47,6 +47,2 @@ /** @import { Attribute, BindDirective } from '#compiler' */ | ||
if (binding?.kind === 'derived') { | ||
e.constant_binding(node.expression, 'derived state'); | ||
} | ||
if (context.state.analysis.runes && binding?.kind === 'each') { | ||
@@ -53,0 +49,0 @@ e.each_item_invalid_assignment(node); |
@@ -74,3 +74,7 @@ /** @import { AssignmentExpression, CallExpression, Expression, Pattern, PrivateIdentifier, Super, TaggedTemplateExpression, UpdateExpression, VariableDeclarator } from 'estree' */ | ||
const binding = scope.get(argument.name); | ||
if (binding?.declaration_kind === 'const' && binding.kind !== 'each') { | ||
if ( | ||
binding?.kind === 'derived' || | ||
binding?.declaration_kind === 'import' || | ||
(binding?.declaration_kind === 'const' && binding.kind !== 'each') | ||
) { | ||
// e.invalid_const_assignment( | ||
@@ -87,3 +91,8 @@ // node, | ||
// TODO have a more specific error message for assignments to things like `{:then foo}` | ||
const thing = 'constant'; | ||
const thing = | ||
binding.declaration_kind === 'import' | ||
? 'import' | ||
: binding.kind === 'derived' | ||
? 'derived state' | ||
: 'constant'; | ||
@@ -90,0 +99,0 @@ if (is_binding) { |
@@ -393,3 +393,3 @@ /** @import { ClassDeclaration, Expression, FunctionDeclaration, Identifier, ImportDeclaration, MemberExpression, Node, Pattern, VariableDeclarator } from 'estree' */ | ||
for (const id of extract_identifiers_from_destructuring(node.expression)) { | ||
const binding = scope.declare(id, 'derived', 'const'); | ||
const binding = scope.declare(id, 'template', 'const'); | ||
bindings.push(binding); | ||
@@ -405,3 +405,3 @@ } | ||
}; | ||
const binding = scope.declare(id, 'derived', 'const'); | ||
const binding = scope.declare(id, 'template', 'const'); | ||
bindings.push(binding); | ||
@@ -497,3 +497,3 @@ } | ||
id, | ||
is_parent_const_tag ? 'derived' : 'normal', | ||
is_parent_const_tag ? 'template' : 'normal', | ||
node.kind, | ||
@@ -554,3 +554,3 @@ declarator.init | ||
if (node.context.type !== 'Identifier') { | ||
scope.declare(b.id('$$item'), 'derived', 'synthetic'); | ||
scope.declare(b.id('$$item'), 'template', 'synthetic'); | ||
} | ||
@@ -564,3 +564,3 @@ // Visit to pick up references from default initializers | ||
(node.key.type !== 'Identifier' || !node.index || node.key.name !== node.index); | ||
scope.declare(b.id(node.index), is_keyed ? 'derived' : 'normal', 'const', node); | ||
scope.declare(b.id(node.index), is_keyed ? 'template' : 'normal', 'const', node); | ||
} | ||
@@ -612,3 +612,3 @@ if (node.key) visit(node.key, { scope }); | ||
for (const id of extract_identifiers(node.value)) { | ||
then_scope.declare(id, 'derived', 'const'); | ||
then_scope.declare(id, 'template', 'const'); | ||
value_scope.declare(id, 'normal', 'const'); | ||
@@ -627,3 +627,3 @@ } | ||
for (const id of extract_identifiers(node.error)) { | ||
catch_scope.declare(id, 'derived', 'const'); | ||
catch_scope.declare(id, 'template', 'const'); | ||
error_scope.declare(id, 'normal', 'const'); | ||
@@ -630,0 +630,0 @@ } |
@@ -270,2 +270,3 @@ import type { | ||
* - `legacy_reactive`: A `$:` declaration | ||
* - `template`: A binding declared in the template, e.g. in an `await` block or `const` tag | ||
*/ | ||
@@ -283,3 +284,4 @@ kind: | ||
| 'store_sub' | ||
| 'legacy_reactive'; | ||
| 'legacy_reactive' | ||
| 'template'; | ||
declaration_kind: DeclarationKind; | ||
@@ -286,0 +288,0 @@ /** |
@@ -95,3 +95,3 @@ /** @import { Snippet } from 'svelte' */ | ||
if (DEV && (get_next_sibling(element) !== null || element.nodeType !== 3)) { | ||
if (DEV && (get_next_sibling(element) !== null || element.nodeType !== 1)) { | ||
w.invalid_raw_snippet_render(); | ||
@@ -98,0 +98,0 @@ } |
@@ -1,6 +0,5 @@ | ||
/** @import { AnimateFn, Animation, AnimationConfig, EachItem, Effect, Task, TransitionFn, TransitionManager } from '#client' */ | ||
/** @import { AnimateFn, Animation, AnimationConfig, EachItem, Effect, TransitionFn, TransitionManager } from '#client' */ | ||
import { noop, is_function } from '../../../shared/utils.js'; | ||
import { effect } from '../../reactivity/effects.js'; | ||
import { current_effect, untrack } from '../../runtime.js'; | ||
import { raf } from '../../timing.js'; | ||
import { loop } from '../../loop.js'; | ||
@@ -100,13 +99,6 @@ import { should_intro } from '../../render.js'; | ||
animation = animate( | ||
this.element, | ||
options, | ||
undefined, | ||
1, | ||
() => { | ||
animation?.abort(); | ||
animation = undefined; | ||
}, | ||
undefined | ||
); | ||
animation = animate(this.element, options, undefined, 1, () => { | ||
animation?.abort(); | ||
animation = undefined; | ||
}); | ||
} | ||
@@ -196,5 +188,2 @@ }, | ||
/** @type {(() => void) | undefined} */ | ||
var reset; | ||
function get_options() { | ||
@@ -204,3 +193,5 @@ // If a transition is still ongoing, we use the existing options rather than generating | ||
// jumping to a new spot because (for example) a different `duration` was used | ||
return (current_options ??= get_fn()(element, get_params?.(), { direction })); | ||
return (current_options ??= get_fn()(element, get_params?.() ?? /** @type {P} */ ({}), { | ||
direction | ||
})); | ||
} | ||
@@ -214,61 +205,39 @@ | ||
// abort the outro to prevent overlap with the intro | ||
outro?.abort(); | ||
// abort previous intro (can happen if an element is intro'd, then outro'd, then intro'd again) | ||
intro?.abort(); | ||
if (!is_intro) { | ||
outro?.abort(); | ||
outro?.reset?.(); | ||
return; | ||
} | ||
if (is_intro) { | ||
dispatch_event(element, 'introstart'); | ||
intro = animate( | ||
element, | ||
get_options(), | ||
outro, | ||
1, | ||
() => { | ||
dispatch_event(element, 'introend'); | ||
// Ensure we cancel the animation to prevent leaking | ||
intro?.abort(); | ||
intro = current_options = undefined; | ||
}, | ||
is_both | ||
? undefined | ||
: () => { | ||
intro = current_options = undefined; | ||
} | ||
); | ||
} else { | ||
reset?.(); | ||
if (!is_outro) { | ||
// if we intro then outro then intro again, we want to abort the first intro, | ||
// if it's not a bidirectional transition | ||
intro?.abort(); | ||
} | ||
dispatch_event(element, 'introstart'); | ||
intro = animate(element, get_options(), outro, 1, () => { | ||
dispatch_event(element, 'introend'); | ||
// Ensure we cancel the animation to prevent leaking | ||
intro?.abort(); | ||
intro = current_options = undefined; | ||
}); | ||
}, | ||
out(fn) { | ||
// abort previous outro (can happen if an element is outro'd, then intro'd, then outro'd again) | ||
outro?.abort(); | ||
if (!is_outro) { | ||
fn?.(); | ||
current_options = undefined; | ||
return; | ||
} | ||
if (is_outro) { | ||
element.inert = true; | ||
element.inert = true; | ||
dispatch_event(element, 'outrostart'); | ||
outro = animate( | ||
element, | ||
get_options(), | ||
intro, | ||
0, | ||
() => { | ||
dispatch_event(element, 'outroend'); | ||
outro = current_options = undefined; | ||
fn?.(); | ||
}, | ||
is_both | ||
? undefined | ||
: () => { | ||
outro = current_options = undefined; | ||
} | ||
); | ||
dispatch_event(element, 'outrostart'); | ||
// TODO arguably the outro should never null itself out until _all_ outros for this effect have completed... | ||
// in that case we wouldn't need to store `reset` separately | ||
reset = outro.reset; | ||
} else { | ||
outro = animate(element, get_options(), intro, 0, () => { | ||
dispatch_event(element, 'outroend'); | ||
fn?.(); | ||
} | ||
}); | ||
}, | ||
@@ -289,3 +258,3 @@ stop: () => { | ||
if (is_intro && should_intro) { | ||
let run = is_global; | ||
var run = is_global; | ||
@@ -319,7 +288,6 @@ if (!run) { | ||
* @param {number} t2 The target `t` value — `1` for intro, `0` for outro | ||
* @param {(() => void) | undefined} on_finish Called after successfully completing the animation | ||
* @param {(() => void) | undefined} on_abort Called if the animation is aborted | ||
* @param {(() => void)} on_finish Called after successfully completing the animation | ||
* @returns {Animation} | ||
*/ | ||
function animate(element, options, counterpart, t2, on_finish, on_abort) { | ||
function animate(element, options, counterpart, t2, on_finish) { | ||
var is_intro = t2 === 1; | ||
@@ -330,3 +298,3 @@ | ||
// a function rather than an `AnimationConfig`. We need to call this function | ||
// once DOM has been updated... | ||
// once the DOM has been updated... | ||
/** @type {Animation} */ | ||
@@ -339,3 +307,3 @@ var a; | ||
var o = options({ direction: is_intro ? 'in' : 'out' }); | ||
a = animate(element, o, counterpart, t2, on_finish, on_abort); | ||
a = animate(element, o, counterpart, t2, on_finish); | ||
}); | ||
@@ -352,3 +320,3 @@ | ||
reset: () => a.reset(), | ||
t: (now) => a.t(now) | ||
t: () => a.t() | ||
}; | ||
@@ -360,3 +328,4 @@ } | ||
if (!options?.duration) { | ||
on_finish?.(); | ||
on_finish(); | ||
return { | ||
@@ -372,32 +341,35 @@ abort: noop, | ||
var start = raf.now() + delay; | ||
var t1 = counterpart?.t(start) ?? 1 - t2; | ||
var delta = t2 - t1; | ||
var keyframes = []; | ||
var duration = options.duration * Math.abs(delta); | ||
var end = start + duration; | ||
if (is_intro && counterpart === undefined) { | ||
if (tick) { | ||
tick(0, 1); // TODO put in nested effect, to avoid interleaved reads/writes? | ||
} | ||
/** @type {globalThis.Animation} */ | ||
var animation; | ||
if (css) { | ||
var styles = css_to_keyframe(css(0, 1)); | ||
keyframes.push(styles, styles); | ||
} | ||
} | ||
/** @type {Task} */ | ||
var task; | ||
var get_t = () => 1 - t2; | ||
if (css) { | ||
// run after a micro task so that all transitions that are lining up and are about to run can correctly measure the DOM | ||
queue_micro_task(() => { | ||
// WAAPI | ||
var keyframes = []; | ||
// create a dummy animation that lasts as long as the delay (but with whatever devtools | ||
// multiplier is in effect). in the common case that it is `0`, we keep it anyway so that | ||
// the CSS keyframes aren't created until the DOM is updated | ||
var animation = element.animate(keyframes, { duration: delay }); | ||
animation.onfinish = () => { | ||
// for bidirectional transitions, we start from the current position, | ||
// rather than doing a full intro/outro | ||
var t1 = counterpart?.t() ?? 1 - t2; | ||
counterpart?.abort(); | ||
var delta = t2 - t1; | ||
var duration = /** @type {number} */ (options.duration) * Math.abs(delta); | ||
var keyframes = []; | ||
if (css) { | ||
var n = Math.ceil(duration / (1000 / 60)); // `n` must be an integer, or we risk missing the `t2` value | ||
// In case of a delayed intro, apply the initial style for the duration of the delay; | ||
// else in case of a fade-in for example the element would be visible until the animation starts | ||
if (is_intro && delay > 0) { | ||
let m = Math.ceil(delay / (1000 / 60)); | ||
let keyframe = css_to_keyframe(css(0, 1)); | ||
for (let i = 0; i < m; i += 1) { | ||
keyframes.push(keyframe); | ||
} | ||
} | ||
for (var i = 0; i <= n; i += 1) { | ||
@@ -408,51 +380,31 @@ var t = t1 + delta * easing(i / n); | ||
} | ||
} | ||
animation = element.animate(keyframes, { | ||
delay: is_intro ? 0 : delay, | ||
duration: duration + (is_intro ? delay : 0), | ||
easing: 'linear', | ||
fill: 'forwards' | ||
}); | ||
animation = element.animate(keyframes, { duration, fill: 'forwards' }); | ||
animation.finished | ||
.then(() => { | ||
on_finish?.(); | ||
animation.onfinish = () => { | ||
get_t = () => t2; | ||
tick?.(t2, 1 - t2); | ||
on_finish(); | ||
}; | ||
if (t2 === 1) { | ||
animation.cancel(); | ||
} | ||
}) | ||
.catch((e) => { | ||
// Error for DOMException: The user aborted a request. This results in two things: | ||
// - startTime is `null` | ||
// - currentTime is `null` | ||
// We can't use the existence of an AbortError as this error and error code is shared | ||
// with other Web APIs such as fetch(). | ||
get_t = () => { | ||
var time = /** @type {number} */ ( | ||
/** @type {globalThis.Animation} */ (animation).currentTime | ||
); | ||
if (animation.startTime !== null && animation.currentTime !== null) { | ||
throw e; | ||
} | ||
}); | ||
}); | ||
} else { | ||
// Timer | ||
if (t1 === 0) { | ||
tick?.(0, 1); // TODO put in nested effect, to avoid interleaved reads/writes? | ||
} | ||
return t1 + delta * easing(time / duration); | ||
}; | ||
task = loop((now) => { | ||
if (now >= end) { | ||
tick?.(t2, 1 - t2); | ||
on_finish?.(); | ||
return false; | ||
} | ||
if (tick) { | ||
loop(() => { | ||
if (animation.playState !== 'running') return false; | ||
if (now >= start) { | ||
var p = t1 + delta * easing((now - start) / duration); | ||
tick?.(p, 1 - p); | ||
} | ||
var t = get_t(); | ||
tick(t, 1 - t); | ||
return true; | ||
}); | ||
} | ||
return true; | ||
}); | ||
} | ||
}; | ||
@@ -466,10 +418,5 @@ return { | ||
} | ||
task?.abort(); | ||
on_abort?.(); | ||
on_finish = undefined; | ||
on_abort = undefined; | ||
}, | ||
deactivate: () => { | ||
on_finish = undefined; | ||
on_abort = undefined; | ||
on_finish = noop; | ||
}, | ||
@@ -481,7 +428,4 @@ reset: () => { | ||
}, | ||
t: (now) => { | ||
var t = t1 + delta * easing((now - start) / duration); | ||
return Math.min(1, Math.max(0, t)); | ||
} | ||
t: () => get_t() | ||
}; | ||
} |
@@ -293,8 +293,8 @@ /** @import { ComponentContext, Effect, TemplateNode } from '#client' */ | ||
const fn = mounted_components.get(component); | ||
if (DEV && !fn) { | ||
if (fn) { | ||
fn(); | ||
} else if (DEV) { | ||
w.lifecycle_double_unmount(); | ||
// eslint-disable-next-line no-console | ||
console.trace('stack trace'); | ||
} | ||
fn?.(); | ||
} |
@@ -124,3 +124,3 @@ import type { Store } from '#shared'; | ||
/** Get the `t` value (between `0` and `1`) of the animation, so that its counterpart can start from the right place */ | ||
t: (now: number) => number; | ||
t: () => number; | ||
} | ||
@@ -127,0 +127,0 @@ |
@@ -53,2 +53,6 @@ /** @import { Component, Payload } from '#server' */ | ||
export function reset_elements() { | ||
parent = null; | ||
} | ||
/** | ||
@@ -55,0 +59,0 @@ * @param {Payload} payload |
@@ -19,2 +19,3 @@ /** @import { ComponentType, SvelteComponent } from 'svelte' */ | ||
import { is_boolean_attribute, is_void } from '../../utils.js'; | ||
import { reset_elements } from './dev.js'; | ||
@@ -104,2 +105,7 @@ // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 | ||
if (DEV) { | ||
// prevent parent/child element state being corrupted by a bad render | ||
reset_elements(); | ||
} | ||
if (options.context) { | ||
@@ -106,0 +112,0 @@ push(); |
@@ -9,3 +9,3 @@ // generated during release, do not modify | ||
*/ | ||
export const VERSION = '5.0.0-next.239'; | ||
export const VERSION = '5.0.0-next.240'; | ||
export const PUBLIC_VERSION = '5'; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2208837
48898