diff --git a/packages/svelte/src/internal/client/dom/blocks/svelte-element.js b/packages/svelte/src/internal/client/dom/blocks/svelte-element.js index 47dfe7707d..6df020d2d7 100644 --- a/packages/svelte/src/internal/client/dom/blocks/svelte-element.js +++ b/packages/svelte/src/internal/client/dom/blocks/svelte-element.js @@ -7,7 +7,7 @@ import { set_hydrate_node, set_hydrating } from '../hydration.js'; -import { create_text, get_first_child } from '../operations.js'; +import { create_element, create_text, get_first_child } from '../operations.js'; import { block, teardown } from '../../reactivity/effects.js'; import { set_should_intro } from '../../render.js'; import { active_effect } from '../../runtime.js'; @@ -57,7 +57,11 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio block(() => { const next_tag = get_tag() || null; - var ns = get_namespace ? get_namespace() : is_svg || next_tag === 'svg' ? NAMESPACE_SVG : null; + var ns = get_namespace + ? get_namespace() + : is_svg || next_tag === 'svg' + ? NAMESPACE_SVG + : undefined; if (next_tag === null) { branches.ensure(null, null); @@ -67,11 +71,7 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio branches.ensure(next_tag, (anchor) => { if (next_tag) { - element = hydrating - ? /** @type {Element} */ (element) - : ns - ? document.createElementNS(ns, next_tag) - : document.createElement(next_tag); + element = hydrating ? /** @type {Element} */ (element) : create_element(next_tag, ns); if (DEV && location) { // @ts-expect-error diff --git a/packages/svelte/src/internal/client/dom/css.js b/packages/svelte/src/internal/client/dom/css.js index 8e6faa0e32..74bf2d49f9 100644 --- a/packages/svelte/src/internal/client/dom/css.js +++ b/packages/svelte/src/internal/client/dom/css.js @@ -1,6 +1,7 @@ import { DEV } from 'esm-env'; import { register_style } from '../dev/css.js'; import { effect } from '../reactivity/effects.js'; +import { create_element } from './operations.js'; /** * @param {Node} anchor @@ -18,7 +19,7 @@ export function append_styles(anchor, css) { // Always querying the DOM is roughly the same perf as additionally checking for presence in a map first assuming // that you'll get cache hits half of the time, so we just always query the dom for simplicity and code savings. if (!target.querySelector('#' + css.hash)) { - const style = document.createElement('style'); + const style = create_element('style'); style.id = css.hash; style.textContent = css.code; diff --git a/packages/svelte/src/internal/client/dom/elements/custom-element.js b/packages/svelte/src/internal/client/dom/elements/custom-element.js index 40d3d68ec0..8316fa7656 100644 --- a/packages/svelte/src/internal/client/dom/elements/custom-element.js +++ b/packages/svelte/src/internal/client/dom/elements/custom-element.js @@ -2,6 +2,7 @@ import { createClassComponent } from '../../../../legacy/legacy-client.js'; import { effect_root, render_effect } from '../../reactivity/effects.js'; import { append } from '../template.js'; import { define_property, get_descriptor, object_keys } from '../../../shared/utils.js'; +import { create_element } from '../operations.js'; /** * @typedef {Object} CustomElementPropDefinition @@ -103,7 +104,7 @@ if (typeof HTMLElement === 'function') { * @param {Element} anchor */ return (anchor) => { - const slot = document.createElement('slot'); + const slot = create_element('slot'); if (name !== 'default') slot.name = name; append(anchor, slot); diff --git a/packages/svelte/src/internal/client/dom/elements/customizable-select.js b/packages/svelte/src/internal/client/dom/elements/customizable-select.js index 1858565d2a..b9f20f63a8 100644 --- a/packages/svelte/src/internal/client/dom/elements/customizable-select.js +++ b/packages/svelte/src/internal/client/dom/elements/customizable-select.js @@ -1,5 +1,5 @@ import { hydrating, reset, set_hydrate_node, set_hydrating } from '../hydration.js'; -import { create_comment } from '../operations.js'; +import { create_comment, create_element } from '../operations.js'; import { attach } from './attachments.js'; /** @type {boolean | null} */ @@ -13,7 +13,7 @@ let supported = null; */ function is_supported() { if (supported === null) { - var select = document.createElement('select'); + var select = create_element('select'); select.innerHTML = ''; supported = /** @type {Element} */ (select.firstChild)?.firstChild?.nodeType === 1; } diff --git a/packages/svelte/src/internal/client/dom/operations.js b/packages/svelte/src/internal/client/dom/operations.js index 61a48bcbfb..876f039a0e 100644 --- a/packages/svelte/src/internal/client/dom/operations.js +++ b/packages/svelte/src/internal/client/dom/operations.js @@ -7,6 +7,7 @@ import { active_effect } from '../runtime.js'; import { async_mode_flag } from '../../flags/index.js'; import { TEXT_NODE, EFFECT_RAN } from '#client/constants'; import { eager_block_effects } from '../reactivity/batch.js'; +import { NAMESPACE_HTML } from '../../../constants.js'; // export these for reference in the compiled code, making global name deduplication unnecessary /** @type {Window} */ @@ -231,18 +232,17 @@ export function should_defer_append() { } /** - * - * @param {string} tag + * @template {keyof HTMLElementTagNameMap | string} T + * @param {T} tag * @param {string} [namespace] * @param {string} [is] - * @returns + * @returns {T extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[T] : Element} */ export function create_element(tag, namespace, is) { let options = is ? { is } : undefined; - if (namespace) { - return document.createElementNS(namespace, tag, options); - } - return document.createElement(tag, options); + return /** @type {T extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[T] : Element} */ ( + document.createElementNS(namespace ?? NAMESPACE_HTML, tag, options) + ); } export function create_fragment() { diff --git a/packages/svelte/src/internal/client/dom/reconciler.js b/packages/svelte/src/internal/client/dom/reconciler.js index 8d3b5c0495..54f2e23c6e 100644 --- a/packages/svelte/src/internal/client/dom/reconciler.js +++ b/packages/svelte/src/internal/client/dom/reconciler.js @@ -1,6 +1,8 @@ +import { create_element } from './operations.js'; + /** @param {string} html */ export function create_fragment_from_html(html) { - var elem = document.createElement('template'); + var elem = create_element('template'); elem.innerHTML = html.replaceAll('', ''); // XHTML compliance return elem.content; } diff --git a/packages/svelte/src/internal/client/dom/template.js b/packages/svelte/src/internal/client/dom/template.js index 567fbeabf0..9c2f2fe82f 100644 --- a/packages/svelte/src/internal/client/dom/template.js +++ b/packages/svelte/src/internal/client/dom/template.js @@ -275,7 +275,7 @@ function run_scripts(node) { const effect = /** @type {Effect & { nodes: EffectNodes }} */ (active_effect); for (const script of scripts) { - const clone = document.createElement('script'); + const clone = create_element('script'); for (var attribute of script.attributes) { clone.setAttribute(attribute.name, attribute.value); }