aboutsummaryrefslogtreecommitdiff
path: root/packages/astro/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/astro/src')
-rw-r--r--packages/astro/src/compiler/codegen/index.ts28
-rw-r--r--packages/astro/src/internal/__astro_component.ts49
-rw-r--r--packages/astro/src/internal/__astro_slot.ts15
-rw-r--r--packages/astro/src/internal/renderer-astro.ts8
4 files changed, 78 insertions, 22 deletions
diff --git a/packages/astro/src/compiler/codegen/index.ts b/packages/astro/src/compiler/codegen/index.ts
index 36f5a0c56..f264b5878 100644
--- a/packages/astro/src/compiler/codegen/index.ts
+++ b/packages/astro/src/compiler/codegen/index.ts
@@ -679,7 +679,8 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile
buffers.out += buffers.out === '' ? '' : ',';
if (node.type === 'Slot') {
- buffers[curr] += `(children`;
+ state.importStatements.add(`import { __astro_slot } from 'astro/dist/internal/__astro_slot.js';`);
+ buffers[curr] += `h(__astro_slot, ${attributes ? generateAttributes(attributes) : 'null'}, children`;
paren++;
return;
}
@@ -687,6 +688,11 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile
if (curr === 'markdown') {
await pushMarkdownToBuffer();
}
+ if (attributes.slot) {
+ state.importStatements.add(`import { __astro_slot_content } from 'astro/dist/internal/__astro_slot.js';`);
+ buffers[curr] += `h(__astro_slot_content, { name: ${attributes.slot} },`;
+ paren++;
+ }
buffers[curr] += `h("${name}", ${attributes ? generateAttributes(attributes) : 'null'}`;
paren++;
return;
@@ -712,8 +718,13 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile
await pushMarkdownToBuffer();
}
- paren++;
+ if (attributes.slot) {
+ state.importStatements.add(`import { __astro_slot_content } from 'astro/dist/internal/__astro_slot.js';`);
+ buffers[curr] += `h(__astro_slot_content, { name: ${attributes.slot} },`;
+ paren++;
+ }
buffers[curr] += `h(${componentName}, ${attributes ? generateAttributes(attributes) : 'null'}`;
+ paren++;
return;
} else if (!state.declarations.has(componentName) && !componentInfo && !isCustomElementTag(componentName)) {
throw new Error(`Unable to render "${componentName}" because it is undefined\n ${state.filename}`);
@@ -741,6 +752,11 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile
await pushMarkdownToBuffer();
}
+ if (attributes.slot) {
+ state.importStatements.add(`import { __astro_slot_content } from 'astro/dist/internal/__astro_slot.js';`);
+ buffers[curr] += `h(__astro_slot_content, { name: ${attributes.slot} },`;
+ paren++;
+ }
paren++;
buffers[curr] += `h(${wrapper}, ${attributes ? generateAttributes(attributes) : 'null'}`;
} catch (err) {
@@ -817,6 +833,10 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile
if (curr === 'markdown') {
await pushMarkdownToBuffer();
}
+ if (node.attributes.find((attr: any) => attr.name === 'slot')) {
+ buffers.out += ')';
+ paren--;
+ }
if (paren !== -1) {
buffers.out += ')';
paren--;
@@ -840,6 +860,10 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile
return;
}
}
+ if (node.attributes.find((attr: any) => attr.name === 'slot')) {
+ buffers.out += ')';
+ paren--;
+ }
if (paren !== -1) {
buffers.out += ')';
paren--;
diff --git a/packages/astro/src/internal/__astro_component.ts b/packages/astro/src/internal/__astro_component.ts
index 873c1b7d4..ff1d2ff54 100644
--- a/packages/astro/src/internal/__astro_component.ts
+++ b/packages/astro/src/internal/__astro_component.ts
@@ -2,7 +2,6 @@ import type { Renderer, AstroComponentMetadata } from '../@types/astro';
import hash from 'shorthash';
import { valueToEstree, Value } from 'estree-util-value-to-estree';
import { generate } from 'astring';
-import * as astro from './renderer-astro';
import * as astroHtml from './renderer-html';
// A more robust version alternative to `JSON.stringify` that can handle most values
@@ -16,13 +15,6 @@ export interface RendererInstance {
hydrationPolyfills: string[];
}
-const astroRendererInstance: RendererInstance = {
- source: '',
- renderer: astro as Renderer,
- polyfills: [],
- hydrationPolyfills: [],
-};
-
const astroHtmlRendererInstance: RendererInstance = {
source: '',
renderer: astroHtml as Renderer,
@@ -33,7 +25,7 @@ const astroHtmlRendererInstance: RendererInstance = {
let rendererInstances: RendererInstance[] = [];
export function setRenderers(_rendererInstances: RendererInstance[]) {
- rendererInstances = [astroRendererInstance].concat(_rendererInstances);
+ rendererInstances = ([] as RendererInstance[]).concat(_rendererInstances);
}
function isCustomElementTag(name: string | Function) {
@@ -121,15 +113,48 @@ const getComponentName = (Component: any, componentProps: any) => {
}
};
-export const __astro_component = (Component: any, metadata: AstroComponentMetadata = {} as any) => {
+const prepareSlottedChildren = (children: string|Record<any, any>[]) => {
+ const $slots: Record<string, string> = {
+ default: ''
+ };
+ for (const child of children) {
+ if (typeof child === 'string') {
+ $slots.default += child;
+ } else if (typeof child === 'object' && child['$slot']) {
+ if (!$slots[child['$slot']]) $slots[child['$slot']] = '';
+ $slots[child['$slot']] += child.children.join('').replace(new RegExp(`slot="${child['$slot']}"\s*`, ''));
+ }
+ }
+
+ return { $slots };
+}
+
+const removeSlottedChildren = (_children: string|Record<any, any>[]) => {
+ let children = '';
+ for (const child of _children) {
+ if (typeof child === 'string') {
+ children += child;
+ } else if (typeof child === 'object' && child['$slot']) {
+ children += child.children.join('');
+ }
+ }
+
+ return children;
+}
+
+/** The main wrapper for any components in Astro files */
+export function __astro_component(Component: any, metadata: AstroComponentMetadata = {} as any) {
if (Component == null) {
throw new Error(`Unable to render ${metadata.displayName} because it is ${Component}!\nDid you forget to import the component or is it possible there is a typo?`);
} else if (typeof Component === 'string' && !isCustomElementTag(Component)) {
throw new Error(`Astro is unable to render ${metadata.displayName}!\nIs there a renderer to handle this type of component defined in your Astro config?`);
}
- return async (props: any, ..._children: string[]) => {
- const children = _children.join('\n');
+ return async function __astro_component_internal(props: any, ..._children: any[]) {
+ if (Component.isAstroComponent) {
+ return Component.__render(props, prepareSlottedChildren(_children));
+ }
+ const children = removeSlottedChildren(_children);
let instance = await resolveRenderer(Component, props, children);
if (!instance) {
diff --git a/packages/astro/src/internal/__astro_slot.ts b/packages/astro/src/internal/__astro_slot.ts
new file mode 100644
index 000000000..c049e82bc
--- /dev/null
+++ b/packages/astro/src/internal/__astro_slot.ts
@@ -0,0 +1,15 @@
+/** */
+export function __astro_slot_content({ name }: { name: string}, ...children: any[]) {
+ return { '$slot': name, children };
+}
+
+export const __astro_slot = ({ name = 'default' }: { name: string}, _children: any, ...fallback: string[]) => {
+ if (name === 'default' && typeof _children === 'string') {
+ return _children ? _children : fallback;
+ }
+ if (!_children.$slots) {
+ throw new Error(`__astro_slot encountered an unexpected child:\n${JSON.stringify(_children)}`);
+ }
+ const children = _children.$slots[name];
+ return children ? children : fallback;
+};
diff --git a/packages/astro/src/internal/renderer-astro.ts b/packages/astro/src/internal/renderer-astro.ts
deleted file mode 100644
index 10af2a5a9..000000000
--- a/packages/astro/src/internal/renderer-astro.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export function check(Component: any) {
- return Component.isAstroComponent;
-}
-
-export async function renderToStaticMarkup(Component: any, props: any, children: string) {
- const html = await Component.__render(props, children);
- return { html };
-}