@tanstack/redact 0.0.14 → 0.0.16
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/internal.d.ts +23 -39
- package/dist/core/internal.js +7 -23
- package/dist/core/internal.js.map +3 -3
- package/dist/dom/dispatcher.d.ts +3 -1
- package/dist/dom/dispatcher.js +104 -97
- package/dist/dom/dispatcher.js.map +2 -2
- package/dist/dom/dom.js +1 -1
- package/dist/dom/dom.js.map +2 -2
- package/dist/dom/event-replay.js +7 -29
- package/dist/dom/event-replay.js.map +2 -2
- package/dist/dom/features/class/full.js +16 -16
- package/dist/dom/features/class/full.js.map +2 -2
- package/dist/dom/features/class/stub.js +7 -7
- package/dist/dom/features/class/stub.js.map +2 -2
- package/dist/dom/features/context/full.js +7 -7
- package/dist/dom/features/context/full.js.map +2 -2
- package/dist/dom/features/context/stub.js +3 -3
- package/dist/dom/features/context/stub.js.map +2 -2
- package/dist/dom/features/forward-ref/full.js +11 -11
- package/dist/dom/features/forward-ref/full.js.map +2 -2
- package/dist/dom/features/hydration/full.d.ts +26 -14
- package/dist/dom/features/hydration/full.js +417 -92
- package/dist/dom/features/hydration/full.js.map +2 -2
- package/dist/dom/features/hydration/stub.d.ts +13 -12
- package/dist/dom/features/hydration/stub.js +23 -8
- package/dist/dom/features/hydration/stub.js.map +2 -2
- package/dist/dom/features/lazy/full.js +3 -43
- package/dist/dom/features/lazy/full.js.map +2 -2
- package/dist/dom/features/lazy/stub.js +1 -1
- package/dist/dom/features/lazy/stub.js.map +2 -2
- package/dist/dom/features/memo/full.js +3 -3
- package/dist/dom/features/memo/full.js.map +2 -2
- package/dist/dom/features/memo/stub.js +1 -1
- package/dist/dom/features/memo/stub.js.map +2 -2
- package/dist/dom/features/portal/full.js +2 -2
- package/dist/dom/features/portal/full.js.map +2 -2
- package/dist/dom/features/suspense/full.js +151 -111
- package/dist/dom/features/suspense/full.js.map +2 -2
- package/dist/dom/reconcile.d.ts +3 -1
- package/dist/dom/reconcile.js +141 -129
- package/dist/dom/reconcile.js.map +2 -2
- package/dist/dom/root-internal.d.ts +9 -0
- package/dist/dom/root-internal.js +31 -0
- package/dist/dom/root-internal.js.map +7 -0
- package/dist/dom/root.d.ts +1 -1
- package/dist/dom/root.js +4 -136
- package/dist/dom/root.js.map +2 -2
- package/dist/dom/test-utils.js +1 -1
- package/dist/dom/test-utils.js.map +2 -2
- package/dist/react/children.js +4 -1
- package/dist/react/children.js.map +2 -2
- package/dist/react/class.js +8 -2
- package/dist/react/class.js.map +2 -2
- package/dist/react/context.js +4 -1
- package/dist/react/context.js.map +2 -2
- package/dist/react/index.js +1 -1
- package/dist/react/index.js.map +2 -2
- package/dist/react/shared-internals.d.ts +4 -7
- package/dist/react/shared-internals.js +4 -7
- package/dist/react/shared-internals.js.map +2 -2
- package/dist/server/stream.d.ts +5 -1
- package/dist/server/stream.js.map +2 -2
- package/package.json +1 -1
- package/src/core/internal.ts +30 -50
- package/src/dom/dispatcher.ts +114 -105
- package/src/dom/dom.ts +1 -1
- package/src/dom/event-replay.ts +14 -30
- package/src/dom/features/class/full.ts +16 -16
- package/src/dom/features/class/stub.ts +7 -7
- package/src/dom/features/context/full.ts +7 -7
- package/src/dom/features/context/stub.ts +3 -3
- package/src/dom/features/forward-ref/full.ts +11 -11
- package/src/dom/features/hydration/full.ts +519 -104
- package/src/dom/features/hydration/stub.ts +28 -14
- package/src/dom/features/lazy/full.ts +3 -56
- package/src/dom/features/lazy/stub.ts +1 -1
- package/src/dom/features/memo/full.ts +3 -3
- package/src/dom/features/memo/stub.ts +1 -1
- package/src/dom/features/portal/full.ts +2 -2
- package/src/dom/features/suspense/full.ts +176 -131
- package/src/dom/reconcile.ts +164 -170
- package/src/dom/root-internal.ts +40 -0
- package/src/dom/root.ts +5 -165
- package/src/dom/test-utils.ts +1 -1
- package/src/react/children.ts +4 -1
- package/src/react/class.ts +8 -2
- package/src/react/context.ts +4 -1
- package/src/react/index.ts +1 -1
- package/src/react/shared-internals.ts +8 -14
- package/src/server/stream.ts +9 -4
package/src/dom/dispatcher.ts
CHANGED
|
@@ -3,37 +3,42 @@ import { ReactSharedInternals, REACT_CONTEXT_TYPE } from '../react'
|
|
|
3
3
|
import { scheduleUpdate, enqueueEffect, readContext } from './reconcile'
|
|
4
4
|
|
|
5
5
|
function getCurrentFiber(): Fiber {
|
|
6
|
-
const f = ReactSharedInternals.
|
|
7
|
-
if (!f)
|
|
6
|
+
const f = ReactSharedInternals.F
|
|
7
|
+
if (!f) {
|
|
8
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
9
|
+
throw new Error('Hook called outside a function component render.')
|
|
10
|
+
}
|
|
11
|
+
throw new Error()
|
|
12
|
+
}
|
|
8
13
|
return f
|
|
9
14
|
}
|
|
10
15
|
|
|
11
16
|
function nextHook(): Hook {
|
|
12
17
|
const fiber = getCurrentFiber()
|
|
13
|
-
const idx = ReactSharedInternals.
|
|
18
|
+
const idx = ReactSharedInternals.I++
|
|
14
19
|
|
|
15
|
-
let prev = ReactSharedInternals.
|
|
20
|
+
let prev = ReactSharedInternals.K
|
|
16
21
|
|
|
17
22
|
if (idx === 0) {
|
|
18
23
|
if (fiber.hooks) {
|
|
19
|
-
ReactSharedInternals.
|
|
24
|
+
ReactSharedInternals.K = fiber.hooks
|
|
20
25
|
return fiber.hooks
|
|
21
26
|
}
|
|
22
|
-
const h: Hook = {
|
|
27
|
+
const h: Hook = { s: undefined, q: undefined, d: undefined, c: undefined, n: null }
|
|
23
28
|
fiber.hooks = h
|
|
24
|
-
ReactSharedInternals.
|
|
29
|
+
ReactSharedInternals.K = h
|
|
25
30
|
return h
|
|
26
31
|
}
|
|
27
32
|
|
|
28
|
-
if (prev && prev.
|
|
29
|
-
ReactSharedInternals.
|
|
30
|
-
return prev.
|
|
33
|
+
if (prev && prev.n) {
|
|
34
|
+
ReactSharedInternals.K = prev.n
|
|
35
|
+
return prev.n
|
|
31
36
|
}
|
|
32
37
|
|
|
33
|
-
const h: Hook = {
|
|
34
|
-
if (prev) prev.
|
|
38
|
+
const h: Hook = { s: undefined, q: undefined, d: undefined, c: undefined, n: null }
|
|
39
|
+
if (prev) prev.n = h
|
|
35
40
|
else fiber.hooks = h
|
|
36
|
-
ReactSharedInternals.
|
|
41
|
+
ReactSharedInternals.K = h
|
|
37
42
|
return h
|
|
38
43
|
}
|
|
39
44
|
|
|
@@ -50,6 +55,8 @@ function depsEqual(
|
|
|
50
55
|
return true
|
|
51
56
|
}
|
|
52
57
|
|
|
58
|
+
type BasicStateAction<S> = S | ((p: S) => S)
|
|
59
|
+
|
|
53
60
|
// Singleton — every method reads render context via ReactSharedInternals,
|
|
54
61
|
// and per-hook closures live on the hook itself, so nothing is render-local
|
|
55
62
|
// to capture. Allocating a fresh wrapper + 17 method closures per function-
|
|
@@ -62,67 +69,65 @@ export function makeDispatcher() {
|
|
|
62
69
|
|
|
63
70
|
function makeDispatcherImpl() {
|
|
64
71
|
return {
|
|
65
|
-
useState<S>(initial: S | (() => S)) {
|
|
66
|
-
return this.useReducer
|
|
67
|
-
basicReducer as
|
|
68
|
-
typeof initial
|
|
72
|
+
useState<S>(initial: S | (() => S)): [S, (a: BasicStateAction<S>) => void] {
|
|
73
|
+
return this.useReducer(
|
|
74
|
+
basicReducer as (state: S, action: BasicStateAction<S>) => S,
|
|
75
|
+
typeof initial == 'function' ? (initial as () => S)() : initial,
|
|
69
76
|
)
|
|
70
77
|
},
|
|
71
78
|
|
|
72
79
|
useReducer<S, A>(reducer: (s: S, a: A) => S, initialArg: any, init?: (a: any) => S) {
|
|
73
80
|
const hook = nextHook()
|
|
74
81
|
const fiber = getCurrentFiber()
|
|
75
|
-
if (hook.
|
|
76
|
-
hook.
|
|
77
|
-
const queue: any = { reducer }
|
|
82
|
+
if (hook.q === undefined) {
|
|
83
|
+
hook.s = init ? init(initialArg) : initialArg
|
|
84
|
+
const queue: any = { r: reducer }
|
|
78
85
|
const dispatch = (action: A) => {
|
|
79
|
-
const currentState = hook.
|
|
80
|
-
const next = queue.
|
|
86
|
+
const currentState = hook.s as S
|
|
87
|
+
const next = queue.r(currentState, action)
|
|
81
88
|
if (!Object.is(next, currentState)) {
|
|
82
|
-
hook.
|
|
89
|
+
hook.s = next
|
|
83
90
|
scheduleUpdate(fiber)
|
|
84
91
|
}
|
|
85
92
|
}
|
|
86
|
-
queue.
|
|
87
|
-
hook.
|
|
93
|
+
queue.d = dispatch
|
|
94
|
+
hook.q = queue
|
|
88
95
|
} else {
|
|
89
|
-
hook.
|
|
96
|
+
hook.q.r = reducer
|
|
90
97
|
}
|
|
91
|
-
return [hook.
|
|
98
|
+
return [hook.s, hook.q.d] as [S, (a: A) => void]
|
|
92
99
|
},
|
|
93
100
|
|
|
94
101
|
useEffect(create: () => any, deps?: ReadonlyArray<unknown>) {
|
|
95
102
|
const hook = nextHook()
|
|
96
103
|
const fiber = getCurrentFiber()
|
|
97
|
-
const prevDeps = hook.
|
|
104
|
+
const prevDeps = hook.d
|
|
98
105
|
if (prevDeps !== undefined && depsEqual(prevDeps, deps)) return
|
|
99
|
-
hook.
|
|
106
|
+
hook.d = deps
|
|
100
107
|
const effect: Effect = {
|
|
101
|
-
|
|
102
|
-
|
|
108
|
+
t: 0,
|
|
109
|
+
c: () => {
|
|
103
110
|
// Run the prior cleanup INSIDE the effect run, not during the
|
|
104
111
|
// dispatch/render phase. If render A → B → C all happen back-to-
|
|
105
112
|
// back before the passive microtask drains, dispatch-time cleanup
|
|
106
|
-
// only fires once (between A→B) and
|
|
107
|
-
// leaving two side-
|
|
113
|
+
// only fires once (between A→B) and fx B + C both run fresh,
|
|
114
|
+
// leaving two side-fx (e.g. two plot SVGs) in the DOM. Doing
|
|
108
115
|
// it here, at effect-run time, means every new create first tears
|
|
109
116
|
// down whatever cleanup is currently live on the hook.
|
|
110
|
-
if (hook.
|
|
111
|
-
try { hook.
|
|
112
|
-
// The prior cleanup was also pushed onto fiber.
|
|
117
|
+
if (hook.c) {
|
|
118
|
+
try { hook.c() } catch {}
|
|
119
|
+
// The prior cleanup was also pushed onto fiber.cu; remove
|
|
113
120
|
// it so unmount doesn't double-call it.
|
|
114
|
-
if (fiber.
|
|
115
|
-
const i = fiber.
|
|
116
|
-
if (i >= 0) fiber.
|
|
121
|
+
if (fiber.cu) {
|
|
122
|
+
const i = fiber.cu.indexOf(hook.c)
|
|
123
|
+
if (i >= 0) fiber.cu.splice(i, 1)
|
|
117
124
|
}
|
|
118
|
-
hook.
|
|
125
|
+
hook.c = null
|
|
119
126
|
}
|
|
120
127
|
const c = create()
|
|
121
|
-
hook.
|
|
122
|
-
return hook.
|
|
128
|
+
hook.c = typeof c == 'function' ? c : null
|
|
129
|
+
return hook.c
|
|
123
130
|
},
|
|
124
|
-
destroy: undefined,
|
|
125
|
-
deps,
|
|
126
131
|
}
|
|
127
132
|
enqueueEffect(fiber, effect)
|
|
128
133
|
},
|
|
@@ -130,28 +135,26 @@ function makeDispatcherImpl() {
|
|
|
130
135
|
useLayoutEffect(create: () => any, deps?: ReadonlyArray<unknown>) {
|
|
131
136
|
const hook = nextHook()
|
|
132
137
|
const fiber = getCurrentFiber()
|
|
133
|
-
const prevDeps = hook.
|
|
138
|
+
const prevDeps = hook.d
|
|
134
139
|
if (prevDeps !== undefined && depsEqual(prevDeps, deps)) return
|
|
135
|
-
hook.
|
|
140
|
+
hook.d = deps
|
|
136
141
|
const effect: Effect = {
|
|
137
|
-
|
|
138
|
-
|
|
142
|
+
t: 1,
|
|
143
|
+
c: () => {
|
|
139
144
|
// Mirror useEffect: tear down the prior cleanup at run time so
|
|
140
|
-
// coalesced renders don't leak side-
|
|
141
|
-
if (hook.
|
|
142
|
-
try { hook.
|
|
143
|
-
if (fiber.
|
|
144
|
-
const i = fiber.
|
|
145
|
-
if (i >= 0) fiber.
|
|
145
|
+
// coalesced renders don't leak side-fx.
|
|
146
|
+
if (hook.c) {
|
|
147
|
+
try { hook.c() } catch {}
|
|
148
|
+
if (fiber.cu) {
|
|
149
|
+
const i = fiber.cu.indexOf(hook.c)
|
|
150
|
+
if (i >= 0) fiber.cu.splice(i, 1)
|
|
146
151
|
}
|
|
147
|
-
hook.
|
|
152
|
+
hook.c = null
|
|
148
153
|
}
|
|
149
154
|
const c = create()
|
|
150
|
-
hook.
|
|
151
|
-
return hook.
|
|
155
|
+
hook.c = typeof c == 'function' ? c : null
|
|
156
|
+
return hook.c
|
|
152
157
|
},
|
|
153
|
-
destroy: undefined,
|
|
154
|
-
deps,
|
|
155
158
|
}
|
|
156
159
|
enqueueEffect(fiber, effect)
|
|
157
160
|
},
|
|
@@ -162,18 +165,18 @@ function makeDispatcherImpl() {
|
|
|
162
165
|
|
|
163
166
|
useRef<T>(initial: T) {
|
|
164
167
|
const hook = nextHook()
|
|
165
|
-
if (hook.
|
|
166
|
-
return hook.
|
|
168
|
+
if (hook.s === undefined) hook.s = { current: initial }
|
|
169
|
+
return hook.s as { current: T }
|
|
167
170
|
},
|
|
168
171
|
|
|
169
172
|
useMemo<T>(factory: () => T, deps?: ReadonlyArray<unknown>) {
|
|
170
173
|
const hook = nextHook()
|
|
171
|
-
if (hook.
|
|
172
|
-
return hook.
|
|
174
|
+
if (hook.d !== undefined && depsEqual(hook.d, deps)) {
|
|
175
|
+
return hook.s as T
|
|
173
176
|
}
|
|
174
177
|
const value = factory()
|
|
175
|
-
hook.
|
|
176
|
-
hook.
|
|
178
|
+
hook.s = value
|
|
179
|
+
hook.d = deps
|
|
177
180
|
return value
|
|
178
181
|
},
|
|
179
182
|
|
|
@@ -188,11 +191,11 @@ function makeDispatcherImpl() {
|
|
|
188
191
|
|
|
189
192
|
useImperativeHandle<T>(ref: any, factory: () => T, deps?: ReadonlyArray<unknown>) {
|
|
190
193
|
const hook = nextHook()
|
|
191
|
-
if (hook.
|
|
192
|
-
hook.
|
|
194
|
+
if (hook.d !== undefined && depsEqual(hook.d, deps)) return
|
|
195
|
+
hook.d = deps
|
|
193
196
|
const value = factory()
|
|
194
197
|
if (ref) {
|
|
195
|
-
if (typeof ref
|
|
198
|
+
if (typeof ref == 'function') ref(value)
|
|
196
199
|
else ref.current = value
|
|
197
200
|
}
|
|
198
201
|
},
|
|
@@ -203,12 +206,12 @@ function makeDispatcherImpl() {
|
|
|
203
206
|
|
|
204
207
|
useId(): string {
|
|
205
208
|
const hook = nextHook()
|
|
206
|
-
if (hook.
|
|
209
|
+
if (hook.s === undefined) {
|
|
207
210
|
const fiber = getCurrentFiber()
|
|
208
211
|
const root = findRootFromFiber(fiber)
|
|
209
|
-
hook.
|
|
212
|
+
hook.s = (root?.i ?? ':r') + (idCounter++).toString(36)
|
|
210
213
|
}
|
|
211
|
-
return hook.
|
|
214
|
+
return hook.s as string
|
|
212
215
|
},
|
|
213
216
|
|
|
214
217
|
useTransition(): [boolean, (fn: () => void) => void] {
|
|
@@ -227,15 +230,15 @@ function makeDispatcherImpl() {
|
|
|
227
230
|
const fiber = getCurrentFiber()
|
|
228
231
|
const hook = nextHook()
|
|
229
232
|
const store: {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
} = hook.
|
|
233
|
-
getSnapshot,
|
|
234
|
-
getServerSnapshot,
|
|
233
|
+
g: () => T
|
|
234
|
+
s: (() => T) | undefined
|
|
235
|
+
} = hook.q ?? {
|
|
236
|
+
g: getSnapshot,
|
|
237
|
+
s: getServerSnapshot,
|
|
235
238
|
}
|
|
236
|
-
hook.
|
|
237
|
-
store.
|
|
238
|
-
store.
|
|
239
|
+
hook.q = store
|
|
240
|
+
store.g = getSnapshot
|
|
241
|
+
store.s = getServerSnapshot
|
|
239
242
|
|
|
240
243
|
// During hydration, use the server snapshot (if provided) so the tree
|
|
241
244
|
// matches the SSR output. Components like TanStack Router's ClientOnly
|
|
@@ -243,54 +246,52 @@ function makeDispatcherImpl() {
|
|
|
243
246
|
// if we return `true` during hydration, client and server diverge and
|
|
244
247
|
// the tree mounts fresh next to the SSR fallback DOM.
|
|
245
248
|
const root = fiber.root ?? findRootFromFiber(fiber)
|
|
246
|
-
const isHydrating = Boolean(root?.
|
|
249
|
+
const isHydrating = Boolean(root?.h)
|
|
247
250
|
const value =
|
|
248
251
|
isHydrating && getServerSnapshot ? getServerSnapshot() : getSnapshot()
|
|
249
|
-
hook.
|
|
252
|
+
hook.s = value
|
|
250
253
|
|
|
251
254
|
const deps = [subscribe]
|
|
252
|
-
if (hook.
|
|
253
|
-
hook.
|
|
255
|
+
if (hook.d === undefined || !depsEqual(hook.d, deps)) {
|
|
256
|
+
hook.d = deps
|
|
254
257
|
const effect: Effect = {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
create: () => {
|
|
259
|
-
if (hook.cleanup) {
|
|
258
|
+
t: 1,
|
|
259
|
+
c: () => {
|
|
260
|
+
if (hook.c) {
|
|
260
261
|
try {
|
|
261
|
-
hook.
|
|
262
|
+
hook.c()
|
|
262
263
|
} catch {
|
|
263
264
|
// ignore cleanup failures
|
|
264
265
|
}
|
|
265
|
-
if (fiber.
|
|
266
|
-
const i = fiber.
|
|
267
|
-
if (i >= 0) fiber.
|
|
266
|
+
if (fiber.cu) {
|
|
267
|
+
const i = fiber.cu.indexOf(hook.c)
|
|
268
|
+
if (i >= 0) fiber.cu.splice(i, 1)
|
|
268
269
|
}
|
|
269
|
-
hook.
|
|
270
|
+
hook.c = null
|
|
270
271
|
}
|
|
271
272
|
|
|
272
273
|
let unsubscribed = false
|
|
273
274
|
const cleanup = () => {
|
|
274
275
|
unsubscribed = true
|
|
275
|
-
if (typeof unsubscribe
|
|
276
|
+
if (typeof unsubscribe == 'function') {
|
|
276
277
|
unsubscribe()
|
|
277
278
|
}
|
|
278
279
|
}
|
|
279
280
|
const forceUpdate = () => {
|
|
280
|
-
if (unsubscribed || fiber.
|
|
281
|
+
if (unsubscribed || fiber.um) {
|
|
281
282
|
return
|
|
282
283
|
}
|
|
283
284
|
|
|
284
285
|
let next: T
|
|
285
286
|
try {
|
|
286
|
-
next = store.
|
|
287
|
+
next = store.g()
|
|
287
288
|
} catch {
|
|
288
289
|
scheduleUpdate(fiber)
|
|
289
290
|
return
|
|
290
291
|
}
|
|
291
292
|
|
|
292
|
-
if (!Object.is(hook.
|
|
293
|
-
hook.
|
|
293
|
+
if (!Object.is(hook.s, next)) {
|
|
294
|
+
hook.s = next
|
|
294
295
|
scheduleUpdate(fiber)
|
|
295
296
|
}
|
|
296
297
|
}
|
|
@@ -299,12 +300,12 @@ function makeDispatcherImpl() {
|
|
|
299
300
|
// If we served the server snapshot, run a post-hydration check so
|
|
300
301
|
// components like `useHydrated()` flip from false → true after the
|
|
301
302
|
// initial render commits. Queued late so hydration finishes first.
|
|
302
|
-
if (isHydrating && store.
|
|
303
|
+
if (isHydrating && store.s) {
|
|
303
304
|
queueMicrotask(() => queueMicrotask(forceUpdate))
|
|
304
305
|
}
|
|
305
306
|
|
|
306
307
|
forceUpdate()
|
|
307
|
-
hook.
|
|
308
|
+
hook.c = cleanup
|
|
308
309
|
return cleanup
|
|
309
310
|
},
|
|
310
311
|
}
|
|
@@ -314,11 +315,16 @@ function makeDispatcherImpl() {
|
|
|
314
315
|
},
|
|
315
316
|
|
|
316
317
|
use<T>(resource: any): T {
|
|
317
|
-
if (resource == null)
|
|
318
|
+
if (resource == null) {
|
|
319
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
320
|
+
throw new Error('use() received null or undefined')
|
|
321
|
+
}
|
|
322
|
+
throw new Error()
|
|
323
|
+
}
|
|
318
324
|
if (resource.$$typeof === REACT_CONTEXT_TYPE) {
|
|
319
325
|
return readContext(getCurrentFiber(), resource)
|
|
320
326
|
}
|
|
321
|
-
if (typeof resource.then
|
|
327
|
+
if (typeof resource.then == 'function') {
|
|
322
328
|
const thenable = resource
|
|
323
329
|
switch (thenable.status) {
|
|
324
330
|
case 'fulfilled':
|
|
@@ -347,13 +353,16 @@ function makeDispatcherImpl() {
|
|
|
347
353
|
}
|
|
348
354
|
}
|
|
349
355
|
}
|
|
350
|
-
|
|
356
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
357
|
+
throw new Error('use() expected a Promise or Context')
|
|
358
|
+
}
|
|
359
|
+
throw new Error()
|
|
351
360
|
},
|
|
352
361
|
}
|
|
353
362
|
}
|
|
354
363
|
|
|
355
|
-
function basicReducer<S>(state: S, action: S
|
|
356
|
-
return typeof action
|
|
364
|
+
function basicReducer<S>(state: S, action: BasicStateAction<S>): S {
|
|
365
|
+
return typeof action == 'function' ? (action as (p: S) => S)(state) : action
|
|
357
366
|
}
|
|
358
367
|
|
|
359
368
|
let idCounter = 0
|
package/src/dom/dom.ts
CHANGED
|
@@ -240,7 +240,7 @@ function setEventHandler(el: Element, name: string, next: any, prev: any): void
|
|
|
240
240
|
// legacy `onclick="..."` HTML attribute (string handler) is a known XSS
|
|
241
241
|
// vector if a parent spreads untrusted props onto a host element. React
|
|
242
242
|
// also ignores non-function handlers.
|
|
243
|
-
if (next != null && typeof next
|
|
243
|
+
if (next != null && typeof next != 'function') next = null
|
|
244
244
|
|
|
245
245
|
const capture = name.endsWith('Capture')
|
|
246
246
|
const reactEventName = name.slice(2, capture ? -7 : undefined)
|
package/src/dom/event-replay.ts
CHANGED
|
@@ -13,43 +13,27 @@
|
|
|
13
13
|
export function drainReplayQueue(): void {
|
|
14
14
|
const g = globalThis as any
|
|
15
15
|
const q = g.$RE_q as Array<[string, EventTarget, number]> | undefined
|
|
16
|
-
if (!q) return
|
|
17
16
|
|
|
17
|
+
if (!q) return
|
|
18
18
|
// Stop capturing before replaying so we don't re-capture what we dispatch.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
} catch {}
|
|
23
|
-
}
|
|
19
|
+
try {
|
|
20
|
+
g.$RE_stop?.()
|
|
21
|
+
} catch {}
|
|
24
22
|
|
|
25
|
-
const
|
|
26
|
-
for (const [type, target] of events) {
|
|
23
|
+
for (const [type, target] of q.splice(0)) {
|
|
27
24
|
try {
|
|
28
|
-
|
|
29
|
-
target.dispatchEvent(ev)
|
|
25
|
+
target.dispatchEvent(createEvent(type))
|
|
30
26
|
} catch {}
|
|
31
27
|
}
|
|
32
28
|
}
|
|
33
29
|
|
|
34
30
|
function createEvent(type: string): Event {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
}
|
|
31
|
+
const options = { bubbles: true, cancelable: true }
|
|
32
|
+
return type === 'click'
|
|
33
|
+
? new MouseEvent(type, options)
|
|
34
|
+
: type === 'keydown'
|
|
35
|
+
? new KeyboardEvent(type, options)
|
|
36
|
+
: type === 'input'
|
|
37
|
+
? new InputEvent(type, options)
|
|
38
|
+
: new Event(type, options)
|
|
55
39
|
}
|
|
@@ -12,8 +12,8 @@ import {
|
|
|
12
12
|
|
|
13
13
|
function renderClass(fiber: Fiber, domParent: Node, anchor: Node | null): void {
|
|
14
14
|
const Ctor = fiber.type as any
|
|
15
|
-
let instance = fiber.
|
|
16
|
-
const props = fiber.
|
|
15
|
+
let instance = fiber.sn
|
|
16
|
+
const props = fiber.pp ?? {}
|
|
17
17
|
const isNew = !instance
|
|
18
18
|
|
|
19
19
|
// Class contextType: read the current value of the subscribed context so
|
|
@@ -26,22 +26,22 @@ function renderClass(fiber: Fiber, domParent: Node, anchor: Node | null): void {
|
|
|
26
26
|
instance.context = ctxValue
|
|
27
27
|
instance._fiber = fiber
|
|
28
28
|
instance._enqueueUpdate = (updater: any, cb?: () => void) => {
|
|
29
|
-
const next = typeof updater
|
|
29
|
+
const next = typeof updater == 'function' ? updater(instance.state, instance.props) : updater
|
|
30
30
|
if (next != null) instance.state = { ...instance.state, ...next }
|
|
31
31
|
if (cb) {
|
|
32
|
-
fiber.
|
|
33
|
-
fiber.
|
|
32
|
+
fiber.cu ||= []
|
|
33
|
+
fiber.cu.push(cb)
|
|
34
34
|
}
|
|
35
35
|
scheduleUpdate(fiber)
|
|
36
36
|
}
|
|
37
37
|
instance._forceUpdate = (cb?: () => void) => {
|
|
38
38
|
if (cb) {
|
|
39
|
-
fiber.
|
|
40
|
-
fiber.
|
|
39
|
+
fiber.cu ||= []
|
|
40
|
+
fiber.cu.push(cb)
|
|
41
41
|
}
|
|
42
42
|
scheduleUpdate(fiber)
|
|
43
43
|
}
|
|
44
|
-
fiber.
|
|
44
|
+
fiber.sn = instance
|
|
45
45
|
if (Ctor.getDerivedStateFromProps) {
|
|
46
46
|
const d = Ctor.getDerivedStateFromProps(props, instance.state)
|
|
47
47
|
if (d) instance.state = { ...instance.state, ...d }
|
|
@@ -58,10 +58,10 @@ function renderClass(fiber: Fiber, domParent: Node, anchor: Node | null): void {
|
|
|
58
58
|
if (instance.shouldComponentUpdate) {
|
|
59
59
|
if (!instance.shouldComponentUpdate(props, instance.state, instance.context)) {
|
|
60
60
|
instance.props = props
|
|
61
|
-
fiber.
|
|
61
|
+
fiber.mp = props
|
|
62
62
|
// Still need to render children with previous output
|
|
63
|
-
if (fiber.
|
|
64
|
-
reconcileChildren(fiber, childrenToArray(fiber.
|
|
63
|
+
if (fiber.ms?.r) {
|
|
64
|
+
reconcileChildren(fiber, childrenToArray(fiber.ms.r), domParent, anchor)
|
|
65
65
|
}
|
|
66
66
|
return
|
|
67
67
|
}
|
|
@@ -70,7 +70,7 @@ function renderClass(fiber: Fiber, domParent: Node, anchor: Node | null): void {
|
|
|
70
70
|
// New snapshot must win over any stale one from a previous render —
|
|
71
71
|
// otherwise componentDidUpdate keeps seeing the original props and can
|
|
72
72
|
// ping-pong setState forever.
|
|
73
|
-
fiber.
|
|
73
|
+
fiber.ms = { ...(fiber.ms ?? {}), p: prevProps, s: prevState }
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
let rendered: ReactNode
|
|
@@ -85,10 +85,10 @@ function renderClass(fiber: Fiber, domParent: Node, anchor: Node | null): void {
|
|
|
85
85
|
return
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
|
-
fiber.
|
|
88
|
+
fiber.ms = { ...(fiber.ms ?? {}), r: rendered }
|
|
89
89
|
|
|
90
90
|
reconcileChildren(fiber, childrenToArray(rendered), domParent, anchor)
|
|
91
|
-
fiber.
|
|
91
|
+
fiber.mp = props
|
|
92
92
|
|
|
93
93
|
// Schedule lifecycle
|
|
94
94
|
if (isNew) {
|
|
@@ -96,8 +96,8 @@ function renderClass(fiber: Fiber, domParent: Node, anchor: Node | null): void {
|
|
|
96
96
|
scheduleLifecycle(fiber, () => instance.componentDidMount())
|
|
97
97
|
}
|
|
98
98
|
} else if (instance.componentDidUpdate) {
|
|
99
|
-
const {
|
|
100
|
-
scheduleLifecycle(fiber, () => instance.componentDidUpdate(
|
|
99
|
+
const { p, s } = fiber.ms ?? {}
|
|
100
|
+
scheduleLifecycle(fiber, () => instance.componentDidUpdate(p, s))
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
|
|
@@ -23,24 +23,24 @@ import {
|
|
|
23
23
|
// still work, and save ~400 B min / ~200 B gz.
|
|
24
24
|
function renderClassStub(fiber: Fiber, domParent: Node, anchor: Node | null): void {
|
|
25
25
|
const Ctor = fiber.type as any
|
|
26
|
-
let instance = fiber.
|
|
27
|
-
const props = fiber.
|
|
26
|
+
let instance = fiber.sn
|
|
27
|
+
const props = fiber.pp ?? {}
|
|
28
28
|
|
|
29
29
|
if (!instance) {
|
|
30
30
|
instance = new Ctor(props, undefined)
|
|
31
31
|
instance.props = props
|
|
32
32
|
instance._fiber = fiber
|
|
33
33
|
instance._enqueueUpdate = (updater: any, cb?: () => void) => {
|
|
34
|
-
const next = typeof updater
|
|
34
|
+
const next = typeof updater == 'function' ? updater(instance.state, instance.props) : updater
|
|
35
35
|
if (next != null) instance.state = { ...instance.state, ...next }
|
|
36
36
|
if (cb) {
|
|
37
|
-
fiber.
|
|
38
|
-
fiber.
|
|
37
|
+
fiber.cu ||= []
|
|
38
|
+
fiber.cu.push(cb)
|
|
39
39
|
}
|
|
40
40
|
scheduleUpdate(fiber)
|
|
41
41
|
}
|
|
42
42
|
instance._forceUpdate = instance._enqueueUpdate
|
|
43
|
-
fiber.
|
|
43
|
+
fiber.sn = instance
|
|
44
44
|
} else {
|
|
45
45
|
instance.props = props
|
|
46
46
|
}
|
|
@@ -59,7 +59,7 @@ function renderClassStub(fiber: Fiber, domParent: Node, anchor: Node | null): vo
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
reconcileChildren(fiber, childrenToArray(rendered), domParent, anchor)
|
|
62
|
-
fiber.
|
|
62
|
+
fiber.mp = props
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
registerRenderer(FiberTag.Class, renderClassStub)
|
|
@@ -12,7 +12,7 @@ function realReadContext(fiber: Fiber, ctx: any): any {
|
|
|
12
12
|
let p: Fiber | null = fiber.parent
|
|
13
13
|
while (p) {
|
|
14
14
|
if (p.tag === FiberTag.Provider && (p.type as any)._context === ctx) {
|
|
15
|
-
return (p.
|
|
15
|
+
return (p.pp ?? p.mp)?.value
|
|
16
16
|
}
|
|
17
17
|
p = p.parent
|
|
18
18
|
}
|
|
@@ -21,7 +21,7 @@ function realReadContext(fiber: Fiber, ctx: any): any {
|
|
|
21
21
|
|
|
22
22
|
function renderProvider(fiber: Fiber, domParent: Node, anchor: Node | null): void {
|
|
23
23
|
const ctx = (fiber.type as any)._context
|
|
24
|
-
const props = fiber.
|
|
24
|
+
const props = fiber.pp ?? {}
|
|
25
25
|
const prevValue = ctx._currentValue
|
|
26
26
|
ctx._currentValue = props.value
|
|
27
27
|
try {
|
|
@@ -31,18 +31,18 @@ function renderProvider(fiber: Fiber, domParent: Node, anchor: Node | null): voi
|
|
|
31
31
|
}
|
|
32
32
|
// Also store the value on the fiber so descendants rendering later (via updates)
|
|
33
33
|
// can read through by walking up.
|
|
34
|
-
fiber.
|
|
35
|
-
fiber.
|
|
34
|
+
fiber.ms = props.value
|
|
35
|
+
fiber.mp = props
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
function renderConsumer(fiber: Fiber, domParent: Node, anchor: Node | null): void {
|
|
39
39
|
const ctx = (fiber.type as any)._context
|
|
40
|
-
const props = fiber.
|
|
40
|
+
const props = fiber.pp ?? {}
|
|
41
41
|
const children = props.children
|
|
42
42
|
const value = realReadContext(fiber, ctx)
|
|
43
|
-
const rendered = typeof children
|
|
43
|
+
const rendered = typeof children == 'function' ? children(value) : null
|
|
44
44
|
reconcileChildren(fiber, childrenToArray(rendered), domParent, anchor)
|
|
45
|
-
fiber.
|
|
45
|
+
fiber.mp = props
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
registerTypeMatcher((_type, marker) =>
|
|
@@ -15,11 +15,11 @@ import {
|
|
|
15
15
|
// walking, which matches the no-Provider-fibers-in-tree reality.
|
|
16
16
|
function renderConsumerStub(fiber: Fiber, domParent: Node, anchor: Node | null): void {
|
|
17
17
|
const ctx = (fiber.type as any)._context
|
|
18
|
-
const props = fiber.
|
|
18
|
+
const props = fiber.pp ?? {}
|
|
19
19
|
const value = ctx._currentValue
|
|
20
|
-
const rendered = typeof props.children
|
|
20
|
+
const rendered = typeof props.children == 'function' ? props.children(value) : null
|
|
21
21
|
reconcileChildren(fiber, childrenToArray(rendered), domParent, anchor)
|
|
22
|
-
fiber.
|
|
22
|
+
fiber.mp = props
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
registerTypeMatcher((_type, marker) =>
|