From 3879d52616eac67883c6853ad15b283b47ef6f11 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 13 Sep 2017 14:31:01 -0400 Subject: [PATCH] dont slot elements inside custom elements - fixes #827 --- src/generators/dom/preprocess.ts | 4 +++- src/generators/dom/visitors/Element/Element.ts | 2 +- src/generators/server-side-rendering/preprocess.ts | 9 +++++++++ .../server-side-rendering/visitors/Element.ts | 4 ++-- src/generators/shared/utils/isChildOfComponent.ts | 13 +++++++++++++ 5 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 src/generators/shared/utils/isChildOfComponent.ts diff --git a/src/generators/dom/preprocess.ts b/src/generators/dom/preprocess.ts index 1e71361f31..1fdfababeb 100644 --- a/src/generators/dom/preprocess.ts +++ b/src/generators/dom/preprocess.ts @@ -2,6 +2,7 @@ import Block from './Block'; import { trimStart, trimEnd } from '../../utils/trim'; import { assign } from '../../shared/index.js'; import getStaticAttributeValue from '../../utils/getStaticAttributeValue'; +import isChildOfComponent from '../shared/utils/isChildOfComponent'; import { DomGenerator } from './index'; import { Node } from '../../interfaces'; import { State } from './interfaces'; @@ -340,7 +341,8 @@ const preprocessors = { }); } else { const slot = getStaticAttributeValue(node, 'slot'); - if (slot) { + if (slot && isChildOfComponent(node, generator)) { + node.slotted = true; // TODO validate slots — no nesting, no dynamic names... const component = componentStack[componentStack.length - 1]; component._slots.add(slot); diff --git a/src/generators/dom/visitors/Element/Element.ts b/src/generators/dom/visitors/Element/Element.ts index 4fa5a04b18..70e8ff280e 100644 --- a/src/generators/dom/visitors/Element/Element.ts +++ b/src/generators/dom/visitors/Element/Element.ts @@ -63,7 +63,7 @@ export default function visitElement( const name = childState.parentNode; const slot = node.attributes.find((attribute: Node) => attribute.name === 'slot'); - const parentNode = slot ? + const parentNode = node.slotted ? `${componentStack[componentStack.length - 1].var}._slotted.${slot.value[0].data}` : // TODO this looks bonkers state.parentNode; diff --git a/src/generators/server-side-rendering/preprocess.ts b/src/generators/server-side-rendering/preprocess.ts index 1f6effc5f7..a8a790f754 100644 --- a/src/generators/server-side-rendering/preprocess.ts +++ b/src/generators/server-side-rendering/preprocess.ts @@ -1,3 +1,5 @@ +import getStaticAttributeValue from '../../utils/getStaticAttributeValue'; +import isChildOfComponent from '../shared/utils/isChildOfComponent'; import { SsrGenerator } from './index'; import { Node } from '../../interfaces'; @@ -62,6 +64,11 @@ const preprocessors = { if (!isComponent) { generator.stylesheet.apply(node, elementStack); + + const slot = getStaticAttributeValue(node, 'slot'); + if (slot && isChildOfComponent(node, generator)) { + node.slotted = true; + } } if (node.children.length) { @@ -80,6 +87,8 @@ function preprocessChildren( elementStack: Node[] ) { node.children.forEach((child: Node, i: number) => { + child.parent = node; + const preprocessor = preprocessors[child.type]; if (preprocessor) preprocessor(generator, child, elementStack); }); diff --git a/src/generators/server-side-rendering/visitors/Element.ts b/src/generators/server-side-rendering/visitors/Element.ts index 3a1c070f26..058ba7a0a7 100644 --- a/src/generators/server-side-rendering/visitors/Element.ts +++ b/src/generators/server-side-rendering/visitors/Element.ts @@ -47,8 +47,8 @@ export default function visitElement( let openingTag = `<${node.name}`; let textareaContents; // awkward special case - const slot = node.attributes.find((attribute: Node) => attribute.name === 'slot'); - if (slot) { + if (node.slotted) { + const slot = node.attributes.find((attribute: Node) => attribute.name === 'slot'); const slotName = slot.value[0].data; const appendTarget = generator.appendTargets[generator.appendTargets.length - 1]; appendTarget.slotStack.push(slotName); diff --git a/src/generators/shared/utils/isChildOfComponent.ts b/src/generators/shared/utils/isChildOfComponent.ts new file mode 100644 index 0000000000..3246d27d35 --- /dev/null +++ b/src/generators/shared/utils/isChildOfComponent.ts @@ -0,0 +1,13 @@ +import { Node } from '../../../interfaces'; +import Generator from '../../Generator'; + +export default function isChildOfComponent(node: Node, generator: Generator) { + while (node = node.parent) { + if (node.type !== 'Element') continue; + if (generator.components.has(node.name)) return true; + if (/-/.test(node.name)) return false; + } + + // TODO do this in validation + throw new Error(`Element with a slot='...' attribute must be a descendant of a component or custom element`); +} \ No newline at end of file