From ba93e5fce31c7b608430b86ed3b29c8b45815cf1 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Mon, 8 Jul 2024 19:27:48 +0200 Subject: [PATCH] breaking: play transitions on `mount` by default (#12351) * breaking: play transitions on `mount` by default closes #11280 * only prevent transitions when the component is invalidated --------- Co-authored-by: Rich Harris --- .changeset/hip-garlics-tap.md | 5 +++++ .../svelte/src/internal/client/dev/hmr.js | 13 ++++++++---- packages/svelte/src/internal/client/render.js | 10 +++++---- packages/svelte/src/legacy/legacy-client.js | 2 +- .../mount-intro-transition/Component.svelte | 5 +++++ .../samples/mount-intro-transition/_config.js | 21 +++++++++++++++++++ .../mount-intro-transition/main.svelte | 21 +++++++++++++++++++ packages/svelte/types/index.d.ts | 3 ++- .../03-appendix/02-breaking-changes.md | 4 ++++ 9 files changed, 74 insertions(+), 10 deletions(-) create mode 100644 .changeset/hip-garlics-tap.md create mode 100644 packages/svelte/tests/runtime-runes/samples/mount-intro-transition/Component.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/mount-intro-transition/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/mount-intro-transition/main.svelte diff --git a/.changeset/hip-garlics-tap.md b/.changeset/hip-garlics-tap.md new file mode 100644 index 0000000000..0913e45d87 --- /dev/null +++ b/.changeset/hip-garlics-tap.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +breaking: play transitions on `mount` by default diff --git a/packages/svelte/src/internal/client/dev/hmr.js b/packages/svelte/src/internal/client/dev/hmr.js index 20f205ade8..0d0edd4ddc 100644 --- a/packages/svelte/src/internal/client/dev/hmr.js +++ b/packages/svelte/src/internal/client/dev/hmr.js @@ -1,9 +1,7 @@ /** @import { Source, Effect } from '#client' */ -import { empty } from '../dom/operations.js'; import { block, branch, destroy_effect } from '../reactivity/effects.js'; import { set_should_intro } from '../render.js'; import { get } from '../runtime.js'; -import { check_target } from './legacy.js'; /** * @template {(anchor: Comment, props: any) => any} Component @@ -20,6 +18,8 @@ export function hmr(source) { /** @type {Effect} */ let effect; + let ran = false; + block(() => { const component = get(source); @@ -30,7 +30,9 @@ export function hmr(source) { } effect = branch(() => { - set_should_intro(false); + // when the component is invalidated, replace it without transitions + if (ran) set_should_intro(false); + // preserve getters/setters Object.defineProperties( instance, @@ -39,10 +41,13 @@ export function hmr(source) { new.target ? new component(anchor, props) : component(anchor, props) ) ); - set_should_intro(true); + + if (ran) set_should_intro(true); }); }); + ran = true; + return instance; }; } diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index e01f8657c7..5820b227e1 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -24,8 +24,8 @@ export const root_event_handles = new Set(); /** * This is normally true — block effects should run their intro transitions — - * but is false during hydration and mounting (unless `options.intro` is `true`) - * and when creating the children of a `` that just changed tag + * but is false during hydration (unless `options.intro` is `true`) and + * when creating the children of a `` that just changed tag */ export let should_intro = true; @@ -66,7 +66,8 @@ export function slot(anchor, slot_fn, slot_props, fallback_fn) { } /** - * Mounts a component to the given target and returns the exports and potentially the props (if compiled with `accessors: true`) of the component + * Mounts a component to the given target and returns the exports and potentially the props (if compiled with `accessors: true`) of the component. + * Transitions will play during the initial render unless the `intro` option is set to `false`. * * @template {Record} Props * @template {Record} Exports @@ -126,6 +127,7 @@ export function hydrate(component, options) { validate_component(component); } + options.intro = options.intro ?? false; const target = options.target; const previous_hydrate_nodes = hydrate_nodes; @@ -190,7 +192,7 @@ export function hydrate(component, options) { * }} options * @returns {Exports} */ -function _mount(Component, { target, anchor, props = {}, events, context, intro = false }) { +function _mount(Component, { target, anchor, props = {}, events, context, intro = true }) { init_operations(); const registered_events = new Set(); diff --git a/packages/svelte/src/legacy/legacy-client.js b/packages/svelte/src/legacy/legacy-client.js index d2eba5be9c..b5f499f37d 100644 --- a/packages/svelte/src/legacy/legacy-client.js +++ b/packages/svelte/src/legacy/legacy-client.js @@ -77,7 +77,7 @@ class Svelte4Component { target: options.target, props, context: options.context, - intro: options.intro, + intro: options.intro ?? false, recover: options.recover }); diff --git a/packages/svelte/tests/runtime-runes/samples/mount-intro-transition/Component.svelte b/packages/svelte/tests/runtime-runes/samples/mount-intro-transition/Component.svelte new file mode 100644 index 0000000000..f9c91fb840 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/mount-intro-transition/Component.svelte @@ -0,0 +1,5 @@ + + +
DIV
diff --git a/packages/svelte/tests/runtime-runes/samples/mount-intro-transition/_config.js b/packages/svelte/tests/runtime-runes/samples/mount-intro-transition/_config.js new file mode 100644 index 0000000000..114f6f0cbf --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/mount-intro-transition/_config.js @@ -0,0 +1,21 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + async test({ assert, target, raf }) { + const [btn1, btn2] = target.querySelectorAll('button'); + const div = target.querySelector('div'); + ok(div); + + btn1.click(); + flushSync(); + assert.htmlEqual(div.innerHTML, `
DIV
`); + + raf.tick(100); + assert.htmlEqual(div.innerHTML, `
DIV
`); + + btn2.click(); + flushSync(); + assert.htmlEqual(div.innerHTML, `
DIV
`); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/mount-intro-transition/main.svelte b/packages/svelte/tests/runtime-runes/samples/mount-intro-transition/main.svelte new file mode 100644 index 0000000000..83021fa537 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/mount-intro-transition/main.svelte @@ -0,0 +1,21 @@ + + +
+ + + diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index 775fd7394b..c63e6366ba 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -366,7 +366,8 @@ declare module 'svelte' { /** Anything except a function */ type NotFunction = T extends Function ? never : T; /** - * Mounts a component to the given target and returns the exports and potentially the props (if compiled with `accessors: true`) of the component + * Mounts a component to the given target and returns the exports and potentially the props (if compiled with `accessors: true`) of the component. + * Transitions will play during the initial render unless the `intro` option is set to `false`. * * */ export function mount, Exports extends Record>(component: ComponentType> | Component, options: {} extends Props ? { diff --git a/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md b/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md index 5b08103d80..8de2bfbfe4 100644 --- a/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md +++ b/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md @@ -281,3 +281,7 @@ In Svelte 4, `` is valid code. This makes little sens ``` Note that whereas Svelte 4 would treat `` (for example) identically to `` for the purposes of determining which `bind:` directives could be applied, Svelte 5 does not. + +### `mount` plays transitions by default + +The `mount` function used to render a component tree plays transitions by default unless the `intro` option is set to `false`. This is different from legacy class components which, when manually instantiated, didn't play transitions by default.