@tanstack/redact 0.0.15 → 0.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/attributes.d.ts +1 -0
- package/dist/core/attributes.js +19 -0
- package/dist/core/attributes.js.map +7 -0
- package/dist/core/internal.d.ts +1 -0
- package/dist/core/internal.js.map +2 -2
- package/dist/dom/dispatcher.js +1 -1
- package/dist/dom/dispatcher.js.map +2 -2
- package/dist/dom/dom.js +9 -7
- package/dist/dom/dom.js.map +2 -2
- package/dist/dom/features/hydration/full.js +27 -6
- package/dist/dom/features/hydration/full.js.map +2 -2
- package/dist/dom/features/suspense/full.js +7 -9
- package/dist/dom/features/suspense/full.js.map +2 -2
- package/dist/dom/root-internal.js +2 -0
- package/dist/dom/root-internal.js.map +2 -2
- package/dist/server/escape.d.ts +1 -2
- package/dist/server/escape.js +3 -13
- package/dist/server/escape.js.map +2 -2
- package/dist/server/walk.d.ts +1 -0
- package/dist/server/walk.js +9 -4
- package/dist/server/walk.js.map +2 -2
- package/package.json +1 -1
- package/src/core/attributes.ts +17 -0
- package/src/core/internal.ts +1 -0
- package/src/dom/dispatcher.ts +3 -1
- package/src/dom/dom.ts +10 -7
- package/src/dom/features/hydration/full.ts +27 -8
- package/src/dom/features/suspense/full.ts +8 -10
- package/src/dom/root-internal.ts +2 -0
- package/src/server/escape.ts +4 -13
- package/src/server/walk.ts +10 -4
|
@@ -58,7 +58,7 @@ function renderSuspense(fiber, domParent, anchor) {
|
|
|
58
58
|
fiber.mp = props;
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
|
-
const hadCommittedPrimary = fiber.mp
|
|
61
|
+
const hadCommittedPrimary = fiber.mp && fiber.child;
|
|
62
62
|
const prevHandler = suspendHandler;
|
|
63
63
|
let pendingThenable;
|
|
64
64
|
suspendHandler = (thenable) => {
|
|
@@ -76,9 +76,9 @@ function renderSuspense(fiber, domParent, anchor) {
|
|
|
76
76
|
scheduleUpdate(fiber);
|
|
77
77
|
};
|
|
78
78
|
pendingThenable.then(onSettle, onSettle);
|
|
79
|
-
if (hadCommittedPrimary
|
|
79
|
+
if (hadCommittedPrimary) {
|
|
80
80
|
const hidden = [];
|
|
81
|
-
let c =
|
|
81
|
+
let c = hadCommittedPrimary;
|
|
82
82
|
while (c) {
|
|
83
83
|
hideRootHostDoms(c, hidden);
|
|
84
84
|
c = c.sibling;
|
|
@@ -111,10 +111,8 @@ function renderSuspense(fiber, domParent, anchor) {
|
|
|
111
111
|
function hideRootHostDoms(fiber, out) {
|
|
112
112
|
if (fiber.tag === FiberTag.Host) {
|
|
113
113
|
const el = fiber.dom;
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
el.style.display = "none";
|
|
117
|
-
}
|
|
114
|
+
out.push([el, el.style.display]);
|
|
115
|
+
el.style.display = "none";
|
|
118
116
|
return;
|
|
119
117
|
}
|
|
120
118
|
if (fiber.tag === FiberTag.Portal) return;
|
|
@@ -205,10 +203,10 @@ function recoverFallbackHydration(fiber, fallback, parent) {
|
|
|
205
203
|
}
|
|
206
204
|
function rehydrateBoundary(fiber) {
|
|
207
205
|
const state = fiber.ms;
|
|
208
|
-
if (!state
|
|
206
|
+
if (!state?.b || !state.e) return;
|
|
209
207
|
const root = findRoot(fiber);
|
|
210
208
|
const parent = state.b.parentNode;
|
|
211
|
-
if (!root
|
|
209
|
+
if (!(root && parent)) return;
|
|
212
210
|
withCurrentRoot(root, () => {
|
|
213
211
|
const prevHydrating = root.h;
|
|
214
212
|
try {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/dom/features/suspense/full.ts"],
|
|
4
|
-
"sourcesContent": ["import { FiberTag, createFiber, type Fiber } from '../../../core'\nimport { REACT_SUSPENSE_TYPE } from '../../../react'\nimport {\n registerRenderer,\n registerTypeMatcher,\n installCapability,\n reconcileChildren,\n childrenToArray,\n renderFiber,\n scheduleUpdate,\n unmountAllChildren,\n unmountFiber,\n findRoot,\n runEffects,\n getCurrentRoot,\n withCurrentRoot,\n discardPendingWork,\n} from '../../reconcile'\nimport {\n HydrationCursor,\n setHydrationCursor,\n clearHydrationCursor,\n advanceCursorPast,\n tryConsumeBoundary,\n isHydrationBailout,\n} from '../hydration'\n\nlet suspendHandler: ((t: Promise<any>) => void) | null = null\n\nfunction realHandleSuspended(fiber: Fiber, thenable: Promise<any>): void {\n if (suspendHandler) return suspendHandler(thenable)\n // Fallback: schedule re-render when promise settles\n thenable.then(\n () => scheduleUpdate(fiber),\n () => scheduleUpdate(fiber),\n )\n}\n\n// React's Suspense semantics: when a re-render of an already-committed\n// boundary suspends, the previously-committed children are kept in the DOM\n// (hidden) so their scroll position, focus, selection, native form state,\n// and component state survive across the suspension. The fallback is mounted\n// alongside the hidden primary until the pending promise resolves.\n//\n// We track the hidden subtree DOM in `state.d` (root host nodes +\n// their original `display` so we can restore it) and the fallback as a\n// detached Fragment fiber in `state.f` (deliberately kept OUT of\n// `fiber.child` so reconciles against `props.children` don't trip on it).\n// First-mount suspensions have no committed DOM worth preserving, so they\n// keep the original unmount-and-render-fallback behavior.\ninterface SuspenseState {\n p?: Promise<any> | null\n b?: Comment\n e?: Comment\n r?: any\n a?: boolean\n // Re-suspend preservation:\n d?: Array<[HTMLElement, string]> | null\n f?: Fiber | null\n}\n\nfunction renderSuspense(fiber: Fiber, domParent: Node, anchor: Node | null): void {\n const props = fiber.pp ?? {}\n const state = (fiber.ms ??= {}) as SuspenseState\n\n // Streaming hydration: if the next DOM node is a server-emitted boundary\n // marker, route through the boundary-aware hydration path.\n const root = getCurrentRoot()\n if (root?.h && !state.b) {\n const boundary = tryConsumeBoundary(fiber.parent!)\n if (boundary) {\n hydrateSuspenseBoundary(fiber, props, boundary, domParent, anchor)\n return\n }\n }\n\n // A descendant Lazy deferred its hydration (see renderLazy's hydrating\n // branch). Its SSR-rendered content is still in the DOM and cursor-bound\n // via the Lazy fiber \u2014 we just haven't swapped it into a fiber subtree\n // yet. Until the Lazy's resume fires, skip our own tryChildren pass so\n // an unrelated re-render can't accidentally flip us into the suspended\n // path and mount a duplicate fallback on top of the SSR content.\n if (state.a) {\n fiber.mp = props\n return\n }\n\n // We were already in the suspended-with-preserved-primary state. Don't\n // re-attempt primary children (would re-throw and churn the tree). Just\n // refresh the fallback in case its JSX changed, and wait for the pending\n // promise to fire scheduleUpdate.\n if (state.p) {\n if (state.f) {\n state.f.pp = { children: props.fallback }\n renderFiber(state.f, domParent, anchor)\n } else {\n // Initial-mount suspended path: no committed primary to preserve.\n reconcileChildren(fiber, childrenToArray(props.fallback), domParent, anchor)\n }\n fiber.mp = props\n return\n }\n\n // Snapshot whether we have an existing committed primary tree before\n // attempting the new render. If the new attempt suspends and we did have a\n // committed primary, we keep it (hidden) rather than destroying it.\n const hadCommittedPrimary = fiber.mp !== undefined && fiber.child !== null\n\n const prevHandler = suspendHandler\n let pendingThenable: any\n suspendHandler = (thenable) => {\n pendingThenable = thenable\n }\n try {\n reconcileChildren(fiber, childrenToArray(props.children), domParent, anchor)\n } finally {\n suspendHandler = prevHandler\n }\n\n if (pendingThenable) {\n state.p = pendingThenable\n const onSettle = () => {\n state.p = null\n scheduleUpdate(fiber)\n }\n pendingThenable.then(onSettle, onSettle)\n\n if (hadCommittedPrimary && fiber.child) {\n // Hide the primary subtree's root host doms so the fallback is the only\n // thing visible, but the underlying nodes (and their scroll/state/focus)\n // survive. Save original `display` for the resume path.\n const hidden: Array<[HTMLElement, string]> = []\n let c: Fiber | null = fiber.child\n while (c) {\n hideRootHostDoms(c, hidden)\n c = c.sibling\n }\n state.d = hidden\n\n // Mount fallback in a detached Fragment fiber. Kept off `fiber.child`\n // so reconciles of primary don't see it as a stale match candidate.\n if (!state.f) {\n state.f = createFiber(FiberTag.Fragment, null, null)\n state.f.parent = fiber\n }\n state.f.pp = { children: props.fallback }\n renderFiber(state.f, domParent, anchor)\n } else {\n // First-mount suspension \u2014 nothing to preserve.\n unmountAllChildren(fiber, domParent)\n reconcileChildren(fiber, childrenToArray(props.fallback), domParent, anchor)\n }\n } else {\n // Render succeeded. Clean up any preserved-suspend state from a prior\n // suspension cycle: unhide primary, unmount the orphan fallback fiber.\n if (state.d) {\n for (const [el, origDisplay] of state.d) {\n el.style.display = origDisplay\n }\n state.d = null\n }\n if (state.f) {\n unmountFiber(state.f, domParent)\n state.f = null\n }\n }\n fiber.mp = props\n}\n\n// Walk a fiber subtree collecting host/text DOM nodes that sit at the root\n// of the subtree (do not descend through their children \u2014 display:none on\n// the root hides the whole element). Used by the hide-on-suspend path.\nfunction hideRootHostDoms(fiber: Fiber, out: Array<[HTMLElement, string]>): void {\n if (fiber.tag === FiberTag.Host) {\n const el = fiber.dom as HTMLElement | null\n if (el) {\n out.push([el, el.style.display])\n el.style.display = 'none'\n }\n return\n }\n if (fiber.tag === FiberTag.Portal) return\n let c = fiber.child\n while (c) {\n hideRootHostDoms(c, out)\n c = c.sibling\n }\n}\n\nfunction hydrateSuspenseBoundary(\n fiber: Fiber,\n props: any,\n boundary: [0 | 1, number, Comment, Comment],\n domParent: Node,\n anchor: Node | null,\n): void {\n const [pendingBoundary, id, startMark, endMark] = boundary\n // Record the boundary shape so we can re-hydrate on reveal.\n fiber.ms = {\n b: startMark,\n e: endMark,\n r: props.children,\n }\n\n if (!pendingBoundary) {\n // Real DOM is inline between startMark and endMark. Hydrate into it.\n const parent = startMark.parentNode!\n try {\n setHydrationCursor(fiber, new HydrationCursor(parent, startMark.nextSibling, endMark))\n reconcileChildren(fiber, childrenToArray(props.children), domParent, anchor)\n advanceCursorPast(fiber.parent!, endMark)\n } catch (e) {\n if (!isHydrationBailout(e)) {\n clearBoundaryRange(startMark, endMark)\n unmountAllChildren(fiber, parent)\n throw e\n }\n recoverBoundaryHydration(fiber, props.children, parent, startMark, endMark)\n } finally {\n clearHydrationCursor(fiber)\n }\n fiber.mp = props\n return\n }\n\n // Pending: fallback DOM lives inside <div id=\"B:ID\">. Hydrate the fallback\n // React subtree against that div's children.\n const bDiv = document.getElementById(`B:${id}`)\n try {\n if (bDiv) {\n setHydrationCursor(fiber, new HydrationCursor(bDiv))\n reconcileChildren(fiber, childrenToArray(props.fallback), domParent, anchor)\n } else {\n // Couldn't find fallback container \u2014 render fresh (non-adopting)\n reconcileChildren(fiber, childrenToArray(props.fallback), domParent, anchor)\n }\n } catch (e) {\n if (!isHydrationBailout(e) || !bDiv) throw e\n recoverFallbackHydration(fiber, props.fallback, bDiv)\n } finally {\n clearHydrationCursor(fiber)\n }\n advanceCursorPast(fiber.parent!, endMark)\n\n // Register for server-streamed reveal (HTML chunks + $RC calls).\n ;(globalThis as any).$RH?.(id, () => rehydrateBoundary(fiber))\n // If the inline runtime isn't present, nothing external will mark us dy.\n\n fiber.mp = props\n}\n\nfunction recoverBoundaryHydration(\n fiber: Fiber,\n children: any,\n parent: Node,\n startMark: Comment,\n endMark: Comment,\n): void {\n const root = findRoot(fiber)!\n const prevHydrating = root.h\n discardPendingWork(root)\n clearBoundaryRange(startMark, endMark)\n unmountAllChildren(fiber, parent)\n root.h = false\n try {\n reconcileChildren(fiber, childrenToArray(children), parent, endMark)\n advanceCursorPast(fiber.parent!, endMark)\n } catch (clientError) {\n clearBoundaryRange(startMark, endMark)\n unmountAllChildren(fiber, parent)\n throw clientError\n } finally {\n root.h = prevHydrating\n }\n}\n\nfunction recoverFallbackHydration(fiber: Fiber, fallback: any, parent: HTMLElement): void {\n const root = findRoot(fiber)!\n const prevHydrating = root.h\n discardPendingWork(root)\n parent.textContent = ''\n unmountAllChildren(fiber, parent)\n root.h = false\n try {\n reconcileChildren(fiber, childrenToArray(fallback), parent, null)\n } catch (clientError) {\n parent.textContent = ''\n unmountAllChildren(fiber, parent)\n throw clientError\n } finally {\n root.h = prevHydrating\n }\n}\n\nfunction rehydrateBoundary(fiber: Fiber): void {\n const state = fiber.ms\n if (!state || !state.b || !state.e) return\n\n const root = findRoot(fiber)\n const parent = state.b.parentNode as Node\n if (!root || !parent) return\n\n // Unmount existing fallback subtree. Its DOM has already been removed by $RC\n // (or at least its container); unmounting here cleans up fibers + fx.\n withCurrentRoot(root, () => {\n const prevHydrating = root.h\n try {\n unmountAllChildren(fiber, parent)\n\n // Re-hydrate with real children against the now-real DOM range.\n root.h = true\n setHydrationCursor(fiber, new HydrationCursor(parent, state.b.nextSibling, state.e))\n reconcileChildren(fiber, childrenToArray(state.r), parent, null)\n } catch (e) {\n if (!isHydrationBailout(e)) {\n clearBoundaryRange(state.b, state.e)\n unmountAllChildren(fiber, parent)\n throw e\n }\n\n recoverBoundaryHydration(fiber, state.r, parent, state.b, state.e)\n } finally {\n root.h = prevHydrating\n clearHydrationCursor(fiber)\n }\n runEffects(root)\n })\n}\n\nfunction clearBoundaryRange(startMark: Comment, endMark: Comment): void {\n let node = startMark.nextSibling\n while (node && node !== endMark) {\n const next = node.nextSibling\n node.parentNode?.removeChild(node)\n node = next\n }\n}\n\nregisterTypeMatcher((type) => (type === REACT_SUSPENSE_TYPE ? FiberTag.Suspense : null))\nregisterRenderer(FiberTag.Suspense, renderSuspense)\ninstallCapability('handleSuspended', realHandleSuspended)\n"],
|
|
5
|
-
"mappings": ";AAAA,SAAS,UAAU,mBAA+B;AAClD,SAAS,2BAA2B;AACpC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,IAAI,iBAAqD;AAEzD,SAAS,oBAAoB,OAAc,UAA8B;AACvE,MAAI,eAAgB,QAAO,eAAe,QAAQ;AAElD,WAAS;AAAA,IACP,MAAM,eAAe,KAAK;AAAA,IAC1B,MAAM,eAAe,KAAK;AAAA,EAC5B;AACF;AAyBA,SAAS,eAAe,OAAc,WAAiB,QAA2B;AAChF,QAAM,QAAQ,MAAM,MAAM,CAAC;AAC3B,QAAM,QAAS,MAAM,OAAO,CAAC;AAI7B,QAAM,OAAO,eAAe;AAC5B,MAAI,MAAM,KAAK,CAAC,MAAM,GAAG;AACvB,UAAM,WAAW,mBAAmB,MAAM,MAAO;AACjD,QAAI,UAAU;AACZ,8BAAwB,OAAO,OAAO,UAAU,WAAW,MAAM;AACjE;AAAA,IACF;AAAA,EACF;AAQA,MAAI,MAAM,GAAG;AACX,UAAM,KAAK;AACX;AAAA,EACF;AAMA,MAAI,MAAM,GAAG;AACX,QAAI,MAAM,GAAG;AACX,YAAM,EAAE,KAAK,EAAE,UAAU,MAAM,SAAS;AACxC,kBAAY,MAAM,GAAG,WAAW,MAAM;AAAA,IACxC,OAAO;AAEL,wBAAkB,OAAO,gBAAgB,MAAM,QAAQ,GAAG,WAAW,MAAM;AAAA,IAC7E;AACA,UAAM,KAAK;AACX;AAAA,EACF;AAKA,QAAM,sBAAsB,MAAM,
|
|
4
|
+
"sourcesContent": ["import { FiberTag, createFiber, type Fiber } from '../../../core'\nimport { REACT_SUSPENSE_TYPE } from '../../../react'\nimport {\n registerRenderer,\n registerTypeMatcher,\n installCapability,\n reconcileChildren,\n childrenToArray,\n renderFiber,\n scheduleUpdate,\n unmountAllChildren,\n unmountFiber,\n findRoot,\n runEffects,\n getCurrentRoot,\n withCurrentRoot,\n discardPendingWork,\n} from '../../reconcile'\nimport {\n HydrationCursor,\n setHydrationCursor,\n clearHydrationCursor,\n advanceCursorPast,\n tryConsumeBoundary,\n isHydrationBailout,\n} from '../hydration'\n\nlet suspendHandler: ((t: Promise<any>) => void) | null = null\n\nfunction realHandleSuspended(fiber: Fiber, thenable: Promise<any>): void {\n if (suspendHandler) return suspendHandler(thenable)\n // Fallback: schedule re-render when promise settles\n thenable.then(\n () => scheduleUpdate(fiber),\n () => scheduleUpdate(fiber),\n )\n}\n\n// React's Suspense semantics: when a re-render of an already-committed\n// boundary suspends, the previously-committed children are kept in the DOM\n// (hidden) so their scroll position, focus, selection, native form state,\n// and component state survive across the suspension. The fallback is mounted\n// alongside the hidden primary until the pending promise resolves.\n//\n// We track the hidden subtree DOM in `state.d` (root host nodes +\n// their original `display` so we can restore it) and the fallback as a\n// detached Fragment fiber in `state.f` (deliberately kept OUT of\n// `fiber.child` so reconciles against `props.children` don't trip on it).\n// First-mount suspensions have no committed DOM worth preserving, so they\n// keep the original unmount-and-render-fallback behavior.\ninterface SuspenseState {\n p?: Promise<any> | null\n b?: Comment\n e?: Comment\n r?: any\n a?: boolean\n // Re-suspend preservation:\n d?: Array<[HTMLElement, string]> | null\n f?: Fiber | null\n}\n\nfunction renderSuspense(fiber: Fiber, domParent: Node, anchor: Node | null): void {\n const props = fiber.pp ?? {}\n const state = (fiber.ms ??= {}) as SuspenseState\n\n // Streaming hydration: if the next DOM node is a server-emitted boundary\n // marker, route through the boundary-aware hydration path.\n const root = getCurrentRoot()\n if (root?.h && !state.b) {\n const boundary = tryConsumeBoundary(fiber.parent!)\n if (boundary) {\n hydrateSuspenseBoundary(fiber, props, boundary, domParent, anchor)\n return\n }\n }\n\n // A descendant Lazy deferred its hydration (see renderLazy's hydrating\n // branch). Its SSR-rendered content is still in the DOM and cursor-bound\n // via the Lazy fiber \u2014 we just haven't swapped it into a fiber subtree\n // yet. Until the Lazy's resume fires, skip our own tryChildren pass so\n // an unrelated re-render can't accidentally flip us into the suspended\n // path and mount a duplicate fallback on top of the SSR content.\n if (state.a) {\n fiber.mp = props\n return\n }\n\n // We were already in the suspended-with-preserved-primary state. Don't\n // re-attempt primary children (would re-throw and churn the tree). Just\n // refresh the fallback in case its JSX changed, and wait for the pending\n // promise to fire scheduleUpdate.\n if (state.p) {\n if (state.f) {\n state.f.pp = { children: props.fallback }\n renderFiber(state.f, domParent, anchor)\n } else {\n // Initial-mount suspended path: no committed primary to preserve.\n reconcileChildren(fiber, childrenToArray(props.fallback), domParent, anchor)\n }\n fiber.mp = props\n return\n }\n\n // Snapshot whether we have an existing committed primary tree before\n // attempting the new render. If the new attempt suspends and we did have a\n // committed primary, we keep it (hidden) rather than destroying it.\n const hadCommittedPrimary = fiber.mp && fiber.child\n\n const prevHandler = suspendHandler\n let pendingThenable: any\n suspendHandler = (thenable) => {\n pendingThenable = thenable\n }\n try {\n reconcileChildren(fiber, childrenToArray(props.children), domParent, anchor)\n } finally {\n suspendHandler = prevHandler\n }\n\n if (pendingThenable) {\n state.p = pendingThenable\n const onSettle = () => {\n state.p = null\n scheduleUpdate(fiber)\n }\n pendingThenable.then(onSettle, onSettle)\n\n if (hadCommittedPrimary) {\n // Hide the primary subtree's root host doms so the fallback is the only\n // thing visible, but the underlying nodes (and their scroll/state/focus)\n // survive. Save original `display` for the resume path.\n const hidden: Array<[HTMLElement, string]> = []\n let c: Fiber | null = hadCommittedPrimary\n while (c) {\n hideRootHostDoms(c, hidden)\n c = c.sibling\n }\n state.d = hidden\n\n // Mount fallback in a detached Fragment fiber. Kept off `fiber.child`\n // so reconciles of primary don't see it as a stale match candidate.\n if (!state.f) {\n state.f = createFiber(FiberTag.Fragment, null, null)\n state.f.parent = fiber\n }\n state.f.pp = { children: props.fallback }\n renderFiber(state.f, domParent, anchor)\n } else {\n // First-mount suspension \u2014 nothing to preserve.\n unmountAllChildren(fiber, domParent)\n reconcileChildren(fiber, childrenToArray(props.fallback), domParent, anchor)\n }\n } else {\n // Render succeeded. Clean up any preserved-suspend state from a prior\n // suspension cycle: unhide primary, unmount the orphan fallback fiber.\n if (state.d) {\n for (const [el, origDisplay] of state.d) {\n el.style.display = origDisplay\n }\n state.d = null\n }\n if (state.f) {\n unmountFiber(state.f, domParent)\n state.f = null\n }\n }\n fiber.mp = props\n}\n\n// Walk a fiber subtree collecting host/text DOM nodes that sit at the root\n// of the subtree (do not descend through their children \u2014 display:none on\n// the root hides the whole element). Used by the hide-on-suspend path.\nfunction hideRootHostDoms(fiber: Fiber, out: Array<[HTMLElement, string]>): void {\n if (fiber.tag === FiberTag.Host) {\n const el = fiber.dom as HTMLElement\n out.push([el, el.style.display])\n el.style.display = 'none'\n return\n }\n if (fiber.tag === FiberTag.Portal) return\n let c = fiber.child\n while (c) {\n hideRootHostDoms(c, out)\n c = c.sibling\n }\n}\n\nfunction hydrateSuspenseBoundary(\n fiber: Fiber,\n props: any,\n boundary: [0 | 1, number, Comment, Comment],\n domParent: Node,\n anchor: Node | null,\n): void {\n const [pendingBoundary, id, startMark, endMark] = boundary\n // Record the boundary shape so we can re-hydrate on reveal.\n fiber.ms = {\n b: startMark,\n e: endMark,\n r: props.children,\n }\n\n if (!pendingBoundary) {\n // Real DOM is inline between startMark and endMark. Hydrate into it.\n const parent = startMark.parentNode!\n try {\n setHydrationCursor(fiber, new HydrationCursor(parent, startMark.nextSibling, endMark))\n reconcileChildren(fiber, childrenToArray(props.children), domParent, anchor)\n advanceCursorPast(fiber.parent!, endMark)\n } catch (e) {\n if (!isHydrationBailout(e)) {\n clearBoundaryRange(startMark, endMark)\n unmountAllChildren(fiber, parent)\n throw e\n }\n recoverBoundaryHydration(fiber, props.children, parent, startMark, endMark)\n } finally {\n clearHydrationCursor(fiber)\n }\n fiber.mp = props\n return\n }\n\n // Pending: fallback DOM lives inside <div id=\"B:ID\">. Hydrate the fallback\n // React subtree against that div's children.\n const bDiv = document.getElementById(`B:${id}`)\n try {\n if (bDiv) {\n setHydrationCursor(fiber, new HydrationCursor(bDiv))\n reconcileChildren(fiber, childrenToArray(props.fallback), domParent, anchor)\n } else {\n // Couldn't find fallback container \u2014 render fresh (non-adopting)\n reconcileChildren(fiber, childrenToArray(props.fallback), domParent, anchor)\n }\n } catch (e) {\n if (!isHydrationBailout(e) || !bDiv) throw e\n recoverFallbackHydration(fiber, props.fallback, bDiv)\n } finally {\n clearHydrationCursor(fiber)\n }\n advanceCursorPast(fiber.parent!, endMark)\n\n // Register for server-streamed reveal (HTML chunks + $RC calls).\n ;(globalThis as any).$RH?.(id, () => rehydrateBoundary(fiber))\n // If the inline runtime isn't present, nothing external will mark us dy.\n\n fiber.mp = props\n}\n\nfunction recoverBoundaryHydration(\n fiber: Fiber,\n children: any,\n parent: Node,\n startMark: Comment,\n endMark: Comment,\n): void {\n const root = findRoot(fiber)!\n const prevHydrating = root.h\n discardPendingWork(root)\n clearBoundaryRange(startMark, endMark)\n unmountAllChildren(fiber, parent)\n root.h = false\n try {\n reconcileChildren(fiber, childrenToArray(children), parent, endMark)\n advanceCursorPast(fiber.parent!, endMark)\n } catch (clientError) {\n clearBoundaryRange(startMark, endMark)\n unmountAllChildren(fiber, parent)\n throw clientError\n } finally {\n root.h = prevHydrating\n }\n}\n\nfunction recoverFallbackHydration(fiber: Fiber, fallback: any, parent: HTMLElement): void {\n const root = findRoot(fiber)!\n const prevHydrating = root.h\n discardPendingWork(root)\n parent.textContent = ''\n unmountAllChildren(fiber, parent)\n root.h = false\n try {\n reconcileChildren(fiber, childrenToArray(fallback), parent, null)\n } catch (clientError) {\n parent.textContent = ''\n unmountAllChildren(fiber, parent)\n throw clientError\n } finally {\n root.h = prevHydrating\n }\n}\n\nfunction rehydrateBoundary(fiber: Fiber): void {\n const state = fiber.ms\n if (!state?.b || !state.e) return\n\n const root = findRoot(fiber)\n const parent = state.b.parentNode as Node\n if (!(root && parent)) return\n\n // Unmount existing fallback subtree. Its DOM has already been removed by $RC\n // (or at least its container); unmounting here cleans up fibers + fx.\n withCurrentRoot(root, () => {\n const prevHydrating = root.h\n try {\n unmountAllChildren(fiber, parent)\n\n // Re-hydrate with real children against the now-real DOM range.\n root.h = true\n setHydrationCursor(fiber, new HydrationCursor(parent, state.b.nextSibling, state.e))\n reconcileChildren(fiber, childrenToArray(state.r), parent, null)\n } catch (e) {\n if (!isHydrationBailout(e)) {\n clearBoundaryRange(state.b, state.e)\n unmountAllChildren(fiber, parent)\n throw e\n }\n\n recoverBoundaryHydration(fiber, state.r, parent, state.b, state.e)\n } finally {\n root.h = prevHydrating\n clearHydrationCursor(fiber)\n }\n runEffects(root)\n })\n}\n\nfunction clearBoundaryRange(startMark: Comment, endMark: Comment): void {\n let node = startMark.nextSibling\n while (node && node !== endMark) {\n const next = node.nextSibling\n node.parentNode?.removeChild(node)\n node = next\n }\n}\n\nregisterTypeMatcher((type) => (type === REACT_SUSPENSE_TYPE ? FiberTag.Suspense : null))\nregisterRenderer(FiberTag.Suspense, renderSuspense)\ninstallCapability('handleSuspended', realHandleSuspended)\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -11,6 +11,7 @@ function createFiberRoot(container, options) {
|
|
|
11
11
|
ce: options.onCaughtError,
|
|
12
12
|
ue: options.onUncaughtError,
|
|
13
13
|
i: options.identifierPrefix ?? ":r",
|
|
14
|
+
ic: 0,
|
|
14
15
|
h: false
|
|
15
16
|
};
|
|
16
17
|
rootFiber.root = root;
|
|
@@ -20,6 +21,7 @@ function createFiberRoot(container, options) {
|
|
|
20
21
|
function attachRootFiber(root, container) {
|
|
21
22
|
const rootFiber = createFiber(FiberTag.Root, null, null);
|
|
22
23
|
root.c = container;
|
|
24
|
+
root.ic = 0;
|
|
23
25
|
rootFiber.root = root;
|
|
24
26
|
rootFiber.sn = container;
|
|
25
27
|
root.r = rootFiber;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/dom/root-internal.ts"],
|
|
4
|
-
"sourcesContent": ["import { FiberTag, createFiber, type Fiber, type FiberRoot } from '../core'\n\nexport interface RootOptionsInternal {\n identifierPrefix?: string\n onRecoverableError?: (error: unknown) => void\n onCaughtError?: (error: unknown) => void\n onUncaughtError?: (error: unknown) => void\n}\n\nexport function createFiberRoot(\n container: Element | Document | DocumentFragment,\n options: RootOptionsInternal,\n): FiberRoot {\n const rootFiber = createFiber(FiberTag.Root, null, null)\n const root: FiberRoot = {\n c: container as any,\n r: rootFiber,\n p: new Set(),\n s: false,\n re: options.onRecoverableError,\n ce: options.onCaughtError,\n ue: options.onUncaughtError,\n i: options.identifierPrefix ?? ':r',\n h: false,\n }\n rootFiber.root = root\n rootFiber.sn = container\n return root\n}\n\nexport function attachRootFiber(\n root: FiberRoot,\n container: Element | Document | DocumentFragment,\n): void {\n const rootFiber = createFiber(FiberTag.Root, null, null)\n root.c = container as any\n rootFiber.root = root\n rootFiber.sn = container\n root.r = rootFiber\n}\n"],
|
|
5
|
-
"mappings": ";AAAA,SAAS,UAAU,mBAA+C;AAS3D,SAAS,gBACd,WACA,SACW;AACX,QAAM,YAAY,YAAY,SAAS,MAAM,MAAM,IAAI;AACvD,QAAM,OAAkB;AAAA,IACtB,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG,oBAAI,IAAI;AAAA,IACX,GAAG;AAAA,IACH,IAAI,QAAQ;AAAA,IACZ,IAAI,QAAQ;AAAA,IACZ,IAAI,QAAQ;AAAA,IACZ,GAAG,QAAQ,oBAAoB;AAAA,IAC/B,GAAG;AAAA,EACL;AACA,YAAU,OAAO;AACjB,YAAU,KAAK;AACf,SAAO;AACT;AAEO,SAAS,gBACd,MACA,WACM;AACN,QAAM,YAAY,YAAY,SAAS,MAAM,MAAM,IAAI;AACvD,OAAK,IAAI;AACT,YAAU,OAAO;AACjB,YAAU,KAAK;AACf,OAAK,IAAI;AACX;",
|
|
4
|
+
"sourcesContent": ["import { FiberTag, createFiber, type Fiber, type FiberRoot } from '../core'\n\nexport interface RootOptionsInternal {\n identifierPrefix?: string\n onRecoverableError?: (error: unknown) => void\n onCaughtError?: (error: unknown) => void\n onUncaughtError?: (error: unknown) => void\n}\n\nexport function createFiberRoot(\n container: Element | Document | DocumentFragment,\n options: RootOptionsInternal,\n): FiberRoot {\n const rootFiber = createFiber(FiberTag.Root, null, null)\n const root: FiberRoot = {\n c: container as any,\n r: rootFiber,\n p: new Set(),\n s: false,\n re: options.onRecoverableError,\n ce: options.onCaughtError,\n ue: options.onUncaughtError,\n i: options.identifierPrefix ?? ':r',\n ic: 0,\n h: false,\n }\n rootFiber.root = root\n rootFiber.sn = container\n return root\n}\n\nexport function attachRootFiber(\n root: FiberRoot,\n container: Element | Document | DocumentFragment,\n): void {\n const rootFiber = createFiber(FiberTag.Root, null, null)\n root.c = container as any\n root.ic = 0\n rootFiber.root = root\n rootFiber.sn = container\n root.r = rootFiber\n}\n"],
|
|
5
|
+
"mappings": ";AAAA,SAAS,UAAU,mBAA+C;AAS3D,SAAS,gBACd,WACA,SACW;AACX,QAAM,YAAY,YAAY,SAAS,MAAM,MAAM,IAAI;AACvD,QAAM,OAAkB;AAAA,IACtB,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG,oBAAI,IAAI;AAAA,IACX,GAAG;AAAA,IACH,IAAI,QAAQ;AAAA,IACZ,IAAI,QAAQ;AAAA,IACZ,IAAI,QAAQ;AAAA,IACZ,GAAG,QAAQ,oBAAoB;AAAA,IAC/B,IAAI;AAAA,IACJ,GAAG;AAAA,EACL;AACA,YAAU,OAAO;AACjB,YAAU,KAAK;AACf,SAAO;AACT;AAEO,SAAS,gBACd,MACA,WACM;AACN,QAAM,YAAY,YAAY,SAAS,MAAM,MAAM,IAAI;AACvD,OAAK,IAAI;AACT,OAAK,KAAK;AACV,YAAU,OAAO;AACjB,YAAU,KAAK;AACf,OAAK,IAAI;AACX;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/server/escape.d.ts
CHANGED
|
@@ -3,5 +3,4 @@ export declare function escapeText(value: string): string;
|
|
|
3
3
|
export declare function escapeScript(value: string): string;
|
|
4
4
|
export declare const VOID_ELEMENTS: Set<string>;
|
|
5
5
|
export declare const RAW_TEXT_ELEMENTS: Set<string>;
|
|
6
|
-
export declare
|
|
7
|
-
export declare function attrToHtml(name: string, value: unknown): string;
|
|
6
|
+
export declare function attrToHtml(name: string, value: unknown, isSvg?: boolean): string;
|
package/dist/server/escape.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// packages/redact/src/server/escape.ts
|
|
2
|
+
import { attributeName } from "../core/attributes";
|
|
2
3
|
var ATTR_MAP = {
|
|
3
4
|
"&": "&",
|
|
4
5
|
'"': """,
|
|
@@ -36,16 +37,6 @@ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
|
36
37
|
"wbr"
|
|
37
38
|
]);
|
|
38
39
|
var RAW_TEXT_ELEMENTS = /* @__PURE__ */ new Set(["script", "style"]);
|
|
39
|
-
var ATTR_ALIASES = {
|
|
40
|
-
className: "class",
|
|
41
|
-
htmlFor: "for",
|
|
42
|
-
httpEquiv: "http-equiv",
|
|
43
|
-
acceptCharset: "accept-charset",
|
|
44
|
-
crossOrigin: "crossorigin",
|
|
45
|
-
viewBox: "viewBox",
|
|
46
|
-
// SVG keeps camelCase
|
|
47
|
-
noModule: "nomodule"
|
|
48
|
-
};
|
|
49
40
|
var BOOLEAN_ATTRS = /* @__PURE__ */ new Set([
|
|
50
41
|
"allowfullscreen",
|
|
51
42
|
"async",
|
|
@@ -73,13 +64,13 @@ var BOOLEAN_ATTRS = /* @__PURE__ */ new Set([
|
|
|
73
64
|
"reversed",
|
|
74
65
|
"selected"
|
|
75
66
|
]);
|
|
76
|
-
function attrToHtml(name, value) {
|
|
67
|
+
function attrToHtml(name, value, isSvg = false) {
|
|
77
68
|
if (name === "children" || name === "key" || name === "ref" || name === "dangerouslySetInnerHTML" || name === "defaultValue" || name === "defaultChecked" || name === "suppressHydrationWarning" || name === "suppressContentEditableWarning") {
|
|
78
69
|
return "";
|
|
79
70
|
}
|
|
80
71
|
if (name[0] === "o" && name[1] === "n" && typeof value === "function") return "";
|
|
81
72
|
if (value == null) return "";
|
|
82
|
-
const htmlName =
|
|
73
|
+
const htmlName = attributeName(name, isSvg);
|
|
83
74
|
if (name.startsWith("aria-") || name.startsWith("data-")) {
|
|
84
75
|
return ` ${htmlName}="${escapeAttr(String(value))}"`;
|
|
85
76
|
}
|
|
@@ -148,7 +139,6 @@ function styleToString(style) {
|
|
|
148
139
|
return out;
|
|
149
140
|
}
|
|
150
141
|
export {
|
|
151
|
-
ATTR_ALIASES,
|
|
152
142
|
RAW_TEXT_ELEMENTS,
|
|
153
143
|
VOID_ELEMENTS,
|
|
154
144
|
attrToHtml,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/server/escape.ts"],
|
|
4
|
-
"sourcesContent": ["
|
|
5
|
-
"mappings": ";AAAA,IAAM,WAAmC;AAAA,EACvC,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AACP;AACA,IAAM,WAAmC;AAAA,EACvC,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AACP;AAEO,SAAS,WAAW,OAAuB;AAChD,SAAO,MAAM,QAAQ,WAAW,CAAC,MAAM,SAAS,CAAC,CAAE;AACrD;AAEO,SAAS,WAAW,OAAuB;AAChD,SAAO,MAAM,QAAQ,UAAU,CAAC,MAAM,SAAS,CAAC,CAAE;AACpD;AAOO,SAAS,aAAa,OAAuB;AAClD,SAAO,MACJ,QAAQ,uBAAuB,QAAQ,EACvC,QAAQ,SAAS,QAAQ;AAC9B;AAEO,IAAM,gBAAgB,oBAAI,IAAI;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,oBAAoB,oBAAI,IAAI,CAAC,UAAU,OAAO,CAAC;
|
|
4
|
+
"sourcesContent": ["import { attributeName } from '../core/attributes'\n\nconst ATTR_MAP: Record<string, string> = {\n '&': '&',\n '\"': '"',\n '<': '<',\n '>': '>',\n}\nconst TEXT_MAP: Record<string, string> = {\n '&': '&',\n '<': '<',\n '>': '>',\n}\n\nexport function escapeAttr(value: string): string {\n return value.replace(/[&\"<>]/g, (c) => ATTR_MAP[c]!)\n}\n\nexport function escapeText(value: string): string {\n return value.replace(/[&<>]/g, (c) => TEXT_MAP[c]!)\n}\n\n// Raw-text element body escaping: prevent any closing tag for the raw-text\n// elements (<script>, <style>) from terminating the element early, plus\n// `<!--` (which would start an HTML comment that survives even inside\n// raw-text bodies and can be exploited to alter following script content).\n// React's serializer follows the same approach.\nexport function escapeScript(value: string): string {\n return value\n .replace(/<\\/(script|style)/gi, '<\\\\/$1')\n .replace(/<!--/g, '<\\\\!--')\n}\n\nexport const VOID_ELEMENTS = new Set([\n 'area',\n 'base',\n 'br',\n 'col',\n 'embed',\n 'hr',\n 'img',\n 'input',\n 'link',\n 'meta',\n 'param',\n 'source',\n 'track',\n 'wbr',\n])\n\nexport const RAW_TEXT_ELEMENTS = new Set(['script', 'style'])\n\nconst BOOLEAN_ATTRS = new Set([\n 'allowfullscreen',\n 'async',\n 'autofocus',\n 'autoplay',\n 'checked',\n 'controls',\n 'default',\n 'defer',\n 'disabled',\n 'formnovalidate',\n 'hidden',\n 'inert',\n 'ismap',\n 'itemscope',\n 'loop',\n 'multiple',\n 'muted',\n 'nomodule',\n 'novalidate',\n 'open',\n 'playsinline',\n 'readonly',\n 'required',\n 'reversed',\n 'selected',\n])\n\nexport function attrToHtml(name: string, value: unknown, isSvg = false): string {\n if (\n name === 'children' ||\n name === 'key' ||\n name === 'ref' ||\n name === 'dangerouslySetInnerHTML' ||\n name === 'defaultValue' ||\n name === 'defaultChecked' ||\n name === 'suppressHydrationWarning' ||\n name === 'suppressContentEditableWarning'\n ) {\n return ''\n }\n if (name[0] === 'o' && name[1] === 'n' && typeof value === 'function') return ''\n if (value == null) return ''\n\n const htmlName = attributeName(name, isSvg)\n\n // aria-* and data-* stringify booleans to `\"true\"`/`\"false\"` rather than\n // using boolean-attribute presence semantics \u2014 matches React and the ARIA\n // spec. Must branch before the general `value === false` / BOOLEAN_ATTRS\n // path, which would drop them.\n if (name.startsWith('aria-') || name.startsWith('data-')) {\n return ` ${htmlName}=\"${escapeAttr(String(value))}\"`\n }\n\n if (value === false) return ''\n\n if (value === true || BOOLEAN_ATTRS.has(htmlName)) {\n return value ? ` ${htmlName}=\"\"` : ''\n }\n\n if (name === 'style' && typeof value === 'object' && value !== null) {\n return ` style=\"${escapeAttr(styleToString(value as Record<string, unknown>))}\"`\n }\n\n return ` ${htmlName}=\"${escapeAttr(String(value))}\"`\n}\n\nconst UNITLESS_STYLE = new Set([\n 'animationIterationCount',\n 'borderImageOutset',\n 'borderImageSlice',\n 'borderImageWidth',\n 'boxFlex',\n 'boxFlexGroup',\n 'boxOrdinalGroup',\n 'columnCount',\n 'columns',\n 'flex',\n 'flexGrow',\n 'flexPositive',\n 'flexShrink',\n 'flexNegative',\n 'flexOrder',\n 'gridArea',\n 'gridRow',\n 'gridRowEnd',\n 'gridRowSpan',\n 'gridRowStart',\n 'gridColumn',\n 'gridColumnEnd',\n 'gridColumnSpan',\n 'gridColumnStart',\n 'fontWeight',\n 'lineClamp',\n 'lineHeight',\n 'opacity',\n 'order',\n 'orphans',\n 'tabSize',\n 'widows',\n 'zIndex',\n 'zoom',\n 'fillOpacity',\n 'floodOpacity',\n 'stopOpacity',\n 'strokeDasharray',\n 'strokeDashoffset',\n 'strokeMiterlimit',\n 'strokeOpacity',\n 'strokeWidth',\n])\n\nfunction styleToString(style: Record<string, unknown>): string {\n let out = ''\n for (const key in style) {\n const v = style[key]\n if (v == null || v === false) continue\n const kebab = key.startsWith('--')\n ? key\n : key.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase())\n const value =\n typeof v === 'number' && !UNITLESS_STYLE.has(key) && v !== 0 ? v + 'px' : v\n out += `${kebab}:${value};`\n }\n return out\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/server/walk.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export interface WalkOptions {
|
|
|
13
13
|
nextBoundaryId: () => number;
|
|
14
14
|
bootstrapped?: boolean | undefined;
|
|
15
15
|
isBoundaryResolution?: boolean | undefined;
|
|
16
|
+
isSvg?: boolean | undefined;
|
|
16
17
|
/**
|
|
17
18
|
* Tracks whether the most recent emission within the *current text flow*
|
|
18
19
|
* ended with a text node. When the next emission is also text, we emit a
|
package/dist/server/walk.js
CHANGED
|
@@ -152,6 +152,7 @@ function walkElement(el, opts) {
|
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
function walkHost(tag, props, opts) {
|
|
155
|
+
const isSvg = opts.isSvg || tag === "svg";
|
|
155
156
|
const isTextarea = tag === "textarea";
|
|
156
157
|
const textareaValue = isTextarea ? props.value != null ? props.value : props.defaultValue : void 0;
|
|
157
158
|
const isInput = tag === "input";
|
|
@@ -170,13 +171,13 @@ function walkHost(tag, props, opts) {
|
|
|
170
171
|
if (isInput && (k === "defaultValue" || k === "defaultChecked")) continue;
|
|
171
172
|
if (isSelect && (k === "value" || k === "defaultValue")) continue;
|
|
172
173
|
if (isOption && k === "selected") continue;
|
|
173
|
-
opts.emit(attrToHtml(k, props[k]));
|
|
174
|
+
opts.emit(attrToHtml(k, props[k], isSvg));
|
|
174
175
|
}
|
|
175
176
|
if (inputValueAttr !== void 0) {
|
|
176
|
-
opts.emit(attrToHtml("value", inputValueAttr));
|
|
177
|
+
opts.emit(attrToHtml("value", inputValueAttr, isSvg));
|
|
177
178
|
}
|
|
178
179
|
if (inputCheckedAttr !== void 0) {
|
|
179
|
-
opts.emit(attrToHtml("checked", inputCheckedAttr));
|
|
180
|
+
opts.emit(attrToHtml("checked", inputCheckedAttr, isSvg));
|
|
180
181
|
}
|
|
181
182
|
if (isOption) {
|
|
182
183
|
const selectVal = currentSelectValue();
|
|
@@ -195,7 +196,11 @@ function walkHost(tag, props, opts) {
|
|
|
195
196
|
}
|
|
196
197
|
opts.emit(">");
|
|
197
198
|
const parentTextState = opts.textState;
|
|
198
|
-
const childOpts = {
|
|
199
|
+
const childOpts = {
|
|
200
|
+
...opts,
|
|
201
|
+
isSvg: isSvg && tag !== "foreignObject",
|
|
202
|
+
textState: { lastWasText: false }
|
|
203
|
+
};
|
|
199
204
|
if (tag === "html" && !hasHeadChild(props.children)) {
|
|
200
205
|
opts.emit("<head></head>");
|
|
201
206
|
}
|
package/dist/server/walk.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/server/walk.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n REACT_ELEMENT_TYPE,\n REACT_LEGACY_ELEMENT_TYPE,\n REACT_FRAGMENT_TYPE,\n type ReactNode,\n type ReactElement,\n} from '../core'\nimport {\n REACT_SUSPENSE_TYPE,\n REACT_PROVIDER_TYPE,\n REACT_CONSUMER_TYPE,\n REACT_FORWARD_REF_TYPE,\n REACT_MEMO_TYPE,\n REACT_LAZY_TYPE,\n REACT_STRICT_MODE_TYPE,\n REACT_PROFILER_TYPE,\n REACT_PORTAL_TYPE,\n} from '../react'\nimport {\n attrToHtml,\n escapeText,\n escapeScript,\n VOID_ELEMENTS,\n RAW_TEXT_ELEMENTS,\n} from './escape'\nimport {\n pushContext,\n popContext,\n snapshotContexts,\n type ContextSnapshot,\n} from './dispatcher'\n\nexport interface SuspendedBoundary {\n id: number\n fallbackHTML: string\n children: ReactNode\n thenable: Promise<any>\n contextSnapshot: ContextSnapshot\n}\n\nexport interface WalkOptions {\n emit: (chunk: string) => void\n onSuspend?: ((boundary: SuspendedBoundary) => void) | undefined\n nextBoundaryId: () => number\n bootstrapped?: boolean | undefined\n isBoundaryResolution?: boolean | undefined\n /**\n * Tracks whether the most recent emission within the *current text flow*\n * ended with a text node. When the next emission is also text, we emit a\n * `<!-- -->` separator so the browser's HTML parser doesn't merge them\n * into a single text node \u2014 required for hydration to line up text\n * boundaries with the React tree. Reset to `false` whenever we enter a\n * new host element (`<tag>` opens a fresh text flow).\n */\n textState?: { lastWasText: boolean }\n}\n\n/**\n * Synchronously walk a React node and emit HTML string pieces to `opts.emit`.\n * Suspended boundaries are emitted as fallbacks with marker IDs; if `opts.onSuspend`\n * is provided, the suspension is recorded for later streaming.\n */\nexport function walk(node: ReactNode, opts: WalkOptions): void {\n // Seed a text state if the caller didn't provide one so the separator logic\n // is active for the whole tree.\n if (!opts.textState) opts = { ...opts, textState: { lastWasText: false } }\n walkNode(node, opts)\n}\n\n// --- <select> selection context ----------------------------------------------\n// Stack of active select values (or `undefined` when the current select has\n// no controlled value). `<option>` walks read the top of stack to decide\n// whether to emit `selected=\"\"`.\nconst selectValueStack: unknown[] = []\nfunction pushSelectContext(value: unknown): void {\n selectValueStack.push(value)\n}\nfunction popSelectContext(): void {\n selectValueStack.pop()\n}\nfunction currentSelectValue(): unknown {\n return selectValueStack.length ? selectValueStack[selectValueStack.length - 1] : undefined\n}\n\nfunction optionChildText(children: unknown): string {\n // `<option>Text</option>` \u2014 if no `value` prop, the option's value is its\n // flat string/number child content. Matches DOM semantics (`option.value`\n // defaults to `textContent` when no attribute is set).\n if (children == null) return ''\n if (typeof children === 'string' || typeof children === 'number') return '' + children\n if (Array.isArray(children)) return children.map(optionChildText).join('')\n return ''\n}\n\nfunction emitText(text: string, opts: WalkOptions): void {\n // Empty string renders no text node and doesn't start/extend a text flow \u2014\n // skip entirely so sibling text isn't separated by a stray `<!-- -->`.\n if (text === '') return\n if (opts.textState?.lastWasText) opts.emit('<!-- -->')\n opts.emit(escapeText(text))\n if (opts.textState) opts.textState.lastWasText = true\n}\n\nfunction walkNode(node: ReactNode, opts: WalkOptions): void {\n if (node == null || node === false || node === true) return\n\n if (typeof node === 'string') {\n emitText(node, opts)\n return\n }\n if (typeof node === 'number') {\n emitText(String(node), opts)\n return\n }\n if (Array.isArray(node)) {\n for (const c of node) walkNode(c, opts)\n return\n }\n if (typeof (node as any)[Symbol.iterator] === 'function') {\n for (const item of node as Iterable<ReactNode>) walkNode(item, opts)\n return\n }\n\n if (typeof node !== 'object') return\n const t = (node as any).$$typeof\n\n // Raw React.lazy in the tree (RSC Flight encodes 'use client' components \u2014\n // CodeBlock, CodeExplorer, etc. \u2014 as bare Lazy objects directly in the\n // tree, not wrapped in REACT_ELEMENT_TYPE). SSR previously dropped these\n // here, so code snippets never made it into the server HTML. The RSC\n // decoder server-side awaits payloads before rendering, so status is\n // 'fulfilled' and `_init()` returns the resolved element synchronously.\n // If still pending (shouldn't happen post-awaitLazyElements), throw the\n // thenable so streaming SSR suspends the current boundary and retries.\n if (t === REACT_LAZY_TYPE) {\n const lazy = node as any\n const resolved = lazy._init(lazy._payload)\n walkNode(resolved, opts)\n return\n }\n\n if (t !== REACT_ELEMENT_TYPE && t !== REACT_LEGACY_ELEMENT_TYPE) return\n\n const el = node as ReactElement\n walkElement(el, opts)\n}\n\nfunction walkElement(el: ReactElement, opts: WalkOptions): void {\n const type = el.type\n const props = el.props ?? {}\n\n if (type === REACT_FRAGMENT_TYPE || type === REACT_STRICT_MODE_TYPE || type === REACT_PROFILER_TYPE) {\n walkNode(props.children, opts)\n return\n }\n\n if (type === REACT_SUSPENSE_TYPE) {\n walkSuspense(props, opts)\n return\n }\n\n if (typeof type === 'string') {\n walkHost(type, props, opts)\n return\n }\n\n const marker = (type as any)?.$$typeof\n\n if (marker === REACT_PORTAL_TYPE) {\n // Portals don't render to the main HTML output on the server.\n return\n }\n\n if (marker === REACT_PROVIDER_TYPE) {\n const ctx = (type as any)._context\n pushContext(ctx, props.value)\n try {\n walkNode(props.children, opts)\n } finally {\n popContext(ctx)\n }\n return\n }\n\n if (marker === REACT_CONSUMER_TYPE) {\n const ctx = (type as any)._context\n const render = props.children\n if (typeof render === 'function') {\n walkNode(render(ctx._currentValue), opts)\n }\n return\n }\n\n if (marker === REACT_FORWARD_REF_TYPE) {\n const render = (type as any).render\n const ref = (props as any).ref ?? null\n const { ref: _omit, ...rest } = props as any\n const rendered = render(rest, ref)\n walkNode(rendered, opts)\n return\n }\n\n if (marker === REACT_MEMO_TYPE) {\n const inner = (type as any).type\n walkElement({ ...el, type: inner } as ReactElement, opts)\n return\n }\n\n if (marker === REACT_LAZY_TYPE) {\n const { _payload, _init } = type as any\n try {\n const resolved = _init(_payload)\n walkElement({ ...el, type: resolved } as ReactElement, opts)\n } catch (thenable: any) {\n if (isThenable(thenable)) {\n // Suspend this point\n throw thenable\n }\n throw thenable\n }\n return\n }\n\n if (typeof type === 'function') {\n walkComponent(type, props, opts)\n return\n }\n}\n\nfunction walkHost(\n tag: string,\n props: Record<string, any>,\n opts: WalkOptions,\n): void {\n // <textarea value=\"...\"> serializes its value as a TEXT CHILD, not an\n // attribute. `defaultValue` is the fallback when `value` is absent. This\n // matches React and the HTML spec \u2014 `<textarea value=\"x\">` is not valid\n // HTML; the value is the element's textContent.\n const isTextarea = tag === 'textarea'\n const textareaValue = isTextarea\n ? props.value != null\n ? props.value\n : props.defaultValue\n : undefined\n\n // <input defaultValue=\"...\"> should parse with that value \u2014 emit it as a\n // `value` attribute. Similarly `defaultChecked` becomes `checked`. This\n // keeps hydration consistent: the browser parser sees the initial value,\n // and on client commit our setProp seeds `.defaultValue`/`.defaultChecked`\n // without stomping the user-typed value.\n const isInput = tag === 'input'\n const inputValueAttr =\n isInput && props.value == null && props.defaultValue != null\n ? props.defaultValue\n : undefined\n const inputCheckedAttr =\n isInput && props.checked == null && props.defaultChecked != null\n ? props.defaultChecked\n : undefined\n\n // <select value=\"...\"> does NOT become an attribute on `<select>` \u2014 the\n // HTML spec has no such attribute. React resolves the selection by stamping\n // `selected` on the matching `<option>` children during render. Stash the\n // target value(s) on the walk state and the child `<option>` walk reads it.\n const isSelect = tag === 'select'\n if (isSelect) {\n const val = props.value != null ? props.value : props.defaultValue\n pushSelectContext(val)\n }\n const isOption = tag === 'option'\n\n // Prepend the HTML5 doctype to the stream when rendering an <html> root.\n // Without it the browser parses the document in quirks mode, which breaks\n // CSS sizing (documentElement.clientHeight returns the content height, not\n // the viewport) \u2014 and Floating-UI-based libraries (Radix dropdowns etc.)\n // then compute off-screen positions for overlays.\n if (tag === 'html') opts.emit('<!DOCTYPE html>')\n\n opts.emit('<' + tag)\n for (const k in props) {\n if (isTextarea && (k === 'value' || k === 'defaultValue')) continue\n if (isInput && (k === 'defaultValue' || k === 'defaultChecked')) continue\n if (isSelect && (k === 'value' || k === 'defaultValue')) continue\n if (isOption && k === 'selected') continue\n opts.emit(attrToHtml(k, props[k]))\n }\n if (inputValueAttr !== undefined) {\n opts.emit(attrToHtml('value', inputValueAttr))\n }\n if (inputCheckedAttr !== undefined) {\n opts.emit(attrToHtml('checked', inputCheckedAttr))\n }\n if (isOption) {\n const selectVal = currentSelectValue()\n if (selectVal !== undefined) {\n const optionValue =\n props.value != null ? props.value : optionChildText(props.children)\n const matches = Array.isArray(selectVal)\n ? selectVal.some((v) => '' + v === '' + optionValue)\n : '' + selectVal === '' + optionValue\n if (matches) opts.emit(' selected=\"\"')\n } else if (props.selected) {\n opts.emit(' selected=\"\"')\n }\n }\n\n if (VOID_ELEMENTS.has(tag)) {\n opts.emit('/>')\n if (opts.textState) opts.textState.lastWasText = false\n return\n }\n opts.emit('>')\n // Opening a host element starts a fresh text flow context for its children.\n // Children's text separator tracking is independent of the outer context.\n const parentTextState = opts.textState\n const childOpts: WalkOptions = { ...opts, textState: { lastWasText: false } }\n\n if (tag === 'html' && !hasHeadChild(props.children)) {\n opts.emit('<head></head>')\n }\n\n const dangerouslyHtml = props.dangerouslySetInnerHTML?.__html\n\n if (isTextarea && textareaValue != null) {\n opts.emit(escapeText(String(textareaValue)))\n opts.emit(`</${tag}>`)\n if (parentTextState) parentTextState.lastWasText = false\n return\n }\n\n if (RAW_TEXT_ELEMENTS.has(tag)) {\n // script/style: raw-text. React allows either a string/number child or\n // dangerouslySetInnerHTML \u2014 some libs (Start's Scripts) use the latter.\n if (dangerouslyHtml != null) {\n opts.emit(escapeScript(String(dangerouslyHtml)))\n } else {\n const children = props.children\n if (typeof children === 'string' || typeof children === 'number') {\n opts.emit(escapeScript(String(children)))\n } else if (Array.isArray(children)) {\n opts.emit(escapeScript(children.filter((c) => c != null).join('')))\n }\n }\n opts.emit(`</${tag}>`)\n if (parentTextState) parentTextState.lastWasText = false\n return\n }\n\n if (dangerouslyHtml != null) {\n opts.emit(String(dangerouslyHtml))\n } else {\n walkNode(props.children, childOpts)\n }\n opts.emit(`</${tag}>`)\n if (isSelect) popSelectContext()\n // Host element closing resets outer flow \u2014 next sibling text starts fresh.\n if (parentTextState) parentTextState.lastWasText = false\n}\n\nfunction hasHeadChild(children: unknown): boolean {\n if (children == null || typeof children === 'boolean') return false\n if (Array.isArray(children)) return children.some(hasHeadChild)\n if (typeof children !== 'string' && isIterable(children)) {\n for (const child of children as Iterable<unknown>) {\n if (hasHeadChild(child)) return true\n }\n return false\n }\n return isElementOfType(children, 'head')\n}\n\nfunction isElementOfType(value: unknown, type: string): value is ReactElement {\n const marker = (value as ReactElement | null)?.$$typeof as unknown\n return (\n !!value &&\n typeof value === 'object' &&\n (marker === REACT_ELEMENT_TYPE || marker === REACT_LEGACY_ELEMENT_TYPE) &&\n (value as ReactElement).type === type\n )\n}\n\nfunction isIterable(value: unknown): value is Iterable<unknown> {\n return !!value && typeof (value as { [Symbol.iterator]?: unknown })[Symbol.iterator] === 'function'\n}\n\nfunction walkComponent(\n fn: Function,\n props: Record<string, any>,\n opts: WalkOptions,\n): void {\n if ((fn as any).prototype?.isReactComponent) {\n const ctxType = (fn as any).contextType\n const ctxValue = ctxType ? ctxType._currentValue : undefined\n const instance = new (fn as any)(props, ctxValue)\n instance.props = props\n instance.context = ctxValue\n if ((fn as any).getDerivedStateFromProps) {\n const d = (fn as any).getDerivedStateFromProps(props, instance.state)\n if (d) instance.state = { ...instance.state, ...d }\n }\n walkNode(instance.render(), opts)\n return\n }\n const rendered = (fn as any)(props)\n walkNode(rendered, opts)\n}\n\nfunction walkSuspense(\n props: Record<string, any>,\n opts: WalkOptions,\n): void {\n const id = opts.nextBoundaryId()\n // Snapshot contexts BEFORE attempting children, so if a descendant suspends\n // we can replay the same provider stack when re-rendering the boundary.\n const contextSnapshot = snapshotContexts()\n\n // Try to render the children synchronously. If a thenable is thrown,\n // record the boundary and emit the fallback.\n const childParts: string[] = []\n const childEmit = (s: string) => childParts.push(s)\n try {\n walkNode(props.children, {\n emit: childEmit,\n onSuspend: opts.onSuspend,\n nextBoundaryId: opts.nextBoundaryId,\n })\n } catch (thenable: any) {\n if (isThenable(thenable)) {\n const fallbackParts: string[] = []\n try {\n walkNode(props.fallback, {\n emit: (s) => fallbackParts.push(s),\n onSuspend: opts.onSuspend,\n nextBoundaryId: opts.nextBoundaryId,\n })\n } catch {\n // Fallback suspending is unsupported; emit nothing\n }\n emitBoundary(opts, id, fallbackParts.join(''))\n\n if (opts.onSuspend) {\n opts.onSuspend({\n id,\n fallbackHTML: fallbackParts.join(''),\n children: props.children,\n thenable,\n contextSnapshot,\n })\n }\n return\n }\n throw thenable\n }\n\n // Children rendered fully \u2014 emit them wrapped in resolved-boundary markers\n // (`<!--$N-->` / `<!--/$-->`). Without markers, the client hydrator has no\n // way to know this subtree is inside a Suspense, so if the client version\n // of a descendant (e.g. `React.lazy`) suspends it can't pinpoint which DOM\n // range to adopt on resolve \u2014 it creates fresh DOM next to the SSR content,\n // producing visible duplicates (e.g. double navbar logos). Markers let the\n // client treat this as a resolved boundary and hydrate in-place.\n opts.emit(`<!--$${id}-->`)\n opts.emit(childParts.join(''))\n opts.emit(`<!--/$-->`)\n}\n\nfunction emitBoundary(opts: WalkOptions, id: number, fallbackHTML: string): void {\n // Visible div wrapper so the fallback UI shows; B: id lets $RC locate it on\n // reveal. The leading/trailing comments let hydration detect a pending\n // boundary and register a reveal callback.\n opts.emit(`<!--$?${id}--><div id=\"B:${id}\">`)\n opts.emit(fallbackHTML)\n opts.emit(`</div><!--/$-->`)\n}\n\nfunction isThenable(x: any): x is Promise<any> {\n return x != null && typeof x.then === 'function'\n}\n"],
|
|
5
|
-
"mappings": ";AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;
|
|
4
|
+
"sourcesContent": ["import {\n REACT_ELEMENT_TYPE,\n REACT_LEGACY_ELEMENT_TYPE,\n REACT_FRAGMENT_TYPE,\n type ReactNode,\n type ReactElement,\n} from '../core'\nimport {\n REACT_SUSPENSE_TYPE,\n REACT_PROVIDER_TYPE,\n REACT_CONSUMER_TYPE,\n REACT_FORWARD_REF_TYPE,\n REACT_MEMO_TYPE,\n REACT_LAZY_TYPE,\n REACT_STRICT_MODE_TYPE,\n REACT_PROFILER_TYPE,\n REACT_PORTAL_TYPE,\n} from '../react'\nimport {\n attrToHtml,\n escapeText,\n escapeScript,\n VOID_ELEMENTS,\n RAW_TEXT_ELEMENTS,\n} from './escape'\nimport {\n pushContext,\n popContext,\n snapshotContexts,\n type ContextSnapshot,\n} from './dispatcher'\n\nexport interface SuspendedBoundary {\n id: number\n fallbackHTML: string\n children: ReactNode\n thenable: Promise<any>\n contextSnapshot: ContextSnapshot\n}\n\nexport interface WalkOptions {\n emit: (chunk: string) => void\n onSuspend?: ((boundary: SuspendedBoundary) => void) | undefined\n nextBoundaryId: () => number\n bootstrapped?: boolean | undefined\n isBoundaryResolution?: boolean | undefined\n isSvg?: boolean | undefined\n /**\n * Tracks whether the most recent emission within the *current text flow*\n * ended with a text node. When the next emission is also text, we emit a\n * `<!-- -->` separator so the browser's HTML parser doesn't merge them\n * into a single text node \u2014 required for hydration to line up text\n * boundaries with the React tree. Reset to `false` whenever we enter a\n * new host element (`<tag>` opens a fresh text flow).\n */\n textState?: { lastWasText: boolean }\n}\n\n/**\n * Synchronously walk a React node and emit HTML string pieces to `opts.emit`.\n * Suspended boundaries are emitted as fallbacks with marker IDs; if `opts.onSuspend`\n * is provided, the suspension is recorded for later streaming.\n */\nexport function walk(node: ReactNode, opts: WalkOptions): void {\n // Seed a text state if the caller didn't provide one so the separator logic\n // is active for the whole tree.\n if (!opts.textState) opts = { ...opts, textState: { lastWasText: false } }\n walkNode(node, opts)\n}\n\n// --- <select> selection context ----------------------------------------------\n// Stack of active select values (or `undefined` when the current select has\n// no controlled value). `<option>` walks read the top of stack to decide\n// whether to emit `selected=\"\"`.\nconst selectValueStack: unknown[] = []\nfunction pushSelectContext(value: unknown): void {\n selectValueStack.push(value)\n}\nfunction popSelectContext(): void {\n selectValueStack.pop()\n}\nfunction currentSelectValue(): unknown {\n return selectValueStack.length ? selectValueStack[selectValueStack.length - 1] : undefined\n}\n\nfunction optionChildText(children: unknown): string {\n // `<option>Text</option>` \u2014 if no `value` prop, the option's value is its\n // flat string/number child content. Matches DOM semantics (`option.value`\n // defaults to `textContent` when no attribute is set).\n if (children == null) return ''\n if (typeof children === 'string' || typeof children === 'number') return '' + children\n if (Array.isArray(children)) return children.map(optionChildText).join('')\n return ''\n}\n\nfunction emitText(text: string, opts: WalkOptions): void {\n // Empty string renders no text node and doesn't start/extend a text flow \u2014\n // skip entirely so sibling text isn't separated by a stray `<!-- -->`.\n if (text === '') return\n if (opts.textState?.lastWasText) opts.emit('<!-- -->')\n opts.emit(escapeText(text))\n if (opts.textState) opts.textState.lastWasText = true\n}\n\nfunction walkNode(node: ReactNode, opts: WalkOptions): void {\n if (node == null || node === false || node === true) return\n\n if (typeof node === 'string') {\n emitText(node, opts)\n return\n }\n if (typeof node === 'number') {\n emitText(String(node), opts)\n return\n }\n if (Array.isArray(node)) {\n for (const c of node) walkNode(c, opts)\n return\n }\n if (typeof (node as any)[Symbol.iterator] === 'function') {\n for (const item of node as Iterable<ReactNode>) walkNode(item, opts)\n return\n }\n\n if (typeof node !== 'object') return\n const t = (node as any).$$typeof\n\n // Raw React.lazy in the tree (RSC Flight encodes 'use client' components \u2014\n // CodeBlock, CodeExplorer, etc. \u2014 as bare Lazy objects directly in the\n // tree, not wrapped in REACT_ELEMENT_TYPE). SSR previously dropped these\n // here, so code snippets never made it into the server HTML. The RSC\n // decoder server-side awaits payloads before rendering, so status is\n // 'fulfilled' and `_init()` returns the resolved element synchronously.\n // If still pending (shouldn't happen post-awaitLazyElements), throw the\n // thenable so streaming SSR suspends the current boundary and retries.\n if (t === REACT_LAZY_TYPE) {\n const lazy = node as any\n const resolved = lazy._init(lazy._payload)\n walkNode(resolved, opts)\n return\n }\n\n if (t !== REACT_ELEMENT_TYPE && t !== REACT_LEGACY_ELEMENT_TYPE) return\n\n const el = node as ReactElement\n walkElement(el, opts)\n}\n\nfunction walkElement(el: ReactElement, opts: WalkOptions): void {\n const type = el.type\n const props = el.props ?? {}\n\n if (type === REACT_FRAGMENT_TYPE || type === REACT_STRICT_MODE_TYPE || type === REACT_PROFILER_TYPE) {\n walkNode(props.children, opts)\n return\n }\n\n if (type === REACT_SUSPENSE_TYPE) {\n walkSuspense(props, opts)\n return\n }\n\n if (typeof type === 'string') {\n walkHost(type, props, opts)\n return\n }\n\n const marker = (type as any)?.$$typeof\n\n if (marker === REACT_PORTAL_TYPE) {\n // Portals don't render to the main HTML output on the server.\n return\n }\n\n if (marker === REACT_PROVIDER_TYPE) {\n const ctx = (type as any)._context\n pushContext(ctx, props.value)\n try {\n walkNode(props.children, opts)\n } finally {\n popContext(ctx)\n }\n return\n }\n\n if (marker === REACT_CONSUMER_TYPE) {\n const ctx = (type as any)._context\n const render = props.children\n if (typeof render === 'function') {\n walkNode(render(ctx._currentValue), opts)\n }\n return\n }\n\n if (marker === REACT_FORWARD_REF_TYPE) {\n const render = (type as any).render\n const ref = (props as any).ref ?? null\n const { ref: _omit, ...rest } = props as any\n const rendered = render(rest, ref)\n walkNode(rendered, opts)\n return\n }\n\n if (marker === REACT_MEMO_TYPE) {\n const inner = (type as any).type\n walkElement({ ...el, type: inner } as ReactElement, opts)\n return\n }\n\n if (marker === REACT_LAZY_TYPE) {\n const { _payload, _init } = type as any\n try {\n const resolved = _init(_payload)\n walkElement({ ...el, type: resolved } as ReactElement, opts)\n } catch (thenable: any) {\n if (isThenable(thenable)) {\n // Suspend this point\n throw thenable\n }\n throw thenable\n }\n return\n }\n\n if (typeof type === 'function') {\n walkComponent(type, props, opts)\n return\n }\n}\n\nfunction walkHost(\n tag: string,\n props: Record<string, any>,\n opts: WalkOptions,\n): void {\n const isSvg = opts.isSvg || tag === 'svg'\n // <textarea value=\"...\"> serializes its value as a TEXT CHILD, not an\n // attribute. `defaultValue` is the fallback when `value` is absent. This\n // matches React and the HTML spec \u2014 `<textarea value=\"x\">` is not valid\n // HTML; the value is the element's textContent.\n const isTextarea = tag === 'textarea'\n const textareaValue = isTextarea\n ? props.value != null\n ? props.value\n : props.defaultValue\n : undefined\n\n // <input defaultValue=\"...\"> should parse with that value \u2014 emit it as a\n // `value` attribute. Similarly `defaultChecked` becomes `checked`. This\n // keeps hydration consistent: the browser parser sees the initial value,\n // and on client commit our setProp seeds `.defaultValue`/`.defaultChecked`\n // without stomping the user-typed value.\n const isInput = tag === 'input'\n const inputValueAttr =\n isInput && props.value == null && props.defaultValue != null\n ? props.defaultValue\n : undefined\n const inputCheckedAttr =\n isInput && props.checked == null && props.defaultChecked != null\n ? props.defaultChecked\n : undefined\n\n // <select value=\"...\"> does NOT become an attribute on `<select>` \u2014 the\n // HTML spec has no such attribute. React resolves the selection by stamping\n // `selected` on the matching `<option>` children during render. Stash the\n // target value(s) on the walk state and the child `<option>` walk reads it.\n const isSelect = tag === 'select'\n if (isSelect) {\n const val = props.value != null ? props.value : props.defaultValue\n pushSelectContext(val)\n }\n const isOption = tag === 'option'\n\n // Prepend the HTML5 doctype to the stream when rendering an <html> root.\n // Without it the browser parses the document in quirks mode, which breaks\n // CSS sizing (documentElement.clientHeight returns the content height, not\n // the viewport) \u2014 and Floating-UI-based libraries (Radix dropdowns etc.)\n // then compute off-screen positions for overlays.\n if (tag === 'html') opts.emit('<!DOCTYPE html>')\n\n opts.emit('<' + tag)\n for (const k in props) {\n if (isTextarea && (k === 'value' || k === 'defaultValue')) continue\n if (isInput && (k === 'defaultValue' || k === 'defaultChecked')) continue\n if (isSelect && (k === 'value' || k === 'defaultValue')) continue\n if (isOption && k === 'selected') continue\n opts.emit(attrToHtml(k, props[k], isSvg))\n }\n if (inputValueAttr !== undefined) {\n opts.emit(attrToHtml('value', inputValueAttr, isSvg))\n }\n if (inputCheckedAttr !== undefined) {\n opts.emit(attrToHtml('checked', inputCheckedAttr, isSvg))\n }\n if (isOption) {\n const selectVal = currentSelectValue()\n if (selectVal !== undefined) {\n const optionValue =\n props.value != null ? props.value : optionChildText(props.children)\n const matches = Array.isArray(selectVal)\n ? selectVal.some((v) => '' + v === '' + optionValue)\n : '' + selectVal === '' + optionValue\n if (matches) opts.emit(' selected=\"\"')\n } else if (props.selected) {\n opts.emit(' selected=\"\"')\n }\n }\n\n if (VOID_ELEMENTS.has(tag)) {\n opts.emit('/>')\n if (opts.textState) opts.textState.lastWasText = false\n return\n }\n opts.emit('>')\n // Opening a host element starts a fresh text flow context for its children.\n // Children's text separator tracking is independent of the outer context.\n const parentTextState = opts.textState\n const childOpts: WalkOptions = {\n ...opts,\n isSvg: isSvg && tag !== 'foreignObject',\n textState: { lastWasText: false },\n }\n\n if (tag === 'html' && !hasHeadChild(props.children)) {\n opts.emit('<head></head>')\n }\n\n const dangerouslyHtml = props.dangerouslySetInnerHTML?.__html\n\n if (isTextarea && textareaValue != null) {\n opts.emit(escapeText(String(textareaValue)))\n opts.emit(`</${tag}>`)\n if (parentTextState) parentTextState.lastWasText = false\n return\n }\n\n if (RAW_TEXT_ELEMENTS.has(tag)) {\n // script/style: raw-text. React allows either a string/number child or\n // dangerouslySetInnerHTML \u2014 some libs (Start's Scripts) use the latter.\n if (dangerouslyHtml != null) {\n opts.emit(escapeScript(String(dangerouslyHtml)))\n } else {\n const children = props.children\n if (typeof children === 'string' || typeof children === 'number') {\n opts.emit(escapeScript(String(children)))\n } else if (Array.isArray(children)) {\n opts.emit(escapeScript(children.filter((c) => c != null).join('')))\n }\n }\n opts.emit(`</${tag}>`)\n if (parentTextState) parentTextState.lastWasText = false\n return\n }\n\n if (dangerouslyHtml != null) {\n opts.emit(String(dangerouslyHtml))\n } else {\n walkNode(props.children, childOpts)\n }\n opts.emit(`</${tag}>`)\n if (isSelect) popSelectContext()\n // Host element closing resets outer flow \u2014 next sibling text starts fresh.\n if (parentTextState) parentTextState.lastWasText = false\n}\n\nfunction hasHeadChild(children: unknown): boolean {\n if (children == null || typeof children === 'boolean') return false\n if (Array.isArray(children)) return children.some(hasHeadChild)\n if (typeof children !== 'string' && isIterable(children)) {\n for (const child of children as Iterable<unknown>) {\n if (hasHeadChild(child)) return true\n }\n return false\n }\n return isElementOfType(children, 'head')\n}\n\nfunction isElementOfType(value: unknown, type: string): value is ReactElement {\n const marker = (value as ReactElement | null)?.$$typeof as unknown\n return (\n !!value &&\n typeof value === 'object' &&\n (marker === REACT_ELEMENT_TYPE || marker === REACT_LEGACY_ELEMENT_TYPE) &&\n (value as ReactElement).type === type\n )\n}\n\nfunction isIterable(value: unknown): value is Iterable<unknown> {\n return !!value && typeof (value as { [Symbol.iterator]?: unknown })[Symbol.iterator] === 'function'\n}\n\nfunction walkComponent(\n fn: Function,\n props: Record<string, any>,\n opts: WalkOptions,\n): void {\n if ((fn as any).prototype?.isReactComponent) {\n const ctxType = (fn as any).contextType\n const ctxValue = ctxType ? ctxType._currentValue : undefined\n const instance = new (fn as any)(props, ctxValue)\n instance.props = props\n instance.context = ctxValue\n if ((fn as any).getDerivedStateFromProps) {\n const d = (fn as any).getDerivedStateFromProps(props, instance.state)\n if (d) instance.state = { ...instance.state, ...d }\n }\n walkNode(instance.render(), opts)\n return\n }\n const rendered = (fn as any)(props)\n walkNode(rendered, opts)\n}\n\nfunction walkSuspense(\n props: Record<string, any>,\n opts: WalkOptions,\n): void {\n const id = opts.nextBoundaryId()\n // Snapshot contexts BEFORE attempting children, so if a descendant suspends\n // we can replay the same provider stack when re-rendering the boundary.\n const contextSnapshot = snapshotContexts()\n\n // Try to render the children synchronously. If a thenable is thrown,\n // record the boundary and emit the fallback.\n const childParts: string[] = []\n const childEmit = (s: string) => childParts.push(s)\n try {\n walkNode(props.children, {\n emit: childEmit,\n onSuspend: opts.onSuspend,\n nextBoundaryId: opts.nextBoundaryId,\n })\n } catch (thenable: any) {\n if (isThenable(thenable)) {\n const fallbackParts: string[] = []\n try {\n walkNode(props.fallback, {\n emit: (s) => fallbackParts.push(s),\n onSuspend: opts.onSuspend,\n nextBoundaryId: opts.nextBoundaryId,\n })\n } catch {\n // Fallback suspending is unsupported; emit nothing\n }\n emitBoundary(opts, id, fallbackParts.join(''))\n\n if (opts.onSuspend) {\n opts.onSuspend({\n id,\n fallbackHTML: fallbackParts.join(''),\n children: props.children,\n thenable,\n contextSnapshot,\n })\n }\n return\n }\n throw thenable\n }\n\n // Children rendered fully \u2014 emit them wrapped in resolved-boundary markers\n // (`<!--$N-->` / `<!--/$-->`). Without markers, the client hydrator has no\n // way to know this subtree is inside a Suspense, so if the client version\n // of a descendant (e.g. `React.lazy`) suspends it can't pinpoint which DOM\n // range to adopt on resolve \u2014 it creates fresh DOM next to the SSR content,\n // producing visible duplicates (e.g. double navbar logos). Markers let the\n // client treat this as a resolved boundary and hydrate in-place.\n opts.emit(`<!--$${id}-->`)\n opts.emit(childParts.join(''))\n opts.emit(`<!--/$-->`)\n}\n\nfunction emitBoundary(opts: WalkOptions, id: number, fallbackHTML: string): void {\n // Visible div wrapper so the fallback UI shows; B: id lets $RC locate it on\n // reveal. The leading/trailing comments let hydration detect a pending\n // boundary and register a reveal callback.\n opts.emit(`<!--$?${id}--><div id=\"B:${id}\">`)\n opts.emit(fallbackHTML)\n opts.emit(`</div><!--/$-->`)\n}\n\nfunction isThenable(x: any): x is Promise<any> {\n return x != null && typeof x.then === 'function'\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function attributeName(name: string, isSvg = false): string {
|
|
2
|
+
if (isSvg && name !== 'viewBox' && SVG_KEBAB_PREFIX.test(name)) {
|
|
3
|
+
return name.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase())
|
|
4
|
+
}
|
|
5
|
+
if (name === 'className') return 'class'
|
|
6
|
+
if (name === 'htmlFor') return 'for'
|
|
7
|
+
if (name === 'httpEquiv') return 'http-equiv'
|
|
8
|
+
if (name === 'acceptCharset') return 'accept-charset'
|
|
9
|
+
if (name === 'crossOrigin') return 'crossorigin'
|
|
10
|
+
if (name === 'noModule') return 'nomodule'
|
|
11
|
+
if (name === 'viewBox') return 'viewBox'
|
|
12
|
+
return name.startsWith('aria-') || name.startsWith('data-')
|
|
13
|
+
? name
|
|
14
|
+
: name.toLowerCase()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const SVG_KEBAB_PREFIX = /^(?:clip|fill|stroke)/
|
package/src/core/internal.ts
CHANGED
package/src/dom/dispatcher.ts
CHANGED
|
@@ -209,7 +209,9 @@ function makeDispatcherImpl() {
|
|
|
209
209
|
if (hook.s === undefined) {
|
|
210
210
|
const fiber = getCurrentFiber()
|
|
211
211
|
const root = findRootFromFiber(fiber)
|
|
212
|
-
hook.s =
|
|
212
|
+
hook.s = root
|
|
213
|
+
? root.i + (root.ic++).toString(36)
|
|
214
|
+
: ':r' + (idCounter++).toString(36)
|
|
213
215
|
}
|
|
214
216
|
return hook.s as string
|
|
215
217
|
},
|
package/src/dom/dom.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { attributeName } from '../core/attributes'
|
|
2
|
+
|
|
1
3
|
const SVG_NS = 'http://www.w3.org/2000/svg'
|
|
2
4
|
|
|
3
5
|
const BOOLEAN_ATTRS = new Set([
|
|
@@ -60,6 +62,7 @@ export function setProp(
|
|
|
60
62
|
isSvg: boolean,
|
|
61
63
|
): void {
|
|
62
64
|
if (name === 'children' || name === 'key' || name === 'ref') return
|
|
65
|
+
const attr = attributeName(name, isSvg)
|
|
63
66
|
|
|
64
67
|
// defaultValue / defaultChecked are IDL-property-only — they seed the
|
|
65
68
|
// initial value/checked of a form control on first mount and must NOT be
|
|
@@ -123,8 +126,8 @@ export function setProp(
|
|
|
123
126
|
}
|
|
124
127
|
|
|
125
128
|
if (BOOLEAN_ATTRS.has(name.toLowerCase())) {
|
|
126
|
-
if (next) el.setAttribute(
|
|
127
|
-
else el.removeAttribute(
|
|
129
|
+
if (next) el.setAttribute(attr, '')
|
|
130
|
+
else el.removeAttribute(attr)
|
|
128
131
|
return
|
|
129
132
|
}
|
|
130
133
|
|
|
@@ -134,20 +137,20 @@ export function setProp(
|
|
|
134
137
|
if (name.length > 5 && (name.charCodeAt(0) === 97 /* a */ || name.charCodeAt(0) === 100 /* d */)) {
|
|
135
138
|
if (name.startsWith('aria-') || name.startsWith('data-')) {
|
|
136
139
|
if (next == null) {
|
|
137
|
-
el.removeAttribute(
|
|
140
|
+
el.removeAttribute(attr)
|
|
138
141
|
} else {
|
|
139
|
-
el.setAttribute(
|
|
142
|
+
el.setAttribute(attr, '' + next)
|
|
140
143
|
}
|
|
141
144
|
return
|
|
142
145
|
}
|
|
143
146
|
}
|
|
144
147
|
|
|
145
148
|
if (next == null || next === false) {
|
|
146
|
-
el.removeAttribute(
|
|
149
|
+
el.removeAttribute(attr)
|
|
147
150
|
} else if (next === true) {
|
|
148
|
-
el.setAttribute(
|
|
151
|
+
el.setAttribute(attr, '')
|
|
149
152
|
} else {
|
|
150
|
-
el.setAttribute(
|
|
153
|
+
el.setAttribute(attr, '' + next)
|
|
151
154
|
}
|
|
152
155
|
}
|
|
153
156
|
|