From 92174559a152113871904d8a0a02085ed9b58b13 Mon Sep 17 00:00:00 2001 From: Samuel Degueldre Date: Wed, 24 Nov 2021 14:13:09 +0100 Subject: [PATCH] [FIX] slots: allow t-call and components in slot default content --- src/app/template_helpers.ts | 6 +- src/compiler/code_generator.ts | 4 +- .../__snapshots__/slots.test.ts.snap | 117 +++++++++++++++--- tests/components/slots.test.ts | 29 +++++ 4 files changed, 133 insertions(+), 23 deletions(-) diff --git a/src/app/template_helpers.ts b/src/app/template_helpers.ts index fa29c95f..fe055377 100644 --- a/src/app/template_helpers.ts +++ b/src/app/template_helpers.ts @@ -19,7 +19,7 @@ function callSlot( name: string, dynamic: boolean, extra: any, - defaultSlot?: (ctx: any, key: string) => BDom + defaultContent?: (ctx: any, node: any, key: string) => BDom ): BDom { const slots = (ctx.props && ctx.props.slots) || {}; const { __render, __ctx, __scope } = slots[name] || {}; @@ -28,13 +28,13 @@ function callSlot( slotScope[__scope] = extra || {}; } const slotBDom = __render ? __render(slotScope, parent, key) : null; - if (defaultSlot) { + if (defaultContent) { let child1: BDom | undefined = undefined; let child2: BDom | undefined = undefined; if (slotBDom) { child1 = dynamic ? toggler(name, slotBDom) : slotBDom; } else { - child2 = defaultSlot(parent, key); + child2 = defaultContent(ctx, parent, key); } return multi([child1, child2]); } diff --git a/src/compiler/code_generator.ts b/src/compiler/code_generator.ts index 69c2d2f9..f77360f7 100644 --- a/src/compiler/code_generator.ts +++ b/src/compiler/code_generator.ts @@ -1095,9 +1095,9 @@ export class CodeGenerator { } if (ast.defaultContent) { - let name = this.generateId("defaultSlot"); + let name = this.generateId("defaultContent"); const slot = new CodeTarget(name); - slot.signature = "ctx => {"; + slot.signature = "(ctx, node, key) => {"; this.functions.push(slot); const initialTarget = this.target; const subCtx: Context = createContext(ctx); diff --git a/tests/components/__snapshots__/slots.test.ts.snap b/tests/components/__snapshots__/slots.test.ts.snap index b1c8c4a9..60f49e18 100644 --- a/tests/components/__snapshots__/slots.test.ts.snap +++ b/tests/components/__snapshots__/slots.test.ts.snap @@ -133,6 +133,87 @@ exports[`slots can render only empty slot 1`] = ` }" `; +exports[`slots can use component in default-content of t-slot 1`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component } = bdom; + let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; + + return function template(ctx, node, key = \\"\\") { + return text(\`\`); + } +}" +`; + +exports[`slots can use component in default-content of t-slot 2`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component } = bdom; + let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; + + const defaultContent1 = (ctx, node, key) => { + return component(\`GrandChild\`, {}, key + \`__2\`, node, ctx); + } + + return function template(ctx, node, key = \\"\\") { + return callSlot(ctx, node, key, 'default', false, {}, defaultContent1); + } +}" +`; + +exports[`slots can use component in default-content of t-slot 3`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component } = bdom; + let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; + + return function template(ctx, node, key = \\"\\") { + return component(\`Child\`, {}, key + \`__1\`, node, ctx); + } +}" +`; + +exports[`slots can use t-call in default-content of t-slot 1`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component } = bdom; + let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; + + return function template(ctx, node, key = \\"\\") { + return text(\`\`); + } +}" +`; + +exports[`slots can use t-call in default-content of t-slot 2`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component } = bdom; + let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; + const callTemplate_3 = getTemplate(\`__template__9\`); + + const defaultContent1 = (ctx, node, key) => { + return callTemplate_3.call(this, ctx, node, key + \`__2\`); + } + + return function template(ctx, node, key = \\"\\") { + return callSlot(ctx, node, key, 'default', false, {}, defaultContent1); + } +}" +`; + +exports[`slots can use t-call in default-content of t-slot 3`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component } = bdom; + let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; + + return function template(ctx, node, key = \\"\\") { + return component(\`Child\`, {}, key + \`__1\`, node, ctx); + } +}" +`; + exports[`slots content is the default slot (variation) 1`] = ` "function anonymous(bdom, helpers ) { @@ -206,12 +287,12 @@ exports[`slots dafault slots can define a default content 1`] = ` let block1 = createBlock(\`\`); - const defaultSlot1 = ctx => { + const defaultContent1 = (ctx, node, key) => { return text(\`default content\`); } return function template(ctx, node, key = \\"\\") { - let b3 = callSlot(ctx, node, key, 'default', false, {}, defaultSlot1); + let b3 = callSlot(ctx, node, key, 'default', false, {}, defaultContent1); return block1([], [b3]); } }" @@ -240,12 +321,12 @@ exports[`slots default content is not rendered if named slot is provided 1`] = ` let block1 = createBlock(\`\`); - const defaultSlot1 = ctx => { + const defaultContent1 = (ctx, node, key) => { return text(\`default content\`); } return function template(ctx, node, key = \\"\\") { - let b3 = callSlot(ctx, node, key, 'header', false, {}, defaultSlot1); + let b3 = callSlot(ctx, node, key, 'header', false, {}, defaultContent1); return block1([], [b3]); } }" @@ -279,12 +360,12 @@ exports[`slots default content is not rendered if slot is provided 1`] = ` let block1 = createBlock(\`\`); - const defaultSlot1 = ctx => { + const defaultContent1 = (ctx, node, key) => { return text(\`default content\`); } return function template(ctx, node, key = \\"\\") { - let b3 = callSlot(ctx, node, key, 'default', false, {}, defaultSlot1); + let b3 = callSlot(ctx, node, key, 'default', false, {}, defaultContent1); return block1([], [b3]); } }" @@ -317,17 +398,17 @@ exports[`slots default slot next to named slot, with default content 1`] = ` let block1 = createBlock(\`
\`); - const defaultSlot1 = ctx => { + const defaultContent1 = (ctx, node, key) => { return text(\` Default content \`); } - const defaultSlot2 = ctx => { + const defaultContent2 = (ctx, node, key) => { return text(\` Default footer \`); } return function template(ctx, node, key = \\"\\") { - let b3 = callSlot(ctx, node, key, 'default', false, {}, defaultSlot1); - let b5 = callSlot(ctx, node, key, 'footer', false, {}, defaultSlot2); + let b3 = callSlot(ctx, node, key, 'default', false, {}, defaultContent1); + let b5 = callSlot(ctx, node, key, 'footer', false, {}, defaultContent2); return block1([], [b3, b5]); } }" @@ -469,13 +550,13 @@ exports[`slots dynamic t-slot call with default 1`] = ` let block1 = createBlock(\`\`); - const defaultSlot1 = ctx => { + const defaultContent1 = (ctx, node, key) => { return text(\` owl \`); } return function template(ctx, node, key = \\"\\") { let d1 = [ctx['toggle'], ctx]; - let b3 = callSlot(ctx, node, key, (ctx['current'].slot), true, {}, defaultSlot1); + let b3 = callSlot(ctx, node, key, (ctx['current'].slot), true, {}, defaultContent1); return block1([d1], [b3]); } }" @@ -806,12 +887,12 @@ exports[`slots named slots can define a default content 1`] = ` let block1 = createBlock(\`\`); - const defaultSlot1 = ctx => { + const defaultContent1 = (ctx, node, key) => { return text(\`default content\`); } return function template(ctx, node, key = \\"\\") { - let b3 = callSlot(ctx, node, key, 'header', false, {}, defaultSlot1); + let b3 = callSlot(ctx, node, key, 'header', false, {}, defaultContent1); return block1([], [b3]); } }" @@ -840,17 +921,17 @@ exports[`slots named slots inside slot, again 1`] = ` let block1 = createBlock(\`\`); - const defaultSlot1 = ctx => { + const defaultContent1 = (ctx, node, key) => { return text(\`default1\`); } - const defaultSlot2 = ctx => { + const defaultContent2 = (ctx, node, key) => { return text(\`default2\`); } return function template(ctx, node, key = \\"\\") { - let b3 = callSlot(ctx, node, key, 'brol1', false, {}, defaultSlot1); - let b5 = callSlot(ctx, node, key, 'brol2', false, {}, defaultSlot2); + let b3 = callSlot(ctx, node, key, 'brol1', false, {}, defaultContent1); + let b5 = callSlot(ctx, node, key, 'brol2', false, {}, defaultContent2); let b6 = callSlot(ctx, node, key, 'default', false, {}); return block1([], [b3, b5, b6]); } diff --git a/tests/components/slots.test.ts b/tests/components/slots.test.ts index 94eb890d..7301e2e7 100644 --- a/tests/components/slots.test.ts +++ b/tests/components/slots.test.ts @@ -1434,4 +1434,33 @@ describe("slots", () => { } expect(error).toBeNull(); }); + + test("can use t-call in default-content of t-slot", async () => { + const template = xml``; + class Child extends Component { + static template = xml``; + } + + class Parent extends Component { + static template = xml``; + static components = { Child }; + } + await mount(Parent, fixture); + }); + + test("can use component in default-content of t-slot", async () => { + class GrandChild extends Component { + static template = xml``; + } + class Child extends Component { + static template = xml``; + static components = { GrandChild }; + } + + class Parent extends Component { + static template = xml``; + static components = { Child }; + } + await mount(Parent, fixture); + }); });