@tanstack/redact 0.0.1

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.
Files changed (233) hide show
  1. package/dist/core/index.d.ts +2 -0
  2. package/dist/core/index.js +4 -0
  3. package/dist/core/index.js.map +7 -0
  4. package/dist/core/internal.d.ts +76 -0
  5. package/dist/core/internal.js +59 -0
  6. package/dist/core/internal.js.map +7 -0
  7. package/dist/core/types.d.ts +21 -0
  8. package/dist/core/types.js +10 -0
  9. package/dist/core/types.js.map +7 -0
  10. package/dist/dom/_all.d.ts +17 -0
  11. package/dist/dom/_all.js +51 -0
  12. package/dist/dom/_all.js.map +7 -0
  13. package/dist/dom/client.d.ts +3 -0
  14. package/dist/dom/client.js +8 -0
  15. package/dist/dom/client.js.map +7 -0
  16. package/dist/dom/dispatcher.d.ts +20 -0
  17. package/dist/dom/dispatcher.js +267 -0
  18. package/dist/dom/dispatcher.js.map +7 -0
  19. package/dist/dom/dom.d.ts +10 -0
  20. package/dist/dom/dom.js +262 -0
  21. package/dist/dom/dom.js.map +7 -0
  22. package/dist/dom/event-replay.d.ts +13 -0
  23. package/dist/dom/event-replay.js +46 -0
  24. package/dist/dom/event-replay.js.map +7 -0
  25. package/dist/dom/features/class/full.d.ts +1 -0
  26. package/dist/dom/features/class/full.js +91 -0
  27. package/dist/dom/features/class/full.js.map +7 -0
  28. package/dist/dom/features/class/index.d.ts +1 -0
  29. package/dist/dom/features/class/index.js +3 -0
  30. package/dist/dom/features/class/index.js.map +7 -0
  31. package/dist/dom/features/class/stub.d.ts +1 -0
  32. package/dist/dom/features/class/stub.js +50 -0
  33. package/dist/dom/features/class/stub.js.map +7 -0
  34. package/dist/dom/features/context/full.d.ts +1 -0
  35. package/dist/dom/features/context/full.js +49 -0
  36. package/dist/dom/features/context/full.js.map +7 -0
  37. package/dist/dom/features/context/index.d.ts +1 -0
  38. package/dist/dom/features/context/index.js +3 -0
  39. package/dist/dom/features/context/index.js.map +7 -0
  40. package/dist/dom/features/context/stub.d.ts +1 -0
  41. package/dist/dom/features/context/stub.js +22 -0
  42. package/dist/dom/features/context/stub.js.map +7 -0
  43. package/dist/dom/features/forward-ref/full.d.ts +1 -0
  44. package/dist/dom/features/forward-ref/full.js +51 -0
  45. package/dist/dom/features/forward-ref/full.js.map +7 -0
  46. package/dist/dom/features/forward-ref/index.d.ts +1 -0
  47. package/dist/dom/features/forward-ref/index.js +3 -0
  48. package/dist/dom/features/forward-ref/index.js.map +7 -0
  49. package/dist/dom/features/forward-ref/stub.d.ts +1 -0
  50. package/dist/dom/features/forward-ref/stub.js +22 -0
  51. package/dist/dom/features/forward-ref/stub.js.map +7 -0
  52. package/dist/dom/features/hydration/full.d.ts +61 -0
  53. package/dist/dom/features/hydration/full.js +264 -0
  54. package/dist/dom/features/hydration/full.js.map +7 -0
  55. package/dist/dom/features/hydration/index.d.ts +1 -0
  56. package/dist/dom/features/hydration/index.js +3 -0
  57. package/dist/dom/features/hydration/index.js.map +7 -0
  58. package/dist/dom/features/hydration/stub.d.ts +28 -0
  59. package/dist/dom/features/hydration/stub.js +66 -0
  60. package/dist/dom/features/hydration/stub.js.map +7 -0
  61. package/dist/dom/features/index.d.ts +7 -0
  62. package/dist/dom/features/index.js +9 -0
  63. package/dist/dom/features/index.js.map +7 -0
  64. package/dist/dom/features/lazy/full.d.ts +1 -0
  65. package/dist/dom/features/lazy/full.js +78 -0
  66. package/dist/dom/features/lazy/full.js.map +7 -0
  67. package/dist/dom/features/lazy/index.d.ts +1 -0
  68. package/dist/dom/features/lazy/index.js +3 -0
  69. package/dist/dom/features/lazy/index.js.map +7 -0
  70. package/dist/dom/features/lazy/stub.d.ts +1 -0
  71. package/dist/dom/features/lazy/stub.js +36 -0
  72. package/dist/dom/features/lazy/stub.js.map +7 -0
  73. package/dist/dom/features/memo/full.d.ts +1 -0
  74. package/dist/dom/features/memo/full.js +59 -0
  75. package/dist/dom/features/memo/full.js.map +7 -0
  76. package/dist/dom/features/memo/index.d.ts +1 -0
  77. package/dist/dom/features/memo/index.js +3 -0
  78. package/dist/dom/features/memo/index.js.map +7 -0
  79. package/dist/dom/features/memo/stub.d.ts +1 -0
  80. package/dist/dom/features/memo/stub.js +36 -0
  81. package/dist/dom/features/memo/stub.js.map +7 -0
  82. package/dist/dom/features/portal/full.d.ts +1 -0
  83. package/dist/dom/features/portal/full.js +19 -0
  84. package/dist/dom/features/portal/full.js.map +7 -0
  85. package/dist/dom/features/portal/index.d.ts +1 -0
  86. package/dist/dom/features/portal/index.js +3 -0
  87. package/dist/dom/features/portal/index.js.map +7 -0
  88. package/dist/dom/features/portal/stub.d.ts +1 -0
  89. package/dist/dom/features/portal/stub.js +7 -0
  90. package/dist/dom/features/portal/stub.js.map +7 -0
  91. package/dist/dom/features/suspense/full.d.ts +1 -0
  92. package/dist/dom/features/suspense/full.js +146 -0
  93. package/dist/dom/features/suspense/full.js.map +7 -0
  94. package/dist/dom/features/suspense/index.d.ts +1 -0
  95. package/dist/dom/features/suspense/index.js +3 -0
  96. package/dist/dom/features/suspense/index.js.map +7 -0
  97. package/dist/dom/features/suspense/stub.d.ts +1 -0
  98. package/dist/dom/features/suspense/stub.js +6 -0
  99. package/dist/dom/features/suspense/stub.js.map +7 -0
  100. package/dist/dom/index.d.ts +25 -0
  101. package/dist/dom/index.js +45 -0
  102. package/dist/dom/index.js.map +7 -0
  103. package/dist/dom/portal.d.ts +2 -0
  104. package/dist/dom/portal.js +15 -0
  105. package/dist/dom/portal.js.map +7 -0
  106. package/dist/dom/reconcile.d.ts +40 -0
  107. package/dist/dom/reconcile.js +795 -0
  108. package/dist/dom/reconcile.js.map +7 -0
  109. package/dist/dom/root.d.ts +15 -0
  110. package/dist/dom/root.js +85 -0
  111. package/dist/dom/root.js.map +7 -0
  112. package/dist/dom/test-utils.d.ts +1 -0
  113. package/dist/dom/test-utils.js +10 -0
  114. package/dist/dom/test-utils.js.map +7 -0
  115. package/dist/react/children.d.ts +8 -0
  116. package/dist/react/children.js +75 -0
  117. package/dist/react/children.js.map +7 -0
  118. package/dist/react/class.d.ts +31 -0
  119. package/dist/react/class.js +40 -0
  120. package/dist/react/class.js.map +7 -0
  121. package/dist/react/context.d.ts +27 -0
  122. package/dist/react/context.js +31 -0
  123. package/dist/react/context.js.map +7 -0
  124. package/dist/react/element.d.ts +10 -0
  125. package/dist/react/element.js +64 -0
  126. package/dist/react/element.js.map +7 -0
  127. package/dist/react/hooks.d.ts +37 -0
  128. package/dist/react/hooks.js +146 -0
  129. package/dist/react/hooks.js.map +7 -0
  130. package/dist/react/index.d.ts +76 -0
  131. package/dist/react/index.js +187 -0
  132. package/dist/react/index.js.map +7 -0
  133. package/dist/react/jsx-runtime.d.ts +5 -0
  134. package/dist/react/jsx-runtime.js +21 -0
  135. package/dist/react/jsx-runtime.js.map +7 -0
  136. package/dist/react/memo.d.ts +29 -0
  137. package/dist/react/memo.js +47 -0
  138. package/dist/react/memo.js.map +7 -0
  139. package/dist/react/portal.d.ts +1 -0
  140. package/dist/react/portal.js +6 -0
  141. package/dist/react/portal.js.map +7 -0
  142. package/dist/react/shared-internals.d.ts +33 -0
  143. package/dist/react/shared-internals.js +29 -0
  144. package/dist/react/shared-internals.js.map +7 -0
  145. package/dist/react/suspense.d.ts +15 -0
  146. package/dist/react/suspense.js +16 -0
  147. package/dist/react/suspense.js.map +7 -0
  148. package/dist/scheduler/index.d.ts +44 -0
  149. package/dist/scheduler/index.js +109 -0
  150. package/dist/scheduler/index.js.map +7 -0
  151. package/dist/server/bootstrap-script.d.ts +22 -0
  152. package/dist/server/bootstrap-script.js +16 -0
  153. package/dist/server/bootstrap-script.js.map +7 -0
  154. package/dist/server/dispatcher.d.ts +37 -0
  155. package/dist/server/dispatcher.js +140 -0
  156. package/dist/server/dispatcher.js.map +7 -0
  157. package/dist/server/escape.d.ts +7 -0
  158. package/dist/server/escape.js +159 -0
  159. package/dist/server/escape.js.map +7 -0
  160. package/dist/server/index.d.ts +16 -0
  161. package/dist/server/index.js +26 -0
  162. package/dist/server/index.js.map +7 -0
  163. package/dist/server/renderToString.d.ts +7 -0
  164. package/dist/server/renderToString.js +29 -0
  165. package/dist/server/renderToString.js.map +7 -0
  166. package/dist/server/stream.d.ts +40 -0
  167. package/dist/server/stream.js +200 -0
  168. package/dist/server/stream.js.map +7 -0
  169. package/dist/server/walk.d.ts +33 -0
  170. package/dist/server/walk.js +298 -0
  171. package/dist/server/walk.js.map +7 -0
  172. package/dist/vite/index.d.ts +96 -0
  173. package/dist/vite/index.js +217 -0
  174. package/dist/vite/index.js.map +7 -0
  175. package/package.json +83 -0
  176. package/src/core/index.ts +2 -0
  177. package/src/core/internal.ts +107 -0
  178. package/src/core/types.ts +36 -0
  179. package/src/dom/_all.ts +54 -0
  180. package/src/dom/client.ts +4 -0
  181. package/src/dom/dispatcher.ts +318 -0
  182. package/src/dom/dom.ts +316 -0
  183. package/src/dom/event-replay.ts +55 -0
  184. package/src/dom/features/class/full.ts +104 -0
  185. package/src/dom/features/class/index.ts +1 -0
  186. package/src/dom/features/class/stub.ts +65 -0
  187. package/src/dom/features/context/full.ts +57 -0
  188. package/src/dom/features/context/index.ts +1 -0
  189. package/src/dom/features/context/stub.ts +32 -0
  190. package/src/dom/features/forward-ref/full.ts +54 -0
  191. package/src/dom/features/forward-ref/index.ts +1 -0
  192. package/src/dom/features/forward-ref/stub.ts +28 -0
  193. package/src/dom/features/hydration/full.ts +345 -0
  194. package/src/dom/features/hydration/index.ts +1 -0
  195. package/src/dom/features/hydration/stub.ts +72 -0
  196. package/src/dom/features/index.ts +11 -0
  197. package/src/dom/features/lazy/full.ts +98 -0
  198. package/src/dom/features/lazy/index.ts +1 -0
  199. package/src/dom/features/lazy/stub.ts +45 -0
  200. package/src/dom/features/memo/full.ts +74 -0
  201. package/src/dom/features/memo/index.ts +1 -0
  202. package/src/dom/features/memo/stub.ts +42 -0
  203. package/src/dom/features/portal/full.ts +22 -0
  204. package/src/dom/features/portal/index.ts +1 -0
  205. package/src/dom/features/portal/stub.ts +11 -0
  206. package/src/dom/features/suspense/full.ts +191 -0
  207. package/src/dom/features/suspense/index.ts +1 -0
  208. package/src/dom/features/suspense/stub.ts +12 -0
  209. package/src/dom/index.ts +33 -0
  210. package/src/dom/portal.ts +16 -0
  211. package/src/dom/reconcile.ts +1169 -0
  212. package/src/dom/root.ts +107 -0
  213. package/src/dom/test-utils.ts +6 -0
  214. package/src/react/children.ts +85 -0
  215. package/src/react/class.ts +56 -0
  216. package/src/react/context.ts +50 -0
  217. package/src/react/element.ts +80 -0
  218. package/src/react/hooks.ts +190 -0
  219. package/src/react/index.ts +132 -0
  220. package/src/react/jsx-runtime.ts +16 -0
  221. package/src/react/memo.ts +45 -0
  222. package/src/react/portal.ts +1 -0
  223. package/src/react/shared-internals.ts +79 -0
  224. package/src/react/suspense.ts +18 -0
  225. package/src/scheduler/index.ts +124 -0
  226. package/src/server/bootstrap-script.ts +52 -0
  227. package/src/server/dispatcher.ts +158 -0
  228. package/src/server/escape.ts +187 -0
  229. package/src/server/index.ts +26 -0
  230. package/src/server/renderToString.ts +33 -0
  231. package/src/server/stream.ts +302 -0
  232. package/src/server/walk.ts +448 -0
  233. package/src/vite/index.ts +401 -0
package/src/dom/dom.ts ADDED
@@ -0,0 +1,316 @@
1
+ const SVG_NS = 'http://www.w3.org/2000/svg'
2
+
3
+ const BOOLEAN_ATTRS = new Set([
4
+ 'allowfullscreen',
5
+ 'async',
6
+ 'autofocus',
7
+ 'autoplay',
8
+ 'checked',
9
+ 'controls',
10
+ 'default',
11
+ 'defer',
12
+ 'disabled',
13
+ 'formnovalidate',
14
+ 'hidden',
15
+ 'inert',
16
+ 'ismap',
17
+ 'itemscope',
18
+ 'loop',
19
+ 'multiple',
20
+ 'muted',
21
+ 'nomodule',
22
+ 'novalidate',
23
+ 'open',
24
+ 'playsinline',
25
+ 'readonly',
26
+ 'required',
27
+ 'reversed',
28
+ 'selected',
29
+ ])
30
+
31
+ const IDL_ATTRS = new Set([
32
+ 'value',
33
+ 'checked',
34
+ 'selected',
35
+ 'disabled',
36
+ 'multiple',
37
+ 'muted',
38
+ 'readonly',
39
+ 'contentEditable',
40
+ 'spellcheck',
41
+ 'draggable',
42
+ ])
43
+
44
+ export function createHostNode(type: string, isSvg: boolean): Element {
45
+ if (isSvg || type === 'svg') {
46
+ return document.createElementNS(SVG_NS, type)
47
+ }
48
+ return document.createElement(type)
49
+ }
50
+
51
+ export function isSvgElement(el: Element): boolean {
52
+ return (el as any).ownerSVGElement !== undefined || el.tagName === 'svg'
53
+ }
54
+
55
+ export function setProp(
56
+ el: Element,
57
+ name: string,
58
+ next: any,
59
+ prev: any,
60
+ isSvg: boolean,
61
+ ): void {
62
+ if (name === 'children' || name === 'key' || name === 'ref') return
63
+
64
+ // defaultValue / defaultChecked are IDL-property-only — they seed the
65
+ // initial value/checked of a form control on first mount and must NOT be
66
+ // emitted as HTML attributes (which would leak as `defaultValue="..."`).
67
+ // Setting `el.defaultValue` on a fresh control also sets the initial
68
+ // `el.value`, which is what consumers expect. Skip on hydrated DOM so we
69
+ // don't clobber a live user-typed value.
70
+ if (name === 'defaultValue' || name === 'defaultChecked') {
71
+ if (prev === undefined && next != null) {
72
+ try {
73
+ ;(el as any)[name] = next
74
+ } catch {}
75
+ }
76
+ return
77
+ }
78
+
79
+ if (name === 'className') {
80
+ if (isSvg) {
81
+ if (next == null) el.removeAttribute('class')
82
+ else el.setAttribute('class', '' + next)
83
+ } else {
84
+ ;(el as HTMLElement).className = next == null ? '' : '' + next
85
+ }
86
+ return
87
+ }
88
+
89
+ if (name === 'class') {
90
+ if (next == null) el.removeAttribute('class')
91
+ else el.setAttribute('class', '' + next)
92
+ return
93
+ }
94
+
95
+ if (name === 'style') {
96
+ setStyle(el as HTMLElement, next, prev)
97
+ return
98
+ }
99
+
100
+ if (name === 'dangerouslySetInnerHTML') {
101
+ const nextHtml = next?.__html ?? ''
102
+ const prevHtml = prev?.__html ?? ''
103
+ if (nextHtml !== prevHtml) (el as HTMLElement).innerHTML = nextHtml
104
+ return
105
+ }
106
+
107
+ if (name[0] === 'o' && name[1] === 'n') {
108
+ setEventHandler(el, name, next, prev)
109
+ return
110
+ }
111
+
112
+ if (name === 'htmlFor') {
113
+ if (next == null) el.removeAttribute('for')
114
+ else el.setAttribute('for', '' + next)
115
+ return
116
+ }
117
+
118
+ if (!isSvg && IDL_ATTRS.has(name) && name in el) {
119
+ try {
120
+ ;(el as any)[name] = next == null ? '' : next
121
+ return
122
+ } catch {}
123
+ }
124
+
125
+ if (BOOLEAN_ATTRS.has(name.toLowerCase())) {
126
+ if (next) el.setAttribute(name, '')
127
+ else el.removeAttribute(name)
128
+ return
129
+ }
130
+
131
+ // aria-* and data-* attributes stringify booleans to `"true"`/`"false"`
132
+ // rather than using the HTML boolean-attribute presence/absence semantics.
133
+ // This matches React and the ARIA spec (aria-hidden="false" is meaningful).
134
+ if (name.length > 5 && (name.charCodeAt(0) === 97 /* a */ || name.charCodeAt(0) === 100 /* d */)) {
135
+ if (name.startsWith('aria-') || name.startsWith('data-')) {
136
+ if (next == null) {
137
+ el.removeAttribute(name)
138
+ } else {
139
+ el.setAttribute(name, '' + next)
140
+ }
141
+ return
142
+ }
143
+ }
144
+
145
+ if (next == null || next === false) {
146
+ el.removeAttribute(name)
147
+ } else if (next === true) {
148
+ el.setAttribute(name, '')
149
+ } else {
150
+ el.setAttribute(name, '' + next)
151
+ }
152
+ }
153
+
154
+ function setStyle(el: HTMLElement, next: any, prev: any): void {
155
+ const style = el.style
156
+ if (typeof next === 'string') {
157
+ style.cssText = next
158
+ return
159
+ }
160
+ if (typeof prev === 'string') style.cssText = ''
161
+ if (prev && typeof prev === 'object') {
162
+ for (const k in prev) {
163
+ if (!next || !(k in next)) setStyleProperty(style, k, '')
164
+ }
165
+ }
166
+ if (next && typeof next === 'object') {
167
+ for (const k in next) {
168
+ if (!prev || prev[k] !== next[k]) setStyleProperty(style, k, next[k])
169
+ }
170
+ }
171
+ }
172
+
173
+ function setStyleProperty(style: CSSStyleDeclaration, key: string, value: any): void {
174
+ if (key[0] === '-') {
175
+ style.setProperty(key, value == null ? '' : '' + value)
176
+ } else if (value == null || value === '') {
177
+ ;(style as any)[key] = ''
178
+ } else if (typeof value === 'number' && !UNITLESS_STYLE.has(key)) {
179
+ ;(style as any)[key] = value + 'px'
180
+ } else {
181
+ ;(style as any)[key] = '' + value
182
+ }
183
+ }
184
+
185
+ const UNITLESS_STYLE = new Set([
186
+ 'animationIterationCount',
187
+ 'borderImageOutset',
188
+ 'borderImageSlice',
189
+ 'borderImageWidth',
190
+ 'boxFlex',
191
+ 'boxFlexGroup',
192
+ 'boxOrdinalGroup',
193
+ 'columnCount',
194
+ 'columns',
195
+ 'flex',
196
+ 'flexGrow',
197
+ 'flexPositive',
198
+ 'flexShrink',
199
+ 'flexNegative',
200
+ 'flexOrder',
201
+ 'gridArea',
202
+ 'gridRow',
203
+ 'gridRowEnd',
204
+ 'gridRowSpan',
205
+ 'gridRowStart',
206
+ 'gridColumn',
207
+ 'gridColumnEnd',
208
+ 'gridColumnSpan',
209
+ 'gridColumnStart',
210
+ 'fontWeight',
211
+ 'lineClamp',
212
+ 'lineHeight',
213
+ 'opacity',
214
+ 'order',
215
+ 'orphans',
216
+ 'tabSize',
217
+ 'widows',
218
+ 'zIndex',
219
+ 'zoom',
220
+ 'fillOpacity',
221
+ 'floodOpacity',
222
+ 'stopOpacity',
223
+ 'strokeDasharray',
224
+ 'strokeDashoffset',
225
+ 'strokeMiterlimit',
226
+ 'strokeOpacity',
227
+ 'strokeWidth',
228
+ ])
229
+
230
+ export interface SyntheticEvent extends Event {
231
+ nativeEvent: Event
232
+ isDefaultPrevented(): boolean
233
+ isPropagationStopped(): boolean
234
+ persist(): void
235
+ currentTarget: EventTarget & Element
236
+ }
237
+
238
+ function setEventHandler(el: Element, name: string, next: any, prev: any): void {
239
+ // Only function handlers are accepted. Reject strings/objects/etc — the
240
+ // legacy `onclick="..."` HTML attribute (string handler) is a known XSS
241
+ // vector if a parent spreads untrusted props onto a host element. React
242
+ // also ignores non-function handlers.
243
+ if (next != null && typeof next !== 'function') next = null
244
+
245
+ const capture = name.endsWith('Capture')
246
+ const reactEventName = name.slice(2, capture ? -7 : undefined)
247
+ const eventName = domEventFor(reactEventName, el)
248
+
249
+ // Key by the React prop name (not DOM event name) so `onChange` and
250
+ // `onInput` on the same text input — which both dispatch from the native
251
+ // `input` event — can coexist without clobbering each other's handlers.
252
+ const handlers = ((el as any).__handlers ||= Object.create(null))
253
+ const key = name
254
+
255
+ const existing = handlers[key]
256
+
257
+ if (existing && !next) {
258
+ el.removeEventListener(existing.event, existing.listener, existing.capture)
259
+ handlers[key] = null
260
+ return
261
+ }
262
+
263
+ if (!existing && next) {
264
+ const entry = {
265
+ current: next as Function,
266
+ listener: null as any,
267
+ event: eventName,
268
+ capture,
269
+ }
270
+ entry.listener = (e: Event) => {
271
+ // React hands handlers a SyntheticEvent that carries `.nativeEvent`.
272
+ // Many libraries check `event.nativeEvent.isComposing` (react-instantsearch)
273
+ // or `event.nativeEvent.shiftKey` (UI kits) — without the alias they throw
274
+ // on `undefined.foo`. Aliasing the native event to itself is the cheapest
275
+ // way to satisfy the shape without building a full synthetic layer.
276
+ if ((e as any).nativeEvent === undefined) (e as any).nativeEvent = e
277
+ entry.current(e)
278
+ }
279
+ handlers[key] = entry
280
+ el.addEventListener(eventName, entry.listener, capture)
281
+ return
282
+ }
283
+
284
+ if (existing) {
285
+ // Re-bind if the effective DOM event changed (e.g. <input> whose `type`
286
+ // flipped from "text" to "checkbox" — onChange should now follow `change`
287
+ // instead of `input`). This is rare but keeps semantics correct.
288
+ if (existing.event !== eventName || existing.capture !== capture) {
289
+ el.removeEventListener(existing.event, existing.listener, existing.capture)
290
+ existing.event = eventName
291
+ existing.capture = capture
292
+ el.addEventListener(eventName, existing.listener, capture)
293
+ }
294
+ existing.current = next
295
+ }
296
+ }
297
+
298
+ function domEventFor(reactEventName: string, el: Element): string {
299
+ const lower = reactEventName.toLowerCase()
300
+ // React's `onChange` on text-like <input> and <textarea> maps to the
301
+ // native `input` event so handlers fire on every keystroke. On checkbox,
302
+ // radio, file inputs, and <select>, React's `onChange` maps to the
303
+ // native `change` event (which fires on click / option select).
304
+ if (lower === 'change') {
305
+ const tag = el.tagName
306
+ if (tag === 'TEXTAREA') return 'input'
307
+ if (tag === 'INPUT') {
308
+ const type = ((el as HTMLInputElement).type || 'text').toLowerCase()
309
+ if (type !== 'checkbox' && type !== 'radio' && type !== 'file') {
310
+ return 'input'
311
+ }
312
+ }
313
+ }
314
+ if (lower === 'doubleclick') return 'dblclick'
315
+ return lower
316
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Drain the `window.$RE_q` event buffer that the inline runtime populated
3
+ * before the main bundle was parsed. For each buffered event, re-dispatch a
4
+ * synthesized event at the original target so handlers attached during
5
+ * hydration see it.
6
+ *
7
+ * Lossy by design: only the event type and target are preserved. Modifier
8
+ * keys, pointer positions, etc. are zeroed. This is acceptable because the
9
+ * replay window is a fraction of a second between shell render and full
10
+ * hydration of a streaming page; users who need pixel-accurate replay won't
11
+ * lose much beyond that.
12
+ */
13
+ export function drainReplayQueue(): void {
14
+ const g = globalThis as any
15
+ const q = g.$RE_q as Array<[string, EventTarget, number]> | undefined
16
+ if (!q) return
17
+
18
+ // Stop capturing before replaying so we don't re-capture what we dispatch.
19
+ if (typeof g.$RE_stop === 'function') {
20
+ try {
21
+ g.$RE_stop()
22
+ } catch {}
23
+ }
24
+
25
+ const events = q.splice(0)
26
+ for (const [type, target] of events) {
27
+ try {
28
+ const ev = createEvent(type)
29
+ target.dispatchEvent(ev)
30
+ } catch {}
31
+ }
32
+ }
33
+
34
+ function createEvent(type: string): Event {
35
+ switch (type) {
36
+ case 'click':
37
+ case 'dblclick':
38
+ case 'mousedown':
39
+ case 'mouseup':
40
+ case 'contextmenu':
41
+ return new MouseEvent(type, { bubbles: true, cancelable: true })
42
+ case 'keydown':
43
+ case 'keyup':
44
+ case 'keypress':
45
+ return new KeyboardEvent(type, { bubbles: true, cancelable: true })
46
+ case 'input':
47
+ return new InputEvent(type, { bubbles: true, cancelable: true })
48
+ case 'submit':
49
+ case 'change':
50
+ case 'focus':
51
+ case 'blur':
52
+ default:
53
+ return new Event(type, { bubbles: true, cancelable: true })
54
+ }
55
+ }
@@ -0,0 +1,104 @@
1
+ import { FiberTag, type Fiber, type ReactNode } from '../../../core'
2
+ import {
3
+ registerRenderer,
4
+ reconcileChildren,
5
+ childrenToArray,
6
+ scheduleUpdate,
7
+ scheduleLifecycle,
8
+ isThenable,
9
+ handleSuspended,
10
+ handleErrorInRender,
11
+ } from '../../reconcile'
12
+
13
+ function renderClass(fiber: Fiber, domParent: Node, anchor: Node | null): void {
14
+ const Ctor = fiber.type as any
15
+ let instance = fiber.stateNode
16
+ const props = fiber.pendingProps ?? {}
17
+ const isNew = !instance
18
+
19
+ // Class contextType: read the current value of the subscribed context so
20
+ // `this.context` reflects the nearest Provider. Evaluated every render.
21
+ const ctxValue = Ctor.contextType ? Ctor.contextType._currentValue : undefined
22
+
23
+ if (isNew) {
24
+ instance = new Ctor(props, ctxValue)
25
+ instance.props = props
26
+ instance.context = ctxValue
27
+ instance._fiber = fiber
28
+ instance._enqueueUpdate = (updater: any, cb?: () => void) => {
29
+ const next = typeof updater === 'function' ? updater(instance.state, instance.props) : updater
30
+ if (next != null) instance.state = { ...instance.state, ...next }
31
+ if (cb) {
32
+ fiber.cleanups ||= []
33
+ fiber.cleanups.push(cb)
34
+ }
35
+ scheduleUpdate(fiber)
36
+ }
37
+ instance._forceUpdate = (cb?: () => void) => {
38
+ if (cb) {
39
+ fiber.cleanups ||= []
40
+ fiber.cleanups.push(cb)
41
+ }
42
+ scheduleUpdate(fiber)
43
+ }
44
+ fiber.stateNode = instance
45
+ if (Ctor.getDerivedStateFromProps) {
46
+ const d = Ctor.getDerivedStateFromProps(props, instance.state)
47
+ if (d) instance.state = { ...instance.state, ...d }
48
+ }
49
+ } else {
50
+ const prevProps = instance.props
51
+ const prevState = instance.state
52
+ // Refresh context on every render — Providers higher up may have changed.
53
+ instance.context = ctxValue
54
+ if (Ctor.getDerivedStateFromProps) {
55
+ const d = Ctor.getDerivedStateFromProps(props, instance.state)
56
+ if (d) instance.state = { ...instance.state, ...d }
57
+ }
58
+ if (instance.shouldComponentUpdate) {
59
+ if (!instance.shouldComponentUpdate(props, instance.state, instance.context)) {
60
+ instance.props = props
61
+ fiber.memoizedProps = props
62
+ // Still need to render children with previous output
63
+ if (fiber.memoizedState?.rendered) {
64
+ reconcileChildren(fiber, childrenToArray(fiber.memoizedState.rendered), domParent, anchor)
65
+ }
66
+ return
67
+ }
68
+ }
69
+ instance.props = props
70
+ // New snapshot must win over any stale one from a previous render —
71
+ // otherwise componentDidUpdate keeps seeing the original props and can
72
+ // ping-pong setState forever.
73
+ fiber.memoizedState = { ...(fiber.memoizedState ?? {}), prevProps, prevState }
74
+ }
75
+
76
+ let rendered: ReactNode
77
+ try {
78
+ rendered = instance.render()
79
+ } catch (e: any) {
80
+ if (isThenable(e)) {
81
+ handleSuspended(fiber, e)
82
+ rendered = null
83
+ } else {
84
+ handleErrorInRender(fiber, e)
85
+ return
86
+ }
87
+ }
88
+ fiber.memoizedState = { ...(fiber.memoizedState ?? {}), rendered }
89
+
90
+ reconcileChildren(fiber, childrenToArray(rendered), domParent, anchor)
91
+ fiber.memoizedProps = props
92
+
93
+ // Schedule lifecycle
94
+ if (isNew) {
95
+ if (instance.componentDidMount) {
96
+ scheduleLifecycle(fiber, () => instance.componentDidMount())
97
+ }
98
+ } else if (instance.componentDidUpdate) {
99
+ const { prevProps, prevState } = fiber.memoizedState ?? {}
100
+ scheduleLifecycle(fiber, () => instance.componentDidUpdate(prevProps, prevState))
101
+ }
102
+ }
103
+
104
+ registerRenderer(FiberTag.Class, renderClass)
@@ -0,0 +1 @@
1
+ export * from './full'
@@ -0,0 +1,65 @@
1
+ import { FiberTag, type Fiber, type ReactNode } from '../../../core'
2
+ import {
3
+ registerRenderer,
4
+ reconcileChildren,
5
+ childrenToArray,
6
+ scheduleUpdate,
7
+ isThenable,
8
+ handleSuspended,
9
+ handleErrorInRender,
10
+ } from '../../reconcile'
11
+
12
+ // Stub: Class feature disabled. Class components still render — they're
13
+ // detected by `type.prototype.isReactComponent` in the reconciler regardless —
14
+ // but ONLY the core contract is honored: constructor, `render()`, and
15
+ // `setState` triggering a re-render. Dropped from this stub:
16
+ // - `contextType` (this.context is always undefined)
17
+ // - `getDerivedStateFromProps`
18
+ // - `shouldComponentUpdate`
19
+ // - `componentDidMount` / `componentDidUpdate` / `componentWillUnmount`
20
+ // - `getDerivedStateFromError` / `componentDidCatch` (error boundaries)
21
+ // Apps that actually need these should keep the feature on. Apps that just
22
+ // have a handful of legacy class components that do `render() + setState`
23
+ // still work, and save ~400 B min / ~200 B gz.
24
+ function renderClassStub(fiber: Fiber, domParent: Node, anchor: Node | null): void {
25
+ const Ctor = fiber.type as any
26
+ let instance = fiber.stateNode
27
+ const props = fiber.pendingProps ?? {}
28
+
29
+ if (!instance) {
30
+ instance = new Ctor(props, undefined)
31
+ instance.props = props
32
+ instance._fiber = fiber
33
+ instance._enqueueUpdate = (updater: any, cb?: () => void) => {
34
+ const next = typeof updater === 'function' ? updater(instance.state, instance.props) : updater
35
+ if (next != null) instance.state = { ...instance.state, ...next }
36
+ if (cb) {
37
+ fiber.cleanups ||= []
38
+ fiber.cleanups.push(cb)
39
+ }
40
+ scheduleUpdate(fiber)
41
+ }
42
+ instance._forceUpdate = instance._enqueueUpdate
43
+ fiber.stateNode = instance
44
+ } else {
45
+ instance.props = props
46
+ }
47
+
48
+ let rendered: ReactNode
49
+ try {
50
+ rendered = instance.render()
51
+ } catch (e: any) {
52
+ if (isThenable(e)) {
53
+ handleSuspended(fiber, e)
54
+ rendered = null
55
+ } else {
56
+ handleErrorInRender(fiber, e)
57
+ return
58
+ }
59
+ }
60
+
61
+ reconcileChildren(fiber, childrenToArray(rendered), domParent, anchor)
62
+ fiber.memoizedProps = props
63
+ }
64
+
65
+ registerRenderer(FiberTag.Class, renderClassStub)
@@ -0,0 +1,57 @@
1
+ import { FiberTag, type Fiber } from '../../../core'
2
+ import { REACT_PROVIDER_TYPE, REACT_CONSUMER_TYPE } from '../../../react'
3
+ import {
4
+ registerRenderer,
5
+ registerTypeMatcher,
6
+ installCapability,
7
+ reconcileChildren,
8
+ childrenToArray,
9
+ } from '../../reconcile'
10
+
11
+ function realReadContext(fiber: Fiber, ctx: any): any {
12
+ let p: Fiber | null = fiber.parent
13
+ while (p) {
14
+ if (p.tag === FiberTag.Provider && (p.type as any)._context === ctx) {
15
+ return (p.pendingProps ?? p.memoizedProps)?.value
16
+ }
17
+ p = p.parent
18
+ }
19
+ return ctx._currentValue
20
+ }
21
+
22
+ function renderProvider(fiber: Fiber, domParent: Node, anchor: Node | null): void {
23
+ const ctx = (fiber.type as any)._context
24
+ const props = fiber.pendingProps ?? {}
25
+ const prevValue = ctx._currentValue
26
+ ctx._currentValue = props.value
27
+ try {
28
+ reconcileChildren(fiber, childrenToArray(props.children), domParent, anchor)
29
+ } finally {
30
+ ctx._currentValue = prevValue
31
+ }
32
+ // Also store the value on the fiber so descendants rendering later (via updates)
33
+ // can read through by walking up.
34
+ fiber.memoizedState = props.value
35
+ fiber.memoizedProps = props
36
+ }
37
+
38
+ function renderConsumer(fiber: Fiber, domParent: Node, anchor: Node | null): void {
39
+ const ctx = (fiber.type as any)._context
40
+ const props = fiber.pendingProps ?? {}
41
+ const children = props.children
42
+ const value = realReadContext(fiber, ctx)
43
+ const rendered = typeof children === 'function' ? children(value) : null
44
+ reconcileChildren(fiber, childrenToArray(rendered), domParent, anchor)
45
+ fiber.memoizedProps = props
46
+ }
47
+
48
+ registerTypeMatcher((_type, marker) =>
49
+ marker === REACT_PROVIDER_TYPE
50
+ ? FiberTag.Provider
51
+ : marker === REACT_CONSUMER_TYPE
52
+ ? FiberTag.Consumer
53
+ : null,
54
+ )
55
+ registerRenderer(FiberTag.Provider, renderProvider)
56
+ registerRenderer(FiberTag.Consumer, renderConsumer)
57
+ installCapability('readContext', realReadContext)
@@ -0,0 +1 @@
1
+ export * from './full'
@@ -0,0 +1,32 @@
1
+ import { FiberTag, type Fiber } from '../../../core'
2
+ import { REACT_PROVIDER_TYPE, REACT_CONSUMER_TYPE } from '../../../react'
3
+ import {
4
+ registerRenderer,
5
+ registerTypeMatcher,
6
+ reconcileChildren,
7
+ childrenToArray,
8
+ } from '../../reconcile'
9
+
10
+ // Stub: Context feature disabled. Provider elements render as Fragments
11
+ // (value is never propagated — descendants see only the Context's default).
12
+ // Consumer elements still invoke their function-children with the default
13
+ // value, so `<Ctx.Consumer>{v => ...}</Ctx.Consumer>` patterns keep working.
14
+ // The default `readContext` capability returns `ctx._currentValue` without
15
+ // walking, which matches the no-Provider-fibers-in-tree reality.
16
+ function renderConsumerStub(fiber: Fiber, domParent: Node, anchor: Node | null): void {
17
+ const ctx = (fiber.type as any)._context
18
+ const props = fiber.pendingProps ?? {}
19
+ const value = ctx._currentValue
20
+ const rendered = typeof props.children === 'function' ? props.children(value) : null
21
+ reconcileChildren(fiber, childrenToArray(rendered), domParent, anchor)
22
+ fiber.memoizedProps = props
23
+ }
24
+
25
+ registerTypeMatcher((_type, marker) =>
26
+ marker === REACT_PROVIDER_TYPE
27
+ ? FiberTag.Fragment
28
+ : marker === REACT_CONSUMER_TYPE
29
+ ? FiberTag.Consumer
30
+ : null,
31
+ )
32
+ registerRenderer(FiberTag.Consumer, renderConsumerStub)
@@ -0,0 +1,54 @@
1
+ import { FiberTag, type Fiber, type ReactNode } from '../../../core'
2
+ import { ReactSharedInternals, REACT_FORWARD_REF_TYPE } from '../../../react'
3
+ import {
4
+ registerRenderer,
5
+ registerTypeMatcher,
6
+ reconcileChildren,
7
+ childrenToArray,
8
+ isThenable,
9
+ handleSuspended,
10
+ handleErrorInRender,
11
+ } from '../../reconcile'
12
+ import { makeDispatcher } from '../../dispatcher'
13
+
14
+ function renderForwardRef(fiber: Fiber, domParent: Node, anchor: Node | null): void {
15
+ const props = fiber.pendingProps ?? {}
16
+ const render = (fiber.type as any).render
17
+ const ref = fiber.ref ?? (props.ref ?? null)
18
+
19
+ const prevDispatcher = ReactSharedInternals.H
20
+ const prevFiber = ReactSharedInternals.currentFiber
21
+ const prevHook = ReactSharedInternals.currentHook
22
+ const prevIndex = ReactSharedInternals.hookIndex
23
+ ReactSharedInternals.H = makeDispatcher()
24
+ ReactSharedInternals.currentFiber = fiber
25
+ ReactSharedInternals.currentHook = null
26
+ ReactSharedInternals.hookIndex = 0
27
+
28
+ let rendered: ReactNode
29
+ try {
30
+ const { ref: _omit, ...rest } = props
31
+ rendered = render(rest, ref)
32
+ } catch (e: any) {
33
+ if (isThenable(e)) {
34
+ handleSuspended(fiber, e)
35
+ rendered = null
36
+ } else {
37
+ handleErrorInRender(fiber, e)
38
+ return
39
+ }
40
+ } finally {
41
+ ReactSharedInternals.H = prevDispatcher
42
+ ReactSharedInternals.currentFiber = prevFiber
43
+ ReactSharedInternals.currentHook = prevHook
44
+ ReactSharedInternals.hookIndex = prevIndex
45
+ }
46
+
47
+ reconcileChildren(fiber, childrenToArray(rendered), domParent, anchor)
48
+ fiber.memoizedProps = props
49
+ }
50
+
51
+ registerTypeMatcher((_type, marker) =>
52
+ marker === REACT_FORWARD_REF_TYPE ? FiberTag.ForwardRef : null,
53
+ )
54
+ registerRenderer(FiberTag.ForwardRef, renderForwardRef)
@@ -0,0 +1 @@
1
+ export * from './full'