diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js index 9be4351563..e0ad34f5bc 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js @@ -545,6 +545,8 @@ function build_element_attribute_update_assignment(element, node_id, attribute, update = b.stmt(b.call('$.set_value', node_id, value)); } else if (name === 'checked') { update = b.stmt(b.call('$.set_checked', node_id, value)); + } else if (name === 'hidden') { + update = b.stmt(b.call('$.set_hidden', node_id, value)); } else if (is_dom_property(name)) { update = b.stmt(b.assignment('=', b.member(node_id, name), value)); } else { diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/TransitionDirective.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/TransitionDirective.js index e331f36472..fa505840cd 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/TransitionDirective.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/TransitionDirective.js @@ -1,7 +1,12 @@ /** @import { Expression } from 'estree' */ /** @import { AST } from '#compiler' */ /** @import { ComponentContext } from '../types' */ -import { TRANSITION_GLOBAL, TRANSITION_IN, TRANSITION_OUT } from '../../../../../constants.js'; +import { + TRANSITION_GLOBAL, + TRANSITION_HIDDEN, + TRANSITION_IN, + TRANSITION_OUT +} from '../../../../../constants.js'; import * as b from '../../../../utils/builders.js'; import { parse_directive_name } from './shared/utils.js'; @@ -13,6 +18,9 @@ export function TransitionDirective(node, context) { let flags = node.modifiers.includes('global') ? TRANSITION_GLOBAL : 0; if (node.intro) flags |= TRANSITION_IN; if (node.outro) flags |= TRANSITION_OUT; + if (node.modifiers.includes('hidden')) { + flags |= TRANSITION_HIDDEN; + } const args = [ b.literal(flags), diff --git a/packages/svelte/src/compiler/types/template.d.ts b/packages/svelte/src/compiler/types/template.d.ts index 9da0320432..2848ccb288 100644 --- a/packages/svelte/src/compiler/types/template.d.ts +++ b/packages/svelte/src/compiler/types/template.d.ts @@ -251,7 +251,7 @@ export namespace AST { name: string; /** The 'y' in `transition:x={y}` */ expression: null | Expression; - modifiers: Array<'local' | 'global'>; + modifiers: Array<'local' | 'global' | 'hidden'>; /** True if this is a `transition:` or `in:` directive */ intro: boolean; /** True if this is a `transition:` or `out:` directive */ diff --git a/packages/svelte/src/constants.js b/packages/svelte/src/constants.js index 03fddc5ebd..84a04e7f2a 100644 --- a/packages/svelte/src/constants.js +++ b/packages/svelte/src/constants.js @@ -14,6 +14,7 @@ export const PROPS_IS_LAZY_INITIAL = 1 << 4; export const TRANSITION_IN = 1; export const TRANSITION_OUT = 1 << 1; export const TRANSITION_GLOBAL = 1 << 2; +export const TRANSITION_HIDDEN = 1 << 3; export const TEMPLATE_FRAGMENT = 1; export const TEMPLATE_USE_IMPORT_NODE = 1 << 1; diff --git a/packages/svelte/src/internal/client/dom/elements/attributes.js b/packages/svelte/src/internal/client/dom/elements/attributes.js index db3ac5fa4e..98d033a26a 100644 --- a/packages/svelte/src/internal/client/dom/elements/attributes.js +++ b/packages/svelte/src/internal/client/dom/elements/attributes.js @@ -74,6 +74,28 @@ export function set_checked(element, checked) { element.checked = checked; } +/** + * @param {Element & { hidden: boolean, __tm?: import('#client').TransitionManager}} element + * @param {boolean} hidden + */ +export function set_hidden(element, hidden) { + // @ts-expect-error + var attributes = (element.__attributes ??= {}); + + if (attributes.hidden === (attributes.hidden = !!hidden)) return; + + if (element.__tm) { + if (hidden) { + element.__tm.out(() => (element.hidden = true)); + } else { + element.hidden = false; + element.__tm.in(); + } + } else { + element.hidden = hidden; + } +} + /** * @param {Element} element * @param {string} attribute diff --git a/packages/svelte/src/internal/client/dom/elements/transitions.js b/packages/svelte/src/internal/client/dom/elements/transitions.js index b473d0029d..ef89d9ecdc 100644 --- a/packages/svelte/src/internal/client/dom/elements/transitions.js +++ b/packages/svelte/src/internal/client/dom/elements/transitions.js @@ -5,7 +5,12 @@ import { active_effect, untrack } from '../../runtime.js'; import { loop } from '../../loop.js'; import { should_intro } from '../../render.js'; import { current_each_item } from '../blocks/each.js'; -import { TRANSITION_GLOBAL, TRANSITION_IN, TRANSITION_OUT } from '../../../../constants.js'; +import { + TRANSITION_GLOBAL, + TRANSITION_HIDDEN, + TRANSITION_IN, + TRANSITION_OUT +} from '../../../../constants.js'; import { BLOCK_EFFECT, EFFECT_RAN, EFFECT_TRANSPARENT } from '../../constants.js'; import { queue_micro_task } from '../task.js'; @@ -169,6 +174,7 @@ export function transition(flags, element, get_fn, get_params) { var is_outro = (flags & TRANSITION_OUT) !== 0; var is_both = is_intro && is_outro; var is_global = (flags & TRANSITION_GLOBAL) !== 0; + var is_hidden = (flags & TRANSITION_HIDDEN) !== 0; /** @type {'in' | 'out' | 'both'} */ var direction = is_both ? 'both' : is_intro ? 'in' : 'out'; @@ -243,6 +249,12 @@ export function transition(flags, element, get_fn, get_params) { } }; + if (is_hidden) { + // @ts-expect-error + element.__tm = transition; + return; + } + var e = /** @type {Effect} */ (active_effect); (e.transitions ??= []).push(transition); diff --git a/packages/svelte/src/internal/client/index.js b/packages/svelte/src/internal/client/index.js index 306fc69ca7..8eff6e88a6 100644 --- a/packages/svelte/src/internal/client/index.js +++ b/packages/svelte/src/internal/client/index.js @@ -33,7 +33,8 @@ export { set_xlink_attribute, handle_lazy_img, set_value, - set_checked + set_checked, + set_hidden } from './dom/elements/attributes.js'; export { set_class, set_svg_class, set_mathml_class, toggle_class } from './dom/elements/class.js'; export { apply, event, delegate, replay_events } from './dom/elements/events.js'; diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index e64abef0c5..4fe73c1515 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -1060,7 +1060,7 @@ declare module 'svelte/compiler' { name: string; /** The 'y' in `transition:x={y}` */ expression: null | Expression; - modifiers: Array<'local' | 'global'>; + modifiers: Array<'local' | 'global' | 'hidden'>; /** True if this is a `transition:` or `in:` directive */ intro: boolean; /** True if this is a `transition:` or `out:` directive */