more gnarly slot stuff

pull/1998/head
Richard Harris 7 years ago
parent 8b0dd112b9
commit 5e30e90e70

@ -6,6 +6,9 @@ import FragmentWrapper from './Fragment';
import deindent from '../../../utils/deindent';
import sanitize from '../../../utils/sanitize';
import addToSet from '../../../utils/addToSet';
import get_slot_data from '../../../utils/get_slot_data';
import stringifyProps from '../../../utils/stringifyProps';
import Expression from '../../nodes/shared/Expression';
export default class SlotWrapper extends Wrapper {
node: Slot;
@ -51,11 +54,50 @@ export default class SlotWrapper extends Wrapper {
const slot_name = this.node.getStaticAttributeValue('name') || 'default';
renderer.slots.add(slot_name);
let get_slot_changes;
let get_slot_context;
const attributes = this.node.attributes.filter(attribute => attribute.name !== 'name');
if (attributes.length > 0) {
get_slot_changes = renderer.component.getUniqueName(`get_${slot_name}_slot_changes`);
get_slot_context = renderer.component.getUniqueName(`get_${slot_name}_slot_context`);
const context_props = get_slot_data(attributes);
const changes_props = [];
const dependencies = new Set();
attributes.forEach(attribute => {
attribute.chunks.forEach(chunk => {
if ((<Expression>chunk).dependencies) {
addToSet(dependencies, (<Expression>chunk).dependencies);
addToSet(dependencies, (<Expression>chunk).contextual_dependencies);
}
});
if (attribute.dependencies.size > 0) {
changes_props.push(`${attribute.name}: ${[...attribute.dependencies].join(' || ')}`)
}
});
const arg = dependencies.size > 0 ? `{ ${[...dependencies].join(', ')} }` : '{}';
renderer.blocks.push(deindent`
const ${get_slot_changes} = (${arg}) => (${stringifyProps(changes_props)});
const ${get_slot_context} = (${arg}) => (${stringifyProps(context_props)});
`);
} else {
get_slot_context = 'null';
}
const slot = block.getUniqueName(`${sanitize(slot_name)}_slot`);
const slot_definition = block.getUniqueName(`${sanitize(slot_name)}_slot`);
block.builders.init.addLine(
`const ${slot} = @create_slot(ctx.$$slot_${sanitize(slot_name)}, ctx);`
);
block.builders.init.addBlock(deindent`
const ${slot_definition} = ctx.$$slot_${sanitize(slot_name)};
const ${slot} = @create_slot(${slot_definition}, ctx, ${get_slot_context});
`);
let mountBefore = block.builders.mount.toString();
@ -100,7 +142,7 @@ export default class SlotWrapper extends Wrapper {
block.builders.update.addBlock(deindent`
if (${slot} && ${update_conditions}) {
${slot}.p(@assign(@assign({}, changed), ctx.$$scope.changed), @get_slot_context(ctx.$$slot_${sanitize(slot_name)}, ctx));
${slot}.p(@assign(@assign({}, ${get_slot_changes}(changed)), ctx.$$scope.changed), @get_slot_context(${slot_definition}, ctx, ${get_slot_context}));
}
`);

@ -1,6 +1,6 @@
import Renderer from '../Renderer';
import { CompileOptions } from '../../../interfaces';
import { snip } from '../utils';
import { snip } from '../../../utils/snip';
export default function(node, renderer: Renderer, options: CompileOptions) {
renderer.append('${(function(__value) { if(@isPromise(__value)) return `');

@ -1,4 +1,4 @@
import { snip } from '../utils';
import { snip } from '../../../utils/snip';
export default function(node, renderer, options) {
const snippet = snip(node.expression);

@ -2,8 +2,8 @@ import { quotePropIfNecessary, quoteNameIfNecessary } from '../../../utils/quote
import isVoidElementName from '../../../utils/isVoidElementName';
import Attribute from '../../nodes/Attribute';
import Node from '../../nodes/shared/Node';
import { snip } from '../utils';
import { stringify_attribute } from './shared/stringify_attribute';
import { snip } from '../../../utils/snip';
import { stringify_attribute } from '../../../utils/stringify_attribute';
import { get_slot_scope } from './shared/get_slot_scope';
// source: https://gist.github.com/ArjanSchouten/0b8574a6ad7f5065a5e7

@ -1,4 +1,4 @@
import { snip } from '../utils';
import { snip } from '../../../utils/snip';
export default function(node, renderer, options) {
renderer.append('${' + snip(node.expression) + '}');

@ -1,4 +1,4 @@
import { snip } from '../utils';
import { snip } from '../../../utils/snip';
export default function(node, renderer, options) {
const snippet = snip(node.expression);

@ -1,6 +1,6 @@
import { escape, escapeTemplate, stringify } from '../../../utils/stringify';
import { quoteNameIfNecessary } from '../../../utils/quoteIfNecessary';
import { snip } from '../utils';
import { snip } from '../../../utils/snip';
import Renderer from '../Renderer';
import stringifyProps from '../../../utils/stringifyProps';
import { get_slot_scope } from './shared/get_slot_scope';

@ -1,6 +1,5 @@
import { quotePropIfNecessary } from '../../../utils/quoteIfNecessary';
import { snip } from '../utils';
import { stringify_attribute } from './shared/stringify_attribute';
import get_slot_data from '../../../utils/get_slot_data';
export default function(node, renderer, options) {
const name = node.attributes.find(attribute => attribute.name === 'name');
@ -8,21 +7,9 @@ export default function(node, renderer, options) {
const slot_name = name && name.chunks[0].data || 'default';
const prop = quotePropIfNecessary(slot_name);
const slot_data = node.attributes
.filter(attribute => attribute.name !== 'name')
.map(attribute => {
const value = attribute.isTrue
? 'true'
: attribute.chunks.length === 0
? '""'
: attribute.chunks.length === 1 && attribute.chunks[0].type !== 'Text'
? snip(attribute.chunks[0])
: stringify_attribute(attribute);
const slot_data = get_slot_data(node.attributes);
return `${attribute.name}: ${value}`;
});
const arg = slot_data ? `{ ${slot_data.join(', ')} }` : '';
const arg = slot_data.length > 0 ? `{ ${slot_data.join(', ')} }` : '';
renderer.append(`\${$$slots${prop} ? $$slots${prop}(${arg}) : \``);

@ -1,4 +1,4 @@
import { snip } from '../utils';
import { snip } from '../../../utils/snip';
export default function(node, renderer, options) {
const snippet = snip(node.expression);

@ -47,16 +47,16 @@ export function validate_store(store, name) {
}
}
export function create_slot(definition, ctx) {
export function create_slot(definition, ctx, fn) {
if (definition) {
const slot_ctx = get_slot_context(definition, ctx);
const slot_ctx = get_slot_context(definition, ctx, fn);
return definition[0](slot_ctx);
}
}
export function get_slot_context(definition, ctx) {
export function get_slot_context(definition, ctx, fn) {
return definition[1]
? assign({}, assign(ctx.$$scope.ctx, definition[1](ctx)))
: ctx.$$scope.ctx
? assign({}, assign(ctx.$$scope.ctx, definition[1](fn ? fn(ctx) : {})))
: ctx.$$scope.ctx;
}

@ -0,0 +1,18 @@
import { snip } from './snip';
import { stringify_attribute } from './stringify_attribute';
export default function(attributes) {
return attributes
.filter(attribute => attribute.name !== 'name')
.map(attribute => {
const value = attribute.isTrue
? 'true'
: attribute.chunks.length === 0
? '""'
: attribute.chunks.length === 1 && attribute.chunks[0].type !== 'Text'
? snip(attribute.chunks[0])
: stringify_attribute(attribute);
return `${attribute.name}: ${value}`;
});
}

@ -1,7 +1,7 @@
import Attribute from '../../../nodes/Attribute';
import Node from '../../../nodes/shared/Node';
import { escapeTemplate, escape } from '../../../../utils/stringify';
import { snip } from '../../utils';
import Attribute from '../compile/nodes/Attribute';
import Node from '../compile/nodes/shared/Node';
import { escapeTemplate, escape } from './stringify';
import { snip } from './snip';
export function stringify_attribute(attribute: Attribute) {
return attribute.chunks

@ -0,0 +1,6 @@
<script>
let count = 0;
</script>
<button on:click="{() => count += 1}">+1</button>
<slot c={count}/>

@ -0,0 +1,18 @@
export default {
html: `
<button>+1</button>
<span>0 (undefined)</span>
`,
async test({ assert, target, window }) {
const button = target.querySelector('button');
const click = new window.MouseEvent('click');
await button.dispatchEvent(click);
assert.htmlEqual(target.innerHTML, `
<button>+1</button>
<span>1 (undefined)</span>
`);
}
};

@ -0,0 +1,7 @@
<script>
import Nested from './Nested.html';
</script>
<Nested let:c let:count>
<span>{c} ({count})</span>
</Nested>
Loading…
Cancel
Save