From 85fec65a11efe54838e2fb962f9d7e3a5f315b25 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Wed, 26 Jun 2024 13:58:09 +0200 Subject: [PATCH] fix: allow slot attribute inside snippets Someone could render a snippet into a custom element, and therefore elements with slot attributes should be allowed within them and be treated as regular elements closes #12158 --- .changeset/seven-bees-tell.md | 5 +++++ .../compiler/phases/2-analyze/validation.js | 10 ++++++++- .../Component.svelte | 18 +++++++++++++++ .../custom-element-slot-in-snippet/_config.js | 22 +++++++++++++++++++ .../main.svelte | 10 +++++++++ 5 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 .changeset/seven-bees-tell.md create mode 100644 packages/svelte/tests/runtime-runes/samples/custom-element-slot-in-snippet/Component.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/custom-element-slot-in-snippet/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/custom-element-slot-in-snippet/main.svelte diff --git a/.changeset/seven-bees-tell.md b/.changeset/seven-bees-tell.md new file mode 100644 index 0000000000..753a93add2 --- /dev/null +++ b/.changeset/seven-bees-tell.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: allow slot attribute inside snippets diff --git a/packages/svelte/src/compiler/phases/2-analyze/validation.js b/packages/svelte/src/compiler/phases/2-analyze/validation.js index 8ae8c264bd..f4778e4322 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/validation.js +++ b/packages/svelte/src/compiler/phases/2-analyze/validation.js @@ -256,8 +256,16 @@ function validate_attribute_name(attribute) { * @param {boolean} is_component */ function validate_slot_attribute(context, attribute, is_component = false) { + const parent = context.path.at(-2); let owner = undefined; + if (parent?.type === 'SnippetBlock') { + if (!is_text_attribute(attribute)) { + e.slot_attribute_invalid(attribute); + } + return; + } + let i = context.path.length; while (i--) { const ancestor = context.path[i]; @@ -283,7 +291,7 @@ function validate_slot_attribute(context, attribute, is_component = false) { owner.type === 'SvelteComponent' || owner.type === 'SvelteSelf' ) { - if (owner !== context.path.at(-2)) { + if (owner !== parent) { e.slot_attribute_invalid_placement(attribute); } diff --git a/packages/svelte/tests/runtime-runes/samples/custom-element-slot-in-snippet/Component.svelte b/packages/svelte/tests/runtime-runes/samples/custom-element-slot-in-snippet/Component.svelte new file mode 100644 index 0000000000..568baa0be9 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/custom-element-slot-in-snippet/Component.svelte @@ -0,0 +1,18 @@ + + + + + + {@render children()} + diff --git a/packages/svelte/tests/runtime-runes/samples/custom-element-slot-in-snippet/_config.js b/packages/svelte/tests/runtime-runes/samples/custom-element-slot-in-snippet/_config.js new file mode 100644 index 0000000000..d40d8f6c72 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/custom-element-slot-in-snippet/_config.js @@ -0,0 +1,22 @@ +import { test } from '../../test'; + +export default test({ + mode: ['client', 'server'], + html: `Default Slotted`, + test({ target, assert }) { + const shadowRoot = /** @type {ShadowRoot} */ ( + target.querySelector('my-custom-element')?.shadowRoot + ); + const [defaultSlot, namedSlot] = shadowRoot.querySelectorAll('slot'); + const assignedDefaultNodes = defaultSlot.assignedNodes(); + const assignedNamedNodes = namedSlot.assignedNodes(); + + assert.equal(assignedDefaultNodes.length, 1); + assert.equal(assignedNamedNodes.length, 1); + assert.htmlEqual(assignedDefaultNodes[0].textContent || '', `Default`); + assert.htmlEqual( + /** @type {HTMLElement} */ (assignedNamedNodes[0]).outerHTML, + `Slotted` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/custom-element-slot-in-snippet/main.svelte b/packages/svelte/tests/runtime-runes/samples/custom-element-slot-in-snippet/main.svelte new file mode 100644 index 0000000000..6902623f75 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/custom-element-slot-in-snippet/main.svelte @@ -0,0 +1,10 @@ + + + + {#snippet children()} + Default + Slotted + {/snippet} +