dont slot elements inside custom elements - fixes #827

pull/847/head
Rich Harris 7 years ago
parent 5ed74df4d3
commit 3879d52616

@ -2,6 +2,7 @@ import Block from './Block';
import { trimStart, trimEnd } from '../../utils/trim'; import { trimStart, trimEnd } from '../../utils/trim';
import { assign } from '../../shared/index.js'; import { assign } from '../../shared/index.js';
import getStaticAttributeValue from '../../utils/getStaticAttributeValue'; import getStaticAttributeValue from '../../utils/getStaticAttributeValue';
import isChildOfComponent from '../shared/utils/isChildOfComponent';
import { DomGenerator } from './index'; import { DomGenerator } from './index';
import { Node } from '../../interfaces'; import { Node } from '../../interfaces';
import { State } from './interfaces'; import { State } from './interfaces';
@ -340,7 +341,8 @@ const preprocessors = {
}); });
} else { } else {
const slot = getStaticAttributeValue(node, 'slot'); const slot = getStaticAttributeValue(node, 'slot');
if (slot) { if (slot && isChildOfComponent(node, generator)) {
node.slotted = true;
// TODO validate slots — no nesting, no dynamic names... // TODO validate slots — no nesting, no dynamic names...
const component = componentStack[componentStack.length - 1]; const component = componentStack[componentStack.length - 1];
component._slots.add(slot); component._slots.add(slot);

@ -63,7 +63,7 @@ export default function visitElement(
const name = childState.parentNode; const name = childState.parentNode;
const slot = node.attributes.find((attribute: Node) => attribute.name === 'slot'); 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 `${componentStack[componentStack.length - 1].var}._slotted.${slot.value[0].data}` : // TODO this looks bonkers
state.parentNode; state.parentNode;

@ -1,3 +1,5 @@
import getStaticAttributeValue from '../../utils/getStaticAttributeValue';
import isChildOfComponent from '../shared/utils/isChildOfComponent';
import { SsrGenerator } from './index'; import { SsrGenerator } from './index';
import { Node } from '../../interfaces'; import { Node } from '../../interfaces';
@ -62,6 +64,11 @@ const preprocessors = {
if (!isComponent) { if (!isComponent) {
generator.stylesheet.apply(node, elementStack); generator.stylesheet.apply(node, elementStack);
const slot = getStaticAttributeValue(node, 'slot');
if (slot && isChildOfComponent(node, generator)) {
node.slotted = true;
}
} }
if (node.children.length) { if (node.children.length) {
@ -80,6 +87,8 @@ function preprocessChildren(
elementStack: Node[] elementStack: Node[]
) { ) {
node.children.forEach((child: Node, i: number) => { node.children.forEach((child: Node, i: number) => {
child.parent = node;
const preprocessor = preprocessors[child.type]; const preprocessor = preprocessors[child.type];
if (preprocessor) preprocessor(generator, child, elementStack); if (preprocessor) preprocessor(generator, child, elementStack);
}); });

@ -47,8 +47,8 @@ export default function visitElement(
let openingTag = `<${node.name}`; let openingTag = `<${node.name}`;
let textareaContents; // awkward special case let textareaContents; // awkward special case
if (node.slotted) {
const slot = node.attributes.find((attribute: Node) => attribute.name === 'slot'); const slot = node.attributes.find((attribute: Node) => attribute.name === 'slot');
if (slot) {
const slotName = slot.value[0].data; const slotName = slot.value[0].data;
const appendTarget = generator.appendTargets[generator.appendTargets.length - 1]; const appendTarget = generator.appendTargets[generator.appendTargets.length - 1];
appendTarget.slotStack.push(slotName); appendTarget.slotStack.push(slotName);

@ -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`);
}
Loading…
Cancel
Save