diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index 1117f3cdb7..9761e6ad7b 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -991,7 +991,7 @@ function serialize_inline_component(node, component_name, context) { const prev = fn; fn = (node_id) => b.call( - '$.cssProps', + '$.css_props', node_id, // TODO would be great to do this at runtime instead. Svelte 4 also can't handle cases today // where it's not statically determinable whether the component is used in a svg or html context diff --git a/packages/svelte/src/internal/client/dom/blocks/css-props.js b/packages/svelte/src/internal/client/dom/blocks/css-props.js new file mode 100644 index 0000000000..43969a1fa2 --- /dev/null +++ b/packages/svelte/src/internal/client/dom/blocks/css-props.js @@ -0,0 +1,58 @@ +import { namespace_svg } from '../../../../constants.js'; +import { current_hydration_fragment, hydrate_block_anchor, hydrating } from '../../hydration.js'; +import { empty } from '../../operations.js'; +import { render_effect } from '../../reactivity/computations.js'; +import { insert, remove } from '../../reconciler.js'; +import { push_destroy_fn } from '../../runtime.js'; + +/** + * @param {Element | Text | Comment} anchor + * @param {boolean} is_html + * @param {() => Record} props + * @param {(anchor: Element | Text | Comment) => any} component + * @returns {void} + */ +export function css_props(anchor, is_html, props, component) { + hydrate_block_anchor(anchor); + + /** @type {HTMLElement | SVGElement} */ + let tag; + + /** @type {Text | Comment} */ + let component_anchor; + if (hydrating) { + // Hydration: css props element is surrounded by a ssr comment ... + tag = /** @type {HTMLElement | SVGElement} */ (current_hydration_fragment[0]); + // ... and the child(ren) of the css props element is also surround by a ssr comment + component_anchor = /** @type {Comment} */ (tag.firstChild); + } else { + if (is_html) { + tag = document.createElement('div'); + tag.style.display = 'contents'; + } else { + tag = document.createElementNS(namespace_svg, 'g'); + } + insert(tag, null, anchor); + component_anchor = empty(); + tag.appendChild(component_anchor); + } + component(component_anchor); + + /** @type {Record} */ + let current_props = {}; + const effect = render_effect(() => { + const next_props = props(); + for (const key in current_props) { + if (!(key in next_props)) { + tag.style.removeProperty(key); + } + } + for (const key in next_props) { + tag.style.setProperty(key, next_props[key]); + } + current_props = next_props; + }); + push_destroy_fn(effect, () => { + remove(tag); + }); +} diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index 7fea35bc5d..4981915717 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -24,7 +24,6 @@ import { create_fragment_from_html, create_fragment_with_script_from_html, insert, - reconcile_html, remove } from './reconciler.js'; import { @@ -1511,58 +1510,6 @@ export function head(fn) { } } -/** - * @param {Element | Text | Comment} anchor - * @param {boolean} is_html - * @param {() => Record} props - * @param {(anchor: Element | Text | Comment) => any} component - * @returns {void} - */ -export function cssProps(anchor, is_html, props, component) { - hydrate_block_anchor(anchor); - - /** @type {HTMLElement | SVGElement} */ - let tag; - - /** @type {Text | Comment} */ - let component_anchor; - if (hydrating) { - // Hydration: css props element is surrounded by a ssr comment ... - tag = /** @type {HTMLElement | SVGElement} */ (current_hydration_fragment[0]); - // ... and the child(ren) of the css props element is also surround by a ssr comment - component_anchor = /** @type {Comment} */ (tag.firstChild); - } else { - if (is_html) { - tag = document.createElement('div'); - tag.style.display = 'contents'; - } else { - tag = document.createElementNS(namespace_svg, 'g'); - } - insert(tag, null, anchor); - component_anchor = empty(); - tag.appendChild(component_anchor); - } - component(component_anchor); - - /** @type {Record} */ - let current_props = {}; - const effect = render_effect(() => { - const next_props = props(); - for (const key in current_props) { - if (!(key in next_props)) { - tag.style.removeProperty(key); - } - } - for (const key in next_props) { - tag.style.setProperty(key, next_props[key]); - } - current_props = next_props; - }); - push_destroy_fn(effect, () => { - remove(tag); - }); -} - /** * @param {unknown} value * @returns {string} diff --git a/packages/svelte/src/internal/index.js b/packages/svelte/src/internal/index.js index 88117a9877..9583a03506 100644 --- a/packages/svelte/src/internal/index.js +++ b/packages/svelte/src/internal/index.js @@ -22,6 +22,7 @@ export { } from './client/runtime.js'; export * from './client/dev/ownership.js'; export { await_block as await } from './client/dom/blocks/await.js'; +export { css_props } from './client/dom/blocks/css-props.js'; export { if_block as if } from './client/dom/blocks/if.js'; export { html } from './client/dom/blocks/html.js'; export { key_block as key } from './client/dom/blocks/key.js';