Added more clarification around using Astro.slots.render (#4456)

* Add an error message for when something that's not an array is passed to Astro.slots.render

* Add changeset

* Add more details
This commit is contained in:
Erika 2022-08-25 12:42:27 -03:00 committed by GitHub
parent 78334b9765
commit 47e71ae8f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 39 additions and 7 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Added an error message when the second argument of Astro.slots.render is not an array

View file

@ -203,7 +203,7 @@ export interface AstroGlobal extends AstroGlobalPartial {
*/ */
has(slotName: string): boolean; has(slotName: string): boolean;
/** /**
* Asychronously renders this slot and returns HTML * Asynchronously renders this slot and returns a string
* *
* Example usage: * Example usage:
* ```astro * ```astro
@ -216,6 +216,21 @@ export interface AstroGlobal extends AstroGlobalPartial {
* <Fragment set:html={html} /> * <Fragment set:html={html} />
* ``` * ```
* *
* A second parameters can be used to pass arguments to a slotted callback
*
* Example usage:
* ```astro
* ---
* html = await Astro.slots.render('default', ["Hello", "World"])
* ---
* ```
* Each item in the array will be passed as an argument that you can use like so:
* ```astro
* <Component>
* {(hello, world) => <div>{hello}, {world}!</div>}
* </Component>
* ```
*
* [Astro reference](https://docs.astro.build/en/reference/api-reference/#astroslots) * [Astro reference](https://docs.astro.build/en/reference/api-reference/#astroslots)
*/ */
render(slotName: string, args?: any[]): Promise<string>; render(slotName: string, args?: any[]): Promise<string>;

View file

@ -55,10 +55,13 @@ class Slots {
#cache = new Map<string, string>(); #cache = new Map<string, string>();
#result: SSRResult; #result: SSRResult;
#slots: Record<string, any> | null; #slots: Record<string, any> | null;
#loggingOpts: LogOptions;
constructor(result: SSRResult, slots: Record<string, any> | null) { constructor(result: SSRResult, slots: Record<string, any> | null, logging: LogOptions) {
this.#result = result; this.#result = result;
this.#slots = slots; this.#slots = slots;
this.#loggingOpts = logging;
if (slots) { if (slots) {
for (const key of Object.keys(slots)) { for (const key of Object.keys(slots)) {
if ((this as any)[key] !== undefined) { if ((this as any)[key] !== undefined) {
@ -92,11 +95,20 @@ class Slots {
if (!cacheable) { if (!cacheable) {
const component = await this.#slots[name](); const component = await this.#slots[name]();
const expression = getFunctionExpression(component); const expression = getFunctionExpression(component);
if (expression) {
const slot = expression(...args); if (!Array.isArray(args)) {
return await renderSlot(this.#result, slot).then((res) => warn(
res != null ? String(res) : res this.#loggingOpts,
'Astro.slots.render',
`Expected second parameter to be an array, received a ${typeof args}. If you're trying to pass an array as a single argument and getting unexpected results, make sure you're passing your array as a item of an array. Ex: Astro.slots.render('default', [["Hello", "World"]])`
); );
} else {
if (expression) {
const slot = expression(...args);
return await renderSlot(this.#result, slot).then((res) =>
res != null ? String(res) : res
);
}
} }
} }
const content = await renderSlot(this.#result, this.#slots[name]).then((res) => const content = await renderSlot(this.#result, this.#slots[name]).then((res) =>
@ -146,7 +158,7 @@ export function createResult(args: CreateResultArgs): SSRResult {
props: Record<string, any>, props: Record<string, any>,
slots: Record<string, any> | null slots: Record<string, any> | null
) { ) {
const astroSlots = new Slots(result, slots); const astroSlots = new Slots(result, slots, args.logging);
const Astro = { const Astro = {
__proto__: astroGlobal, __proto__: astroGlobal,