Merge branch 'main' into svelte-custom-renderer

svelte-custom-renderer-single-type-argument
Paolo Ricciuti 1 month ago committed by GitHub
commit d333a7f0bb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: do not dispatch introstart event with animation of animate directive

@ -241,7 +241,7 @@ When the value of an `<option>` matches its text content, the attribute can be o
</select>
```
You can give the `<select>` a default value by adding a `selected` attribute to the`<option>` (or options, in the case of `<select multiple>`) that should be initially selected. If the `<select>` is part of a form, it will revert to that selection when the form is reset. Note that for the initial render the value of the binding takes precedence if it's not `undefined`.
You can give the `<select>` a default value by adding a `selected` attribute to the `<option>` (or options, in the case of `<select multiple>`) that should be initially selected. If the `<select>` is part of a form, it will revert to that selection when the form is reset. Note that for the initial render the value of the binding takes precedence if it's not `undefined`.
```svelte
<select bind:value={selected}>

@ -115,10 +115,17 @@ export function animation(element, get_fn, get_params) {
) {
const options = get_fn()(this.element, { from, to }, get_params?.());
animation = animate(this.element, options, undefined, 1, () => {
animation?.abort();
animation = undefined;
});
animation = animate(
this.element,
options,
undefined,
1,
() => {},
() => {
animation?.abort();
animation = undefined;
}
);
}
},
fix() {
@ -239,15 +246,24 @@ export function transition(flags, element, get_fn, get_params) {
intro?.abort();
}
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;
element.style.overflow = overflow;
});
intro = animate(
element,
get_options(),
outro,
1,
() => {
dispatch_event(element, 'introstart');
},
() => {
dispatch_event(element, 'introend');
// Ensure we cancel the animation to prevent leaking
intro?.abort();
intro = current_options = undefined;
element.style.overflow = overflow;
}
);
},
out(fn) {
if (!is_outro) {
@ -258,10 +274,19 @@ export function transition(flags, element, get_fn, get_params) {
element.inert = true;
outro = animate(element, get_options(), intro, 0, () => {
dispatch_event(element, 'outroend');
fn?.();
});
outro = animate(
element,
get_options(),
intro,
0,
() => {
dispatch_event(element, 'outrostart');
},
() => {
dispatch_event(element, 'outroend');
fn?.();
}
);
},
stop: () => {
intro?.abort();
@ -306,10 +331,11 @@ export function transition(flags, element, get_fn, get_params) {
* @param {AnimationConfig | ((opts: { direction: 'in' | 'out' }) => AnimationConfig)} options
* @param {Animation | undefined} counterpart The corresponding intro/outro to this outro/intro
* @param {number} t2 The target `t` value `1` for intro, `0` for outro
* @param {(() => void)} on_begin Called just before beginning the animation
* @param {(() => void)} on_finish Called after successfully completing the animation
* @returns {Animation}
*/
function animate(element, options, counterpart, t2, on_finish) {
function animate(element, options, counterpart, t2, on_begin, on_finish) {
var is_intro = t2 === 1;
if (is_function(options)) {
@ -323,7 +349,7 @@ function animate(element, options, counterpart, t2, on_finish) {
queue_micro_task(() => {
if (aborted) return;
var o = options({ direction: is_intro ? 'in' : 'out' });
a = animate(element, o, counterpart, t2, on_finish);
a = animate(element, o, counterpart, t2, on_begin, on_finish);
});
// ...but we want to do so without using `async`/`await` everywhere, so
@ -342,7 +368,7 @@ function animate(element, options, counterpart, t2, on_finish) {
counterpart?.deactivate();
if (!options?.duration && !options?.delay) {
dispatch_event(element, is_intro ? 'introstart' : 'outrostart');
on_begin();
on_finish();
return {
@ -382,7 +408,7 @@ function animate(element, options, counterpart, t2, on_finish) {
// remove dummy animation from the stack to prevent conflict with main animation
animation.cancel();
dispatch_event(element, is_intro ? 'introstart' : 'outrostart');
on_begin();
// for bidirectional transitions, we start from the current position,
// rather than doing a full intro/outro

@ -0,0 +1,31 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
test({ assert, raf, target, logs }) {
let divs = target.querySelectorAll('div');
divs.forEach((div) => {
// @ts-expect-error
div.getBoundingClientRect = function () {
// @ts-expect-error
const index = [...this.parentNode.children].indexOf(this);
const top = index * 30;
return {
left: 0,
right: 100,
top,
bottom: top + 20
};
};
});
const [btn] = target.querySelectorAll('button');
flushSync(() => btn.click());
raf.tick(1);
assert.deepEqual(logs, []);
raf.tick(100);
assert.deepEqual(logs, []);
}
});

@ -0,0 +1,19 @@
<script>
import { flip } from "svelte/animate";
let numbers = $state([0,1]);
</script>
<button onclick={() => numbers.reverse()}>reverse</button>
{#each numbers as num (num)}
<div
onintrostart={() => console.log("intro start")}
onoutrostart={() => console.log("outro start")}
onintroend={() => console.log("intro end")}
onoutroend={() => console.log("outro end")}
animate:flip={{ duration: 100 }}
>
{num}
</div>
{/each}
Loading…
Cancel
Save