summaryrefslogtreecommitdiff
path: root/packages/integrations/solid/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/integrations/solid/src')
-rw-r--r--packages/integrations/solid/src/client.ts45
-rw-r--r--packages/integrations/solid/src/context.ts28
-rw-r--r--packages/integrations/solid/src/server.ts45
-rw-r--r--packages/integrations/solid/src/types.ts4
4 files changed, 122 insertions, 0 deletions
diff --git a/packages/integrations/solid/src/client.ts b/packages/integrations/solid/src/client.ts
new file mode 100644
index 000000000..b58bdd0b8
--- /dev/null
+++ b/packages/integrations/solid/src/client.ts
@@ -0,0 +1,45 @@
+import { sharedConfig } from 'solid-js';
+import { hydrate, render, createComponent } from 'solid-js/web';
+
+export default (element: HTMLElement) =>
+ (Component: any, props: any, slotted: any, { client }: { client: string }) => {
+ // Prepare global object expected by Solid's hydration logic
+ if (!(window as any)._$HY) {
+ (window as any)._$HY = { events: [], completed: new WeakSet(), r: {} };
+ }
+ if (!element.hasAttribute('ssr')) return;
+
+ const fn = client === 'only' ? render : hydrate;
+
+ let _slots: Record<string, any> = {};
+ if (Object.keys(slotted).length > 0) {
+ // hydrating
+ if (sharedConfig.context) {
+ element.querySelectorAll('astro-slot').forEach((slot) => {
+ _slots[slot.getAttribute('name') || 'default'] = slot.cloneNode(true);
+ });
+ } else {
+ for (const [key, value] of Object.entries(slotted)) {
+ _slots[key] = document.createElement('astro-slot');
+ if (key !== 'default') _slots[key].setAttribute('name', key);
+ _slots[key].innerHTML = value;
+ }
+ }
+ }
+
+ const { default: children, ...slots } = _slots;
+ const renderId = element.dataset.solidRenderId;
+
+ fn(
+ () =>
+ createComponent(Component, {
+ ...props,
+ ...slots,
+ children,
+ }),
+ element,
+ {
+ renderId
+ }
+ );
+ };
diff --git a/packages/integrations/solid/src/context.ts b/packages/integrations/solid/src/context.ts
new file mode 100644
index 000000000..c7b6cc392
--- /dev/null
+++ b/packages/integrations/solid/src/context.ts
@@ -0,0 +1,28 @@
+import type { RendererContext } from './types';
+
+type Context = {
+ id: string;
+ c: number;
+}
+
+const contexts = new WeakMap<RendererContext['result'], Context>();
+
+export function getContext(result: RendererContext['result']): Context {
+ if(contexts.has(result)) {
+ return contexts.get(result)!;
+ }
+ let ctx = {
+ c: 0,
+ get id() {
+ return 's' + this.c.toString();
+ }
+ };
+ contexts.set(result, ctx);
+ return ctx;
+}
+
+export function incrementId(ctx: Context): string {
+ let id = ctx.id;
+ ctx.c++;
+ return id;
+}
diff --git a/packages/integrations/solid/src/server.ts b/packages/integrations/solid/src/server.ts
new file mode 100644
index 000000000..bd50d8d77
--- /dev/null
+++ b/packages/integrations/solid/src/server.ts
@@ -0,0 +1,45 @@
+import type { RendererContext } from './types';
+import { renderToString, ssr, createComponent } from 'solid-js/web';
+import { getContext, incrementId } from './context.js';
+
+const slotName = (str: string) => str.trim().replace(/[-_]([a-z])/g, (_, w) => w.toUpperCase());
+
+function check(this: RendererContext, Component: any, props: Record<string, any>, children: any) {
+ if (typeof Component !== 'function') return false;
+ const { html } = renderToStaticMarkup.call(this, Component, props, children);
+ return typeof html === 'string';
+}
+
+function renderToStaticMarkup(this: RendererContext, Component: any, props: Record<string, any>, { default: children, ...slotted }: any, metadata?: undefined | Record<string, any>) {
+ const renderId = metadata?.hydrate ? incrementId(getContext(this.result)) : '';
+
+ const html = renderToString(() => {
+ const slots: Record<string, any> = {};
+ for (const [key, value] of Object.entries(slotted)) {
+ const name = slotName(key);
+ slots[name] = ssr(`<astro-slot name="${name}">${value}</astro-slot>`);
+ }
+ // Note: create newProps to avoid mutating `props` before they are serialized
+ const newProps = {
+ ...props,
+ ...slots,
+ // In Solid SSR mode, `ssr` creates the expected structure for `children`.
+ children: children != null ? ssr(`<astro-slot>${children}</astro-slot>`) : children,
+ };
+
+ return createComponent(Component, newProps);
+ }, {
+ renderId
+ });
+ return {
+ attrs: {
+ 'data-solid-render-id': renderId
+ },
+ html
+ };
+}
+
+export default {
+ check,
+ renderToStaticMarkup,
+};
diff --git a/packages/integrations/solid/src/types.ts b/packages/integrations/solid/src/types.ts
new file mode 100644
index 000000000..5dff5b0b4
--- /dev/null
+++ b/packages/integrations/solid/src/types.ts
@@ -0,0 +1,4 @@
+import type { SSRResult } from 'astro';
+export type RendererContext = {
+ result: SSRResult;
+};