feat: allow dom elements as `svelte:element` `this` attribute

svelte-element-element
paoloricciuti 6 months ago
parent e2bbc560e4
commit 5385faf360

@ -0,0 +1,5 @@
---
'svelte': minor
---
feat: allow dom elements as `svelte:element` `this` attribute

@ -26,7 +26,7 @@ import { is_raw_text_element } from '../../../../utils.js';
/** /**
* @param {Comment | Element} node * @param {Comment | Element} node
* @param {() => string} get_tag * @param {() => string | HTMLElement | SVGElement} get_tag
* @param {boolean} is_svg * @param {boolean} is_svg
* @param {undefined | ((element: Element, anchor: Node | null) => void)} render_fn, * @param {undefined | ((element: Element, anchor: Node | null) => void)} render_fn,
* @param {undefined | (() => string)} get_namespace * @param {undefined | (() => string)} get_namespace
@ -42,10 +42,10 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio
var filename = DEV && location && component_context?.function[FILENAME]; var filename = DEV && location && component_context?.function[FILENAME];
/** @type {string | null} */ /** @type {string | HTMLElement | SVGElement | null} */
var tag; var tag;
/** @type {string | null} */ /** @type {string | HTMLElement | SVGElement | null} */
var current_tag; var current_tag;
/** @type {null | Element} */ /** @type {null | Element} */
@ -100,9 +100,11 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio
effect = branch(() => { effect = branch(() => {
element = hydrating element = hydrating
? /** @type {Element} */ (element) ? /** @type {Element} */ (element)
: ns : typeof next_tag === 'string'
? document.createElementNS(ns, next_tag) ? ns
: document.createElement(next_tag); ? document.createElementNS(ns, next_tag)
: document.createElement(next_tag)
: next_tag;
if (DEV && location) { if (DEV && location) {
// @ts-expect-error // @ts-expect-error
@ -118,7 +120,10 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio
assign_nodes(element, element); assign_nodes(element, element);
if (render_fn) { if (render_fn) {
if (hydrating && is_raw_text_element(next_tag)) { if (
hydrating &&
is_raw_text_element(typeof next_tag === 'string' ? next_tag : next_tag.nodeName)
) {
// prevent hydration glitches // prevent hydration glitches
element.append(document.createComment('')); element.append(document.createComment(''));
} }

@ -7,13 +7,14 @@ import * as e from './errors.js';
export { invalid_default_snippet } from './errors.js'; export { invalid_default_snippet } from './errors.js';
/** /**
* @param {() => string} tag_fn * @param {() => string | HTMLElement | SVGElement} tag_fn
* @returns {void} * @returns {void}
*/ */
export function validate_void_dynamic_element(tag_fn) { export function validate_void_dynamic_element(tag_fn) {
const tag = tag_fn(); const tag = tag_fn();
if (tag && is_void(tag)) { const tag_name = typeof tag === 'string' ? tag : tag?.tagName;
w.dynamic_void_element_content(tag); if (tag_name && is_void(tag_name)) {
w.dynamic_void_element_content(tag_name);
} }
} }
@ -21,7 +22,8 @@ export function validate_void_dynamic_element(tag_fn) {
export function validate_dynamic_element_tag(tag_fn) { export function validate_dynamic_element_tag(tag_fn) {
const tag = tag_fn(); const tag = tag_fn();
const is_string = typeof tag === 'string'; const is_string = typeof tag === 'string';
if (tag && !is_string) { const is_element = tag instanceof HTMLElement || tag instanceof SVGElement;
if (tag && !(is_string || is_element)) {
e.svelte_element_invalid_this_value(); e.svelte_element_invalid_this_value();
} }
} }

@ -0,0 +1,8 @@
import { test } from '../../test';
export default test({
ssrHtml: ``,
test({ assert, target }) {
assert.htmlEqual(target.innerHTML, `<div><b>children</b><p>children</p></div>`);
}
});

@ -0,0 +1,13 @@
<script>
let div = $state(null);
$effect(()=>{
const to_add = document.createElement("div");
to_add.innerHTML=`<b>children</b>`;
div = to_add;
})
</script>
<svelte:element this={div}>
<p>children</p>
</svelte:element>

@ -0,0 +1,8 @@
import { test } from '../../test';
export default test({
ssrHtml: `<div><p>children</p></div>`,
test({ assert, target }) {
assert.htmlEqual(target.innerHTML, `<div><b>children</b><p>children</p></div>`);
}
});

@ -0,0 +1,13 @@
<script>
let div = $state(null);
$effect(()=>{
const to_add = document.createElement("div");
to_add.innerHTML=`<b>children</b>`;
div = to_add;
})
</script>
<svelte:element this={div ?? "div"}>
<p>children</p>
</svelte:element>
Loading…
Cancel
Save