summaryrefslogtreecommitdiff
path: root/packages/integrations/react/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--packages/integrations/react/src/client-v17.ts (renamed from packages/integrations/react/client-v17.js)9
-rw-r--r--packages/integrations/react/src/client.ts (renamed from packages/integrations/react/client.js)29
-rw-r--r--packages/integrations/react/src/context.ts (renamed from packages/integrations/react/context.js)10
-rw-r--r--packages/integrations/react/src/jsx-runtime.ts (renamed from packages/integrations/react/jsx-runtime.js)2
-rw-r--r--packages/integrations/react/src/server-v17.ts (renamed from packages/integrations/react/server-v17.js)20
-rw-r--r--packages/integrations/react/src/server.ts (renamed from packages/integrations/react/server.js)48
-rw-r--r--packages/integrations/react/src/static-html.ts (renamed from packages/integrations/react/static-html.js)6
-rw-r--r--packages/integrations/react/src/types.ts4
-rw-r--r--packages/integrations/react/src/vnode-children.ts (renamed from packages/integrations/react/vnode-children.js)6
9 files changed, 87 insertions, 47 deletions
diff --git a/packages/integrations/react/client-v17.js b/packages/integrations/react/src/client-v17.ts
index bd17050ea..4ba4bcf60 100644
--- a/packages/integrations/react/client-v17.js
+++ b/packages/integrations/react/src/client-v17.ts
@@ -2,8 +2,13 @@ import { createElement } from 'react';
import { hydrate, render, unmountComponentAtNode } from 'react-dom';
import StaticHtml from './static-html.js';
-export default (element) =>
- (Component, props, { default: children, ...slotted }, { client }) => {
+export default (element: HTMLElement) =>
+ (
+ Component: any,
+ props: Record<string, any>,
+ { default: children, ...slotted }: Record<string, any>,
+ { client }: Record<string, string>,
+ ) => {
for (const [key, value] of Object.entries(slotted)) {
props[key] = createElement(StaticHtml, { value, name: key });
}
diff --git a/packages/integrations/react/client.js b/packages/integrations/react/src/client.ts
index 044eaf26f..ea187a1a1 100644
--- a/packages/integrations/react/client.js
+++ b/packages/integrations/react/src/client.ts
@@ -1,17 +1,17 @@
import { createElement, startTransition } from 'react';
-import { createRoot, hydrateRoot } from 'react-dom/client';
+import { type Root, createRoot, hydrateRoot } from 'react-dom/client';
import StaticHtml from './static-html.js';
-function isAlreadyHydrated(element) {
+function isAlreadyHydrated(element: HTMLElement) {
for (const key in element) {
if (key.startsWith('__reactContainer')) {
- return key;
+ return key as keyof HTMLElement;
}
}
}
-function createReactElementFromDOMElement(element) {
- let attrs = {};
+function createReactElementFromDOMElement(element: any): any {
+ let attrs: Record<string, string> = {};
for (const attr of element.attributes) {
attrs[attr.name] = attr.value;
}
@@ -24,7 +24,7 @@ function createReactElementFromDOMElement(element) {
element.localName,
attrs,
Array.from(element.childNodes)
- .map((c) => {
+ .map((c: any) => {
if (c.nodeType === Node.TEXT_NODE) {
return c.data;
} else if (c.nodeType === Node.ELEMENT_NODE) {
@@ -37,7 +37,7 @@ function createReactElementFromDOMElement(element) {
);
}
-function getChildren(childString, experimentalReactChildren) {
+function getChildren(childString: string, experimentalReactChildren: boolean) {
if (experimentalReactChildren && childString) {
let children = [];
let template = document.createElement('template');
@@ -54,8 +54,8 @@ function getChildren(childString, experimentalReactChildren) {
}
// Keep a map of roots so we can reuse them on re-renders
-let rootMap = new WeakMap();
-const getOrCreateRoot = (element, creator) => {
+let rootMap = new WeakMap<HTMLElement, Root>();
+const getOrCreateRoot = (element: HTMLElement, creator: () => Root) => {
let root = rootMap.get(element);
if (!root) {
root = creator();
@@ -64,8 +64,13 @@ const getOrCreateRoot = (element, creator) => {
return root;
};
-export default (element) =>
- (Component, props, { default: children, ...slotted }, { client }) => {
+export default (element: HTMLElement) =>
+ (
+ Component: any,
+ props: Record<string, any>,
+ { default: children, ...slotted }: Record<string, any>,
+ { client }: Record<string, string>,
+ ) => {
if (!element.hasAttribute('ssr')) return;
const actionKey = element.getAttribute('data-action-key');
@@ -107,7 +112,7 @@ export default (element) =>
}
startTransition(() => {
const root = getOrCreateRoot(element, () => {
- const r = hydrateRoot(element, componentEl, renderOptions);
+ const r = hydrateRoot(element, componentEl, renderOptions as any);
element.addEventListener('astro:unmount', () => r.unmount(), { once: true });
return r;
});
diff --git a/packages/integrations/react/context.js b/packages/integrations/react/src/context.ts
index 2e3e37fd5..953c35c6a 100644
--- a/packages/integrations/react/context.js
+++ b/packages/integrations/react/src/context.ts
@@ -1,8 +1,10 @@
-const contexts = new WeakMap();
+import type { SSRResult } from 'astro';
+
+const contexts = new WeakMap<SSRResult, { currentIndex: number; readonly id: string }>();
const ID_PREFIX = 'r';
-function getContext(rendererContextResult) {
+function getContext(rendererContextResult: SSRResult) {
if (contexts.has(rendererContextResult)) {
return contexts.get(rendererContextResult);
}
@@ -16,8 +18,8 @@ function getContext(rendererContextResult) {
return ctx;
}
-export function incrementId(rendererContextResult) {
- const ctx = getContext(rendererContextResult);
+export function incrementId(rendererContextResult: SSRResult) {
+ const ctx = getContext(rendererContextResult)!;
const id = ctx.id;
ctx.currentIndex++;
return id;
diff --git a/packages/integrations/react/jsx-runtime.js b/packages/integrations/react/src/jsx-runtime.ts
index d86f698b9..3f0e51c65 100644
--- a/packages/integrations/react/jsx-runtime.js
+++ b/packages/integrations/react/src/jsx-runtime.ts
@@ -2,7 +2,7 @@
// it can run in Node ESM. 'react' doesn't declare this module as an export map
// So we have to use the .js. The .js is not added via the babel automatic JSX transform
// hence this module as a workaround.
-import jsxr from 'react/jsx-runtime.js';
+import jsxr from 'react/jsx-runtime';
const { jsx, jsxs, Fragment } = jsxr;
export { jsx, jsxs, Fragment };
diff --git a/packages/integrations/react/server-v17.js b/packages/integrations/react/src/server-v17.ts
index 4e577883a..a91b6e6d5 100644
--- a/packages/integrations/react/server-v17.js
+++ b/packages/integrations/react/src/server-v17.ts
@@ -1,11 +1,12 @@
+import type { AstroComponentMetadata } from 'astro';
import React from 'react';
-import ReactDOM from 'react-dom/server.js';
+import ReactDOM from 'react-dom/server';
import StaticHtml from './static-html.js';
-const slotName = (str) => str.trim().replace(/[-_]([a-z])/g, (_, w) => w.toUpperCase());
+const slotName = (str: string) => str.trim().replace(/[-_]([a-z])/g, (_, w) => w.toUpperCase());
const reactTypeof = Symbol.for('react.element');
-function check(Component, props, children) {
+function check(Component: any, props: Record<string, any>, children: any) {
// Note: there are packages that do some unholy things to create "components".
// Checking the $$typeof property catches most of these patterns.
if (typeof Component === 'object') {
@@ -19,7 +20,7 @@ function check(Component, props, children) {
}
let isReactComponent = false;
- function Tester(...args) {
+ function Tester(...args: Array<any>) {
try {
const vnode = Component(...args);
if (vnode && vnode['$$typeof'] === reactTypeof) {
@@ -30,14 +31,19 @@ function check(Component, props, children) {
return React.createElement('div');
}
- renderToStaticMarkup(Tester, props, children, {});
+ renderToStaticMarkup(Tester, props, children, {} as any);
return isReactComponent;
}
-function renderToStaticMarkup(Component, props, { default: children, ...slotted }, metadata) {
+function renderToStaticMarkup(
+ Component: any,
+ props: Record<string, any>,
+ { default: children, ...slotted }: Record<string, any>,
+ metadata: AstroComponentMetadata,
+) {
delete props['class'];
- const slots = {};
+ const slots: Record<string, any> = {};
for (const [key, value] of Object.entries(slotted)) {
const name = slotName(key);
slots[name] = React.createElement(StaticHtml, { value, name });
diff --git a/packages/integrations/react/server.js b/packages/integrations/react/src/server.ts
index 67d9e9386..5581a95db 100644
--- a/packages/integrations/react/server.js
+++ b/packages/integrations/react/src/server.ts
@@ -1,14 +1,21 @@
import opts from 'astro:react:opts';
+import type { AstroComponentMetadata } from 'astro';
import React from 'react';
import ReactDOM from 'react-dom/server';
import { incrementId } from './context.js';
import StaticHtml from './static-html.js';
+import type { RendererContext } from './types.js';
-const slotName = (str) => str.trim().replace(/[-_]([a-z])/g, (_, w) => w.toUpperCase());
+const slotName = (str: string) => str.trim().replace(/[-_]([a-z])/g, (_, w) => w.toUpperCase());
const reactTypeof = Symbol.for('react.element');
const reactTransitionalTypeof = Symbol.for('react.transitional.element');
-async function check(Component, props, children) {
+async function check(
+ this: RendererContext,
+ Component: any,
+ props: Record<string, any>,
+ children: any,
+) {
// Note: there are packages that do some unholy things to create "components".
// Checking the $$typeof property catches most of these patterns.
if (typeof Component === 'object') {
@@ -26,7 +33,7 @@ async function check(Component, props, children) {
}
let isReactComponent = false;
- function Tester(...args) {
+ function Tester(...args: Array<any>) {
try {
const vnode = Component(...args);
if (
@@ -40,31 +47,37 @@ async function check(Component, props, children) {
return React.createElement('div');
}
- await renderToStaticMarkup(Tester, props, children, {});
+ await renderToStaticMarkup.call(this, Tester, props, children, {} as any);
return isReactComponent;
}
-async function getNodeWritable() {
+async function getNodeWritable(): Promise<typeof import('node:stream').Writable> {
let nodeStreamBuiltinModuleName = 'node:stream';
let { Writable } = await import(/* @vite-ignore */ nodeStreamBuiltinModuleName);
return Writable;
}
-function needsHydration(metadata) {
+function needsHydration(metadata: AstroComponentMetadata) {
// Adjust how this is hydrated only when the version of Astro supports `astroStaticSlot`
return metadata.astroStaticSlot ? !!metadata.hydrate : true;
}
-async function renderToStaticMarkup(Component, props, { default: children, ...slotted }, metadata) {
+async function renderToStaticMarkup(
+ this: RendererContext,
+ Component: any,
+ props: Record<string, any>,
+ { default: children, ...slotted }: Record<string, any>,
+ metadata: AstroComponentMetadata,
+) {
let prefix;
if (this && this.result) {
prefix = incrementId(this.result);
}
- const attrs = { prefix };
+ const attrs: Record<string, any> = { prefix };
delete props['class'];
- const slots = {};
+ const slots: Record<string, any> = {};
for (const [key, value] of Object.entries(slotted)) {
const name = slotName(key);
slots[name] = React.createElement(StaticHtml, {
@@ -111,10 +124,11 @@ async function renderToStaticMarkup(Component, props, { default: children, ...sl
return { html, attrs };
}
-/**
- * @returns {Promise<[actionResult: any, actionKey: string, actionName: string] | undefined>}
- */
-async function getFormState({ result }) {
+async function getFormState({
+ result,
+}: RendererContext): Promise<
+ [actionResult: any, actionKey: string, actionName: string] | undefined
+> {
const { request, actionResult } = result;
if (!actionResult) return undefined;
@@ -139,7 +153,7 @@ async function getFormState({ result }) {
return [actionResult, actionKey, actionName];
}
-async function renderToPipeableStreamAsync(vnode, options) {
+async function renderToPipeableStreamAsync(vnode: any, options: Record<string, any>) {
const Writable = await getNodeWritable();
let html = '';
return new Promise((resolve, reject) => {
@@ -171,7 +185,7 @@ async function renderToPipeableStreamAsync(vnode, options) {
* Use a while loop instead of "for await" due to cloudflare and Vercel Edge issues
* See https://github.com/facebook/react/issues/24169
*/
-async function readResult(stream) {
+async function readResult(stream: ReactDOM.ReactDOMServerReadableStream) {
const reader = stream.getReader();
let result = '';
const decoder = new TextDecoder('utf-8');
@@ -191,13 +205,13 @@ async function readResult(stream) {
}
}
-async function renderToReadableStreamAsync(vnode, options) {
+async function renderToReadableStreamAsync(vnode: any, options: Record<string, any>) {
return await readResult(await ReactDOM.renderToReadableStream(vnode, options));
}
const formContentTypes = ['application/x-www-form-urlencoded', 'multipart/form-data'];
-function isFormRequest(contentType) {
+function isFormRequest(contentType: string | null) {
// Split off parameters like charset or boundary
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type#content-type_in_html_forms
const type = contentType?.split(';')[0].toLowerCase();
diff --git a/packages/integrations/react/static-html.js b/packages/integrations/react/src/static-html.ts
index e319a40c7..010896196 100644
--- a/packages/integrations/react/static-html.js
+++ b/packages/integrations/react/src/static-html.ts
@@ -7,7 +7,11 @@ import { createElement as h } from 'react';
* As a bonus, we can signal to React that this subtree is
* entirely static and will never change via `shouldComponentUpdate`.
*/
-const StaticHtml = ({ value, name, hydrate = true }) => {
+const StaticHtml = ({
+ value,
+ name,
+ hydrate = true,
+}: { value: string | null; name?: string; hydrate?: boolean }) => {
if (!value) return null;
const tagName = hydrate ? 'astro-slot' : 'astro-static-slot';
return h(tagName, {
diff --git a/packages/integrations/react/src/types.ts b/packages/integrations/react/src/types.ts
new file mode 100644
index 000000000..5dff5b0b4
--- /dev/null
+++ b/packages/integrations/react/src/types.ts
@@ -0,0 +1,4 @@
+import type { SSRResult } from 'astro';
+export type RendererContext = {
+ result: SSRResult;
+};
diff --git a/packages/integrations/react/vnode-children.js b/packages/integrations/react/src/vnode-children.ts
index e0751c95a..6aa9724c6 100644
--- a/packages/integrations/react/vnode-children.js
+++ b/packages/integrations/react/src/vnode-children.ts
@@ -2,15 +2,15 @@ import { Fragment, createElement } from 'react';
import { DOCUMENT_NODE, ELEMENT_NODE, TEXT_NODE, parse } from 'ultrahtml';
let ids = 0;
-export default function convert(children) {
+export default function convert(children: any) {
let doc = parse(children.toString().trim());
let id = ids++;
let key = 0;
- function createReactElementFromNode(node) {
+ function createReactElementFromNode(node: any) {
const childVnodes =
Array.isArray(node.children) && node.children.length
- ? node.children.map((child) => createReactElementFromNode(child)).filter(Boolean)
+ ? node.children.map((child: any) => createReactElementFromNode(child)).filter(Boolean)
: undefined;
if (node.type === DOCUMENT_NODE) {