@tanstack/redact 0.0.18 → 0.0.20
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 +6 -0
- package/dist/core/attributes.js.map +2 -2
- package/dist/dom/dom.js +7 -5
- package/dist/dom/dom.js.map +2 -2
- package/dist/dom/features/hydration/full.js +80 -58
- package/dist/dom/features/hydration/full.js.map +2 -2
- package/dist/server/escape.js +2 -2
- package/dist/server/escape.js.map +2 -2
- package/package.json +10 -5
- package/src/core/attributes.ts +6 -0
- package/src/dom/dom.ts +7 -4
- package/src/dom/features/hydration/full.ts +130 -62
- package/src/server/escape.ts +7 -6
package/dist/core/attributes.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
// packages/redact/src/core/attributes.ts
|
|
2
|
+
var STRING_BOOLEAN_ATTRS = /* @__PURE__ */ new Set([
|
|
3
|
+
"contenteditable",
|
|
4
|
+
"draggable",
|
|
5
|
+
"spellcheck"
|
|
6
|
+
]);
|
|
2
7
|
function attributeName(name, isSvg = false) {
|
|
3
8
|
if (isSvg && name !== "viewBox" && SVG_KEBAB_PREFIX.test(name)) {
|
|
4
9
|
return name.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
|
|
@@ -14,6 +19,7 @@ function attributeName(name, isSvg = false) {
|
|
|
14
19
|
}
|
|
15
20
|
var SVG_KEBAB_PREFIX = /^(?:clip|fill|stroke)/;
|
|
16
21
|
export {
|
|
22
|
+
STRING_BOOLEAN_ATTRS,
|
|
17
23
|
attributeName
|
|
18
24
|
};
|
|
19
25
|
//# sourceMappingURL=attributes.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/core/attributes.ts"],
|
|
4
|
-
"sourcesContent": ["export function attributeName(name: string, isSvg = false): string {\n if (isSvg && name !== 'viewBox' && SVG_KEBAB_PREFIX.test(name)) {\n return name.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase())\n }\n if (name === 'className') return 'class'\n if (name === 'htmlFor') return 'for'\n if (name === 'httpEquiv') return 'http-equiv'\n if (name === 'acceptCharset') return 'accept-charset'\n if (name === 'crossOrigin') return 'crossorigin'\n if (name === 'noModule') return 'nomodule'\n if (name === 'viewBox') return 'viewBox'\n return name.startsWith('aria-') || name.startsWith('data-')\n ? name\n : name.toLowerCase()\n}\n\nconst SVG_KEBAB_PREFIX = /^(?:clip|fill|stroke)/\n"],
|
|
5
|
-
"mappings": ";AAAO,SAAS,cAAc,MAAc,QAAQ,OAAe;AACjE,MAAI,SAAS,SAAS,aAAa,iBAAiB,KAAK,IAAI,GAAG;AAC9D,WAAO,KAAK,QAAQ,UAAU,CAAC,MAAM,MAAM,EAAE,YAAY,CAAC;AAAA,EAC5D;AACA,MAAI,SAAS,YAAa,QAAO;AACjC,MAAI,SAAS,UAAW,QAAO;AAC/B,MAAI,SAAS,YAAa,QAAO;AACjC,MAAI,SAAS,gBAAiB,QAAO;AACrC,MAAI,SAAS,cAAe,QAAO;AACnC,MAAI,SAAS,WAAY,QAAO;AAChC,MAAI,SAAS,UAAW,QAAO;AAC/B,SAAO,KAAK,WAAW,OAAO,KAAK,KAAK,WAAW,OAAO,IACtD,OACA,KAAK,YAAY;AACvB;AAEA,IAAM,mBAAmB;",
|
|
4
|
+
"sourcesContent": ["export const STRING_BOOLEAN_ATTRS = new Set([\n 'contenteditable',\n 'draggable',\n 'spellcheck',\n])\n\nexport function attributeName(name: string, isSvg = false): string {\n if (isSvg && name !== 'viewBox' && SVG_KEBAB_PREFIX.test(name)) {\n return name.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase())\n }\n if (name === 'className') return 'class'\n if (name === 'htmlFor') return 'for'\n if (name === 'httpEquiv') return 'http-equiv'\n if (name === 'acceptCharset') return 'accept-charset'\n if (name === 'crossOrigin') return 'crossorigin'\n if (name === 'noModule') return 'nomodule'\n if (name === 'viewBox') return 'viewBox'\n return name.startsWith('aria-') || name.startsWith('data-')\n ? name\n : name.toLowerCase()\n}\n\nconst SVG_KEBAB_PREFIX = /^(?:clip|fill|stroke)/\n"],
|
|
5
|
+
"mappings": ";AAAO,IAAM,uBAAuB,oBAAI,IAAI;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,SAAS,cAAc,MAAc,QAAQ,OAAe;AACjE,MAAI,SAAS,SAAS,aAAa,iBAAiB,KAAK,IAAI,GAAG;AAC9D,WAAO,KAAK,QAAQ,UAAU,CAAC,MAAM,MAAM,EAAE,YAAY,CAAC;AAAA,EAC5D;AACA,MAAI,SAAS,YAAa,QAAO;AACjC,MAAI,SAAS,UAAW,QAAO;AAC/B,MAAI,SAAS,YAAa,QAAO;AACjC,MAAI,SAAS,gBAAiB,QAAO;AACrC,MAAI,SAAS,cAAe,QAAO;AACnC,MAAI,SAAS,WAAY,QAAO;AAChC,MAAI,SAAS,UAAW,QAAO;AAC/B,SAAO,KAAK,WAAW,OAAO,KAAK,KAAK,WAAW,OAAO,IACtD,OACA,KAAK,YAAY;AACvB;AAEA,IAAM,mBAAmB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/dom/dom.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// packages/redact/src/dom/dom.ts
|
|
2
|
-
import { attributeName } from "../core/attributes";
|
|
2
|
+
import { attributeName, STRING_BOOLEAN_ATTRS } from "../core/attributes";
|
|
3
3
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
4
4
|
var BOOLEAN_ATTRS = /* @__PURE__ */ new Set([
|
|
5
5
|
"allowfullscreen",
|
|
@@ -35,10 +35,7 @@ var IDL_ATTRS = /* @__PURE__ */ new Set([
|
|
|
35
35
|
"disabled",
|
|
36
36
|
"multiple",
|
|
37
37
|
"muted",
|
|
38
|
-
"readonly"
|
|
39
|
-
"contentEditable",
|
|
40
|
-
"spellcheck",
|
|
41
|
-
"draggable"
|
|
38
|
+
"readonly"
|
|
42
39
|
]);
|
|
43
40
|
function createHostNode(type, isSvg) {
|
|
44
41
|
if (isSvg || type === "svg") {
|
|
@@ -96,6 +93,11 @@ function setProp(el, name, next, prev, isSvg) {
|
|
|
96
93
|
else el.setAttribute("for", "" + next);
|
|
97
94
|
return;
|
|
98
95
|
}
|
|
96
|
+
if (STRING_BOOLEAN_ATTRS.has(attr)) {
|
|
97
|
+
if (next == null) el.removeAttribute(attr);
|
|
98
|
+
else el.setAttribute(attr, "" + next);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
99
101
|
if (!isSvg && IDL_ATTRS.has(name) && name in el) {
|
|
100
102
|
try {
|
|
101
103
|
;
|
package/dist/dom/dom.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/dom/dom.ts"],
|
|
4
|
-
"sourcesContent": ["import { attributeName } from '../core/attributes'\n\nconst SVG_NS = 'http://www.w3.org/2000/svg'\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\nconst IDL_ATTRS = new Set([\n 'value',\n 'checked',\n 'selected',\n 'disabled',\n 'multiple',\n 'muted',\n 'readonly',\n
|
|
5
|
-
"mappings": ";AAAA,SAAS,
|
|
4
|
+
"sourcesContent": ["import { attributeName, STRING_BOOLEAN_ATTRS } from '../core/attributes'\n\nconst SVG_NS = 'http://www.w3.org/2000/svg'\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\nconst IDL_ATTRS = new Set([\n 'value',\n 'checked',\n 'selected',\n 'disabled',\n 'multiple',\n 'muted',\n 'readonly',\n])\n\nexport function createHostNode(type: string, isSvg: boolean): Element {\n if (isSvg || type === 'svg') {\n return document.createElementNS(SVG_NS, type)\n }\n return document.createElement(type)\n}\n\nexport function isSvgElement(el: Element): boolean {\n return (el as any).ownerSVGElement !== undefined || el.tagName === 'svg'\n}\n\nexport function setProp(\n el: Element,\n name: string,\n next: any,\n prev: any,\n isSvg: boolean,\n): void {\n if (name === 'children' || name === 'key' || name === 'ref') return\n const attr = attributeName(name, isSvg)\n\n // defaultValue / defaultChecked are IDL-property-only \u2014 they seed the\n // initial value/checked of a form control on first mount and must NOT be\n // emitted as HTML attributes (which would leak as `defaultValue=\"...\"`).\n // Setting `el.defaultValue` on a fresh control also sets the initial\n // `el.value`, which is what consumers expect. Skip on hydrated DOM so we\n // don't clobber a live user-typed value.\n if (name === 'defaultValue' || name === 'defaultChecked') {\n if (prev === undefined && next != null) {\n try {\n ;(el as any)[name] = next\n } catch {}\n }\n return\n }\n\n if (name === 'className') {\n if (isSvg) {\n if (next == null) el.removeAttribute('class')\n else el.setAttribute('class', '' + next)\n } else {\n ;(el as HTMLElement).className = next == null ? '' : '' + next\n }\n return\n }\n\n if (name === 'class') {\n if (next == null) el.removeAttribute('class')\n else el.setAttribute('class', '' + next)\n return\n }\n\n if (name === 'style') {\n setStyle(el as HTMLElement, next, prev)\n return\n }\n\n if (name === 'dangerouslySetInnerHTML') {\n const nextHtml = next?.__html ?? ''\n const prevHtml = prev?.__html ?? ''\n if (nextHtml !== prevHtml) (el as HTMLElement).innerHTML = nextHtml\n return\n }\n\n if (name[0] === 'o' && name[1] === 'n') {\n setEventHandler(el, name, next, prev)\n return\n }\n\n if (name === 'htmlFor') {\n if (next == null) el.removeAttribute('for')\n else el.setAttribute('for', '' + next)\n return\n }\n\n if (STRING_BOOLEAN_ATTRS.has(attr)) {\n if (next == null) el.removeAttribute(attr)\n else el.setAttribute(attr, '' + next)\n return\n }\n\n if (!isSvg && IDL_ATTRS.has(name) && name in el) {\n try {\n ;(el as any)[name] = next == null ? '' : next\n return\n } catch {}\n }\n\n if (BOOLEAN_ATTRS.has(name.toLowerCase())) {\n if (next) el.setAttribute(attr, '')\n else el.removeAttribute(attr)\n return\n }\n\n // aria-* and data-* attributes stringify booleans to `\"true\"`/`\"false\"`\n // rather than using the HTML boolean-attribute presence/absence semantics.\n // This matches React and the ARIA spec (aria-hidden=\"false\" is meaningful).\n if (name.length > 5 && (name.charCodeAt(0) === 97 /* a */ || name.charCodeAt(0) === 100 /* d */)) {\n if (name.startsWith('aria-') || name.startsWith('data-')) {\n if (next == null) {\n el.removeAttribute(attr)\n } else {\n el.setAttribute(attr, '' + next)\n }\n return\n }\n }\n\n if (next == null || next === false) {\n el.removeAttribute(attr)\n } else if (next === true) {\n el.setAttribute(attr, '')\n } else {\n el.setAttribute(attr, '' + next)\n }\n}\n\nfunction setStyle(el: HTMLElement, next: any, prev: any): void {\n const style = el.style\n if (typeof next === 'string') {\n style.cssText = next\n return\n }\n if (typeof prev === 'string') style.cssText = ''\n if (prev && typeof prev === 'object') {\n for (const k in prev) {\n if (!next || !(k in next)) setStyleProperty(style, k, '')\n }\n }\n if (next && typeof next === 'object') {\n for (const k in next) {\n if (!prev || prev[k] !== next[k]) setStyleProperty(style, k, next[k])\n }\n }\n}\n\nfunction setStyleProperty(style: CSSStyleDeclaration, key: string, value: any): void {\n if (key[0] === '-') {\n style.setProperty(key, value == null ? '' : '' + value)\n } else if (value == null || value === '') {\n ;(style as any)[key] = ''\n } else if (typeof value === 'number' && !UNITLESS_STYLE.has(key)) {\n ;(style as any)[key] = value + 'px'\n } else {\n ;(style as any)[key] = '' + value\n }\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\nexport interface SyntheticEvent extends Event {\n nativeEvent: Event\n isDefaultPrevented(): boolean\n isPropagationStopped(): boolean\n persist(): void\n currentTarget: EventTarget & Element\n}\n\nfunction setEventHandler(el: Element, name: string, next: any, prev: any): void {\n // Only function handlers are accepted. Reject strings/objects/etc \u2014 the\n // legacy `onclick=\"...\"` HTML attribute (string handler) is a known XSS\n // vector if a parent spreads untrusted props onto a host element. React\n // also ignores non-function handlers.\n if (next != null && typeof next != 'function') next = null\n\n const capture = name.endsWith('Capture')\n const reactEventName = name.slice(2, capture ? -7 : undefined)\n const eventName = domEventFor(reactEventName, el)\n\n // Key by the React prop name (not DOM event name) so `onChange` and\n // `onInput` on the same text input \u2014 which both dispatch from the native\n // `input` event \u2014 can coexist without clobbering each other's handlers.\n const handlers = ((el as any).__handlers ||= Object.create(null))\n const key = name\n\n const existing = handlers[key]\n\n if (existing && !next) {\n el.removeEventListener(existing.event, existing.listener, existing.capture)\n handlers[key] = null\n return\n }\n\n if (!existing && next) {\n const entry = {\n current: next as Function,\n listener: null as any,\n event: eventName,\n capture,\n }\n entry.listener = (e: Event) => {\n // React hands handlers a SyntheticEvent that carries `.nativeEvent`.\n // Many libraries check `event.nativeEvent.isComposing` (react-instantsearch)\n // or `event.nativeEvent.shiftKey` (UI kits) \u2014 without the alias they throw\n // on `undefined.foo`. Aliasing the native event to itself is the cheapest\n // way to satisfy the shape without building a full synthetic layer.\n if ((e as any).nativeEvent === undefined) (e as any).nativeEvent = e\n entry.current(e)\n }\n handlers[key] = entry\n el.addEventListener(eventName, entry.listener, capture)\n return\n }\n\n if (existing) {\n // Re-bind if the effective DOM event changed (e.g. <input> whose `type`\n // flipped from \"text\" to \"checkbox\" \u2014 onChange should now follow `change`\n // instead of `input`). This is rare but keeps semantics correct.\n if (existing.event !== eventName || existing.capture !== capture) {\n el.removeEventListener(existing.event, existing.listener, existing.capture)\n existing.event = eventName\n existing.capture = capture\n el.addEventListener(eventName, existing.listener, capture)\n }\n existing.current = next\n }\n}\n\nfunction domEventFor(reactEventName: string, el: Element): string {\n const lower = reactEventName.toLowerCase()\n // React's `onChange` on text-like <input> and <textarea> maps to the\n // native `input` event so handlers fire on every keystroke. On checkbox,\n // radio, file inputs, and <select>, React's `onChange` maps to the\n // native `change` event (which fires on click / option select).\n if (lower === 'change') {\n const tag = el.tagName\n if (tag === 'TEXTAREA') return 'input'\n if (tag === 'INPUT') {\n const type = ((el as HTMLInputElement).type || 'text').toLowerCase()\n if (type !== 'checkbox' && type !== 'radio' && type !== 'file') {\n return 'input'\n }\n }\n }\n if (lower === 'doubleclick') return 'dblclick'\n return lower\n}\n"],
|
|
5
|
+
"mappings": ";AAAA,SAAS,eAAe,4BAA4B;AAEpD,IAAM,SAAS;AAEf,IAAM,gBAAgB,oBAAI,IAAI;AAAA,EAC5B;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,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,IAAM,YAAY,oBAAI,IAAI;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,SAAS,eAAe,MAAc,OAAyB;AACpE,MAAI,SAAS,SAAS,OAAO;AAC3B,WAAO,SAAS,gBAAgB,QAAQ,IAAI;AAAA,EAC9C;AACA,SAAO,SAAS,cAAc,IAAI;AACpC;AAEO,SAAS,aAAa,IAAsB;AACjD,SAAQ,GAAW,oBAAoB,UAAa,GAAG,YAAY;AACrE;AAEO,SAAS,QACd,IACA,MACA,MACA,MACA,OACM;AACN,MAAI,SAAS,cAAc,SAAS,SAAS,SAAS,MAAO;AAC7D,QAAM,OAAO,cAAc,MAAM,KAAK;AAQtC,MAAI,SAAS,kBAAkB,SAAS,kBAAkB;AACxD,QAAI,SAAS,UAAa,QAAQ,MAAM;AACtC,UAAI;AACF;AAAC,QAAC,GAAW,IAAI,IAAI;AAAA,MACvB,QAAQ;AAAA,MAAC;AAAA,IACX;AACA;AAAA,EACF;AAEA,MAAI,SAAS,aAAa;AACxB,QAAI,OAAO;AACT,UAAI,QAAQ,KAAM,IAAG,gBAAgB,OAAO;AAAA,UACvC,IAAG,aAAa,SAAS,KAAK,IAAI;AAAA,IACzC,OAAO;AACL;AAAC,MAAC,GAAmB,YAAY,QAAQ,OAAO,KAAK,KAAK;AAAA,IAC5D;AACA;AAAA,EACF;AAEA,MAAI,SAAS,SAAS;AACpB,QAAI,QAAQ,KAAM,IAAG,gBAAgB,OAAO;AAAA,QACvC,IAAG,aAAa,SAAS,KAAK,IAAI;AACvC;AAAA,EACF;AAEA,MAAI,SAAS,SAAS;AACpB,aAAS,IAAmB,MAAM,IAAI;AACtC;AAAA,EACF;AAEA,MAAI,SAAS,2BAA2B;AACtC,UAAM,WAAW,MAAM,UAAU;AACjC,UAAM,WAAW,MAAM,UAAU;AACjC,QAAI,aAAa,SAAU,CAAC,GAAmB,YAAY;AAC3D;AAAA,EACF;AAEA,MAAI,KAAK,CAAC,MAAM,OAAO,KAAK,CAAC,MAAM,KAAK;AACtC,oBAAgB,IAAI,MAAM,MAAM,IAAI;AACpC;AAAA,EACF;AAEA,MAAI,SAAS,WAAW;AACtB,QAAI,QAAQ,KAAM,IAAG,gBAAgB,KAAK;AAAA,QACrC,IAAG,aAAa,OAAO,KAAK,IAAI;AACrC;AAAA,EACF;AAEA,MAAI,qBAAqB,IAAI,IAAI,GAAG;AAClC,QAAI,QAAQ,KAAM,IAAG,gBAAgB,IAAI;AAAA,QACpC,IAAG,aAAa,MAAM,KAAK,IAAI;AACpC;AAAA,EACF;AAEA,MAAI,CAAC,SAAS,UAAU,IAAI,IAAI,KAAK,QAAQ,IAAI;AAC/C,QAAI;AACF;AAAC,MAAC,GAAW,IAAI,IAAI,QAAQ,OAAO,KAAK;AACzC;AAAA,IACF,QAAQ;AAAA,IAAC;AAAA,EACX;AAEA,MAAI,cAAc,IAAI,KAAK,YAAY,CAAC,GAAG;AACzC,QAAI,KAAM,IAAG,aAAa,MAAM,EAAE;AAAA,QAC7B,IAAG,gBAAgB,IAAI;AAC5B;AAAA,EACF;AAKA,MAAI,KAAK,SAAS,MAAM,KAAK,WAAW,CAAC,MAAM,MAAc,KAAK,WAAW,CAAC,MAAM,MAAc;AAChG,QAAI,KAAK,WAAW,OAAO,KAAK,KAAK,WAAW,OAAO,GAAG;AACxD,UAAI,QAAQ,MAAM;AAChB,WAAG,gBAAgB,IAAI;AAAA,MACzB,OAAO;AACL,WAAG,aAAa,MAAM,KAAK,IAAI;AAAA,MACjC;AACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,QAAQ,QAAQ,SAAS,OAAO;AAClC,OAAG,gBAAgB,IAAI;AAAA,EACzB,WAAW,SAAS,MAAM;AACxB,OAAG,aAAa,MAAM,EAAE;AAAA,EAC1B,OAAO;AACL,OAAG,aAAa,MAAM,KAAK,IAAI;AAAA,EACjC;AACF;AAEA,SAAS,SAAS,IAAiB,MAAW,MAAiB;AAC7D,QAAM,QAAQ,GAAG;AACjB,MAAI,OAAO,SAAS,UAAU;AAC5B,UAAM,UAAU;AAChB;AAAA,EACF;AACA,MAAI,OAAO,SAAS,SAAU,OAAM,UAAU;AAC9C,MAAI,QAAQ,OAAO,SAAS,UAAU;AACpC,eAAW,KAAK,MAAM;AACpB,UAAI,CAAC,QAAQ,EAAE,KAAK,MAAO,kBAAiB,OAAO,GAAG,EAAE;AAAA,IAC1D;AAAA,EACF;AACA,MAAI,QAAQ,OAAO,SAAS,UAAU;AACpC,eAAW,KAAK,MAAM;AACpB,UAAI,CAAC,QAAQ,KAAK,CAAC,MAAM,KAAK,CAAC,EAAG,kBAAiB,OAAO,GAAG,KAAK,CAAC,CAAC;AAAA,IACtE;AAAA,EACF;AACF;AAEA,SAAS,iBAAiB,OAA4B,KAAa,OAAkB;AACnF,MAAI,IAAI,CAAC,MAAM,KAAK;AAClB,UAAM,YAAY,KAAK,SAAS,OAAO,KAAK,KAAK,KAAK;AAAA,EACxD,WAAW,SAAS,QAAQ,UAAU,IAAI;AACxC;AAAC,IAAC,MAAc,GAAG,IAAI;AAAA,EACzB,WAAW,OAAO,UAAU,YAAY,CAAC,eAAe,IAAI,GAAG,GAAG;AAChE;AAAC,IAAC,MAAc,GAAG,IAAI,QAAQ;AAAA,EACjC,OAAO;AACL;AAAC,IAAC,MAAc,GAAG,IAAI,KAAK;AAAA,EAC9B;AACF;AAEA,IAAM,iBAAiB,oBAAI,IAAI;AAAA,EAC7B;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,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,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,EACA;AAAA,EACA;AACF,CAAC;AAUD,SAAS,gBAAgB,IAAa,MAAc,MAAW,MAAiB;AAK9E,MAAI,QAAQ,QAAQ,OAAO,QAAQ,WAAY,QAAO;AAEtD,QAAM,UAAU,KAAK,SAAS,SAAS;AACvC,QAAM,iBAAiB,KAAK,MAAM,GAAG,UAAU,KAAK,MAAS;AAC7D,QAAM,YAAY,YAAY,gBAAgB,EAAE;AAKhD,QAAM,WAAa,GAAW,eAAe,uBAAO,OAAO,IAAI;AAC/D,QAAM,MAAM;AAEZ,QAAM,WAAW,SAAS,GAAG;AAE7B,MAAI,YAAY,CAAC,MAAM;AACrB,OAAG,oBAAoB,SAAS,OAAO,SAAS,UAAU,SAAS,OAAO;AAC1E,aAAS,GAAG,IAAI;AAChB;AAAA,EACF;AAEA,MAAI,CAAC,YAAY,MAAM;AACrB,UAAM,QAAQ;AAAA,MACZ,SAAS;AAAA,MACT,UAAU;AAAA,MACV,OAAO;AAAA,MACP;AAAA,IACF;AACA,UAAM,WAAW,CAAC,MAAa;AAM7B,UAAK,EAAU,gBAAgB,OAAW,CAAC,EAAU,cAAc;AACnE,YAAM,QAAQ,CAAC;AAAA,IACjB;AACA,aAAS,GAAG,IAAI;AAChB,OAAG,iBAAiB,WAAW,MAAM,UAAU,OAAO;AACtD;AAAA,EACF;AAEA,MAAI,UAAU;AAIZ,QAAI,SAAS,UAAU,aAAa,SAAS,YAAY,SAAS;AAChE,SAAG,oBAAoB,SAAS,OAAO,SAAS,UAAU,SAAS,OAAO;AAC1E,eAAS,QAAQ;AACjB,eAAS,UAAU;AACnB,SAAG,iBAAiB,WAAW,SAAS,UAAU,OAAO;AAAA,IAC3D;AACA,aAAS,UAAU;AAAA,EACrB;AACF;AAEA,SAAS,YAAY,gBAAwB,IAAqB;AAChE,QAAM,QAAQ,eAAe,YAAY;AAKzC,MAAI,UAAU,UAAU;AACtB,UAAM,MAAM,GAAG;AACf,QAAI,QAAQ,WAAY,QAAO;AAC/B,QAAI,QAAQ,SAAS;AACnB,YAAM,QAAS,GAAwB,QAAQ,QAAQ,YAAY;AACnE,UAAI,SAAS,cAAc,SAAS,WAAW,SAAS,QAAQ;AAC9D,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACA,MAAI,UAAU,cAAe,QAAO;AACpC,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
FiberTag,
|
|
4
4
|
REACT_ELEMENT_TYPE
|
|
5
5
|
} from "../../../core";
|
|
6
|
-
import { attributeName } from "../../../core/attributes";
|
|
6
|
+
import { attributeName, STRING_BOOLEAN_ATTRS } from "../../../core/attributes";
|
|
7
7
|
import { createHostNode, setProp } from "../../dom";
|
|
8
8
|
import { drainReplayQueue } from "../../event-replay";
|
|
9
9
|
import { discardPendingWork, findRoot, flushSyncWork, renderRoot } from "../../reconcile";
|
|
@@ -140,7 +140,8 @@ function hydrateRootImpl(container, initialChildren, options) {
|
|
|
140
140
|
var HEAD_KEY_ATTRS = {
|
|
141
141
|
link: ["rel", "href", "sizes", "type"],
|
|
142
142
|
meta: ["name", "property", "charSet", "httpEquiv"],
|
|
143
|
-
script: ["src", "type"]
|
|
143
|
+
script: ["src", "type"],
|
|
144
|
+
style: ["id", "media", "nonce", "title"]
|
|
144
145
|
};
|
|
145
146
|
var DOCUMENT_HEAD_TAGS = /* @__PURE__ */ new Set(["base", "link", "meta", "script", "style", "title"]);
|
|
146
147
|
var CLAIMED = /* @__PURE__ */ new WeakSet();
|
|
@@ -233,10 +234,11 @@ function adoptHostDom(fiber, parent) {
|
|
|
233
234
|
fiber.dom = candidate;
|
|
234
235
|
const props = fiber.pp ?? {};
|
|
235
236
|
const isSvg = tag === "svg" || candidate.namespaceURI === "http://www.w3.org/2000/svg" && tag !== "foreignobject";
|
|
237
|
+
const syncHydrationProps = !props.suppressHydrationWarning && canRecoverHydrationPropMismatch(candidate, tag);
|
|
236
238
|
validateHydrationProps(fiber, candidate, props, tag, isSvg);
|
|
237
239
|
for (const k in props) {
|
|
238
|
-
if (k === "children") continue;
|
|
239
|
-
if (k[0] === "o" && k[1] === "n" && typeof props[k] == "function") {
|
|
240
|
+
if (k === "children" || k === "key" || k === "ref" || k === "suppressHydrationWarning" || k === "suppressContentEditableWarning") continue;
|
|
241
|
+
if (syncHydrationProps || k[0] === "o" && k[1] === "n" && typeof props[k] == "function") {
|
|
240
242
|
setProp(candidate, k, props[k], void 0, isSvg);
|
|
241
243
|
}
|
|
242
244
|
}
|
|
@@ -247,16 +249,23 @@ function adoptTextDom(fiber, parent, text) {
|
|
|
247
249
|
const cursor = hydrationCursors.get(findHostParent(parent));
|
|
248
250
|
if (!cursor) return false;
|
|
249
251
|
const candidate = cursor.take();
|
|
250
|
-
if (!candidate)
|
|
252
|
+
if (!candidate) {
|
|
253
|
+
onMismatch(fiber, null);
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
251
256
|
if (candidate.nodeType === 3) {
|
|
252
257
|
if (candidate.data !== text) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
)
|
|
258
|
+
const recovered = failHydration(
|
|
259
|
+
fiber,
|
|
260
|
+
true ? new Error(
|
|
261
|
+
`Hydration text mismatch: expected "${text}" but found "${candidate.data}".`
|
|
262
|
+
) : void 0,
|
|
263
|
+
canRecoverHydrationPropMismatch(candidate)
|
|
264
|
+
);
|
|
265
|
+
if (recovered) {
|
|
266
|
+
;
|
|
267
|
+
candidate.data = text;
|
|
258
268
|
}
|
|
259
|
-
failHydration(fiber);
|
|
260
269
|
}
|
|
261
270
|
fiber.dom = candidate;
|
|
262
271
|
return true;
|
|
@@ -279,23 +288,24 @@ function findHostParent(fiber) {
|
|
|
279
288
|
throw new Error();
|
|
280
289
|
}
|
|
281
290
|
function onMismatch(fiber, actualNode) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
);
|
|
289
|
-
}
|
|
290
|
-
failHydration(fiber);
|
|
291
|
+
failHydration(
|
|
292
|
+
fiber,
|
|
293
|
+
true ? new Error(
|
|
294
|
+
`Hydration mismatch: expected <${fiber.type ?? "text"}> but found ${actualNode ? actualNode.nodeType === 1 ? actualNode.tagName : "text" : "nothing"}.`
|
|
295
|
+
) : void 0
|
|
296
|
+
);
|
|
291
297
|
}
|
|
292
|
-
function failHydration(fiber, error = new Error(PROD_HYDRATION_ERROR)) {
|
|
298
|
+
function failHydration(fiber, error = new Error(PROD_HYDRATION_ERROR), recoverInPlace = false) {
|
|
293
299
|
const root = findRoot(fiber);
|
|
294
300
|
if (root?.re) {
|
|
295
301
|
root.re(error);
|
|
296
302
|
}
|
|
303
|
+
if (recoverInPlace) return true;
|
|
297
304
|
abortHydration(error, findHostRecoveryParent(fiber) ?? fiber);
|
|
298
305
|
}
|
|
306
|
+
function canRecoverHydrationPropMismatch(node, tag) {
|
|
307
|
+
return tag === "html" || tag === "head" || tag === "body" || !!node.ownerDocument?.head?.contains(node);
|
|
308
|
+
}
|
|
299
309
|
function findHostRecoveryParent(fiber) {
|
|
300
310
|
if (fiber.tag === FiberTag.Text) {
|
|
301
311
|
let directHost = fiber.parent;
|
|
@@ -481,6 +491,7 @@ function createHostElement(type, props) {
|
|
|
481
491
|
}
|
|
482
492
|
function validateHydrationProps(fiber, el, props, tag, isSvg) {
|
|
483
493
|
if (props.suppressHydrationWarning) return;
|
|
494
|
+
const recoverInPlace = canRecoverHydrationPropMismatch(el, tag);
|
|
484
495
|
let expected;
|
|
485
496
|
for (const k in props) {
|
|
486
497
|
const value = props[k];
|
|
@@ -493,13 +504,11 @@ function validateHydrationProps(fiber, el, props, tag, isSvg) {
|
|
|
493
504
|
html = probe.innerHTML;
|
|
494
505
|
}
|
|
495
506
|
if (el.innerHTML !== html) {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
}
|
|
502
|
-
failHydration(fiber);
|
|
507
|
+
failHydration(
|
|
508
|
+
fiber,
|
|
509
|
+
true ? new Error(`Hydration HTML mismatch inside <${tag}>.`) : void 0,
|
|
510
|
+
recoverInPlace
|
|
511
|
+
);
|
|
503
512
|
}
|
|
504
513
|
continue;
|
|
505
514
|
}
|
|
@@ -508,10 +517,11 @@ function validateHydrationProps(fiber, el, props, tag, isSvg) {
|
|
|
508
517
|
if (tag === "input" || tag === "textarea") {
|
|
509
518
|
if (k === "value" || props.value == null) {
|
|
510
519
|
if (value != null && el.value !== "" + value) {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
520
|
+
failHydration(
|
|
521
|
+
fiber,
|
|
522
|
+
true ? new Error(`Hydration ${tag} value mismatch on <${tag}>.`) : void 0,
|
|
523
|
+
recoverInPlace
|
|
524
|
+
);
|
|
515
525
|
}
|
|
516
526
|
}
|
|
517
527
|
continue;
|
|
@@ -520,42 +530,47 @@ function validateHydrationProps(fiber, el, props, tag, isSvg) {
|
|
|
520
530
|
if (tag === "input" && (k === "checked" || k === "defaultChecked")) {
|
|
521
531
|
if (k === "checked" || props.checked == null) {
|
|
522
532
|
if (value != null && el.checked !== !!value) {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
533
|
+
failHydration(
|
|
534
|
+
fiber,
|
|
535
|
+
true ? new Error(`Hydration checked mismatch on <input>.`) : void 0,
|
|
536
|
+
recoverInPlace
|
|
537
|
+
);
|
|
527
538
|
}
|
|
528
539
|
}
|
|
529
540
|
continue;
|
|
530
541
|
}
|
|
531
542
|
if (tag === "option" && k === "selected") {
|
|
532
543
|
if (value != null && el.selected !== !!value) {
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
544
|
+
failHydration(
|
|
545
|
+
fiber,
|
|
546
|
+
true ? new Error(`Hydration selected mismatch on <option>.`) : void 0,
|
|
547
|
+
recoverInPlace
|
|
548
|
+
);
|
|
537
549
|
}
|
|
538
550
|
continue;
|
|
539
551
|
}
|
|
540
552
|
if (k === "style") {
|
|
541
553
|
expected ??= createHostNode(tag, isSvg);
|
|
542
554
|
setProp(expected, k, value, void 0, isSvg);
|
|
543
|
-
if (
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
555
|
+
if (!hydrationStylesMatch(
|
|
556
|
+
el.style,
|
|
557
|
+
expected.style
|
|
558
|
+
)) {
|
|
559
|
+
failHydration(
|
|
560
|
+
fiber,
|
|
561
|
+
true ? new Error(`Hydration style mismatch on <${tag}>.`) : void 0,
|
|
562
|
+
recoverInPlace
|
|
563
|
+
);
|
|
551
564
|
}
|
|
552
565
|
continue;
|
|
553
566
|
}
|
|
554
|
-
const stringifiedBoolean = k.startsWith("aria-") || k.startsWith("data-");
|
|
555
567
|
const attr = attributeName(k, isSvg);
|
|
568
|
+
const stringifiedBoolean = STRING_BOOLEAN_ATTRS.has(attr) || k.startsWith("aria-") || k.startsWith("data-");
|
|
556
569
|
let expectedValue;
|
|
557
570
|
if (value == null || value === false && !stringifiedBoolean) {
|
|
558
571
|
expectedValue = null;
|
|
572
|
+
} else if (k === "muted" && !isSvg && (tag === "video" || tag === "audio")) {
|
|
573
|
+
expectedValue = value ? "" : null;
|
|
559
574
|
} else {
|
|
560
575
|
expected ??= createHostNode(tag, isSvg);
|
|
561
576
|
setProp(expected, k, value, void 0, isSvg);
|
|
@@ -563,18 +578,25 @@ function validateHydrationProps(fiber, el, props, tag, isSvg) {
|
|
|
563
578
|
}
|
|
564
579
|
const actualValue = el.getAttribute(attr);
|
|
565
580
|
if (expectedValue !== actualValue) {
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
}
|
|
574
|
-
failHydration(fiber);
|
|
581
|
+
failHydration(
|
|
582
|
+
fiber,
|
|
583
|
+
true ? new Error(
|
|
584
|
+
`Hydration attribute mismatch on <${tag}> for "${attr}": expected ${formatHydrationValue(expectedValue)} but found ${formatHydrationValue(actualValue)}.`
|
|
585
|
+
) : void 0,
|
|
586
|
+
recoverInPlace
|
|
587
|
+
);
|
|
575
588
|
}
|
|
576
589
|
}
|
|
577
590
|
}
|
|
591
|
+
function hydrationStylesMatch(actual, expected) {
|
|
592
|
+
for (let index = 0; index < expected.length; index++) {
|
|
593
|
+
const property = expected.item(index);
|
|
594
|
+
if (actual.getPropertyValue(property) !== expected.getPropertyValue(property) || actual.getPropertyPriority(property) !== expected.getPropertyPriority(property)) {
|
|
595
|
+
return false;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
return true;
|
|
599
|
+
}
|
|
578
600
|
function formatHydrationValue(value) {
|
|
579
601
|
return value == null ? "nothing" : JSON.stringify(value);
|
|
580
602
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/dom/features/hydration/full.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n FiberTag,\n REACT_ELEMENT_TYPE,\n type Fiber,\n type FiberRoot,\n type ReactElement,\n type ReactNode,\n} from '../../../core'\nimport { attributeName } from '../../../core/attributes'\nimport { createHostNode, setProp } from '../../dom'\nimport { drainReplayQueue } from '../../event-replay'\nimport { discardPendingWork, findRoot, flushSyncWork, renderRoot } from '../../reconcile'\nimport { attachRootFiber, createFiberRoot } from '../../root-internal'\n\n// Re-export from event-replay so all hydration concerns live behind one\n// feature boundary \u2014 the plugin's stub swap strips drainReplayQueue too.\nexport { drainReplayQueue }\n\n/**\n * Preserve the user's scroll position across hydration. If the user scrolled\n * between SSR paint and hydrate (common in dev where JS takes seconds to\n * load), libraries that wire scroll-restoration into a `useLayoutEffect`\n * near the root (e.g. TanStack Router) will run during our synchronous\n * hydrate and call `window.scrollTo(savedFromLastVisit)` \u2014 overwriting the\n * user's fresh scroll. We install a short-lived wrapper around scrollTo that\n * suppresses programmatic calls when a user-initiated scroll happened\n * recently. Only runs in the hydration feature \u2014 the stub skips it.\n */\nexport function installHydrationScrollGuard(): void {\n if (typeof window === 'undefined') return\n const w = window as any\n if (w._r) return\n const time = Date.now\n const guardStartedAt = w._r = time()\n let lastUserScrollAt = 0\n let programmatic = false\n w.addEventListener(\n 'scroll',\n () => {\n if (!programmatic) {\n lastUserScrollAt = time()\n }\n },\n { capture: true, passive: true },\n )\n const origScrollTo = w.scrollTo\n w.scrollTo = function (...args: any[]) {\n const now = time()\n if (\n now - guardStartedAt < 3000 &&\n now - lastUserScrollAt < 1500\n ) {\n return\n }\n programmatic = true\n try {\n return (origScrollTo as any).apply(w, args)\n } finally {\n queueMicrotask(() => {\n programmatic = false\n })\n }\n }\n}\n\n/**\n * Hydration cursor: walks existing DOM children in document order so we can\n * adopt them during fiber tree construction. One cursor per host parent.\n *\n * `endBefore` scopes the cursor to a subrange \u2014 used by rehydrateBoundary()\n * so we only adopt DOM up to the closing `/$` marker for that boundary.\n */\nexport class HydrationCursor {\n n: ChildNode | null\n p: Node\n e: ChildNode | null\n constructor(parent: Node, start: ChildNode | null = null, endBefore: ChildNode | null = null) {\n this.p = parent\n this.n = start ?? parent.firstChild\n this.e = endBefore\n }\n take(): ChildNode | null {\n while (this.n && this.n !== this.e) {\n const n = this.n\n // Skip anything that isn't an element (1) or text (3):\n // comments (8), doctype (10), processing instructions (7), cdata (4).\n if (n.nodeType !== 1 && n.nodeType !== 3) {\n this.n = n.nextSibling\n continue\n }\n this.n = n.nextSibling\n return n\n }\n return null\n }\n /**\n * Position-insensitive lookup for head/html adoption. Scans forward past\n * non-matching nodes without removing them, matching by tag AND the key\n * attributes that identify head elements uniquely (rel/href for links,\n * name/property for meta, src for script). Non-matching nodes stay in\n * place so the SSR'd stylesheet/script order is preserved.\n */\n head(tag: string, props: Record<string, any>): ChildNode | null {\n const target = tag.toLowerCase()\n const keyAttrs = HEAD_KEY_ATTRS[target]\n let scan = this.p.firstChild\n while (scan) {\n if (\n scan.nodeType === 1 &&\n (scan as Element).tagName.toLowerCase() === target &&\n headAttrsMatch(scan as Element, props, keyAttrs)\n ) {\n CLAIMED.add(scan)\n return scan\n }\n scan = scan.nextSibling\n }\n return null\n }\n has(): boolean {\n let n = this.n\n while (n && n !== this.e) {\n if (n.nodeType === 1 || n.nodeType === 3) return true\n n = n.nextSibling\n }\n return false\n }\n}\n\nconst hydrationCursors = new WeakMap<Fiber, HydrationCursor>()\nconst PROD_HYDRATION_ERROR = 'Hydration mismatch.'\n\nexport interface HydrationBailoutError extends Error {\n f: Fiber | null\n}\n\nexport function isHydrationBailout(error: unknown): error is HydrationBailoutError {\n return !!error && (error as any).f !== undefined\n}\n\nexport function abortHydration(cause: unknown, fiber: Fiber | null = null): never {\n const error = (cause instanceof Error ? cause : new Error(PROD_HYDRATION_ERROR)) as HydrationBailoutError\n ;(error as any).f = fiber\n throw error\n}\n\ninterface HydrateRootOptions {\n identifierPrefix?: string\n onRecoverableError?: (error: unknown) => void\n onCaughtError?: (error: unknown) => void\n onUncaughtError?: (error: unknown) => void\n}\n\ninterface HydratedRoot {\n render(children: ReactNode): void\n unmount(): void\n}\n\nexport function hydrateRootImpl(\n container: Element | Document,\n initialChildren: ReactNode,\n options: HydrateRootOptions,\n): HydratedRoot {\n const target = container as any as Element | Document\n const isDocument = (container as Node).nodeType === 9\n const body = isDocument ? (target as Document).body : null\n const root = createFiberRoot(target, options)\n\n installHydrationScrollGuard()\n\n const normalizedInitialChildren =\n isDocument ? normalizeDocumentChildren(initialChildren) : initialChildren\n let hydrationError: unknown = null\n beginHydration(root)\n try {\n flushSyncWork(() => {\n renderRoot(root, normalizedInitialChildren)\n })\n } catch (e) {\n hydrationError = e\n }\n endHydration(root)\n\n if (hydrationError && !recoverHydration(root, hydrationError)) throw hydrationError\n drainReplayQueue()\n\n return {\n render(children) {\n flushSyncWork(() => {\n const normalized = isDocument ? normalizeDocumentChildren(children) : children\n renderRoot(\n root,\n root.c === body ? getStaticDocumentBodyChildren(normalized) ?? normalized : normalized,\n )\n })\n },\n unmount() {\n flushSyncWork(() => {\n renderRoot(root, null)\n })\n },\n }\n}\n\n// Head elements that we match against server DOM by attribute signature.\nconst HEAD_KEY_ATTRS: Record<string, ReadonlyArray<string>> = {\n link: ['rel', 'href', 'sizes', 'type'],\n meta: ['name', 'property', 'charSet', 'httpEquiv'],\n script: ['src', 'type'],\n}\n\nconst DOCUMENT_HEAD_TAGS = new Set(['base', 'link', 'meta', 'script', 'style', 'title'])\n\n// DOM elements already claimed by some fiber during this hydration pass.\nconst CLAIMED = new WeakSet<Node>()\n\nfunction headAttrsMatch(\n el: Element,\n props: Record<string, any>,\n keys: ReadonlyArray<string> | undefined,\n): boolean {\n if (CLAIMED.has(el)) return false\n if (!keys) return true\n for (const k of keys) {\n const propVal = props[k]\n const elVal = el.getAttribute(attributeName(k))\n if (propVal == null && elVal == null) continue\n if (propVal == null || elVal == null || String(propVal) !== elVal) return false\n }\n return true\n}\n\nexport function beginHydration(root: FiberRoot): void {\n root.ic = 0\n root.h = true\n hydrationCursors.set(root.r, new HydrationCursor(root.c))\n}\n\nexport function endHydration(root: FiberRoot): void {\n root.h = false\n hydrationCursors.delete(root.r)\n}\n\n/**\n * Inspect the current cursor position for a streaming-suspense boundary\n * marker emitted by the server. Returns info + advances the cursor past the\n * marker pair (start comment + fallback/real content + end comment).\n */\nexport type BoundaryInfo = [0 | 1, number, Comment, Comment]\n\nexport function tryConsumeBoundary(parent: Fiber): BoundaryInfo | null {\n const cursor = hydrationCursors.get(findHostParent(parent))\n if (!cursor) return null\n const peek = cursor.n\n if (!peek || peek.nodeType !== 8) return null\n const data = (peek as Comment).data\n const m = /^(\\$\\??)(\\d+)$/.exec(data)\n if (!m) return null\n const kind = m[1] === '$?' ? 1 : 0\n const id = Number(m[2])\n const startMark = peek as Comment\n // Advance past the start comment\n cursor.n = startMark.nextSibling\n // Locate end comment: closest <!--/$-->\n let endMark: Comment | null = null\n let scan = startMark.nextSibling\n while (scan) {\n if (scan.nodeType === 8 && (scan as Comment).data === '/$') {\n endMark = scan as Comment\n break\n }\n scan = scan.nextSibling\n }\n if (!endMark) return null\n return [kind, id, startMark, endMark]\n}\n\nexport function advanceCursorPast(parent: Fiber, node: Node): void {\n const cursor = hydrationCursors.get(findHostParent(parent))\n if (!cursor) return\n cursor.n = node.nextSibling\n}\n\nexport function getHydrationCursor(hostFiber: Fiber): HydrationCursor | undefined {\n return hydrationCursors.get(hostFiber)\n}\n\nexport function setHydrationCursor(hostFiber: Fiber, cursor: HydrationCursor): void {\n hydrationCursors.set(hostFiber, cursor)\n}\n\nexport function clearHydrationCursor(hostFiber: Fiber): void {\n hydrationCursors.delete(hostFiber)\n}\n\n/**\n * Try to adopt a DOM node for this host fiber. Returns true if adopted.\n * Attaches existing attrs/children via separate hydrate pass.\n */\nexport function adoptHostDom(fiber: Fiber, parent: Fiber): boolean {\n const hostParent = findHostParent(parent)\n const cursor = hydrationCursors.get(hostParent)\n if (!cursor) return false\n\n const tag = (fiber.type as string).toLowerCase()\n const documentHeadParent =\n cursor.p.nodeType === 9 && DOCUMENT_HEAD_TAGS.has(tag)\n ? (cursor.p as Document).head\n : null\n const parentEl = cursor.p as Element\n const parentTag =\n parentEl.nodeType === 1 ? (parentEl as Element).tagName.toLowerCase() : ''\n const isHeadish = parentTag === 'head' || parentTag === 'html' || !!documentHeadParent\n\n let candidate: ChildNode | null\n if (documentHeadParent) {\n // React 19 can project <meta>/<title>/<link> from anywhere in the tree into\n // document.head. Redact does not have that projection yet, so when a\n // document-root hydration pass sees a top-level head element, adopt it\n // from <head> rather than trying to append it beside <html>.\n candidate = new HydrationCursor(documentHeadParent).head(\n tag,\n fiber.pp ?? {},\n )\n } else if (isHeadish) {\n // Head/html children are position-insensitive \u2014 server may emit them in\n // a different order than the React tree (React 19 head hoisting, etc.).\n // Scan forward without removing non-matching nodes; match on attribute\n // signature so we don't adopt the wrong <link> and clobber its props.\n candidate = cursor.head(tag, fiber.pp ?? {})\n } else {\n candidate = cursor.take()\n }\n\n if (!candidate) {\n // Client expected a host here but the cursor is exhausted \u2014 server gave\n // fewer children than the client tree. Report the structural gap (React\n // fires `onRecoverableError` for this exact case) and let the reconciler\n // mount a fresh DOM for this fiber below.\n // Exception: <head> children are position-insensitive; a missing match\n // there means \"server didn't hoist this one yet\", which we silently mount.\n if (!isHeadish) onMismatch(fiber, null)\n return false\n }\n\n if (candidate.nodeType !== 1 || (candidate as Element).tagName.toLowerCase() !== tag) {\n // mismatch \u2014 log and re-render fresh from this point\n onMismatch(fiber, candidate)\n return false\n }\n fiber.dom = candidate\n // Apply props (attach events, sync IDL props). Don't re-set existing attrs.\n const props = fiber.pp ?? {}\n const isSvg =\n tag === 'svg' ||\n ((candidate as Element).namespaceURI === 'http://www.w3.org/2000/svg' &&\n tag !== 'foreignobject')\n validateHydrationProps(fiber, candidate as Element, props, tag, isSvg)\n for (const k in props) {\n if (k === 'children') continue\n if (k[0] === 'o' && k[1] === 'n' && typeof props[k] == 'function') {\n setProp(candidate as Element, k, props[k], undefined, isSvg)\n }\n // Non-event props: trust the server HTML, skip\n }\n // Set up child cursor for this host's children\n hydrationCursors.set(fiber, new HydrationCursor(candidate))\n return true\n}\n\nexport function adoptTextDom(fiber: Fiber, parent: Fiber, text: string): boolean {\n const cursor = hydrationCursors.get(findHostParent(parent))\n if (!cursor) return false\n const candidate = cursor.take()\n if (!candidate) onMismatch(fiber, null)\n if (candidate.nodeType === 3) {\n if ((candidate as Text).data !== text) {\n if (process.env.NODE_ENV !== 'production') {\n failHydration(\n fiber,\n new Error(`Hydration text mismatch: expected \"${text}\" but found \"${(candidate as Text).data}\".`),\n )\n }\n failHydration(fiber)\n }\n fiber.dom = candidate\n return true\n }\n onMismatch(fiber, candidate)\n return false\n}\n\nexport function findHostParent(fiber: Fiber): Fiber {\n let f: Fiber | null = fiber\n while (f) {\n // A fiber explicitly holding a cursor acts as a boundary for hydration\n // (e.g. Suspense with a scoped cursor during fallback/boundary hydration).\n if (hydrationCursors.has(f)) return f\n if (f.tag === FiberTag.Host || f.tag === FiberTag.Root || f.tag === FiberTag.Portal) {\n return f\n }\n f = f.parent\n }\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('No host parent found')\n }\n throw new Error()\n}\n\nfunction onMismatch(fiber: Fiber, actualNode: ChildNode | null): never {\n if (process.env.NODE_ENV !== 'production') {\n failHydration(\n fiber,\n new Error(\n `Hydration mismatch: expected <${(fiber.type as string) ?? 'text'}> but found ${\n actualNode ? (actualNode.nodeType === 1 ? (actualNode as Element).tagName : 'text') : 'nothing'\n }.`,\n ),\n )\n }\n failHydration(fiber)\n}\n\nfunction failHydration(fiber: Fiber, error: Error = new Error(PROD_HYDRATION_ERROR)): never {\n const root = findRoot(fiber)\n if (root?.re) {\n root.re(error)\n }\n abortHydration(error, findHostRecoveryParent(fiber) ?? fiber)\n}\n\nfunction findHostRecoveryParent(fiber: Fiber): Fiber | null {\n if (fiber.tag === FiberTag.Text) {\n let directHost = fiber.parent\n while (directHost && (directHost.tag !== FiberTag.Host || !directHost.dom)) {\n directHost = directHost.parent\n }\n if (!directHost) return null\n let hasEvent\n const props = directHost.pp ?? directHost.mp\n if (props) {\n for (const k in props) {\n if (k[0] === 'o' && k[1] === 'n' && typeof props[k] == 'function') {\n hasEvent = true\n }\n }\n }\n return findNearestSafeHostAboveComposite(\n hasEvent\n ? directHost.parent\n : directHost.parent?.tag === FiberTag.Host\n ? directHost.parent\n : directHost,\n )\n }\n\n return findNearestSafeHostAboveComposite(fiber.parent)\n}\n\nfunction findNearestSafeHostAboveComposite(fiber: Fiber | null): Fiber | null {\n let host: Fiber | null = null\n let f = fiber\n while (f) {\n if (f.tag === FiberTag.Host && f.dom) {\n if (!isSafeHostRecoveryElement(f)) return null\n const parentTag = f.parent?.tag as number\n if (!host || (parentTag > FiberTag.Text && parentTag < FiberTag.Suspense)) {\n host = f\n }\n }\n f = f.parent\n }\n return host\n}\n\nfunction isSafeHostRecoveryElement(fiber: Fiber): boolean {\n const tag = fiber.type.toLowerCase()\n return tag !== 'html' && tag !== 'head' && tag !== 'body'\n}\n\nexport function recoverHydration(root: FiberRoot, error: unknown): boolean {\n if (!isHydrationBailout(error)) return false\n\n let container = root.c as Element | Document\n let children = root.r.pp?.children ?? null\n const hostRecovery = getRecoverableHostChildren(error)\n if (hostRecovery) {\n container = hostRecovery[0]\n children = hostRecovery[1]\n } else if (container.nodeType === 9) {\n const bodyChildren = getRecoverableDocumentBodyChildren(error)\n if (bodyChildren != null) {\n container = (container as Document).body\n children = bodyChildren\n }\n }\n\n resetAfterHydrationFailure(root, container)\n try {\n flushSyncWork(() => renderRoot(root, children))\n } catch (clientError) {\n resetAfterHydrationFailure(root, container)\n throw clientError\n }\n return true\n}\n\nfunction resetAfterHydrationFailure(\n root: FiberRoot,\n container: Element | Document,\n): void {\n discardPendingWork(root)\n clearHydrationContainer(container)\n attachRootFiber(root, container)\n root.h = false\n}\n\nfunction clearHydrationContainer(container: Element | Document): void {\n if (container.nodeType === 9) {\n let node = container.firstChild\n while (node) {\n const next = node.nextSibling\n if (node.nodeType !== 10 /* DOCUMENT_TYPE_NODE */) {\n container.removeChild(node)\n }\n node = next\n }\n return\n }\n ;(container as Element).textContent = ''\n}\n\nfunction getRecoverableHostChildren(\n error: HydrationBailoutError,\n): [Element, ReactNode] | null {\n const host = error.f\n if (\n host?.tag !== FiberTag.Host ||\n !host.dom ||\n !findNearestSafeHostAboveComposite(host.parent)\n ) {\n return null\n }\n return [host.dom as Element, (host.pp ?? host.mp)?.children ?? null]\n}\n\nfunction getRecoverableDocumentBodyChildren(error: HydrationBailoutError): ReactNode | null {\n const bodyFiber = findBodyAncestor(error.f)\n if (!bodyFiber) return null\n return (bodyFiber.pp ?? bodyFiber.mp)?.children ?? null\n}\n\nfunction findBodyAncestor(fiber: Fiber | null): Fiber | null {\n let f = fiber\n while (f) {\n if (f.tag === FiberTag.Host && f.type === 'body') {\n return f === fiber ? null : f\n }\n f = f.parent\n }\n return null\n}\n\nfunction getStaticDocumentBodyChildren(children: ReactNode): ReactNode | null {\n const list = toChildArray(children)\n const html = list.find((child) => isHostElement(child, 'html')) as ReactElement | undefined\n if (!html) return null\n const htmlChildren = toChildArray(html.props?.children)\n const body = htmlChildren.find((child) => isHostElement(child, 'body')) as ReactElement | undefined\n return body ? body.props?.children ?? null : null\n}\n\nfunction normalizeDocumentChildren(children: ReactNode): ReactNode {\n const list = toChildArray(children)\n const htmlIndex = list.findIndex((child) => isHostElement(child, 'html'))\n if (htmlIndex === -1) return children\n\n const headNodes = list.filter(isHeadElement)\n if (headNodes.length === 0) return children\n\n const htmlElement = list[htmlIndex] as ReactElement\n const normalizedHtml = hoistIntoHtmlHead(htmlElement, headNodes)\n return list\n .filter((child, index) => index === htmlIndex || !isHeadElement(child))\n .map((child) => (child === htmlElement ? normalizedHtml : child))\n}\n\nfunction hoistIntoHtmlHead(htmlElement: ReactElement, headNodes: ReactNode[]): ReactElement {\n const htmlChildren = toChildArray(htmlElement.props?.children)\n const headIndex = htmlChildren.findIndex((child) => isHostElement(child, 'head'))\n let nextChildren: ReactNode[]\n\n if (headIndex === -1) {\n nextChildren = [\n createHostElement('head', { children: headNodes }),\n ...htmlChildren,\n ]\n } else {\n const headElement = htmlChildren[headIndex] as ReactElement\n const existingHeadChildren = toChildArray(headElement.props?.children)\n const nextHead = {\n ...headElement,\n props: {\n ...headElement.props,\n children: [...headNodes, ...existingHeadChildren],\n },\n }\n nextChildren = htmlChildren.map((child, index) => (index === headIndex ? nextHead : child))\n }\n\n return {\n ...htmlElement,\n props: {\n ...htmlElement.props,\n children: nextChildren,\n },\n }\n}\n\nfunction toChildArray(children: unknown): ReactNode[] {\n if (children == null || typeof children === 'boolean') return []\n if (Array.isArray(children)) return children as ReactNode[]\n if (isReactElement(children)) return [children]\n if (typeof children !== 'string' && isIterable(children)) return Array.from(children) as ReactNode[]\n return [children as ReactNode]\n}\n\nfunction isHeadElement(value: ReactNode): boolean {\n return isReactElement(value) && typeof value.type === 'string' && DOCUMENT_HEAD_TAGS.has(value.type)\n}\n\nfunction isHostElement(value: ReactNode, tag: string): boolean {\n return isReactElement(value) && value.type === tag\n}\n\nfunction isReactElement(value: unknown): value is ReactElement {\n return !!value && typeof value === 'object' && (value as ReactElement).$$typeof === REACT_ELEMENT_TYPE\n}\n\nfunction isIterable(value: unknown): value is Iterable<ReactNode> {\n return !!value && typeof (value as { [Symbol.iterator]?: unknown })[Symbol.iterator] == 'function'\n}\n\nfunction createHostElement(type: string, props: Record<string, unknown>): ReactElement {\n return {\n $$typeof: REACT_ELEMENT_TYPE,\n type,\n key: null,\n ref: null,\n props,\n }\n}\n\nfunction validateHydrationProps(\n fiber: Fiber,\n el: Element,\n props: Record<string, any>,\n tag: string,\n isSvg: boolean,\n): void {\n if (props.suppressHydrationWarning) return\n\n let expected: Element | undefined\n\n for (const k in props) {\n const value = props[k]\n if (\n k === 'children' ||\n k === 'key' ||\n k === 'ref' ||\n k === 'suppressHydrationWarning' ||\n k === 'suppressContentEditableWarning' ||\n (k[0] === 'o' && k[1] === 'n' && typeof value == 'function')\n ) continue\n\n if (k === 'dangerouslySetInnerHTML') {\n let html = '' + (value?.__html ?? '')\n if (tag !== 'script' && tag !== 'style') {\n const probe = document.createElement('div')\n probe.innerHTML = html\n html = probe.innerHTML\n }\n if ((el as HTMLElement).innerHTML !== html) {\n if (process.env.NODE_ENV !== 'production') {\n failHydration(\n fiber,\n new Error(`Hydration HTML mismatch inside <${tag}>.`),\n )\n }\n failHydration(fiber)\n }\n continue\n }\n\n if (k === 'value' || k === 'defaultValue') {\n if (tag === 'select') continue\n if (tag === 'input' || tag === 'textarea') {\n if (k === 'value' || props.value == null) {\n if (value != null && (el as HTMLInputElement).value !== '' + value) {\n if (process.env.NODE_ENV !== 'production') {\n failHydration(fiber, new Error(`Hydration ${tag} value mismatch on <${tag}>.`))\n }\n failHydration(fiber)\n }\n }\n continue\n }\n }\n\n if (tag === 'input' && (k === 'checked' || k === 'defaultChecked')) {\n if (k === 'checked' || props.checked == null) {\n if (value != null && (el as HTMLInputElement).checked !== !!value) {\n if (process.env.NODE_ENV !== 'production') {\n failHydration(fiber, new Error(`Hydration checked mismatch on <input>.`))\n }\n failHydration(fiber)\n }\n }\n continue\n }\n\n if (tag === 'option' && k === 'selected') {\n if (value != null && (el as HTMLOptionElement).selected !== !!value) {\n if (process.env.NODE_ENV !== 'production') {\n failHydration(fiber, new Error(`Hydration selected mismatch on <option>.`))\n }\n failHydration(fiber)\n }\n continue\n }\n\n if (k === 'style') {\n expected ??= createHostNode(tag, isSvg)\n setProp(expected, k, value, undefined, isSvg)\n if ((el as HTMLElement).style.cssText !== (expected as HTMLElement).style.cssText) {\n if (process.env.NODE_ENV !== 'production') {\n failHydration(\n fiber,\n new Error(`Hydration style mismatch on <${tag}>.`),\n )\n }\n failHydration(fiber)\n }\n continue\n }\n\n const stringifiedBoolean = k.startsWith('aria-') || k.startsWith('data-')\n const attr = attributeName(k, isSvg)\n\n let expectedValue: string | null\n if (value == null || (value === false && !stringifiedBoolean)) {\n expectedValue = null\n } else {\n expected ??= createHostNode(tag, isSvg)\n setProp(expected, k, value, undefined, isSvg)\n expectedValue = expected.getAttribute(attr)\n }\n const actualValue = el.getAttribute(attr)\n if (expectedValue !== actualValue) {\n if (process.env.NODE_ENV !== 'production') {\n failHydration(\n fiber,\n new Error(\n `Hydration attribute mismatch on <${tag}> for \"${attr}\": ` +\n `expected ${formatHydrationValue(expectedValue)} but found ${formatHydrationValue(actualValue)}.`,\n ),\n )\n }\n failHydration(fiber)\n }\n }\n}\n\nfunction formatHydrationValue(value: string | null): string {\n return value == null ? 'nothing' : JSON.stringify(value)\n}\n"],
|
|
5
|
-
"mappings": ";AAAA;AAAA,EACE;AAAA,EACA;AAAA,OAKK;AACP,SAAS,qBAAqB;AAC9B,SAAS,gBAAgB,eAAe;AACxC,SAAS,wBAAwB;AACjC,SAAS,oBAAoB,UAAU,eAAe,kBAAkB;AACxE,SAAS,iBAAiB,uBAAuB;AAgB1C,SAAS,8BAAoC;AAClD,MAAI,OAAO,WAAW,YAAa;AACnC,QAAM,IAAI;AACV,MAAI,EAAE,GAAI;AACV,QAAM,OAAO,KAAK;AAClB,QAAM,iBAAiB,EAAE,KAAK,KAAK;AACnC,MAAI,mBAAmB;AACvB,MAAI,eAAe;AACnB,IAAE;AAAA,IACA;AAAA,IACA,MAAM;AACJ,UAAI,CAAC,cAAc;AACjB,2BAAmB,KAAK;AAAA,MAC1B;AAAA,IACF;AAAA,IACA,EAAE,SAAS,MAAM,SAAS,KAAK;AAAA,EACjC;AACA,QAAM,eAAe,EAAE;AACvB,IAAE,WAAW,YAAa,MAAa;AACrC,UAAM,MAAM,KAAK;AACjB,QACE,MAAM,iBAAiB,OACvB,MAAM,mBAAmB,MACzB;AACA;AAAA,IACF;AACA,mBAAe;AACf,QAAI;AACF,aAAQ,aAAqB,MAAM,GAAG,IAAI;AAAA,IAC5C,UAAE;AACA,qBAAe,MAAM;AACnB,uBAAe;AAAA,MACjB,CAAC;AAAA,IACH;AAAA,EACF;AACF;AASO,IAAM,kBAAN,MAAsB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY,QAAc,QAA0B,MAAM,YAA8B,MAAM;AAC5F,SAAK,IAAI;AACT,SAAK,IAAI,SAAS,OAAO;AACzB,SAAK,IAAI;AAAA,EACX;AAAA,EACA,OAAyB;AACvB,WAAO,KAAK,KAAK,KAAK,MAAM,KAAK,GAAG;AAClC,YAAM,IAAI,KAAK;AAGf,UAAI,EAAE,aAAa,KAAK,EAAE,aAAa,GAAG;AACxC,aAAK,IAAI,EAAE;AACX;AAAA,MACF;AACA,WAAK,IAAI,EAAE;AACX,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,KAAK,KAAa,OAA8C;AAC9D,UAAM,SAAS,IAAI,YAAY;AAC/B,UAAM,WAAW,eAAe,MAAM;AACtC,QAAI,OAAO,KAAK,EAAE;AAClB,WAAO,MAAM;AACX,UACE,KAAK,aAAa,KACjB,KAAiB,QAAQ,YAAY,MAAM,UAC5C,eAAe,MAAiB,OAAO,QAAQ,GAC/C;AACA,gBAAQ,IAAI,IAAI;AAChB,eAAO;AAAA,MACT;AACA,aAAO,KAAK;AAAA,IACd;AACA,WAAO;AAAA,EACT;AAAA,EACA,MAAe;AACb,QAAI,IAAI,KAAK;AACb,WAAO,KAAK,MAAM,KAAK,GAAG;AACxB,UAAI,EAAE,aAAa,KAAK,EAAE,aAAa,EAAG,QAAO;AACjD,UAAI,EAAE;AAAA,IACR;AACA,WAAO;AAAA,EACT;AACF;AAEA,IAAM,mBAAmB,oBAAI,QAAgC;AAC7D,IAAM,uBAAuB;AAMtB,SAAS,mBAAmB,OAAgD;AACjF,SAAO,CAAC,CAAC,SAAU,MAAc,MAAM;AACzC;AAEO,SAAS,eAAe,OAAgB,QAAsB,MAAa;AAChF,QAAM,QAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,oBAAoB;AAC7E,EAAC,MAAc,IAAI;AACpB,QAAM;AACR;AAcO,SAAS,gBACd,WACA,iBACA,SACc;AACd,QAAM,SAAS;AACf,QAAM,aAAc,UAAmB,aAAa;AACpD,QAAM,OAAO,aAAc,OAAoB,OAAO;AACtD,QAAM,OAAO,gBAAgB,QAAQ,OAAO;AAE5C,8BAA4B;AAE5B,QAAM,4BACJ,aAAa,0BAA0B,eAAe,IAAI;AAC5D,MAAI,iBAA0B;AAC9B,iBAAe,IAAI;AACnB,MAAI;AACF,kBAAc,MAAM;AAClB,iBAAW,MAAM,yBAAyB;AAAA,IAC5C,CAAC;AAAA,EACH,SAAS,GAAG;AACV,qBAAiB;AAAA,EACnB;AACA,eAAa,IAAI;AAEjB,MAAI,kBAAkB,CAAC,iBAAiB,MAAM,cAAc,EAAG,OAAM;AACrE,mBAAiB;AAEjB,SAAO;AAAA,IACL,OAAO,UAAU;AACf,oBAAc,MAAM;AAClB,cAAM,aAAa,aAAa,0BAA0B,QAAQ,IAAI;AACtE;AAAA,UACE;AAAA,UACA,KAAK,MAAM,OAAO,8BAA8B,UAAU,KAAK,aAAa;AAAA,QAC9E;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA,UAAU;AACR,oBAAc,MAAM;AAClB,mBAAW,MAAM,IAAI;AAAA,MACvB,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAGA,IAAM,iBAAwD;AAAA,EAC5D,MAAM,CAAC,OAAO,QAAQ,SAAS,MAAM;AAAA,EACrC,MAAM,CAAC,QAAQ,YAAY,WAAW,WAAW;AAAA,EACjD,QAAQ,CAAC,OAAO,MAAM;AACxB;AAEA,IAAM,qBAAqB,oBAAI,IAAI,CAAC,QAAQ,QAAQ,QAAQ,UAAU,SAAS,OAAO,CAAC;AAGvF,IAAM,UAAU,oBAAI,QAAc;AAElC,SAAS,eACP,IACA,OACA,MACS;AACT,MAAI,QAAQ,IAAI,EAAE,EAAG,QAAO;AAC5B,MAAI,CAAC,KAAM,QAAO;AAClB,aAAW,KAAK,MAAM;AACpB,UAAM,UAAU,MAAM,CAAC;AACvB,UAAM,QAAQ,GAAG,aAAa,cAAc,CAAC,CAAC;AAC9C,QAAI,WAAW,QAAQ,SAAS,KAAM;AACtC,QAAI,WAAW,QAAQ,SAAS,QAAQ,OAAO,OAAO,MAAM,MAAO,QAAO;AAAA,EAC5E;AACA,SAAO;AACT;AAEO,SAAS,eAAe,MAAuB;AACpD,OAAK,KAAK;AACV,OAAK,IAAI;AACT,mBAAiB,IAAI,KAAK,GAAG,IAAI,gBAAgB,KAAK,CAAC,CAAC;AAC1D;AAEO,SAAS,aAAa,MAAuB;AAClD,OAAK,IAAI;AACT,mBAAiB,OAAO,KAAK,CAAC;AAChC;AASO,SAAS,mBAAmB,QAAoC;AACrE,QAAM,SAAS,iBAAiB,IAAI,eAAe,MAAM,CAAC;AAC1D,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,OAAO,OAAO;AACpB,MAAI,CAAC,QAAQ,KAAK,aAAa,EAAG,QAAO;AACzC,QAAM,OAAQ,KAAiB;AAC/B,QAAM,IAAI,iBAAiB,KAAK,IAAI;AACpC,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,OAAO,EAAE,CAAC,MAAM,OAAO,IAAI;AACjC,QAAM,KAAK,OAAO,EAAE,CAAC,CAAC;AACtB,QAAM,YAAY;AAElB,SAAO,IAAI,UAAU;AAErB,MAAI,UAA0B;AAC9B,MAAI,OAAO,UAAU;AACrB,SAAO,MAAM;AACX,QAAI,KAAK,aAAa,KAAM,KAAiB,SAAS,MAAM;AAC1D,gBAAU;AACV;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACd;AACA,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,CAAC,MAAM,IAAI,WAAW,OAAO;AACtC;AAEO,SAAS,kBAAkB,QAAe,MAAkB;AACjE,QAAM,SAAS,iBAAiB,IAAI,eAAe,MAAM,CAAC;AAC1D,MAAI,CAAC,OAAQ;AACb,SAAO,IAAI,KAAK;AAClB;AAEO,SAAS,mBAAmB,WAA+C;AAChF,SAAO,iBAAiB,IAAI,SAAS;AACvC;AAEO,SAAS,mBAAmB,WAAkB,QAA+B;AAClF,mBAAiB,IAAI,WAAW,MAAM;AACxC;AAEO,SAAS,qBAAqB,WAAwB;AAC3D,mBAAiB,OAAO,SAAS;AACnC;AAMO,SAAS,aAAa,OAAc,QAAwB;AACjE,QAAM,aAAa,eAAe,MAAM;AACxC,QAAM,SAAS,iBAAiB,IAAI,UAAU;AAC9C,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,MAAO,MAAM,KAAgB,YAAY;AAC/C,QAAM,qBACJ,OAAO,EAAE,aAAa,KAAK,mBAAmB,IAAI,GAAG,IAChD,OAAO,EAAe,OACvB;AACN,QAAM,WAAW,OAAO;AACxB,QAAM,YACJ,SAAS,aAAa,IAAK,SAAqB,QAAQ,YAAY,IAAI;AAC1E,QAAM,YAAY,cAAc,UAAU,cAAc,UAAU,CAAC,CAAC;AAEpE,MAAI;AACJ,MAAI,oBAAoB;AAKtB,gBAAY,IAAI,gBAAgB,kBAAkB,EAAE;AAAA,MAClD;AAAA,MACA,MAAM,MAAM,CAAC;AAAA,IACf;AAAA,EACF,WAAW,WAAW;AAKpB,gBAAY,OAAO,KAAK,KAAK,MAAM,MAAM,CAAC,CAAC;AAAA,EAC7C,OAAO;AACL,gBAAY,OAAO,KAAK;AAAA,EAC1B;AAEA,MAAI,CAAC,WAAW;AAOd,QAAI,CAAC,UAAW,YAAW,OAAO,IAAI;AACtC,WAAO;AAAA,EACT;AAEA,MAAI,UAAU,aAAa,KAAM,UAAsB,QAAQ,YAAY,MAAM,KAAK;AAEpF,eAAW,OAAO,SAAS;AAC3B,WAAO;AAAA,EACT;AACA,QAAM,MAAM;AAEZ,QAAM,QAAQ,MAAM,MAAM,CAAC;AAC3B,QAAM,QACJ,QAAQ,SACN,UAAsB,iBAAiB,gCACvC,QAAQ;AACZ,yBAAuB,OAAO,WAAsB,OAAO,KAAK,KAAK;AACrE,aAAW,KAAK,OAAO;AACrB,QAAI,MAAM,WAAY;AACtB,QAAI,EAAE,CAAC,MAAM,OAAO,EAAE,CAAC,MAAM,OAAO,OAAO,MAAM,CAAC,KAAK,YAAY;AACjE,cAAQ,WAAsB,GAAG,MAAM,CAAC,GAAG,QAAW,KAAK;AAAA,IAC7D;AAAA,EAEF;AAEA,mBAAiB,IAAI,OAAO,IAAI,gBAAgB,SAAS,CAAC;AAC1D,SAAO;AACT;AAEO,SAAS,aAAa,OAAc,QAAe,MAAuB;AAC/E,QAAM,SAAS,iBAAiB,IAAI,eAAe,MAAM,CAAC;AAC1D,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,YAAY,OAAO,KAAK;AAC9B,MAAI,CAAC,UAAW,YAAW,OAAO,IAAI;AACtC,MAAI,UAAU,aAAa,GAAG;AAC5B,QAAK,UAAmB,SAAS,MAAM;AACrC,UAAI,MAAuC;AACzC;AAAA,UACE;AAAA,UACA,IAAI,MAAM,sCAAsC,IAAI,gBAAiB,UAAmB,IAAI,IAAI;AAAA,QAClG;AAAA,MACF;AACA,oBAAc,KAAK;AAAA,IACrB;AACA,UAAM,MAAM;AACZ,WAAO;AAAA,EACT;AACA,aAAW,OAAO,SAAS;AAC3B,SAAO;AACT;AAEO,SAAS,eAAe,OAAqB;AAClD,MAAI,IAAkB;AACtB,SAAO,GAAG;AAGR,QAAI,iBAAiB,IAAI,CAAC,EAAG,QAAO;AACpC,QAAI,EAAE,QAAQ,SAAS,QAAQ,EAAE,QAAQ,SAAS,QAAQ,EAAE,QAAQ,SAAS,QAAQ;AACnF,aAAO;AAAA,IACT;AACA,QAAI,EAAE;AAAA,EACR;AACA,MAAI,MAAuC;AACzC,UAAM,IAAI,MAAM,sBAAsB;AAAA,EACxC;AACA,QAAM,IAAI,MAAM;AAClB;AAEA,SAAS,WAAW,OAAc,YAAqC;AACrE,MAAI,MAAuC;AACzC;AAAA,MACE;AAAA,MACA,IAAI;AAAA,QACF,iCAAkC,MAAM,QAAmB,MAAM,eAC/D,aAAc,WAAW,aAAa,IAAK,WAAuB,UAAU,SAAU,SACxF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,gBAAc,KAAK;AACrB;AAEA,SAAS,cAAc,OAAc,QAAe,IAAI,MAAM,oBAAoB,GAAU;AAC1F,QAAM,OAAO,SAAS,KAAK;AAC3B,MAAI,MAAM,IAAI;AACZ,SAAK,GAAG,KAAK;AAAA,EACf;AACA,iBAAe,OAAO,uBAAuB,KAAK,KAAK,KAAK;AAC9D;AAEA,SAAS,uBAAuB,OAA4B;AAC1D,MAAI,MAAM,QAAQ,SAAS,MAAM;AAC/B,QAAI,aAAa,MAAM;AACvB,WAAO,eAAe,WAAW,QAAQ,SAAS,QAAQ,CAAC,WAAW,MAAM;AAC1E,mBAAa,WAAW;AAAA,IAC1B;AACA,QAAI,CAAC,WAAY,QAAO;AACxB,QAAI;AACJ,UAAM,QAAQ,WAAW,MAAM,WAAW;AAC1C,QAAI,OAAO;AACT,iBAAW,KAAK,OAAO;AACrB,YAAI,EAAE,CAAC,MAAM,OAAO,EAAE,CAAC,MAAM,OAAO,OAAO,MAAM,CAAC,KAAK,YAAY;AACjE,qBAAW;AAAA,QACb;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,MACL,WACI,WAAW,SACX,WAAW,QAAQ,QAAQ,SAAS,OAClC,WAAW,SACX;AAAA,IACR;AAAA,EACF;AAEA,SAAO,kCAAkC,MAAM,MAAM;AACvD;AAEA,SAAS,kCAAkC,OAAmC;AAC5E,MAAI,OAAqB;AACzB,MAAI,IAAI;AACR,SAAO,GAAG;AACR,QAAI,EAAE,QAAQ,SAAS,QAAQ,EAAE,KAAK;AACpC,UAAI,CAAC,0BAA0B,CAAC,EAAG,QAAO;AAC1C,YAAM,YAAY,EAAE,QAAQ;AAC5B,UAAI,CAAC,QAAS,YAAY,SAAS,QAAQ,YAAY,SAAS,UAAW;AACzE,eAAO;AAAA,MACT;AAAA,IACF;AACA,QAAI,EAAE;AAAA,EACR;AACA,SAAO;AACT;AAEA,SAAS,0BAA0B,OAAuB;AACxD,QAAM,MAAM,MAAM,KAAK,YAAY;AACnC,SAAO,QAAQ,UAAU,QAAQ,UAAU,QAAQ;AACrD;AAEO,SAAS,iBAAiB,MAAiB,OAAyB;AACzE,MAAI,CAAC,mBAAmB,KAAK,EAAG,QAAO;AAEvC,MAAI,YAAY,KAAK;AACrB,MAAI,WAAW,KAAK,EAAE,IAAI,YAAY;AACtC,QAAM,eAAe,2BAA2B,KAAK;AACrD,MAAI,cAAc;AAChB,gBAAY,aAAa,CAAC;AAC1B,eAAW,aAAa,CAAC;AAAA,EAC3B,WAAW,UAAU,aAAa,GAAG;AACnC,UAAM,eAAe,mCAAmC,KAAK;AAC7D,QAAI,gBAAgB,MAAM;AACxB,kBAAa,UAAuB;AACpC,iBAAW;AAAA,IACb;AAAA,EACF;AAEA,6BAA2B,MAAM,SAAS;AAC1C,MAAI;AACF,kBAAc,MAAM,WAAW,MAAM,QAAQ,CAAC;AAAA,EAChD,SAAS,aAAa;AACpB,+BAA2B,MAAM,SAAS;AAC1C,UAAM;AAAA,EACR;AACA,SAAO;AACT;AAEA,SAAS,2BACP,MACA,WACM;AACN,qBAAmB,IAAI;AACvB,0BAAwB,SAAS;AACjC,kBAAgB,MAAM,SAAS;AAC/B,OAAK,IAAI;AACX;AAEA,SAAS,wBAAwB,WAAqC;AACpE,MAAI,UAAU,aAAa,GAAG;AAC5B,QAAI,OAAO,UAAU;AACrB,WAAO,MAAM;AACX,YAAM,OAAO,KAAK;AAClB,UAAI,KAAK,aAAa,IAA6B;AACjD,kBAAU,YAAY,IAAI;AAAA,MAC5B;AACA,aAAO;AAAA,IACT;AACA;AAAA,EACF;AACA;AAAC,EAAC,UAAsB,cAAc;AACxC;AAEA,SAAS,2BACP,OAC6B;AAC7B,QAAM,OAAO,MAAM;AACnB,MACE,MAAM,QAAQ,SAAS,QACvB,CAAC,KAAK,OACN,CAAC,kCAAkC,KAAK,MAAM,GAC9C;AACA,WAAO;AAAA,EACT;AACA,SAAO,CAAC,KAAK,MAAiB,KAAK,MAAM,KAAK,KAAK,YAAY,IAAI;AACrE;AAEA,SAAS,mCAAmC,OAAgD;AAC1F,QAAM,YAAY,iBAAiB,MAAM,CAAC;AAC1C,MAAI,CAAC,UAAW,QAAO;AACvB,UAAQ,UAAU,MAAM,UAAU,KAAK,YAAY;AACrD;AAEA,SAAS,iBAAiB,OAAmC;AAC3D,MAAI,IAAI;AACR,SAAO,GAAG;AACR,QAAI,EAAE,QAAQ,SAAS,QAAQ,EAAE,SAAS,QAAQ;AAChD,aAAO,MAAM,QAAQ,OAAO;AAAA,IAC9B;AACA,QAAI,EAAE;AAAA,EACR;AACA,SAAO;AACT;AAEA,SAAS,8BAA8B,UAAuC;AAC5E,QAAM,OAAO,aAAa,QAAQ;AAClC,QAAM,OAAO,KAAK,KAAK,CAAC,UAAU,cAAc,OAAO,MAAM,CAAC;AAC9D,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,eAAe,aAAa,KAAK,OAAO,QAAQ;AACtD,QAAM,OAAO,aAAa,KAAK,CAAC,UAAU,cAAc,OAAO,MAAM,CAAC;AACtE,SAAO,OAAO,KAAK,OAAO,YAAY,OAAO;AAC/C;AAEA,SAAS,0BAA0B,UAAgC;AACjE,QAAM,OAAO,aAAa,QAAQ;AAClC,QAAM,YAAY,KAAK,UAAU,CAAC,UAAU,cAAc,OAAO,MAAM,CAAC;AACxE,MAAI,cAAc,GAAI,QAAO;AAE7B,QAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,MAAI,UAAU,WAAW,EAAG,QAAO;AAEnC,QAAM,cAAc,KAAK,SAAS;AAClC,QAAM,iBAAiB,kBAAkB,aAAa,SAAS;AAC/D,SAAO,KACJ,OAAO,CAAC,OAAO,UAAU,UAAU,aAAa,CAAC,cAAc,KAAK,CAAC,EACrE,IAAI,CAAC,UAAW,UAAU,cAAc,iBAAiB,KAAM;AACpE;AAEA,SAAS,kBAAkB,aAA2B,WAAsC;AAC1F,QAAM,eAAe,aAAa,YAAY,OAAO,QAAQ;AAC7D,QAAM,YAAY,aAAa,UAAU,CAAC,UAAU,cAAc,OAAO,MAAM,CAAC;AAChF,MAAI;AAEJ,MAAI,cAAc,IAAI;AACpB,mBAAe;AAAA,MACb,kBAAkB,QAAQ,EAAE,UAAU,UAAU,CAAC;AAAA,MACjD,GAAG;AAAA,IACL;AAAA,EACF,OAAO;AACL,UAAM,cAAc,aAAa,SAAS;AAC1C,UAAM,uBAAuB,aAAa,YAAY,OAAO,QAAQ;AACrE,UAAM,WAAW;AAAA,MACf,GAAG;AAAA,MACH,OAAO;AAAA,QACL,GAAG,YAAY;AAAA,QACf,UAAU,CAAC,GAAG,WAAW,GAAG,oBAAoB;AAAA,MAClD;AAAA,IACF;AACA,mBAAe,aAAa,IAAI,CAAC,OAAO,UAAW,UAAU,YAAY,WAAW,KAAM;AAAA,EAC5F;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,OAAO;AAAA,MACL,GAAG,YAAY;AAAA,MACf,UAAU;AAAA,IACZ;AAAA,EACF;AACF;AAEA,SAAS,aAAa,UAAgC;AACpD,MAAI,YAAY,QAAQ,OAAO,aAAa,UAAW,QAAO,CAAC;AAC/D,MAAI,MAAM,QAAQ,QAAQ,EAAG,QAAO;AACpC,MAAI,eAAe,QAAQ,EAAG,QAAO,CAAC,QAAQ;AAC9C,MAAI,OAAO,aAAa,YAAY,WAAW,QAAQ,EAAG,QAAO,MAAM,KAAK,QAAQ;AACpF,SAAO,CAAC,QAAqB;AAC/B;AAEA,SAAS,cAAc,OAA2B;AAChD,SAAO,eAAe,KAAK,KAAK,OAAO,MAAM,SAAS,YAAY,mBAAmB,IAAI,MAAM,IAAI;AACrG;AAEA,SAAS,cAAc,OAAkB,KAAsB;AAC7D,SAAO,eAAe,KAAK,KAAK,MAAM,SAAS;AACjD;AAEA,SAAS,eAAe,OAAuC;AAC7D,SAAO,CAAC,CAAC,SAAS,OAAO,UAAU,YAAa,MAAuB,aAAa;AACtF;AAEA,SAAS,WAAW,OAA8C;AAChE,SAAO,CAAC,CAAC,SAAS,OAAQ,MAA0C,OAAO,QAAQ,KAAK;AAC1F;AAEA,SAAS,kBAAkB,MAAc,OAA8C;AACrF,SAAO;AAAA,IACL,UAAU;AAAA,IACV;AAAA,IACA,KAAK;AAAA,IACL,KAAK;AAAA,IACL;AAAA,EACF;AACF;AAEA,SAAS,uBACP,OACA,IACA,OACA,KACA,OACM;AACN,MAAI,MAAM,yBAA0B;AAEpC,MAAI;AAEJ,aAAW,KAAK,OAAO;AACrB,UAAM,QAAQ,MAAM,CAAC;AACrB,QACE,MAAM,cACN,MAAM,SACN,MAAM,SACN,MAAM,8BACN,MAAM,oCACL,EAAE,CAAC,MAAM,OAAO,EAAE,CAAC,MAAM,OAAO,OAAO,SAAS,WACjD;AAEF,QAAI,MAAM,2BAA2B;AACnC,UAAI,OAAO,MAAM,OAAO,UAAU;AAClC,UAAI,QAAQ,YAAY,QAAQ,SAAS;AACvC,cAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,cAAM,YAAY;AAClB,eAAO,MAAM;AAAA,MACf;AACA,UAAK,GAAmB,cAAc,MAAM;AAC1C,YAAI,MAAuC;AACzC;AAAA,YACE;AAAA,YACA,IAAI,MAAM,mCAAmC,GAAG,IAAI;AAAA,UACtD;AAAA,QACF;AACA,sBAAc,KAAK;AAAA,MACrB;AACA;AAAA,IACF;AAEA,QAAI,MAAM,WAAW,MAAM,gBAAgB;AACzC,UAAI,QAAQ,SAAU;AACtB,UAAI,QAAQ,WAAW,QAAQ,YAAY;AACzC,YAAI,MAAM,WAAW,MAAM,SAAS,MAAM;AACxC,cAAI,SAAS,QAAS,GAAwB,UAAU,KAAK,OAAO;AAClE,gBAAI,MAAuC;AACzC,4BAAc,OAAO,IAAI,MAAM,aAAa,GAAG,uBAAuB,GAAG,IAAI,CAAC;AAAA,YAChF;AACA,0BAAc,KAAK;AAAA,UACrB;AAAA,QACF;AACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,QAAQ,YAAY,MAAM,aAAa,MAAM,mBAAmB;AAClE,UAAI,MAAM,aAAa,MAAM,WAAW,MAAM;AAC5C,YAAI,SAAS,QAAS,GAAwB,YAAY,CAAC,CAAC,OAAO;AACjE,cAAI,MAAuC;AACzC,0BAAc,OAAO,IAAI,MAAM,wCAAwC,CAAC;AAAA,UAC1E;AACA,wBAAc,KAAK;AAAA,QACrB;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI,QAAQ,YAAY,MAAM,YAAY;AACxC,UAAI,SAAS,QAAS,GAAyB,aAAa,CAAC,CAAC,OAAO;AACnE,YAAI,MAAuC;AACzC,wBAAc,OAAO,IAAI,MAAM,0CAA0C,CAAC;AAAA,QAC5E;AACA,sBAAc,KAAK;AAAA,MACrB;AACA;AAAA,IACF;AAEA,QAAI,MAAM,SAAS;AACjB,mBAAa,eAAe,KAAK,KAAK;AACtC,cAAQ,UAAU,GAAG,OAAO,QAAW,KAAK;AAC5C,UAAK,GAAmB,MAAM,YAAa,SAAyB,MAAM,SAAS;AACjF,YAAI,MAAuC;AACzC;AAAA,YACE;AAAA,YACA,IAAI,MAAM,gCAAgC,GAAG,IAAI;AAAA,UACnD;AAAA,QACF;AACA,sBAAc,KAAK;AAAA,MACrB;AACA;AAAA,IACF;AAEA,UAAM,qBAAqB,EAAE,WAAW,OAAO,KAAK,EAAE,WAAW,OAAO;AACxE,UAAM,OAAO,cAAc,GAAG,KAAK;AAEnC,QAAI;AACJ,QAAI,SAAS,QAAS,UAAU,SAAS,CAAC,oBAAqB;AAC7D,sBAAgB;AAAA,IAClB,OAAO;AACL,mBAAa,eAAe,KAAK,KAAK;AACtC,cAAQ,UAAU,GAAG,OAAO,QAAW,KAAK;AAC5C,sBAAgB,SAAS,aAAa,IAAI;AAAA,IAC5C;AACA,UAAM,cAAc,GAAG,aAAa,IAAI;AACxC,QAAI,kBAAkB,aAAa;AACjC,UAAI,MAAuC;AACzC;AAAA,UACE;AAAA,UACA,IAAI;AAAA,YACF,oCAAoC,GAAG,UAAU,IAAI,eACvC,qBAAqB,aAAa,CAAC,cAAc,qBAAqB,WAAW,CAAC;AAAA,UAClG;AAAA,QACF;AAAA,MACF;AACA,oBAAc,KAAK;AAAA,IACrB;AAAA,EACF;AACF;AAEA,SAAS,qBAAqB,OAA8B;AAC1D,SAAO,SAAS,OAAO,YAAY,KAAK,UAAU,KAAK;AACzD;",
|
|
4
|
+
"sourcesContent": ["import {\n FiberTag,\n REACT_ELEMENT_TYPE,\n type Fiber,\n type FiberRoot,\n type ReactElement,\n type ReactNode,\n} from '../../../core'\nimport { attributeName, STRING_BOOLEAN_ATTRS } from '../../../core/attributes'\nimport { createHostNode, setProp } from '../../dom'\nimport { drainReplayQueue } from '../../event-replay'\nimport { discardPendingWork, findRoot, flushSyncWork, renderRoot } from '../../reconcile'\nimport { attachRootFiber, createFiberRoot } from '../../root-internal'\n\n// Re-export from event-replay so all hydration concerns live behind one\n// feature boundary \u2014 the plugin's stub swap strips drainReplayQueue too.\nexport { drainReplayQueue }\n\n/**\n * Preserve the user's scroll position across hydration. If the user scrolled\n * between SSR paint and hydrate (common in dev where JS takes seconds to\n * load), libraries that wire scroll-restoration into a `useLayoutEffect`\n * near the root (e.g. TanStack Router) will run during our synchronous\n * hydrate and call `window.scrollTo(savedFromLastVisit)` \u2014 overwriting the\n * user's fresh scroll. We install a short-lived wrapper around scrollTo that\n * suppresses programmatic calls when a user-initiated scroll happened\n * recently. Only runs in the hydration feature \u2014 the stub skips it.\n */\nexport function installHydrationScrollGuard(): void {\n if (typeof window === 'undefined') return\n const w = window as any\n if (w._r) return\n const time = Date.now\n const guardStartedAt = w._r = time()\n let lastUserScrollAt = 0\n let programmatic = false\n w.addEventListener(\n 'scroll',\n () => {\n if (!programmatic) {\n lastUserScrollAt = time()\n }\n },\n { capture: true, passive: true },\n )\n const origScrollTo = w.scrollTo\n w.scrollTo = function (...args: any[]) {\n const now = time()\n if (\n now - guardStartedAt < 3000 &&\n now - lastUserScrollAt < 1500\n ) {\n return\n }\n programmatic = true\n try {\n return (origScrollTo as any).apply(w, args)\n } finally {\n queueMicrotask(() => {\n programmatic = false\n })\n }\n }\n}\n\n/**\n * Hydration cursor: walks existing DOM children in document order so we can\n * adopt them during fiber tree construction. One cursor per host parent.\n *\n * `endBefore` scopes the cursor to a subrange \u2014 used by rehydrateBoundary()\n * so we only adopt DOM up to the closing `/$` marker for that boundary.\n */\nexport class HydrationCursor {\n n: ChildNode | null\n p: Node\n e: ChildNode | null\n constructor(parent: Node, start: ChildNode | null = null, endBefore: ChildNode | null = null) {\n this.p = parent\n this.n = start ?? parent.firstChild\n this.e = endBefore\n }\n take(): ChildNode | null {\n while (this.n && this.n !== this.e) {\n const n = this.n\n // Skip anything that isn't an element (1) or text (3):\n // comments (8), doctype (10), processing instructions (7), cdata (4).\n if (n.nodeType !== 1 && n.nodeType !== 3) {\n this.n = n.nextSibling\n continue\n }\n this.n = n.nextSibling\n return n\n }\n return null\n }\n /**\n * Position-insensitive lookup for head/html adoption. Scans forward past\n * non-matching nodes without removing them, matching by tag AND the key\n * attributes that identify head elements uniquely (rel/href for links,\n * name/property for meta, src for script). Non-matching nodes stay in\n * place so the SSR'd stylesheet/script order is preserved.\n */\n head(tag: string, props: Record<string, any>): ChildNode | null {\n const target = tag.toLowerCase()\n const keyAttrs = HEAD_KEY_ATTRS[target]\n let scan = this.p.firstChild\n while (scan) {\n if (\n scan.nodeType === 1 &&\n (scan as Element).tagName.toLowerCase() === target &&\n headAttrsMatch(scan as Element, props, keyAttrs)\n ) {\n CLAIMED.add(scan)\n return scan\n }\n scan = scan.nextSibling\n }\n return null\n }\n has(): boolean {\n let n = this.n\n while (n && n !== this.e) {\n if (n.nodeType === 1 || n.nodeType === 3) return true\n n = n.nextSibling\n }\n return false\n }\n}\n\nconst hydrationCursors = new WeakMap<Fiber, HydrationCursor>()\nconst PROD_HYDRATION_ERROR = 'Hydration mismatch.'\n\nexport interface HydrationBailoutError extends Error {\n f: Fiber | null\n}\n\nexport function isHydrationBailout(error: unknown): error is HydrationBailoutError {\n return !!error && (error as any).f !== undefined\n}\n\nexport function abortHydration(cause: unknown, fiber: Fiber | null = null): never {\n const error = (cause instanceof Error ? cause : new Error(PROD_HYDRATION_ERROR)) as HydrationBailoutError\n ;(error as any).f = fiber\n throw error\n}\n\ninterface HydrateRootOptions {\n identifierPrefix?: string\n onRecoverableError?: (error: unknown) => void\n onCaughtError?: (error: unknown) => void\n onUncaughtError?: (error: unknown) => void\n}\n\ninterface HydratedRoot {\n render(children: ReactNode): void\n unmount(): void\n}\n\nexport function hydrateRootImpl(\n container: Element | Document,\n initialChildren: ReactNode,\n options: HydrateRootOptions,\n): HydratedRoot {\n const target = container as any as Element | Document\n const isDocument = (container as Node).nodeType === 9\n const body = isDocument ? (target as Document).body : null\n const root = createFiberRoot(target, options)\n\n installHydrationScrollGuard()\n\n const normalizedInitialChildren =\n isDocument ? normalizeDocumentChildren(initialChildren) : initialChildren\n let hydrationError: unknown = null\n beginHydration(root)\n try {\n flushSyncWork(() => {\n renderRoot(root, normalizedInitialChildren)\n })\n } catch (e) {\n hydrationError = e\n }\n endHydration(root)\n\n if (hydrationError && !recoverHydration(root, hydrationError)) throw hydrationError\n drainReplayQueue()\n\n return {\n render(children) {\n flushSyncWork(() => {\n const normalized = isDocument ? normalizeDocumentChildren(children) : children\n renderRoot(\n root,\n root.c === body ? getStaticDocumentBodyChildren(normalized) ?? normalized : normalized,\n )\n })\n },\n unmount() {\n flushSyncWork(() => {\n renderRoot(root, null)\n })\n },\n }\n}\n\n// Head elements that we match against server DOM by attribute signature.\nconst HEAD_KEY_ATTRS: Record<string, ReadonlyArray<string>> = {\n link: ['rel', 'href', 'sizes', 'type'],\n meta: ['name', 'property', 'charSet', 'httpEquiv'],\n script: ['src', 'type'],\n style: ['id', 'media', 'nonce', 'title'],\n}\n\nconst DOCUMENT_HEAD_TAGS = new Set(['base', 'link', 'meta', 'script', 'style', 'title'])\n\n// DOM elements already claimed by some fiber during this hydration pass.\nconst CLAIMED = new WeakSet<Node>()\n\nfunction headAttrsMatch(\n el: Element,\n props: Record<string, any>,\n keys: ReadonlyArray<string> | undefined,\n): boolean {\n if (CLAIMED.has(el)) return false\n if (!keys) return true\n for (const k of keys) {\n const propVal = props[k]\n const elVal = el.getAttribute(attributeName(k))\n if (propVal == null && elVal == null) continue\n if (propVal == null || elVal == null || String(propVal) !== elVal) return false\n }\n return true\n}\n\nexport function beginHydration(root: FiberRoot): void {\n root.ic = 0\n root.h = true\n hydrationCursors.set(root.r, new HydrationCursor(root.c))\n}\n\nexport function endHydration(root: FiberRoot): void {\n root.h = false\n hydrationCursors.delete(root.r)\n}\n\n/**\n * Inspect the current cursor position for a streaming-suspense boundary\n * marker emitted by the server. Returns info + advances the cursor past the\n * marker pair (start comment + fallback/real content + end comment).\n */\nexport type BoundaryInfo = [0 | 1, number, Comment, Comment]\n\nexport function tryConsumeBoundary(parent: Fiber): BoundaryInfo | null {\n const cursor = hydrationCursors.get(findHostParent(parent))\n if (!cursor) return null\n const peek = cursor.n\n if (!peek || peek.nodeType !== 8) return null\n const data = (peek as Comment).data\n const m = /^(\\$\\??)(\\d+)$/.exec(data)\n if (!m) return null\n const kind = m[1] === '$?' ? 1 : 0\n const id = Number(m[2])\n const startMark = peek as Comment\n // Advance past the start comment\n cursor.n = startMark.nextSibling\n // Locate end comment: closest <!--/$-->\n let endMark: Comment | null = null\n let scan = startMark.nextSibling\n while (scan) {\n if (scan.nodeType === 8 && (scan as Comment).data === '/$') {\n endMark = scan as Comment\n break\n }\n scan = scan.nextSibling\n }\n if (!endMark) return null\n return [kind, id, startMark, endMark]\n}\n\nexport function advanceCursorPast(parent: Fiber, node: Node): void {\n const cursor = hydrationCursors.get(findHostParent(parent))\n if (!cursor) return\n cursor.n = node.nextSibling\n}\n\nexport function getHydrationCursor(hostFiber: Fiber): HydrationCursor | undefined {\n return hydrationCursors.get(hostFiber)\n}\n\nexport function setHydrationCursor(hostFiber: Fiber, cursor: HydrationCursor): void {\n hydrationCursors.set(hostFiber, cursor)\n}\n\nexport function clearHydrationCursor(hostFiber: Fiber): void {\n hydrationCursors.delete(hostFiber)\n}\n\n/**\n * Try to adopt a DOM node for this host fiber. Returns true if adopted.\n * Attaches existing attrs/children via separate hydrate pass.\n */\nexport function adoptHostDom(fiber: Fiber, parent: Fiber): boolean {\n const hostParent = findHostParent(parent)\n const cursor = hydrationCursors.get(hostParent)\n if (!cursor) return false\n\n const tag = (fiber.type as string).toLowerCase()\n const documentHeadParent =\n cursor.p.nodeType === 9 && DOCUMENT_HEAD_TAGS.has(tag)\n ? (cursor.p as Document).head\n : null\n const parentEl = cursor.p as Element\n const parentTag =\n parentEl.nodeType === 1 ? (parentEl as Element).tagName.toLowerCase() : ''\n const isHeadish = parentTag === 'head' || parentTag === 'html' || !!documentHeadParent\n\n let candidate: ChildNode | null\n if (documentHeadParent) {\n // React 19 can project <meta>/<title>/<link> from anywhere in the tree into\n // document.head. Redact does not have that projection yet, so when a\n // document-root hydration pass sees a top-level head element, adopt it\n // from <head> rather than trying to append it beside <html>.\n candidate = new HydrationCursor(documentHeadParent).head(\n tag,\n fiber.pp ?? {},\n )\n } else if (isHeadish) {\n // Head/html children are position-insensitive \u2014 server may emit them in\n // a different order than the React tree (React 19 head hoisting, etc.).\n // Scan forward without removing non-matching nodes; match on attribute\n // signature so we don't adopt the wrong <link> and clobber its props.\n candidate = cursor.head(tag, fiber.pp ?? {})\n } else {\n candidate = cursor.take()\n }\n\n if (!candidate) {\n // Client expected a host here but the cursor is exhausted \u2014 server gave\n // fewer children than the client tree. Report the structural gap (React\n // fires `onRecoverableError` for this exact case) and let the reconciler\n // mount a fresh DOM for this fiber below.\n // Exception: <head> children are position-insensitive; a missing match\n // there means \"server didn't hoist this one yet\", which we silently mount.\n if (!isHeadish) onMismatch(fiber, null)\n return false\n }\n\n if (candidate.nodeType !== 1 || (candidate as Element).tagName.toLowerCase() !== tag) {\n // mismatch \u2014 log and re-render fresh from this point\n onMismatch(fiber, candidate)\n return false\n }\n fiber.dom = candidate\n // Apply props (attach events, sync IDL props). Don't re-set existing attrs.\n const props = fiber.pp ?? {}\n const isSvg =\n tag === 'svg' ||\n ((candidate as Element).namespaceURI === 'http://www.w3.org/2000/svg' &&\n tag !== 'foreignobject')\n const syncHydrationProps =\n !props.suppressHydrationWarning &&\n canRecoverHydrationPropMismatch(candidate, tag)\n validateHydrationProps(fiber, candidate as Element, props, tag, isSvg)\n for (const k in props) {\n if (\n k === 'children' ||\n k === 'key' ||\n k === 'ref' ||\n k === 'suppressHydrationWarning' ||\n k === 'suppressContentEditableWarning'\n ) continue\n if (\n syncHydrationProps ||\n (k[0] === 'o' && k[1] === 'n' && typeof props[k] == 'function')\n ) {\n setProp(candidate as Element, k, props[k], undefined, isSvg)\n }\n }\n // Set up child cursor for this host's children\n hydrationCursors.set(fiber, new HydrationCursor(candidate))\n return true\n}\n\nexport function adoptTextDom(fiber: Fiber, parent: Fiber, text: string): boolean {\n const cursor = hydrationCursors.get(findHostParent(parent))\n if (!cursor) return false\n const candidate = cursor.take()\n if (!candidate) {\n onMismatch(fiber, null)\n return false\n }\n if (candidate.nodeType === 3) {\n if ((candidate as Text).data !== text) {\n const recovered = failHydration(\n fiber,\n process.env.NODE_ENV !== 'production'\n ? new Error(\n `Hydration text mismatch: expected \"${text}\" but found \"${(candidate as Text).data}\".`,\n )\n : undefined,\n canRecoverHydrationPropMismatch(candidate),\n )\n if (recovered) {\n ;(candidate as Text).data = text\n }\n }\n fiber.dom = candidate\n return true\n }\n onMismatch(fiber, candidate)\n return false\n}\n\nexport function findHostParent(fiber: Fiber): Fiber {\n let f: Fiber | null = fiber\n while (f) {\n // A fiber explicitly holding a cursor acts as a boundary for hydration\n // (e.g. Suspense with a scoped cursor during fallback/boundary hydration).\n if (hydrationCursors.has(f)) return f\n if (f.tag === FiberTag.Host || f.tag === FiberTag.Root || f.tag === FiberTag.Portal) {\n return f\n }\n f = f.parent\n }\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('No host parent found')\n }\n throw new Error()\n}\n\nfunction onMismatch(fiber: Fiber, actualNode: ChildNode | null): void {\n failHydration(\n fiber,\n process.env.NODE_ENV !== 'production'\n ? new Error(\n `Hydration mismatch: expected <${(fiber.type as string) ?? 'text'}> but found ${\n actualNode ? (actualNode.nodeType === 1 ? (actualNode as Element).tagName : 'text') : 'nothing'\n }.`,\n )\n : undefined,\n )\n}\n\nfunction failHydration(\n fiber: Fiber,\n error: Error = new Error(PROD_HYDRATION_ERROR),\n recoverInPlace = false,\n): boolean {\n const root = findRoot(fiber)\n if (root?.re) {\n root.re(error)\n }\n if (recoverInPlace) return true\n abortHydration(error, findHostRecoveryParent(fiber) ?? fiber)\n}\n\nfunction canRecoverHydrationPropMismatch(node: Node, tag?: string): boolean {\n return (\n tag === 'html' ||\n tag === 'head' ||\n tag === 'body' ||\n !!node.ownerDocument?.head?.contains(node)\n )\n}\n\nfunction findHostRecoveryParent(fiber: Fiber): Fiber | null {\n if (fiber.tag === FiberTag.Text) {\n let directHost = fiber.parent\n while (directHost && (directHost.tag !== FiberTag.Host || !directHost.dom)) {\n directHost = directHost.parent\n }\n if (!directHost) return null\n let hasEvent\n const props = directHost.pp ?? directHost.mp\n if (props) {\n for (const k in props) {\n if (k[0] === 'o' && k[1] === 'n' && typeof props[k] == 'function') {\n hasEvent = true\n }\n }\n }\n return findNearestSafeHostAboveComposite(\n hasEvent\n ? directHost.parent\n : directHost.parent?.tag === FiberTag.Host\n ? directHost.parent\n : directHost,\n )\n }\n\n return findNearestSafeHostAboveComposite(fiber.parent)\n}\n\nfunction findNearestSafeHostAboveComposite(fiber: Fiber | null): Fiber | null {\n let host: Fiber | null = null\n let f = fiber\n while (f) {\n if (f.tag === FiberTag.Host && f.dom) {\n if (!isSafeHostRecoveryElement(f)) return null\n const parentTag = f.parent?.tag as number\n if (!host || (parentTag > FiberTag.Text && parentTag < FiberTag.Suspense)) {\n host = f\n }\n }\n f = f.parent\n }\n return host\n}\n\nfunction isSafeHostRecoveryElement(fiber: Fiber): boolean {\n const tag = fiber.type.toLowerCase()\n return tag !== 'html' && tag !== 'head' && tag !== 'body'\n}\n\nexport function recoverHydration(root: FiberRoot, error: unknown): boolean {\n if (!isHydrationBailout(error)) return false\n\n let container = root.c as Element | Document\n let children = root.r.pp?.children ?? null\n const hostRecovery = getRecoverableHostChildren(error)\n if (hostRecovery) {\n container = hostRecovery[0]\n children = hostRecovery[1]\n } else if (container.nodeType === 9) {\n const bodyChildren = getRecoverableDocumentBodyChildren(error)\n if (bodyChildren != null) {\n container = (container as Document).body\n children = bodyChildren\n }\n }\n\n resetAfterHydrationFailure(root, container)\n try {\n flushSyncWork(() => renderRoot(root, children))\n } catch (clientError) {\n resetAfterHydrationFailure(root, container)\n throw clientError\n }\n return true\n}\n\nfunction resetAfterHydrationFailure(\n root: FiberRoot,\n container: Element | Document,\n): void {\n discardPendingWork(root)\n clearHydrationContainer(container)\n attachRootFiber(root, container)\n root.h = false\n}\n\nfunction clearHydrationContainer(container: Element | Document): void {\n if (container.nodeType === 9) {\n let node = container.firstChild\n while (node) {\n const next = node.nextSibling\n if (node.nodeType !== 10 /* DOCUMENT_TYPE_NODE */) {\n container.removeChild(node)\n }\n node = next\n }\n return\n }\n ;(container as Element).textContent = ''\n}\n\nfunction getRecoverableHostChildren(\n error: HydrationBailoutError,\n): [Element, ReactNode] | null {\n const host = error.f\n if (\n host?.tag !== FiberTag.Host ||\n !host.dom ||\n !findNearestSafeHostAboveComposite(host.parent)\n ) {\n return null\n }\n return [host.dom as Element, (host.pp ?? host.mp)?.children ?? null]\n}\n\nfunction getRecoverableDocumentBodyChildren(error: HydrationBailoutError): ReactNode | null {\n const bodyFiber = findBodyAncestor(error.f)\n if (!bodyFiber) return null\n return (bodyFiber.pp ?? bodyFiber.mp)?.children ?? null\n}\n\nfunction findBodyAncestor(fiber: Fiber | null): Fiber | null {\n let f = fiber\n while (f) {\n if (f.tag === FiberTag.Host && f.type === 'body') {\n return f === fiber ? null : f\n }\n f = f.parent\n }\n return null\n}\n\nfunction getStaticDocumentBodyChildren(children: ReactNode): ReactNode | null {\n const list = toChildArray(children)\n const html = list.find((child) => isHostElement(child, 'html')) as ReactElement | undefined\n if (!html) return null\n const htmlChildren = toChildArray(html.props?.children)\n const body = htmlChildren.find((child) => isHostElement(child, 'body')) as ReactElement | undefined\n return body ? body.props?.children ?? null : null\n}\n\nfunction normalizeDocumentChildren(children: ReactNode): ReactNode {\n const list = toChildArray(children)\n const htmlIndex = list.findIndex((child) => isHostElement(child, 'html'))\n if (htmlIndex === -1) return children\n\n const headNodes = list.filter(isHeadElement)\n if (headNodes.length === 0) return children\n\n const htmlElement = list[htmlIndex] as ReactElement\n const normalizedHtml = hoistIntoHtmlHead(htmlElement, headNodes)\n return list\n .filter((child, index) => index === htmlIndex || !isHeadElement(child))\n .map((child) => (child === htmlElement ? normalizedHtml : child))\n}\n\nfunction hoistIntoHtmlHead(htmlElement: ReactElement, headNodes: ReactNode[]): ReactElement {\n const htmlChildren = toChildArray(htmlElement.props?.children)\n const headIndex = htmlChildren.findIndex((child) => isHostElement(child, 'head'))\n let nextChildren: ReactNode[]\n\n if (headIndex === -1) {\n nextChildren = [\n createHostElement('head', { children: headNodes }),\n ...htmlChildren,\n ]\n } else {\n const headElement = htmlChildren[headIndex] as ReactElement\n const existingHeadChildren = toChildArray(headElement.props?.children)\n const nextHead = {\n ...headElement,\n props: {\n ...headElement.props,\n children: [...headNodes, ...existingHeadChildren],\n },\n }\n nextChildren = htmlChildren.map((child, index) => (index === headIndex ? nextHead : child))\n }\n\n return {\n ...htmlElement,\n props: {\n ...htmlElement.props,\n children: nextChildren,\n },\n }\n}\n\nfunction toChildArray(children: unknown): ReactNode[] {\n if (children == null || typeof children === 'boolean') return []\n if (Array.isArray(children)) return children as ReactNode[]\n if (isReactElement(children)) return [children]\n if (typeof children !== 'string' && isIterable(children)) return Array.from(children) as ReactNode[]\n return [children as ReactNode]\n}\n\nfunction isHeadElement(value: ReactNode): boolean {\n return isReactElement(value) && typeof value.type === 'string' && DOCUMENT_HEAD_TAGS.has(value.type)\n}\n\nfunction isHostElement(value: ReactNode, tag: string): boolean {\n return isReactElement(value) && value.type === tag\n}\n\nfunction isReactElement(value: unknown): value is ReactElement {\n return !!value && typeof value === 'object' && (value as ReactElement).$$typeof === REACT_ELEMENT_TYPE\n}\n\nfunction isIterable(value: unknown): value is Iterable<ReactNode> {\n return !!value && typeof (value as { [Symbol.iterator]?: unknown })[Symbol.iterator] == 'function'\n}\n\nfunction createHostElement(type: string, props: Record<string, unknown>): ReactElement {\n return {\n $$typeof: REACT_ELEMENT_TYPE,\n type,\n key: null,\n ref: null,\n props,\n }\n}\n\nfunction validateHydrationProps(\n fiber: Fiber,\n el: Element,\n props: Record<string, any>,\n tag: string,\n isSvg: boolean,\n): void {\n if (props.suppressHydrationWarning) return\n\n const recoverInPlace = canRecoverHydrationPropMismatch(el, tag)\n let expected: Element | undefined\n\n for (const k in props) {\n const value = props[k]\n if (\n k === 'children' ||\n k === 'key' ||\n k === 'ref' ||\n k === 'suppressHydrationWarning' ||\n k === 'suppressContentEditableWarning' ||\n (k[0] === 'o' && k[1] === 'n' && typeof value == 'function')\n ) continue\n\n if (k === 'dangerouslySetInnerHTML') {\n let html = '' + (value?.__html ?? '')\n if (tag !== 'script' && tag !== 'style') {\n const probe = document.createElement('div')\n probe.innerHTML = html\n html = probe.innerHTML\n }\n if ((el as HTMLElement).innerHTML !== html) {\n failHydration(\n fiber,\n process.env.NODE_ENV !== 'production'\n ? new Error(`Hydration HTML mismatch inside <${tag}>.`)\n : undefined,\n recoverInPlace,\n )\n }\n continue\n }\n\n if (k === 'value' || k === 'defaultValue') {\n if (tag === 'select') continue\n if (tag === 'input' || tag === 'textarea') {\n if (k === 'value' || props.value == null) {\n if (value != null && (el as HTMLInputElement).value !== '' + value) {\n failHydration(\n fiber,\n process.env.NODE_ENV !== 'production'\n ? new Error(`Hydration ${tag} value mismatch on <${tag}>.`)\n : undefined,\n recoverInPlace,\n )\n }\n }\n continue\n }\n }\n\n if (tag === 'input' && (k === 'checked' || k === 'defaultChecked')) {\n if (k === 'checked' || props.checked == null) {\n if (value != null && (el as HTMLInputElement).checked !== !!value) {\n failHydration(\n fiber,\n process.env.NODE_ENV !== 'production'\n ? new Error(`Hydration checked mismatch on <input>.`)\n : undefined,\n recoverInPlace,\n )\n }\n }\n continue\n }\n\n if (tag === 'option' && k === 'selected') {\n if (value != null && (el as HTMLOptionElement).selected !== !!value) {\n failHydration(\n fiber,\n process.env.NODE_ENV !== 'production'\n ? new Error(`Hydration selected mismatch on <option>.`)\n : undefined,\n recoverInPlace,\n )\n }\n continue\n }\n\n if (k === 'style') {\n expected ??= createHostNode(tag, isSvg)\n setProp(expected, k, value, undefined, isSvg)\n if (\n !hydrationStylesMatch(\n (el as HTMLElement).style,\n (expected as HTMLElement).style,\n )\n ) {\n failHydration(\n fiber,\n process.env.NODE_ENV !== 'production'\n ? new Error(`Hydration style mismatch on <${tag}>.`)\n : undefined,\n recoverInPlace,\n )\n }\n continue\n }\n\n const attr = attributeName(k, isSvg)\n const stringifiedBoolean =\n STRING_BOOLEAN_ATTRS.has(attr) || k.startsWith('aria-') || k.startsWith('data-')\n\n let expectedValue: string | null\n if (value == null || (value === false && !stringifiedBoolean)) {\n expectedValue = null\n } else if (k === 'muted' && !isSvg && (tag === 'video' || tag === 'audio')) {\n // The muted property controls playback; defaultMuted reflects the SSR attribute.\n expectedValue = value ? '' : null\n } else {\n expected ??= createHostNode(tag, isSvg)\n setProp(expected, k, value, undefined, isSvg)\n expectedValue = expected.getAttribute(attr)\n }\n const actualValue = el.getAttribute(attr)\n if (expectedValue !== actualValue) {\n failHydration(\n fiber,\n process.env.NODE_ENV !== 'production'\n ? new Error(\n `Hydration attribute mismatch on <${tag}> for \"${attr}\": ` +\n `expected ${formatHydrationValue(expectedValue)} but found ${formatHydrationValue(actualValue)}.`,\n )\n : undefined,\n recoverInPlace,\n )\n }\n }\n}\n\nfunction hydrationStylesMatch(\n actual: CSSStyleDeclaration,\n expected: CSSStyleDeclaration,\n): boolean {\n for (let index = 0; index < expected.length; index++) {\n const property = expected.item(index)\n if (\n actual.getPropertyValue(property) !== expected.getPropertyValue(property) ||\n actual.getPropertyPriority(property) !== expected.getPropertyPriority(property)\n ) {\n return false\n }\n }\n return true\n}\n\nfunction formatHydrationValue(value: string | null): string {\n return value == null ? 'nothing' : JSON.stringify(value)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/server/escape.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// packages/redact/src/server/escape.ts
|
|
2
|
-
import { attributeName } from "../core/attributes";
|
|
2
|
+
import { attributeName, STRING_BOOLEAN_ATTRS } from "../core/attributes";
|
|
3
3
|
var ATTR_MAP = {
|
|
4
4
|
"&": "&",
|
|
5
5
|
'"': """,
|
|
@@ -71,7 +71,7 @@ function attrToHtml(name, value, isSvg = false) {
|
|
|
71
71
|
if (name[0] === "o" && name[1] === "n" && typeof value === "function") return "";
|
|
72
72
|
if (value == null) return "";
|
|
73
73
|
const htmlName = attributeName(name, isSvg);
|
|
74
|
-
if (name.startsWith("aria-") || name.startsWith("data-")) {
|
|
74
|
+
if (STRING_BOOLEAN_ATTRS.has(htmlName) || name.startsWith("aria-") || name.startsWith("data-")) {
|
|
75
75
|
return ` ${htmlName}="${escapeAttr(String(value))}"`;
|
|
76
76
|
}
|
|
77
77
|
if (value === false) return "";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/server/escape.ts"],
|
|
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 //
|
|
5
|
-
"mappings": ";AAAA,SAAS,
|
|
4
|
+
"sourcesContent": ["import { attributeName, STRING_BOOLEAN_ATTRS } 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 // These attributes need explicit \"false\", not boolean-attribute absence.\n if (\n STRING_BOOLEAN_ATTRS.has(htmlName) ||\n name.startsWith('aria-') ||\n name.startsWith('data-')\n ) {\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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/redact",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.20",
|
|
4
4
|
"description": "React, redacted. A minimal React-API-compatible drop-in replacement.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/react/index.js",
|
|
@@ -78,10 +78,15 @@
|
|
|
78
78
|
"optional": true
|
|
79
79
|
}
|
|
80
80
|
},
|
|
81
|
-
"scripts": {
|
|
82
|
-
"build": "echo done-by-root-build"
|
|
83
|
-
},
|
|
84
81
|
"publishConfig": {
|
|
85
82
|
"access": "public"
|
|
83
|
+
},
|
|
84
|
+
"repository": {
|
|
85
|
+
"type": "git",
|
|
86
|
+
"url": "git+https://github.com/TanStack/redact.git",
|
|
87
|
+
"directory": "packages/redact"
|
|
88
|
+
},
|
|
89
|
+
"scripts": {
|
|
90
|
+
"build": "echo done-by-root-build"
|
|
86
91
|
}
|
|
87
|
-
}
|
|
92
|
+
}
|
package/src/core/attributes.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
export const STRING_BOOLEAN_ATTRS = new Set([
|
|
2
|
+
'contenteditable',
|
|
3
|
+
'draggable',
|
|
4
|
+
'spellcheck',
|
|
5
|
+
])
|
|
6
|
+
|
|
1
7
|
export function attributeName(name: string, isSvg = false): string {
|
|
2
8
|
if (isSvg && name !== 'viewBox' && SVG_KEBAB_PREFIX.test(name)) {
|
|
3
9
|
return name.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase())
|
package/src/dom/dom.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { attributeName } from '../core/attributes'
|
|
1
|
+
import { attributeName, STRING_BOOLEAN_ATTRS } from '../core/attributes'
|
|
2
2
|
|
|
3
3
|
const SVG_NS = 'http://www.w3.org/2000/svg'
|
|
4
4
|
|
|
@@ -38,9 +38,6 @@ const IDL_ATTRS = new Set([
|
|
|
38
38
|
'multiple',
|
|
39
39
|
'muted',
|
|
40
40
|
'readonly',
|
|
41
|
-
'contentEditable',
|
|
42
|
-
'spellcheck',
|
|
43
|
-
'draggable',
|
|
44
41
|
])
|
|
45
42
|
|
|
46
43
|
export function createHostNode(type: string, isSvg: boolean): Element {
|
|
@@ -118,6 +115,12 @@ export function setProp(
|
|
|
118
115
|
return
|
|
119
116
|
}
|
|
120
117
|
|
|
118
|
+
if (STRING_BOOLEAN_ATTRS.has(attr)) {
|
|
119
|
+
if (next == null) el.removeAttribute(attr)
|
|
120
|
+
else el.setAttribute(attr, '' + next)
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
|
|
121
124
|
if (!isSvg && IDL_ATTRS.has(name) && name in el) {
|
|
122
125
|
try {
|
|
123
126
|
;(el as any)[name] = next == null ? '' : next
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
type ReactElement,
|
|
7
7
|
type ReactNode,
|
|
8
8
|
} from '../../../core'
|
|
9
|
-
import { attributeName } from '../../../core/attributes'
|
|
9
|
+
import { attributeName, STRING_BOOLEAN_ATTRS } from '../../../core/attributes'
|
|
10
10
|
import { createHostNode, setProp } from '../../dom'
|
|
11
11
|
import { drainReplayQueue } from '../../event-replay'
|
|
12
12
|
import { discardPendingWork, findRoot, flushSyncWork, renderRoot } from '../../reconcile'
|
|
@@ -207,6 +207,7 @@ const HEAD_KEY_ATTRS: Record<string, ReadonlyArray<string>> = {
|
|
|
207
207
|
link: ['rel', 'href', 'sizes', 'type'],
|
|
208
208
|
meta: ['name', 'property', 'charSet', 'httpEquiv'],
|
|
209
209
|
script: ['src', 'type'],
|
|
210
|
+
style: ['id', 'media', 'nonce', 'title'],
|
|
210
211
|
}
|
|
211
212
|
|
|
212
213
|
const DOCUMENT_HEAD_TAGS = new Set(['base', 'link', 'meta', 'script', 'style', 'title'])
|
|
@@ -355,13 +356,24 @@ export function adoptHostDom(fiber: Fiber, parent: Fiber): boolean {
|
|
|
355
356
|
tag === 'svg' ||
|
|
356
357
|
((candidate as Element).namespaceURI === 'http://www.w3.org/2000/svg' &&
|
|
357
358
|
tag !== 'foreignobject')
|
|
359
|
+
const syncHydrationProps =
|
|
360
|
+
!props.suppressHydrationWarning &&
|
|
361
|
+
canRecoverHydrationPropMismatch(candidate, tag)
|
|
358
362
|
validateHydrationProps(fiber, candidate as Element, props, tag, isSvg)
|
|
359
363
|
for (const k in props) {
|
|
360
|
-
if (
|
|
361
|
-
|
|
364
|
+
if (
|
|
365
|
+
k === 'children' ||
|
|
366
|
+
k === 'key' ||
|
|
367
|
+
k === 'ref' ||
|
|
368
|
+
k === 'suppressHydrationWarning' ||
|
|
369
|
+
k === 'suppressContentEditableWarning'
|
|
370
|
+
) continue
|
|
371
|
+
if (
|
|
372
|
+
syncHydrationProps ||
|
|
373
|
+
(k[0] === 'o' && k[1] === 'n' && typeof props[k] == 'function')
|
|
374
|
+
) {
|
|
362
375
|
setProp(candidate as Element, k, props[k], undefined, isSvg)
|
|
363
376
|
}
|
|
364
|
-
// Non-event props: trust the server HTML, skip
|
|
365
377
|
}
|
|
366
378
|
// Set up child cursor for this host's children
|
|
367
379
|
hydrationCursors.set(fiber, new HydrationCursor(candidate))
|
|
@@ -372,16 +384,24 @@ export function adoptTextDom(fiber: Fiber, parent: Fiber, text: string): boolean
|
|
|
372
384
|
const cursor = hydrationCursors.get(findHostParent(parent))
|
|
373
385
|
if (!cursor) return false
|
|
374
386
|
const candidate = cursor.take()
|
|
375
|
-
if (!candidate)
|
|
387
|
+
if (!candidate) {
|
|
388
|
+
onMismatch(fiber, null)
|
|
389
|
+
return false
|
|
390
|
+
}
|
|
376
391
|
if (candidate.nodeType === 3) {
|
|
377
392
|
if ((candidate as Text).data !== text) {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
new Error(
|
|
382
|
-
|
|
393
|
+
const recovered = failHydration(
|
|
394
|
+
fiber,
|
|
395
|
+
process.env.NODE_ENV !== 'production'
|
|
396
|
+
? new Error(
|
|
397
|
+
`Hydration text mismatch: expected "${text}" but found "${(candidate as Text).data}".`,
|
|
398
|
+
)
|
|
399
|
+
: undefined,
|
|
400
|
+
canRecoverHydrationPropMismatch(candidate),
|
|
401
|
+
)
|
|
402
|
+
if (recovered) {
|
|
403
|
+
;(candidate as Text).data = text
|
|
383
404
|
}
|
|
384
|
-
failHydration(fiber)
|
|
385
405
|
}
|
|
386
406
|
fiber.dom = candidate
|
|
387
407
|
return true
|
|
@@ -407,28 +427,41 @@ export function findHostParent(fiber: Fiber): Fiber {
|
|
|
407
427
|
throw new Error()
|
|
408
428
|
}
|
|
409
429
|
|
|
410
|
-
function onMismatch(fiber: Fiber, actualNode: ChildNode | null):
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
new Error(
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
failHydration(fiber)
|
|
430
|
+
function onMismatch(fiber: Fiber, actualNode: ChildNode | null): void {
|
|
431
|
+
failHydration(
|
|
432
|
+
fiber,
|
|
433
|
+
process.env.NODE_ENV !== 'production'
|
|
434
|
+
? new Error(
|
|
435
|
+
`Hydration mismatch: expected <${(fiber.type as string) ?? 'text'}> but found ${
|
|
436
|
+
actualNode ? (actualNode.nodeType === 1 ? (actualNode as Element).tagName : 'text') : 'nothing'
|
|
437
|
+
}.`,
|
|
438
|
+
)
|
|
439
|
+
: undefined,
|
|
440
|
+
)
|
|
422
441
|
}
|
|
423
442
|
|
|
424
|
-
function failHydration(
|
|
443
|
+
function failHydration(
|
|
444
|
+
fiber: Fiber,
|
|
445
|
+
error: Error = new Error(PROD_HYDRATION_ERROR),
|
|
446
|
+
recoverInPlace = false,
|
|
447
|
+
): boolean {
|
|
425
448
|
const root = findRoot(fiber)
|
|
426
449
|
if (root?.re) {
|
|
427
450
|
root.re(error)
|
|
428
451
|
}
|
|
452
|
+
if (recoverInPlace) return true
|
|
429
453
|
abortHydration(error, findHostRecoveryParent(fiber) ?? fiber)
|
|
430
454
|
}
|
|
431
455
|
|
|
456
|
+
function canRecoverHydrationPropMismatch(node: Node, tag?: string): boolean {
|
|
457
|
+
return (
|
|
458
|
+
tag === 'html' ||
|
|
459
|
+
tag === 'head' ||
|
|
460
|
+
tag === 'body' ||
|
|
461
|
+
!!node.ownerDocument?.head?.contains(node)
|
|
462
|
+
)
|
|
463
|
+
}
|
|
464
|
+
|
|
432
465
|
function findHostRecoveryParent(fiber: Fiber): Fiber | null {
|
|
433
466
|
if (fiber.tag === FiberTag.Text) {
|
|
434
467
|
let directHost = fiber.parent
|
|
@@ -660,6 +693,7 @@ function validateHydrationProps(
|
|
|
660
693
|
): void {
|
|
661
694
|
if (props.suppressHydrationWarning) return
|
|
662
695
|
|
|
696
|
+
const recoverInPlace = canRecoverHydrationPropMismatch(el, tag)
|
|
663
697
|
let expected: Element | undefined
|
|
664
698
|
|
|
665
699
|
for (const k in props) {
|
|
@@ -681,13 +715,13 @@ function validateHydrationProps(
|
|
|
681
715
|
html = probe.innerHTML
|
|
682
716
|
}
|
|
683
717
|
if ((el as HTMLElement).innerHTML !== html) {
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
new Error(`Hydration HTML mismatch inside <${tag}>.`)
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
718
|
+
failHydration(
|
|
719
|
+
fiber,
|
|
720
|
+
process.env.NODE_ENV !== 'production'
|
|
721
|
+
? new Error(`Hydration HTML mismatch inside <${tag}>.`)
|
|
722
|
+
: undefined,
|
|
723
|
+
recoverInPlace,
|
|
724
|
+
)
|
|
691
725
|
}
|
|
692
726
|
continue
|
|
693
727
|
}
|
|
@@ -697,10 +731,13 @@ function validateHydrationProps(
|
|
|
697
731
|
if (tag === 'input' || tag === 'textarea') {
|
|
698
732
|
if (k === 'value' || props.value == null) {
|
|
699
733
|
if (value != null && (el as HTMLInputElement).value !== '' + value) {
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
734
|
+
failHydration(
|
|
735
|
+
fiber,
|
|
736
|
+
process.env.NODE_ENV !== 'production'
|
|
737
|
+
? new Error(`Hydration ${tag} value mismatch on <${tag}>.`)
|
|
738
|
+
: undefined,
|
|
739
|
+
recoverInPlace,
|
|
740
|
+
)
|
|
704
741
|
}
|
|
705
742
|
}
|
|
706
743
|
continue
|
|
@@ -710,10 +747,13 @@ function validateHydrationProps(
|
|
|
710
747
|
if (tag === 'input' && (k === 'checked' || k === 'defaultChecked')) {
|
|
711
748
|
if (k === 'checked' || props.checked == null) {
|
|
712
749
|
if (value != null && (el as HTMLInputElement).checked !== !!value) {
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
750
|
+
failHydration(
|
|
751
|
+
fiber,
|
|
752
|
+
process.env.NODE_ENV !== 'production'
|
|
753
|
+
? new Error(`Hydration checked mismatch on <input>.`)
|
|
754
|
+
: undefined,
|
|
755
|
+
recoverInPlace,
|
|
756
|
+
)
|
|
717
757
|
}
|
|
718
758
|
}
|
|
719
759
|
continue
|
|
@@ -721,10 +761,13 @@ function validateHydrationProps(
|
|
|
721
761
|
|
|
722
762
|
if (tag === 'option' && k === 'selected') {
|
|
723
763
|
if (value != null && (el as HTMLOptionElement).selected !== !!value) {
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
764
|
+
failHydration(
|
|
765
|
+
fiber,
|
|
766
|
+
process.env.NODE_ENV !== 'production'
|
|
767
|
+
? new Error(`Hydration selected mismatch on <option>.`)
|
|
768
|
+
: undefined,
|
|
769
|
+
recoverInPlace,
|
|
770
|
+
)
|
|
728
771
|
}
|
|
729
772
|
continue
|
|
730
773
|
}
|
|
@@ -732,24 +775,33 @@ function validateHydrationProps(
|
|
|
732
775
|
if (k === 'style') {
|
|
733
776
|
expected ??= createHostNode(tag, isSvg)
|
|
734
777
|
setProp(expected, k, value, undefined, isSvg)
|
|
735
|
-
if (
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
778
|
+
if (
|
|
779
|
+
!hydrationStylesMatch(
|
|
780
|
+
(el as HTMLElement).style,
|
|
781
|
+
(expected as HTMLElement).style,
|
|
782
|
+
)
|
|
783
|
+
) {
|
|
784
|
+
failHydration(
|
|
785
|
+
fiber,
|
|
786
|
+
process.env.NODE_ENV !== 'production'
|
|
787
|
+
? new Error(`Hydration style mismatch on <${tag}>.`)
|
|
788
|
+
: undefined,
|
|
789
|
+
recoverInPlace,
|
|
790
|
+
)
|
|
743
791
|
}
|
|
744
792
|
continue
|
|
745
793
|
}
|
|
746
794
|
|
|
747
|
-
const stringifiedBoolean = k.startsWith('aria-') || k.startsWith('data-')
|
|
748
795
|
const attr = attributeName(k, isSvg)
|
|
796
|
+
const stringifiedBoolean =
|
|
797
|
+
STRING_BOOLEAN_ATTRS.has(attr) || k.startsWith('aria-') || k.startsWith('data-')
|
|
749
798
|
|
|
750
799
|
let expectedValue: string | null
|
|
751
800
|
if (value == null || (value === false && !stringifiedBoolean)) {
|
|
752
801
|
expectedValue = null
|
|
802
|
+
} else if (k === 'muted' && !isSvg && (tag === 'video' || tag === 'audio')) {
|
|
803
|
+
// The muted property controls playback; defaultMuted reflects the SSR attribute.
|
|
804
|
+
expectedValue = value ? '' : null
|
|
753
805
|
} else {
|
|
754
806
|
expected ??= createHostNode(tag, isSvg)
|
|
755
807
|
setProp(expected, k, value, undefined, isSvg)
|
|
@@ -757,20 +809,36 @@ function validateHydrationProps(
|
|
|
757
809
|
}
|
|
758
810
|
const actualValue = el.getAttribute(attr)
|
|
759
811
|
if (expectedValue !== actualValue) {
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
new Error(
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
812
|
+
failHydration(
|
|
813
|
+
fiber,
|
|
814
|
+
process.env.NODE_ENV !== 'production'
|
|
815
|
+
? new Error(
|
|
816
|
+
`Hydration attribute mismatch on <${tag}> for "${attr}": ` +
|
|
817
|
+
`expected ${formatHydrationValue(expectedValue)} but found ${formatHydrationValue(actualValue)}.`,
|
|
818
|
+
)
|
|
819
|
+
: undefined,
|
|
820
|
+
recoverInPlace,
|
|
821
|
+
)
|
|
770
822
|
}
|
|
771
823
|
}
|
|
772
824
|
}
|
|
773
825
|
|
|
826
|
+
function hydrationStylesMatch(
|
|
827
|
+
actual: CSSStyleDeclaration,
|
|
828
|
+
expected: CSSStyleDeclaration,
|
|
829
|
+
): boolean {
|
|
830
|
+
for (let index = 0; index < expected.length; index++) {
|
|
831
|
+
const property = expected.item(index)
|
|
832
|
+
if (
|
|
833
|
+
actual.getPropertyValue(property) !== expected.getPropertyValue(property) ||
|
|
834
|
+
actual.getPropertyPriority(property) !== expected.getPropertyPriority(property)
|
|
835
|
+
) {
|
|
836
|
+
return false
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
return true
|
|
840
|
+
}
|
|
841
|
+
|
|
774
842
|
function formatHydrationValue(value: string | null): string {
|
|
775
843
|
return value == null ? 'nothing' : JSON.stringify(value)
|
|
776
844
|
}
|
package/src/server/escape.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { attributeName } from '../core/attributes'
|
|
1
|
+
import { attributeName, STRING_BOOLEAN_ATTRS } from '../core/attributes'
|
|
2
2
|
|
|
3
3
|
const ATTR_MAP: Record<string, string> = {
|
|
4
4
|
'&': '&',
|
|
@@ -96,11 +96,12 @@ export function attrToHtml(name: string, value: unknown, isSvg = false): string
|
|
|
96
96
|
|
|
97
97
|
const htmlName = attributeName(name, isSvg)
|
|
98
98
|
|
|
99
|
-
//
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
99
|
+
// These attributes need explicit "false", not boolean-attribute absence.
|
|
100
|
+
if (
|
|
101
|
+
STRING_BOOLEAN_ATTRS.has(htmlName) ||
|
|
102
|
+
name.startsWith('aria-') ||
|
|
103
|
+
name.startsWith('data-')
|
|
104
|
+
) {
|
|
104
105
|
return ` ${htmlName}="${escapeAttr(String(value))}"`
|
|
105
106
|
}
|
|
106
107
|
|