diff --git a/packages/svelte2tsx/src/interfaces.ts b/packages/svelte2tsx/src/interfaces.ts index 742e323d2..d4a9d520d 100644 --- a/packages/svelte2tsx/src/interfaces.ts +++ b/packages/svelte2tsx/src/interfaces.ts @@ -8,6 +8,7 @@ export interface InstanceScriptProcessResult { events: ComponentEvents; uses$$props: boolean; uses$$restProps: boolean; + uses$$slots: boolean; getters: Set; } diff --git a/packages/svelte2tsx/src/svelte2tsx.ts b/packages/svelte2tsx/src/svelte2tsx.ts index 26ba91c8e..83757768e 100644 --- a/packages/svelte2tsx/src/svelte2tsx.ts +++ b/packages/svelte2tsx/src/svelte2tsx.ts @@ -51,6 +51,7 @@ function AttributeValueAsJsExpression(htmlx: string, attr: Node): string { type TemplateProcessResult = { uses$$props: boolean; uses$$restProps: boolean; + uses$$slots: boolean; slots: Map>; scriptTag: Node; moduleScriptTag: Node; @@ -91,6 +92,7 @@ function processSvelteTemplate(str: MagicString): TemplateProcessResult { let uses$$props = false; let uses$$restProps = false; + let uses$$slots = false; let componentDocumentation = null; @@ -224,6 +226,11 @@ function processSvelteTemplate(str: MagicString): TemplateProcessResult { return; } + if (node.name === '$$slots') { + uses$$slots = true; + return; + } + //handle potential store if (node.name[0] == '$') { if (isDeclaration) { @@ -383,6 +390,7 @@ function processSvelteTemplate(str: MagicString): TemplateProcessResult { events: new ComponentEventsFromEventsMap(eventHandler), uses$$props, uses$$restProps, + uses$$slots, componentDocumentation, }; } @@ -408,6 +416,7 @@ function processInstanceScriptContent( const implicitTopLevelNames = new ImplicitTopLevelNames(); let uses$$props = false; let uses$$restProps = false; + let uses$$slots = false; //track if we are in a declaration scope let isDeclaration = false; @@ -607,6 +616,10 @@ function processInstanceScriptContent( uses$$restProps = true; return; } + if (ident.text === '$$slots') { + uses$$slots = true; + return; + } if (ts.isLabeledStatement(parent) && parent.label == ident) { return; @@ -821,6 +834,7 @@ function processInstanceScriptContent( events, uses$$props, uses$$restProps, + uses$$slots, getters, }; } @@ -910,6 +924,7 @@ function createRenderFunction({ isTsFile, uses$$props, uses$$restProps, + uses$$slots, }: CreateRenderFunctionPara) { const htmlx = str.original; let propsDecl = ''; @@ -921,6 +936,15 @@ function createRenderFunction({ propsDecl += ' let $$restProps = __sveltets_restPropsType();'; } + if (uses$$slots) { + propsDecl += + ' let $$slots = __sveltets_slotsType({' + + Array.from(slots.keys()) + .map((name) => `${name}: ''`) + .join(', ') + + '});'; + } + if (scriptTag) { //I couldn't get magicstring to let me put the script before the <> we prepend during conversion of the template to jsx, so we just close it instead const scriptTagEnd = htmlx.lastIndexOf('>', scriptTag.content.start) + 1; @@ -973,6 +997,7 @@ export function svelte2tsx( scriptTag, slots, uses$$props, + uses$$slots, uses$$restProps, events, componentDocumentation, @@ -1006,6 +1031,7 @@ export function svelte2tsx( const res = processInstanceScriptContent(str, scriptTag, events); uses$$props = uses$$props || res.uses$$props; uses$$restProps = uses$$restProps || res.uses$$restProps; + uses$$slots = uses$$slots || res.uses$$slots; ({ exportedNames, events, getters } = res); } @@ -1022,6 +1048,7 @@ export function svelte2tsx( isTsFile: options?.isTsFile, uses$$props, uses$$restProps, + uses$$slots, }); // we need to process the module script after the instance script has moved otherwise we get warnings about moving edited items diff --git a/packages/svelte2tsx/svelte-shims.d.ts b/packages/svelte2tsx/svelte-shims.d.ts index b3a4e54d9..2bd7180b8 100644 --- a/packages/svelte2tsx/svelte-shims.d.ts +++ b/packages/svelte2tsx/svelte-shims.d.ts @@ -85,6 +85,7 @@ type SvelteAnimation = (node: Element, move: { from: DOMRect, t type SvelteAllProps = { [index: string]: any } type SvelteRestProps = { [index: string]: any } +type SvelteSlots = { [index: string]: any } type SvelteStore = { subscribe: (run: (value: T) => any, invalidate?: any) => any } @@ -103,6 +104,7 @@ declare function __sveltets_ctorOf(type: T): AConstructorTypeOf; declare function __sveltets_instanceOf(type: AConstructorTypeOf): T; declare function __sveltets_allPropsType(): SvelteAllProps declare function __sveltets_restPropsType(): SvelteRestProps +declare function __sveltets_slotsType(slots: Slots): Record; declare function __sveltets_partial( render: () => {props?: Props, events?: Events, slots?: Slots } ): () => {props?: Partial, events?: Events, slots?: Slots } diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/uses-$$slots-script/expected.tsx b/packages/svelte2tsx/test/svelte2tsx/samples/uses-$$slots-script/expected.tsx new file mode 100644 index 000000000..9c3fd99e7 --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/uses-$$slots-script/expected.tsx @@ -0,0 +1,14 @@ +/// +<>;function render() { let $$slots = __sveltets_slotsType({foo: '', default: ''}); + + let name = $$slots['name']; +; +() => (<> + +

{name}

+ +); +return { props: {}, slots: {foo: {}, default: {}}, getters: {}, events: {} }} + +export default class Input__SvelteComponent_ extends createSvelte2TsxComponent(__sveltets_partial(__sveltets_with_any_event(render))) { +} diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/uses-$$slots-script/input.svelte b/packages/svelte2tsx/test/svelte2tsx/samples/uses-$$slots-script/input.svelte new file mode 100644 index 000000000..feed3be0e --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/uses-$$slots-script/input.svelte @@ -0,0 +1,7 @@ + + +

{name}

+ + \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/uses-$$slots/expected.tsx b/packages/svelte2tsx/test/svelte2tsx/samples/uses-$$slots/expected.tsx new file mode 100644 index 000000000..28a81cd1e --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/uses-$$slots/expected.tsx @@ -0,0 +1,10 @@ +/// +<>;function render() { let $$slots = __sveltets_slotsType({foo: '', default: ''}); +<>

{$$slots['name']}

+ + + +return { props: {}, slots: {foo: {}, default: {}}, getters: {}, events: {} }} + +export default class Input__SvelteComponent_ extends createSvelte2TsxComponent(__sveltets_partial(__sveltets_with_any_event(render))) { +} \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/uses-$$slots/input.svelte b/packages/svelte2tsx/test/svelte2tsx/samples/uses-$$slots/input.svelte new file mode 100644 index 000000000..9412f8fac --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/uses-$$slots/input.svelte @@ -0,0 +1,4 @@ +

{$$slots['name']}

+ + + \ No newline at end of file