0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2024-12-16 21:46:22 -05:00

Expose slots to components (#1368)

* Expose slots to components via Astro.slots

* test: Add Astro.slots API tests

* docs: Document Astro.slots API

* docs: Duplicate Astro.slots documentation to other api-reference markdown

* Update proposal to use booleans, based upon RFC feedback

* update implementation & tests based on request

* changeset
This commit is contained in:
Jonathan Neal 2021-09-15 11:27:59 -04:00 committed by GitHub
parent 8f727647af
commit 98d785af1d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 169 additions and 0 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Expose slots to components

View file

@ -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:

View file

@ -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.

View file

@ -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

View file

@ -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();

View file

@ -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>}

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>