mirror of https://github.com/sveltejs/svelte
commit
6fad3cbf9c
@ -0,0 +1,76 @@
|
||||
import { DomGenerator } from '../index';
|
||||
import deindent from '../../../utils/deindent';
|
||||
import visit from '../visit';
|
||||
import Block from '../Block';
|
||||
import getStaticAttributeValue from '../../shared/getStaticAttributeValue';
|
||||
import { Node } from '../../../interfaces';
|
||||
import { State } from '../interfaces';
|
||||
|
||||
export default function visitSlot(
|
||||
generator: DomGenerator,
|
||||
block: Block,
|
||||
state: State,
|
||||
node: Node,
|
||||
elementStack: Node[],
|
||||
componentStack: Node[]
|
||||
) {
|
||||
const slotName = getStaticAttributeValue(node, 'name') || 'default';
|
||||
generator.slots.add(slotName);
|
||||
|
||||
const content_name = block.getUniqueName(`slot_content_${slotName}`);
|
||||
block.addVariable(content_name, `#component._slotted.${slotName}`);
|
||||
|
||||
// TODO use surrounds as anchors where possible, a la if/each blocks
|
||||
const before = block.getUniqueName(`${content_name}_before`);
|
||||
const after = block.getUniqueName(`${content_name}_after`);
|
||||
block.addVariable(before);
|
||||
block.addVariable(after);
|
||||
|
||||
block.builders.create.pushCondition(`!${content_name}`);
|
||||
block.builders.hydrate.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, state, child, elementStack, componentStack);
|
||||
});
|
||||
|
||||
block.builders.create.popCondition();
|
||||
block.builders.hydrate.popCondition();
|
||||
block.builders.mount.popCondition();
|
||||
block.builders.unmount.popCondition();
|
||||
block.builders.destroy.popCondition();
|
||||
|
||||
// TODO can we use an else here?
|
||||
if (state.parentNode) {
|
||||
block.builders.mount.addBlock(deindent`
|
||||
if (${content_name}) {
|
||||
@appendNode(${before} || (${before} = @createComment()), ${state.parentNode});
|
||||
@appendNode(${content_name}, ${state.parentNode});
|
||||
@appendNode(${after} || (${after} = @createComment()), ${state.parentNode});
|
||||
}
|
||||
`);
|
||||
} else {
|
||||
block.builders.mount.addBlock(deindent`
|
||||
if (${content_name}) {
|
||||
@insertNode(${before} || (${before} = @createComment()), #target, anchor);
|
||||
@insertNode(${content_name}, #target, anchor);
|
||||
@insertNode(${after} || (${after} = @createComment()), #target, anchor);
|
||||
}
|
||||
`);
|
||||
}
|
||||
|
||||
// if the slot is unmounted, move nodes back into the document fragment,
|
||||
// so that it can be reinserted later
|
||||
// TODO so that this can work with public API, component._slotted should
|
||||
// be all fragments, derived from options.slots. Not === options.slots
|
||||
// TODO can we use an else here?
|
||||
block.builders.unmount.addBlock(deindent`
|
||||
if (${content_name}) {
|
||||
@reinsertBetween(${before}, ${after}, ${content_name});
|
||||
@detachNode(${before});
|
||||
@detachNode(${after});
|
||||
}
|
||||
`);
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
import visit from '../visit';
|
||||
import { SsrGenerator } from '../index';
|
||||
import Block from '../Block';
|
||||
import { Node } from '../../../interfaces';
|
||||
|
||||
export default function visitSlot(
|
||||
generator: SsrGenerator,
|
||||
block: Block,
|
||||
node: Node
|
||||
) {
|
||||
// TODO named slots
|
||||
const name = node.attributes.find((attribute: Node) => attribute.name);
|
||||
const slotName = name && name.value[0].data || 'default';
|
||||
|
||||
generator.append(`\${options && options.slotted && options.slotted.${slotName} ? options.slotted.${slotName}() : '`);
|
||||
|
||||
generator.elementDepth += 1;
|
||||
|
||||
node.children.forEach((child: Node) => {
|
||||
visit(generator, block, child);
|
||||
});
|
||||
|
||||
generator.elementDepth -= 1;
|
||||
|
||||
generator.append(`'}`);
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
import { SsrGenerator } from '../index';
|
||||
|
||||
export default function visitYieldTag(generator: SsrGenerator) {
|
||||
generator.append(`\${options && options.yield ? options.yield() : ''}`);
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
export default function repeat(str: string, i: number) {
|
||||
let result = '';
|
||||
while (i--) result += str;
|
||||
return result;
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
export default function spaces(i: number) {
|
||||
let result = '';
|
||||
while (i--) result += ' ';
|
||||
return result;
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
<p>
|
||||
<slot/>
|
||||
</p>
|
@ -0,0 +1,3 @@
|
||||
export default {
|
||||
html: '<p>Hello</p>'
|
||||
};
|
@ -0,0 +1,13 @@
|
||||
<Nested ref:nested>
|
||||
Hello
|
||||
</Nested>
|
||||
|
||||
<script>
|
||||
import Nested from './Nested.html';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Nested
|
||||
}
|
||||
};
|
||||
</script>
|
@ -0,0 +1,5 @@
|
||||
<div>
|
||||
<slot><p class='default'>default fallback content</p></slot>
|
||||
<slot name='bar'><p class='default'>bar fallback content</p></slot>
|
||||
<slot name='foo'><p class='default'>foo fallback content</p></slot>
|
||||
</div>
|
@ -0,0 +1,9 @@
|
||||
export default {
|
||||
html: `
|
||||
<div>
|
||||
<p>not fallback</p>
|
||||
<p class='default'>bar fallback content</p>
|
||||
<p class='default'>foo fallback content</p>
|
||||
</div>
|
||||
`
|
||||
};
|
@ -0,0 +1,13 @@
|
||||
<Nested ref:nested>
|
||||
<p>not fallback</p>
|
||||
</Nested>
|
||||
|
||||
<script>
|
||||
import Nested from './Nested.html';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Nested
|
||||
}
|
||||
};
|
||||
</script>
|
@ -0,0 +1,5 @@
|
||||
<div>
|
||||
<slot/>
|
||||
<slot name='bar'/>
|
||||
<slot name='foo'/>
|
||||
</div>
|
@ -0,0 +1,9 @@
|
||||
export default {
|
||||
html: `
|
||||
<div>
|
||||
Hello
|
||||
<p slot='bar'>bar</p>
|
||||
<p slot='foo'>foo</p>
|
||||
</div>
|
||||
`
|
||||
};
|
@ -0,0 +1,16 @@
|
||||
<Nested ref:nested>
|
||||
Hello
|
||||
|
||||
<p slot='foo'>foo</p>
|
||||
<p slot='bar'>bar</p>
|
||||
</Nested>
|
||||
|
||||
<script>
|
||||
import Nested from './Nested.html';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Nested
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,14 +1,17 @@
|
||||
<div>
|
||||
<Widget ref:widget>{{data}}</Widget>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
import Widget from './Widget.html'
|
||||
import Widget from './Widget.html';
|
||||
|
||||
export default {
|
||||
components: { Widget },
|
||||
|
||||
data() {
|
||||
return {
|
||||
data: "Hello"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@ -1,10 +1,19 @@
|
||||
export default {
|
||||
html: '<p>Hello Alice</p><p>Hello Bob</p><p>Hello Charles</p>',
|
||||
html: `
|
||||
<p>Hello Alice</p>
|
||||
<p>Hello Bob</p>
|
||||
<p>Hello Charles</p>
|
||||
`,
|
||||
|
||||
test ( assert, component, target ) {
|
||||
component.set({
|
||||
people: [ 'Alice', 'Charles', 'Bob' ]
|
||||
});
|
||||
assert.htmlEqual( target.innerHTML, `<p>Hello Alice</p><p>Hello Charles</p><p>Hello Bob</p>` );
|
||||
|
||||
assert.htmlEqual( target.innerHTML, `
|
||||
<p>Hello Alice</p>
|
||||
<p>Hello Charles</p>
|
||||
<p>Hello Bob</p>
|
||||
`);
|
||||
}
|
||||
};
|
||||
|
@ -1,3 +1,6 @@
|
||||
export default {
|
||||
html: '<p>Hello</p>'
|
||||
html: `
|
||||
<p>Hello
|
||||
|
||||
</p>`
|
||||
};
|
||||
|
@ -1 +1,3 @@
|
||||
<div><p>Hello</p></div>
|
||||
<div>
|
||||
<p>Hello</p>
|
||||
</div>
|
@ -0,0 +1,8 @@
|
||||
[{
|
||||
"message": "duplicate default <slot> element",
|
||||
"loc": {
|
||||
"line": 2,
|
||||
"column": 0
|
||||
},
|
||||
"pos": 14
|
||||
}]
|
@ -0,0 +1,2 @@
|
||||
<slot></slot>
|
||||
<slot></slot>
|
@ -0,0 +1,8 @@
|
||||
[{
|
||||
"message": "default is a reserved word — it cannot be used as a slot name",
|
||||
"loc": {
|
||||
"line": 1,
|
||||
"column": 6
|
||||
},
|
||||
"pos": 6
|
||||
}]
|
@ -0,0 +1 @@
|
||||
<slot name='default'></slot>
|
@ -0,0 +1,8 @@
|
||||
[{
|
||||
"message": "slot attribute cannot have a dynamic value",
|
||||
"loc": {
|
||||
"line": 2,
|
||||
"column": 9
|
||||
},
|
||||
"pos": 18
|
||||
}]
|
@ -0,0 +1,3 @@
|
||||
<Nested>
|
||||
<button slot='{{foo}}'>click me</button>
|
||||
</Nested>
|
@ -0,0 +1,8 @@
|
||||
[{
|
||||
"message": "<slot> name cannot be dynamic",
|
||||
"loc": {
|
||||
"line": 1,
|
||||
"column": 6
|
||||
},
|
||||
"pos": 6
|
||||
}]
|
@ -0,0 +1 @@
|
||||
<slot name='{{foo}}'></slot>
|
@ -0,0 +1,8 @@
|
||||
[{
|
||||
"message": "<slot> cannot be a child of an each-block",
|
||||
"loc": {
|
||||
"line": 2,
|
||||
"column": 1
|
||||
},
|
||||
"pos": 27
|
||||
}]
|
@ -0,0 +1,3 @@
|
||||
{{#each things as thing}}
|
||||
<slot name='foo'></slot>
|
||||
{{/each}}
|
@ -0,0 +1,8 @@
|
||||
[{
|
||||
"message": "duplicate 'foo' <slot> element",
|
||||
"loc": {
|
||||
"line": 2,
|
||||
"column": 6
|
||||
},
|
||||
"pos": 31
|
||||
}]
|
@ -0,0 +1,2 @@
|
||||
<slot name='foo'></slot>
|
||||
<slot name='foo'></slot>
|
@ -0,0 +1,8 @@
|
||||
[{
|
||||
"message": "<slot> elements cannot be nested",
|
||||
"loc": {
|
||||
"line": 2,
|
||||
"column": 1
|
||||
},
|
||||
"pos": 8
|
||||
}]
|
@ -0,0 +1,3 @@
|
||||
<slot>
|
||||
<slot name='foo'></slot>
|
||||
</slot>
|
Loading…
Reference in new issue