client-side named slots

pull/787/head
Rich Harris 7 years ago
parent 7a8c8fd577
commit efe25555cf

@ -72,7 +72,7 @@ export default function dom(
generator.stylesheet.warnOnUnusedSelectors(options.onwarn);
parsed.html.children.forEach((node: Node) => {
visit(generator, block, state, node, []);
visit(generator, block, state, node, [], []);
});
const builder = new CodeBuilder();

@ -1,3 +1,7 @@
import { DomGenerator } from './index';
import Block from './Block';
import { Node } from '../../interfaces';
export interface State {
name?: string;
namespace: string;
@ -11,3 +15,12 @@ export interface State {
usesComponent?: boolean;
selectBindingDependencies?: string[];
}
export type Visitor = (
generator: DomGenerator,
block: Block,
state: State,
node: Node,
elementStack: Node[],
componentStack: Node[]
) => void;

@ -348,7 +348,7 @@ const preprocessors = {
if (slot) {
// TODO validate slots — no nesting, no dynamic names...
const component = componentStack[componentStack.length - 1];
component._slots.add(slot);
component._slots.add(slot.value[0].data);
}
const name = block.getUniqueName(
@ -376,16 +376,9 @@ const preprocessors = {
(node.name === ':Self' ? generator.name : node.name).toLowerCase()
);
// node._block = block.child({
// name: generator.getUniqueName(`create_${name}_yield_fragment`),
// });
if (node.children) node._slots = new Set(['default']); // TODO only include default if there are unslotted children
// generator.blocks.push(node._block);
preprocessChildren(generator, block, node._state, node, inEachBlock, elementStack, componentStack.concat(node), stripWhitespace, nextSibling);
// block.addDependencies(node._block.dependencies);
// node._block.hasUpdateMethod = node._block.dependencies.size > 0;
} else {
if (node.name === 'pre' || node.name === 'textarea') stripWhitespace = false;
preprocessChildren(generator, block, node._state, node, inEachBlock, elementStack.concat(node), componentStack, stripWhitespace, nextSibling);

@ -9,8 +9,9 @@ export default function visit(
block: Block,
state: State,
node: Node,
elementStack: Node[]
elementStack: Node[],
componentStack: Node[]
) {
const visitor = visitors[node.type];
visitor(generator, block, state, node, elementStack);
visitor(generator, block, state, node, elementStack, componentStack);
}

@ -43,7 +43,8 @@ export default function visitComponent(
block: Block,
state: State,
node: Node,
elementStack: Node[]
elementStack: Node[],
componentStack: Node[]
) {
generator.hasComponents = true;
@ -56,7 +57,7 @@ export default function visitComponent(
componentInitProperties.push(`slots: { ${slots.join(', ')} }`);
node.children.forEach((child: Node) => {
visit(generator, block, node._state, child, elementStack);
visit(generator, block, node._state, child, elementStack, componentStack.concat(node));
});
}

@ -10,7 +10,8 @@ export default function visitEachBlock(
block: Block,
state: State,
node: Node,
elementStack: Node[]
elementStack: Node[],
componentStack: Node[]
) {
const each_block = generator.getUniqueName(`each_block`);
const create_each_block = node._block.name;
@ -125,12 +126,12 @@ export default function visitEachBlock(
}
node.children.forEach((child: Node) => {
visit(generator, node._block, node._state, child, elementStack);
visit(generator, node._block, node._state, child, elementStack, componentStack);
});
if (node.else) {
node.else.children.forEach((child: Node) => {
visit(generator, node.else._block, node.else._state, child, elementStack);
visit(generator, node.else._block, node.else._state, child, elementStack, componentStack);
});
}
}

@ -37,7 +37,8 @@ export default function visitElement(
block: Block,
state: State,
node: Node,
elementStack: Node[]
elementStack: Node[],
componentStack: Node[]
) {
if (node.name in meta) {
return meta[node.name](generator, block, node);
@ -48,13 +49,18 @@ export default function visitElement(
}
if (generator.components.has(node.name) || node.name === ':Self') {
return visitComponent(generator, block, state, node, elementStack);
return visitComponent(generator, block, state, node, elementStack, componentStack);
}
const childState = node._state;
const name = childState.parentNode;
const isToplevel = !state.parentNode;
const slot = node.attributes.find((attribute: Node) => attribute.name === 'slot');
const parentNode = slot ?
`${componentStack[componentStack.length - 1]._state.name}._slotted.${slot.value[0].data}` : // TODO this looks bonkers
state.parentNode;
const isToplevel = !parentNode;
block.addVariable(name);
block.builders.create.addLine(
@ -77,9 +83,9 @@ export default function visitElement(
`);
}
if (state.parentNode) {
if (parentNode) {
block.builders.mount.addLine(
`@appendNode( ${name}, ${state.parentNode} );`
`@appendNode( ${name}, ${parentNode} );`
);
} else {
block.builders.mount.addLine(`@insertNode( ${name}, #target, anchor );`);
@ -195,7 +201,7 @@ export default function visitElement(
}
node.children.forEach((child: Node) => {
visit(generator, block, childState, child, elementStack.concat(node));
visit(generator, block, childState, child, elementStack.concat(node), componentStack);
});
if (node.lateUpdate) {

@ -20,7 +20,8 @@ function getBranches(
block: Block,
state: State,
node: Node,
elementStack: Node[]
elementStack: Node[],
componentStack: Node[]
) {
const branches = [
{
@ -32,11 +33,11 @@ function getBranches(
},
];
visitChildren(generator, block, state, node, elementStack);
visitChildren(generator, block, state, node, elementStack, componentStack);
if (isElseIf(node.else)) {
branches.push(
...getBranches(generator, block, state, node.else.children[0], elementStack)
...getBranches(generator, block, state, node.else.children[0], elementStack, componentStack)
);
} else {
branches.push({
@ -48,7 +49,7 @@ function getBranches(
});
if (node.else) {
visitChildren(generator, block, state, node.else, elementStack);
visitChildren(generator, block, state, node.else, elementStack, componentStack);
}
}
@ -60,10 +61,11 @@ function visitChildren(
block: Block,
state: State,
node: Node,
elementStack: Node[]
elementStack: Node[],
componentStack: Node[]
) {
node.children.forEach((child: Node) => {
visit(generator, node._block, node._state, child, elementStack);
visit(generator, node._block, node._state, child, elementStack, componentStack);
});
}
@ -72,7 +74,8 @@ export default function visitIfBlock(
block: Block,
state: State,
node: Node,
elementStack: Node[]
elementStack: Node[],
componentStack: Node[]
) {
const name = generator.getUniqueName(`if_block`);
const anchor = node.needsAnchor
@ -80,7 +83,7 @@ export default function visitIfBlock(
: (node.next && node.next._state.name) || 'null';
const params = block.params.join(', ');
const branches = getBranches(generator, block, state, node, elementStack);
const branches = getBranches(generator, block, state, node, elementStack, componentStack);
const hasElse = isElseBranch(branches[branches.length - 1]);
const if_name = hasElse ? '' : `if ( ${name} ) `;

@ -11,7 +11,8 @@ export default function visitSlot(
block: Block,
state: State,
node: Node,
elementStack: Node[]
elementStack: Node[],
componentStack: Node[]
) {
const slotName = getStaticAttributeValue(node, 'name') || 'default';
const name = block.getUniqueName(`slot_${slotName}`);
@ -27,13 +28,19 @@ export default function visitSlot(
state.parentNode
);
if (slotName !== 'default') {
block.builders.hydrate.addBlock(deindent`
@setAttribute(${name}, 'name', '${slotName}');
`);
}
block.builders.create.pushCondition(`!${content_name}`);
block.builders.mount.pushCondition(`!${content_name}`);
block.builders.unmount.pushCondition(`!${content_name}`);
block.builders.destroy.pushCondition(`!${content_name}`);
node.children.forEach((child: Node) => {
visit(generator, block, node._state, child, elementStack.concat(node));
visit(generator, block, node._state, child, elementStack.concat(node), componentStack);
});
block.builders.create.popCondition();

@ -5,8 +5,9 @@ import MustacheTag from './MustacheTag';
import RawMustacheTag from './RawMustacheTag';
import Text from './Text';
import YieldTag from './YieldTag';
import { Visitor } from '../interfaces';
export default {
const visitors: Record<string, Visitor> = {
EachBlock,
Element,
IfBlock,
@ -15,3 +16,5 @@ export default {
Text,
YieldTag,
};
export default visitors;

@ -0,0 +1,5 @@
<div>
<slot/>
<slot name='bar'/>
<slot name='foo'/>
</div>

@ -0,0 +1,10 @@
export default {
solo: true,
html: `
<div>
<slot>Hello</slot>
<slot name='bar'><p slot='bar'>bar</p></slot>
<slot name='foo'><p slot='foo'>foo</p></slot>
</div>
`
};

@ -0,0 +1,16 @@
<Nested>
Hello
<p slot='foo'>foo</p>
<p slot='bar'>bar</p>
</Nested>
<script>
import Nested from './Nested.html';
export default {
components: {
Nested
}
};
</script>
Loading…
Cancel
Save