allow passing snippets rendered as slots

snippet-work-cont
Simon Holthausen 1 year ago
parent 1bdf919904
commit 3494f4cc6b

@ -789,6 +789,8 @@ function serialize_inline_component(node, component_name, context) {
/** @type {import('estree').Statement[]} */ /** @type {import('estree').Statement[]} */
const snippet_declarations = []; const snippet_declarations = [];
/** @type {import('estree').Property[]} */
const serialized_slots = [];
// Group children by slot // Group children by slot
for (const child of node.fragment.nodes) { for (const child of node.fragment.nodes) {
@ -802,6 +804,8 @@ function serialize_inline_component(node, component_name, context) {
}); });
push_prop(b.prop('init', child.expression, child.expression)); push_prop(b.prop('init', child.expression, child.expression));
// Back/forward compatibility: allows people to pass snippets when component still uses slots
serialized_slots.push(b.init(child.expression.name, b.true));
continue; continue;
} }
@ -825,8 +829,6 @@ function serialize_inline_component(node, component_name, context) {
} }
// Serialize each slot // Serialize each slot
/** @type {import('estree').Property[]} */
const serialized_slots = [];
for (const slot_name of Object.keys(children)) { for (const slot_name of Object.keys(children)) {
const body = create_block(node, `${node.name}_${slot_name}`, children[slot_name], context); const body = create_block(node, `${node.name}_${slot_name}`, children[slot_name], context);
if (body.length === 0) continue; if (body.length === 0) continue;
@ -3070,11 +3072,14 @@ export const template_visitors = {
b.block(create_block(node, 'fallback', node.fragment.nodes, context)) b.block(create_block(node, 'fallback', node.fragment.nodes, context))
); );
const expression = is_default const slot = b.call(
? b.call('$.default_slot', b.id('$$props')) '$.slot',
: b.member(b.member(b.id('$$props'), b.id('$$slots')), name, true, true); context.state.node,
b.id('$$props'),
const slot = b.call('$.slot', context.state.node, expression, props_expression, fallback); name,
props_expression,
fallback
);
context.state.init.push(b.stmt(slot)); context.state.init.push(b.stmt(slot));
}, },
SvelteHead(node, context) { SvelteHead(node, context) {

@ -1037,6 +1037,8 @@ function serialize_inline_component(node, component_name, context) {
/** @type {import('estree').Statement[]} */ /** @type {import('estree').Statement[]} */
const snippet_declarations = []; const snippet_declarations = [];
/** @type {import('estree').Property[]} */
const serialized_slots = [];
// Group children by slot // Group children by slot
for (const child of node.fragment.nodes) { for (const child of node.fragment.nodes) {
@ -1050,6 +1052,8 @@ function serialize_inline_component(node, component_name, context) {
}); });
push_prop(b.prop('init', child.expression, child.expression)); push_prop(b.prop('init', child.expression, child.expression));
// Back/forward compatibility: allows people to pass snippets when component still uses slots
serialized_slots.push(b.init(child.expression.name, b.true));
continue; continue;
} }
@ -1071,9 +1075,6 @@ function serialize_inline_component(node, component_name, context) {
} }
// Serialize each slot // Serialize each slot
/** @type {import('estree').Property[]} */
const serialized_slots = [];
for (const slot_name of Object.keys(children)) { for (const slot_name of Object.keys(children)) {
const body = create_block(node, children[slot_name], context); const body = create_block(node, children[slot_name], context);
if (body.length === 0) continue; if (body.length === 0) continue;
@ -1750,7 +1751,7 @@ const template_visitors = {
const lets = []; const lets = [];
/** @type {import('estree').Expression} */ /** @type {import('estree').Expression} */
let expression = b.call('$.default_slot', b.id('$$props')); let slot_name = b.literal('default');
for (const attribute of node.attributes) { for (const attribute of node.attributes) {
if (attribute.type === 'SpreadAttribute') { if (attribute.type === 'SpreadAttribute') {
@ -1758,7 +1759,7 @@ const template_visitors = {
} else if (attribute.type === 'Attribute') { } else if (attribute.type === 'Attribute') {
const value = serialize_attribute_value(attribute.value, context, false, true); const value = serialize_attribute_value(attribute.value, context, false, true);
if (attribute.name === 'name') { if (attribute.name === 'name') {
expression = b.member(b.member_id('$$props.$$slots'), value, true, true); slot_name = value;
} else if (attribute.name !== 'slot') { } else if (attribute.name !== 'slot') {
if (attribute.metadata.dynamic) { if (attribute.metadata.dynamic) {
props.push(b.get(attribute.name, [b.return(value)])); props.push(b.get(attribute.name, [b.return(value)]));
@ -1782,7 +1783,14 @@ const template_visitors = {
node.fragment.nodes.length === 0 node.fragment.nodes.length === 0
? b.literal(null) ? b.literal(null)
: b.thunk(b.block(create_block(node, node.fragment.nodes, context))); : b.thunk(b.block(create_block(node, node.fragment.nodes, context)));
const slot = b.call('$.slot', b.id('$$payload'), expression, props_expression, fallback); const slot = b.call(
'$.slot',
b.id('$$payload'),
b.id('$$props'),
slot_name,
props_expression,
fallback
);
state.template.push(t_statement(b.stmt(slot))); state.template.push(t_statement(b.stmt(slot)));
state.template.push(block_close); state.template.push(block_close);

@ -66,15 +66,3 @@ export function update_legacy_props($$new_props) {
} }
} }
} }
/**
* @param {Record<string, any>} $$props
*/
export function default_slot($$props) {
var children = $$props.$$slots?.default;
if (children === true) {
return $$props.children;
} else {
return children;
}
}

@ -72,8 +72,7 @@ export {
add_legacy_event_listener, add_legacy_event_listener,
bubble_event, bubble_event,
reactive_import, reactive_import,
update_legacy_props, update_legacy_props
default_slot
} from './dom/legacy/misc.js'; } from './dom/legacy/misc.js';
export { export {
append, append,

@ -63,11 +63,21 @@ export function set_text(dom, value) {
/** /**
* @param {Comment} anchor * @param {Comment} anchor
* @param {void | ((anchor: Comment, slot_props: Record<string, unknown>) => void)} slot_fn * @param {Record<string, any>} $$props
* @param {string} slot_name
* @param {Record<string, unknown>} slot_props * @param {Record<string, unknown>} slot_props
* @param {null | ((anchor: Comment) => void)} fallback_fn * @param {null | ((anchor: Comment) => void)} fallback_fn
*/ */
export function slot(anchor, slot_fn, slot_props, fallback_fn) { export function slot(anchor, $$props, slot_name, slot_props, fallback_fn) {
var slot_fn = $$props.$$slots?.[slot_name];
if (slot_fn === true) {
if (slot_name === 'default') {
slot_fn = $$props.children;
} else {
slot_fn = $$props[slot_name];
}
}
if (slot_fn === undefined) { if (slot_fn === undefined) {
if (fallback_fn !== null) { if (fallback_fn !== null) {
fallback_fn(anchor); fallback_fn(anchor);

@ -499,12 +499,22 @@ export async function value_or_fallback_async(value, fallback) {
/** /**
* @param {Payload} payload * @param {Payload} payload
* @param {void | ((payload: Payload, props: Record<string, unknown>) => void)} slot_fn * @param {Record<string, any>} $$props
* @param {string} slot_name
* @param {Record<string, unknown>} slot_props * @param {Record<string, unknown>} slot_props
* @param {null | (() => void)} fallback_fn * @param {null | (() => void)} fallback_fn
* @returns {void} * @returns {void}
*/ */
export function slot(payload, slot_fn, slot_props, fallback_fn) { export function slot(payload, $$props, slot_name, slot_props, fallback_fn) {
var slot_fn = $$props.$$slots?.[slot_name];
if (slot_fn === true) {
if (slot_name === 'default') {
slot_fn = $$props.children;
} else {
slot_fn = $$props[slot_name];
}
}
if (slot_fn === undefined) { if (slot_fn === undefined) {
if (fallback_fn !== null) { if (fallback_fn !== null) {
fallback_fn(); fallback_fn();
@ -631,5 +641,3 @@ export {
} from '../shared/validate.js'; } from '../shared/validate.js';
export { escape_html as escape }; export { escape_html as escape };
export { default_slot } from '../client/dom/legacy/misc.js';

@ -0,0 +1,5 @@
import { test } from '../../test';
export default test({
html: `<p>Default</p> <p>Named</p>`
});

@ -0,0 +1,10 @@
<script>
import Child from './Child.svelte';
</script>
<Child>
Default
{#snippet named()}
Named
{/snippet}
</Child>
Loading…
Cancel
Save