diff options
10 files changed, 169 insertions, 0 deletions
diff --git a/.changeset/pink-toes-shake.md b/.changeset/pink-toes-shake.md new file mode 100644 index 000000000..16ab79a5e --- /dev/null +++ b/.changeset/pink-toes-shake.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Expose slots to components diff --git a/docs/reference/api-reference.md b/docs/reference/api-reference.md index 3f3d8526b..e997a1859 100644 --- a/docs/reference/api-reference.md +++ b/docs/reference/api-reference.md @@ -49,6 +49,17 @@ const data = Astro.fetchContent('../pages/post/*.md'); // returns an array of po }[] ``` +### `Astro.slots` + +`Astro.slots` returns an object with any slotted regions passed into the current Astro file. + +```js +const { + heading as headingSlot, // true or undefined, based on whether `<* slot="heading">` was used. + default as defaultSlot, // true or undefined, based on whether `<* slot>` or `<* default>` was used. +} = Astro.slots; +``` + ### `Astro.request` `Astro.request` returns an object with the following properties: diff --git a/docs/src/pages/reference/api-reference.md b/docs/src/pages/reference/api-reference.md index 624ed2986..08178b4b5 100644 --- a/docs/src/pages/reference/api-reference.md +++ b/docs/src/pages/reference/api-reference.md @@ -86,6 +86,17 @@ const path = Astro.site.pathname; <h1>Welcome to {path}</h1> ``` +### `Astro.slots` + +`Astro.slots` returns an object with any slotted regions passed into the current Astro file. + +```js +const { + heading as headingSlot, // true or undefined, based on whether `<* slot="heading">` was used. + default as defaultSlot, // true or undefined, based on whether `<* slot>` or `<* default>` was used. +} = Astro.slots; +``` + ## `getStaticPaths()` If a page uses dynamic params in the filename, that component will need to export a `getStaticPaths()` function. diff --git a/packages/astro/src/compiler/index.ts b/packages/astro/src/compiler/index.ts index 7f416a30a..62809b285 100644 --- a/packages/astro/src/compiler/index.ts +++ b/packages/astro/src/compiler/index.ts @@ -158,12 +158,25 @@ import { __astro_hoisted_scripts } from 'astro/dist/internal/__astro_hoisted_scr const __astroScripts = __astro_hoisted_scripts([${result.components.map((n) => `typeof ${n} !== 'undefined' && ${n}`)}], ${JSON.stringify(result.hoistedScripts)}); const __astroInternal = Symbol('astro.internal'); const __astroContext = Symbol.for('astro.context'); +const __astroSlotted = Symbol.for('astro.slotted'); async function __render(props, ...children) { const Astro = Object.create(__TopLevelAstro, { props: { value: props, enumerable: true }, + slots: { + value: children.reduce( + (slots, child) => { + for (let name in child.$slots) { + slots[name] = Boolean(child.$slots[name]) + } + return slots + }, + {} + ), + enumerable: true + }, pageCSS: { value: (props[__astroContext] && props[__astroContext].pageCSS) || [], enumerable: true diff --git a/packages/astro/test/astro-slots.test.js b/packages/astro/test/astro-slots.test.js index 72b53c3e6..354036873 100644 --- a/packages/astro/test/astro-slots.test.js +++ b/packages/astro/test/astro-slots.test.js @@ -74,4 +74,60 @@ Slots('Slots work on Components', async ({ runtime }) => { assert.equal($('#default').children('astro-component').length, 1, 'Slotted component into default slot'); }); +Slots('Slots API work on Components', async ({ runtime }) => { + // IDs will exist whether the slots are filled or not + { + const result = await runtime.load('/slottedapi-default'); + assert.ok(!result.error, `build error: ${result.error}`); + + const $ = doc(result.contents); + + assert.equal($('#a').length, 1); + assert.equal($('#b').length, 1); + assert.equal($('#c').length, 1); + assert.equal($('#default').length, 1); + } + + // IDs will not exist because the slots are not filled + { + const result = await runtime.load('/slottedapi-empty'); + assert.ok(!result.error, `build error: ${result.error}`); + + const $ = doc(result.contents); + + assert.equal($('#a').length, 0); + assert.equal($('#b').length, 0); + assert.equal($('#c').length, 0); + assert.equal($('#default').length, 0); + } + + // IDs will exist because the slots are filled + { + const result = await runtime.load('/slottedapi-filled'); + assert.ok(!result.error, `build error: ${result.error}`); + + const $ = doc(result.contents); + + assert.equal($('#a').length, 1); + assert.equal($('#b').length, 1); + assert.equal($('#c').length, 1); + + assert.equal($('#default').length, 0); // the default slot is not filled + } + + // Default ID will exist because the default slot is filled + { + const result = await runtime.load('/slottedapi-default-filled'); + assert.ok(!result.error, `build error: ${result.error}`); + + const $ = doc(result.contents); + + assert.equal($('#a').length, 0); + assert.equal($('#b').length, 0); + assert.equal($('#c').length, 0); + + assert.equal($('#default').length, 1); // the default slot is filled + } +}); + Slots.run(); diff --git a/packages/astro/test/fixtures/astro-slots/src/components/SlottedAPI.astro b/packages/astro/test/fixtures/astro-slots/src/components/SlottedAPI.astro new file mode 100644 index 000000000..e1b00fff8 --- /dev/null +++ b/packages/astro/test/fixtures/astro-slots/src/components/SlottedAPI.astro @@ -0,0 +1,15 @@ +{Astro.slots.a && <div id="a"> + <slot name="a" /> +</div>} + +{Astro.slots.b && <div id="b"> + <slot name="b" /> +</div>} + +{Astro.slots.c && <div id="c"> + <slot name="c" /> +</div>} + +{Astro.slots.default && <div id="default"> + <slot /> +</div>} diff --git a/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-default-filled.astro b/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-default-filled.astro new file mode 100644 index 000000000..2800cb94d --- /dev/null +++ b/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-default-filled.astro @@ -0,0 +1,15 @@ +--- +import Slotted from '../components/SlottedAPI.astro'; +--- + +<html> + <head> + <!-- Test Astro.slots behavior. --> + <!-- IDs will exist because the slots are filled --> + </head> + <body> + <Slotted> + Default + </Slotted> + </body> +</html> diff --git a/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-default.astro b/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-default.astro new file mode 100644 index 000000000..349d63683 --- /dev/null +++ b/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-default.astro @@ -0,0 +1,13 @@ +--- +import Slotted from '../components/Slotted.astro'; +--- + +<html> + <head> + <!-- Test default slots behavior. --> + <!-- IDs will exist whether the slots are filled or not --> + </head> + <body> + <Slotted /> + </body> +</html> diff --git a/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-empty.astro b/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-empty.astro new file mode 100644 index 000000000..2f2ad04e9 --- /dev/null +++ b/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-empty.astro @@ -0,0 +1,13 @@ +--- +import Slotted from '../components/SlottedAPI.astro'; +--- + +<html> + <head> + <!-- Test Astro.slots behavior. --> + <!-- IDs will not exist because the slots are not filled --> + </head> + <body> + <Slotted /> + </body> +</html> diff --git a/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-filled.astro b/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-filled.astro new file mode 100644 index 000000000..01714e5d1 --- /dev/null +++ b/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-filled.astro @@ -0,0 +1,17 @@ +--- +import Slotted from '../components/SlottedAPI.astro'; +--- + +<html> + <head> + <!-- Test Astro.slots behavior. --> + <!-- IDs will exist because the slots are filled --> + </head> + <body> + <Slotted> + <span slot="a">A</span> + <span slot="b">B</span> + <span slot="c">C</span> + </Slotted> + </body> +</html> |