@tanstack/redact 0.0.21 → 0.1.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.
- package/dist/core/attributes.js +2 -1
- package/dist/core/attributes.js.map +2 -2
- package/dist/core/browser.d.ts +9 -0
- package/dist/core/browser.js +35 -0
- package/dist/core/browser.js.map +7 -0
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +3 -3
- package/dist/core/internal.d.ts +31 -8
- package/dist/core/internal.js +3 -1
- package/dist/core/internal.js.map +2 -2
- package/dist/core/resource-hints.d.ts +7 -0
- package/dist/core/resource-hints.js +19 -0
- package/dist/core/resource-hints.js.map +7 -0
- package/dist/core/types.js +1 -1
- package/dist/dom/_all.d.ts +11 -16
- package/dist/dom/_all.js +9 -20
- package/dist/dom/_all.js.map +2 -2
- package/dist/dom/client.d.ts +4 -4
- package/dist/dom/client.js +4 -4
- package/dist/dom/commit.d.ts +23 -0
- package/dist/dom/commit.js +191 -0
- package/dist/dom/commit.js.map +7 -0
- package/dist/dom/dispatcher.d.ts +4 -22
- package/dist/dom/dispatcher.js +184 -126
- package/dist/dom/dispatcher.js.map +3 -3
- package/dist/dom/dom.d.ts +2 -0
- package/dist/dom/dom.js +72 -52
- package/dist/dom/dom.js.map +2 -2
- package/dist/dom/error-info.d.ts +2 -0
- package/dist/dom/error-info.js +16 -0
- package/dist/dom/error-info.js.map +7 -0
- package/dist/dom/event-replay.js +1 -1
- package/dist/dom/features/activity/full.d.ts +1 -0
- package/dist/dom/features/activity/full.js +162 -0
- package/dist/dom/features/activity/full.js.map +7 -0
- package/dist/dom/features/activity/index.d.ts +1 -0
- package/dist/dom/features/activity/index.js +3 -0
- package/dist/dom/features/activity/index.js.map +7 -0
- package/dist/dom/features/activity/stub.d.ts +1 -0
- package/dist/dom/features/activity/stub.js +12 -0
- package/dist/dom/features/activity/stub.js.map +7 -0
- package/dist/dom/features/class/full.js +87 -27
- package/dist/dom/features/class/full.js.map +2 -2
- package/dist/dom/features/class/index.d.ts +1 -1
- package/dist/dom/features/class/index.js +2 -2
- package/dist/dom/features/class/stub.js +3 -3
- package/dist/dom/features/context/full.d.ts +4 -1
- package/dist/dom/features/context/full.js +72 -15
- package/dist/dom/features/context/full.js.map +2 -2
- package/dist/dom/features/context/index.d.ts +1 -1
- package/dist/dom/features/context/index.js +2 -2
- package/dist/dom/features/context/stub.d.ts +4 -1
- package/dist/dom/features/context/stub.js +17 -8
- package/dist/dom/features/context/stub.js.map +2 -2
- package/dist/dom/features/forward-ref/full.js +12 -21
- package/dist/dom/features/forward-ref/full.js.map +2 -2
- package/dist/dom/features/forward-ref/index.d.ts +1 -1
- package/dist/dom/features/forward-ref/index.js +2 -2
- package/dist/dom/features/forward-ref/stub.js +4 -4
- package/dist/dom/features/fragment-refs/index.d.ts +1 -0
- package/dist/dom/features/fragment-refs/index.js +8 -0
- package/dist/dom/features/fragment-refs/index.js.map +7 -0
- package/dist/dom/features/fragment-refs/stub.d.ts +3 -0
- package/dist/dom/features/fragment-refs/stub.js +14 -0
- package/dist/dom/features/fragment-refs/stub.js.map +7 -0
- package/dist/dom/features/hydration/full.d.ts +11 -6
- package/dist/dom/features/hydration/full.js +76 -77
- package/dist/dom/features/hydration/full.js.map +2 -2
- package/dist/dom/features/hydration/index.d.ts +1 -1
- package/dist/dom/features/hydration/index.js +2 -2
- package/dist/dom/features/hydration/stub.d.ts +7 -2
- package/dist/dom/features/hydration/stub.js +1 -1
- package/dist/dom/features/hydration/stub.js.map +1 -1
- package/dist/dom/features/index.d.ts +8 -7
- package/dist/dom/features/index.js +9 -8
- package/dist/dom/features/index.js.map +2 -2
- package/dist/dom/features/lazy/full.js +4 -4
- package/dist/dom/features/lazy/index.d.ts +1 -1
- package/dist/dom/features/lazy/index.js +2 -2
- package/dist/dom/features/lazy/stub.js +4 -4
- package/dist/dom/features/memo/full.js +8 -6
- package/dist/dom/features/memo/full.js.map +2 -2
- package/dist/dom/features/memo/index.d.ts +1 -1
- package/dist/dom/features/memo/index.js +2 -2
- package/dist/dom/features/memo/stub.js +4 -4
- package/dist/dom/features/portal/full.js +4 -4
- package/dist/dom/features/portal/index.d.ts +1 -1
- package/dist/dom/features/portal/index.js +2 -2
- package/dist/dom/features/portal/stub.js +4 -4
- package/dist/dom/features/suspense/full.js +197 -52
- package/dist/dom/features/suspense/full.js.map +2 -2
- package/dist/dom/features/suspense/index.d.ts +1 -1
- package/dist/dom/features/suspense/index.js +2 -2
- package/dist/dom/features/suspense/stub.js +4 -4
- package/dist/dom/features/view-transition/full.d.ts +6 -0
- package/dist/dom/features/view-transition/full.js +280 -0
- package/dist/dom/features/view-transition/full.js.map +7 -0
- package/dist/dom/features/view-transition/index.d.ts +1 -0
- package/dist/dom/features/view-transition/index.js +3 -0
- package/dist/dom/features/view-transition/index.js.map +7 -0
- package/dist/dom/features/view-transition/resources.d.ts +11 -0
- package/dist/dom/features/view-transition/resources.js +108 -0
- package/dist/dom/features/view-transition/resources.js.map +7 -0
- package/dist/dom/features/view-transition/stub.d.ts +6 -0
- package/dist/dom/features/view-transition/stub.js +22 -0
- package/dist/dom/features/view-transition/stub.js.map +7 -0
- package/dist/dom/features/view-transition/visual.d.ts +14 -0
- package/dist/dom/features/view-transition/visual.js +356 -0
- package/dist/dom/features/view-transition/visual.js.map +7 -0
- package/dist/dom/fragment-instance.d.ts +40 -0
- package/dist/dom/fragment-instance.js +324 -0
- package/dist/dom/fragment-instance.js.map +7 -0
- package/dist/dom/index.d.ts +11 -11
- package/dist/dom/index.js +11 -18
- package/dist/dom/index.js.map +3 -3
- package/dist/dom/portal.d.ts +2 -2
- package/dist/dom/portal.js +2 -2
- package/dist/dom/portal.js.map +1 -1
- package/dist/dom/reconcile.d.ts +32 -3
- package/dist/dom/reconcile.js +689 -221
- package/dist/dom/reconcile.js.map +2 -2
- package/dist/dom/resource-hints.d.ts +6 -0
- package/dist/dom/resource-hints.js +115 -0
- package/dist/dom/resource-hints.js.map +7 -0
- package/dist/dom/resource-store.d.ts +13 -0
- package/dist/dom/resource-store.js +43 -0
- package/dist/dom/resource-store.js.map +7 -0
- package/dist/dom/resources.d.ts +1 -0
- package/dist/dom/resources.js +44 -0
- package/dist/dom/resources.js.map +7 -0
- package/dist/dom/retained-effects.d.ts +6 -0
- package/dist/dom/retained-effects.js +49 -0
- package/dist/dom/retained-effects.js.map +7 -0
- package/dist/dom/root-internal.d.ts +4 -4
- package/dist/dom/root-internal.js +2 -2
- package/dist/dom/root-internal.js.map +2 -2
- package/dist/dom/root.d.ts +5 -5
- package/dist/dom/root.js +11 -11
- package/dist/dom/root.js.map +2 -2
- package/dist/dom/test-utils.js +1 -1
- package/dist/react/activity.d.ts +7 -0
- package/dist/react/activity.js +8 -0
- package/dist/react/activity.js.map +7 -0
- package/dist/react/children.d.ts +1 -1
- package/dist/react/children.js +3 -3
- package/dist/react/children.js.map +1 -1
- package/dist/react/class.d.ts +1 -1
- package/dist/react/class.js +3 -3
- package/dist/react/class.js.map +1 -1
- package/dist/react/compiler-runtime.js +2 -2
- package/dist/react/context.d.ts +7 -2
- package/dist/react/context.js +3 -11
- package/dist/react/context.js.map +3 -3
- package/dist/react/element.d.ts +6 -3
- package/dist/react/element.js +7 -11
- package/dist/react/element.js.map +2 -2
- package/dist/react/hooks.d.ts +26 -7
- package/dist/react/hooks.js +13 -3
- package/dist/react/hooks.js.map +2 -2
- package/dist/react/index.d.ts +39 -24
- package/dist/react/index.js +39 -19
- package/dist/react/index.js.map +3 -3
- package/dist/react/jsx-runtime.d.ts +2 -2
- package/dist/react/jsx-runtime.js +3 -3
- package/dist/react/memo.d.ts +1 -1
- package/dist/react/memo.js +1 -1
- package/dist/react/portal.js +1 -1
- package/dist/react/shared-internals.d.ts +15 -5
- package/dist/react/shared-internals.js +2 -3
- package/dist/react/shared-internals.js.map +2 -2
- package/dist/react/suspense.js +1 -1
- package/dist/react/view-transition.d.ts +32 -0
- package/dist/react/view-transition.js +13 -0
- package/dist/react/view-transition.js.map +7 -0
- package/dist/scheduler/index.js +1 -1
- package/dist/server/bootstrap-script.d.ts +1 -23
- package/dist/server/bootstrap-script.js +7 -6
- package/dist/server/bootstrap-script.js.map +2 -2
- package/dist/server/dispatcher.d.ts +28 -6
- package/dist/server/dispatcher.js +33 -15
- package/dist/server/dispatcher.js.map +2 -2
- package/dist/server/escape.js +16 -15
- package/dist/server/escape.js.map +2 -2
- package/dist/server/index.d.ts +6 -6
- package/dist/server/index.js +7 -7
- package/dist/server/renderToString.d.ts +1 -1
- package/dist/server/renderToString.js +12 -8
- package/dist/server/renderToString.js.map +2 -2
- package/dist/server/resource-hints.d.ts +22 -0
- package/dist/server/resource-hints.js +148 -0
- package/dist/server/resource-hints.js.map +7 -0
- package/dist/server/stream.d.ts +15 -2
- package/dist/server/stream.js +155 -63
- package/dist/server/stream.js.map +2 -2
- package/dist/server/walk.d.ts +15 -2
- package/dist/server/walk.js +150 -110
- package/dist/server/walk.js.map +2 -2
- package/dist/vite/index.d.ts +6 -0
- package/dist/vite/index.js +22 -6
- package/dist/vite/index.js.map +2 -2
- package/package.json +1 -1
- package/src/core/attributes.ts +1 -0
- package/src/core/browser.ts +33 -0
- package/src/core/internal.ts +24 -6
- package/src/core/resource-hints.ts +36 -0
- package/src/dom/_all.ts +1 -7
- package/src/dom/commit.ts +186 -0
- package/src/dom/dispatcher.ts +190 -134
- package/src/dom/dom.ts +70 -54
- package/src/dom/error-info.ts +15 -0
- package/src/dom/features/activity/full.ts +166 -0
- package/src/dom/features/activity/index.ts +1 -0
- package/src/dom/features/activity/stub.ts +14 -0
- package/src/dom/features/class/full.ts +72 -28
- package/src/dom/features/context/full.ts +70 -13
- package/src/dom/features/context/stub.ts +10 -5
- package/src/dom/features/forward-ref/full.ts +9 -19
- package/src/dom/features/fragment-refs/index.ts +1 -0
- package/src/dom/features/fragment-refs/stub.ts +3 -0
- package/src/dom/features/hydration/full.ts +84 -85
- package/src/dom/features/hydration/stub.ts +1 -1
- package/src/dom/features/index.ts +1 -0
- package/src/dom/features/memo/full.ts +4 -3
- package/src/dom/features/suspense/full.ts +192 -55
- package/src/dom/features/view-transition/full.ts +288 -0
- package/src/dom/features/view-transition/index.ts +1 -0
- package/src/dom/features/view-transition/resources.ts +107 -0
- package/src/dom/features/view-transition/stub.ts +7 -0
- package/src/dom/features/view-transition/visual.ts +406 -0
- package/src/dom/fragment-instance.ts +337 -0
- package/src/dom/index.ts +6 -7
- package/src/dom/portal.ts +1 -1
- package/src/dom/reconcile.ts +695 -242
- package/src/dom/resource-hints.ts +115 -0
- package/src/dom/resource-store.ts +52 -0
- package/src/dom/resources.ts +39 -0
- package/src/dom/retained-effects.ts +38 -0
- package/src/dom/root-internal.ts +4 -4
- package/src/dom/root.ts +12 -14
- package/src/react/activity.ts +10 -0
- package/src/react/context.ts +4 -11
- package/src/react/element.ts +11 -12
- package/src/react/hooks.ts +12 -3
- package/src/react/index.ts +18 -0
- package/src/react/shared-internals.ts +3 -3
- package/src/react/view-transition.ts +41 -0
- package/src/server/bootstrap-script.ts +36 -5
- package/src/server/dispatcher.ts +35 -13
- package/src/server/escape.ts +15 -12
- package/src/server/renderToString.ts +7 -5
- package/src/server/resource-hints.ts +165 -0
- package/src/server/stream.ts +154 -62
- package/src/server/walk.ts +79 -26
- package/src/vite/index.ts +30 -13
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { FiberTag, type Fiber, type Hook } from '../core'
|
|
2
|
+
import { setProp } from './dom'
|
|
3
|
+
|
|
4
|
+
export interface CommitPlan {
|
|
5
|
+
q: any[][] // Before-mutation, mutation, effect, rollback and failure queues.
|
|
6
|
+
c: number[][] // Queue lengths saved at each rollback checkpoint.
|
|
7
|
+
b: number // Next before-mutation callback, including reentrant commits.
|
|
8
|
+
m: boolean // Mutation phase has started, preventing duplicate commits.
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export let currentCommit: CommitPlan | null = null
|
|
12
|
+
let activeCommit: CommitPlan | null = null
|
|
13
|
+
let reusableCommit: CommitPlan | undefined
|
|
14
|
+
let checkpointHook: (() => void) | undefined
|
|
15
|
+
|
|
16
|
+
function createCommit(): CommitPlan {
|
|
17
|
+
return { q: [[], [], [], [], []], c: [], b: 0, m: false }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function prepareCommit(render: () => void, plan = createCommit()): CommitPlan {
|
|
21
|
+
const previous = currentCommit
|
|
22
|
+
currentCommit = plan
|
|
23
|
+
try { render() } catch (error) {
|
|
24
|
+
currentCommit = null
|
|
25
|
+
const failed = plan.q[4]!
|
|
26
|
+
for (let i = 0; i < failed.length; i++) {
|
|
27
|
+
const work = failed[i]
|
|
28
|
+
if (typeof work === 'function') work()
|
|
29
|
+
else {
|
|
30
|
+
const children = failed[++i] as Fiber[] | undefined
|
|
31
|
+
work.child = children?.[0] ?? null
|
|
32
|
+
if (children) for (let j = 0; j < children.length; j++) children[j]!.sibling = children[j + 1] ?? null
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
throw error
|
|
36
|
+
} finally { currentCommit = previous }
|
|
37
|
+
return plan
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function queueMutation(work: () => void): void {
|
|
41
|
+
if (!currentCommit) { work(); return }
|
|
42
|
+
currentCommit.q[1]!.push(work)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function queueText(node: Text, value: string): void {
|
|
46
|
+
if (currentCommit) currentCommit.q[1]!.push(value, node)
|
|
47
|
+
else node.data = value
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function queueProp(node: Element, key: string, value: any, previous: any, svg: boolean): void {
|
|
51
|
+
if (currentCommit) currentCommit.q[1]!.push(node, key, value, previous, svg)
|
|
52
|
+
else setProp(node, key, value, previous, svg)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function queueBeforeMutation(work: () => void): void {
|
|
56
|
+
if (currentCommit) currentCommit.q[0]!.push(work)
|
|
57
|
+
else work()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function queueCommitEffects(work: () => void): void {
|
|
61
|
+
const plan = currentCommit || activeCommit
|
|
62
|
+
if (plan) plan.q[2]!.push(work)
|
|
63
|
+
else work()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function onCommitRollback(work: () => void): void {
|
|
67
|
+
currentCommit?.q[3]!.push(work)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function onCommitFailure(work: () => void): void {
|
|
71
|
+
if (currentCommit) currentCommit.q[4]!.push(work)
|
|
72
|
+
else work()
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Structural reconciliation already builds the previous child list. Keep
|
|
76
|
+
// that list for a failed preparation without allocating per-fiber closures.
|
|
77
|
+
export function rememberChildList(parent: Fiber, children?: Fiber[]): void {
|
|
78
|
+
currentCommit?.q[4]!.push(parent, children)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function setCommitCheckpointHook(hook: () => void): void {
|
|
82
|
+
checkpointHook = hook
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function checkpointCommit(fiber?: Fiber): number {
|
|
86
|
+
if (!currentCommit) return -1
|
|
87
|
+
const checkpoint = currentCommit.c.length
|
|
88
|
+
currentCommit.c.push(currentCommit.q.map(queue => queue.length))
|
|
89
|
+
if (fiber) rememberSubtree(fiber)
|
|
90
|
+
checkpointHook?.()
|
|
91
|
+
return checkpoint
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function rememberSubtree(fiber: Fiber): void {
|
|
95
|
+
const saved = { ...fiber }
|
|
96
|
+
// Memo and lazy preserve their wrapper tag around the same class instance.
|
|
97
|
+
const instance = fiber.sn?._fiber === fiber ? fiber.sn : null
|
|
98
|
+
// Hook has four fields. One flat snapshot preserves slot and dispatch
|
|
99
|
+
// identity without a tuple and object clone for every hook.
|
|
100
|
+
const hooks: any[] | null = fiber.hooks && []
|
|
101
|
+
if (hooks) for (const hook of fiber.hooks!) {
|
|
102
|
+
const queue = hook.q
|
|
103
|
+
hooks.push(hook, hook.s, queue, hook.d, hook.c, queue && typeof queue === 'object' ? { ...queue } : null)
|
|
104
|
+
}
|
|
105
|
+
const memoized = fiber.ms && (instance || fiber.tag === FiberTag.Suspense || fiber.tag === FiberTag.Fragment)
|
|
106
|
+
? { ...fiber.ms } : null
|
|
107
|
+
if (fiber.cx) saved.cx = new Map(fiber.cx)
|
|
108
|
+
if (fiber.cu) saved.cu = fiber.cu.slice()
|
|
109
|
+
const props = instance?.props, state = instance?.state, context = instance?.context
|
|
110
|
+
onCommitRollback(() => {
|
|
111
|
+
Object.assign(fiber, saved)
|
|
112
|
+
if (memoized) {
|
|
113
|
+
for (const key in fiber.ms) if (!(key in memoized)) delete fiber.ms[key]
|
|
114
|
+
Object.assign(fiber.ms, memoized)
|
|
115
|
+
}
|
|
116
|
+
if (hooks) {
|
|
117
|
+
fiber.hooks!.length = hooks.length / 6
|
|
118
|
+
for (let index = 0; index < hooks.length; index += 6) {
|
|
119
|
+
const hook: Hook = fiber.hooks![index / 6] = hooks[index]
|
|
120
|
+
hook.s = hooks[index + 1]
|
|
121
|
+
hook.q = hooks[index + 2]
|
|
122
|
+
hook.d = hooks[index + 3]
|
|
123
|
+
hook.c = hooks[index + 4]
|
|
124
|
+
const queue = hooks[index + 5]
|
|
125
|
+
if (queue) Object.assign(hook.q, queue)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (instance) { instance.props = props; instance.state = state; instance.context = context }
|
|
129
|
+
})
|
|
130
|
+
for (let child = fiber.child; child; child = child.sibling) rememberSubtree(child)
|
|
131
|
+
if (fiber.tag === FiberTag.Suspense && fiber.ms?.f) rememberSubtree(fiber.ms.f)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function rewindCommit(checkpoint: number): void {
|
|
135
|
+
if (!currentCommit || checkpoint < 0) return
|
|
136
|
+
const lengths = currentCommit.c[checkpoint]!
|
|
137
|
+
const undo = currentCommit.q[3]!
|
|
138
|
+
for (let index = undo.length - 1; index >= lengths[3]!; index--) undo[index]!()
|
|
139
|
+
currentCommit.q.forEach((queue, index) => { queue.length = lengths[index]! })
|
|
140
|
+
currentCommit.c.length = checkpoint
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function commitBeforeMutation(plan: CommitPlan): void {
|
|
144
|
+
const queue = plan.q[0]!
|
|
145
|
+
while (plan.b < queue.length) queue[plan.b++]!()
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function commitMutation(plan: CommitPlan): void {
|
|
149
|
+
if (plan.m) return
|
|
150
|
+
commitBeforeMutation(plan)
|
|
151
|
+
if (plan.m) return
|
|
152
|
+
plan.m = true
|
|
153
|
+
const previous = activeCommit
|
|
154
|
+
activeCommit = plan
|
|
155
|
+
try {
|
|
156
|
+
const mutations = plan.q[1]!
|
|
157
|
+
for (let index = 0; index < mutations.length; index++) {
|
|
158
|
+
const work = mutations[index]
|
|
159
|
+
if (typeof work === 'function') work()
|
|
160
|
+
else if (typeof work === 'string') mutations[++index].data = work
|
|
161
|
+
else setProp(work, mutations[++index], mutations[++index], mutations[++index], mutations[++index])
|
|
162
|
+
}
|
|
163
|
+
for (const work of plan.q[2]!) work()
|
|
164
|
+
} finally {
|
|
165
|
+
activeCommit = previous
|
|
166
|
+
for (const queue of plan.q) queue.length = 0
|
|
167
|
+
plan.c.length = 0
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function commitSynchronously(render: () => void): void {
|
|
172
|
+
if (currentCommit) { render(); return }
|
|
173
|
+
const plan = reusableCommit || createCommit()
|
|
174
|
+
reusableCommit = undefined
|
|
175
|
+
plan.b = 0
|
|
176
|
+
plan.m = false
|
|
177
|
+
try { commitMutation(prepareCommit(render, plan)) }
|
|
178
|
+
finally {
|
|
179
|
+
// Failed preparation must not leave work for a later synchronous root.
|
|
180
|
+
if (!plan.m) {
|
|
181
|
+
for (const queue of plan.q) queue.length = 0
|
|
182
|
+
plan.c.length = 0
|
|
183
|
+
}
|
|
184
|
+
reusableCommit = plan
|
|
185
|
+
}
|
|
186
|
+
}
|
package/src/dom/dispatcher.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import type { Hook, Fiber, FiberRoot, Effect } from '../core'
|
|
2
|
-
import { ReactSharedInternals, REACT_CONTEXT_TYPE } from '../react'
|
|
3
|
-
import { scheduleUpdate, enqueueEffect, readContext } from './reconcile'
|
|
1
|
+
import type { Hook, Fiber, FiberRoot, Effect, ReactNode } from '../core'
|
|
2
|
+
import { ReactSharedInternals, REACT_CONTEXT_TYPE, startTransition } from '../react'
|
|
3
|
+
import { scheduleUpdate, enqueueEffect, readContext, rememberActivityEffect, handleCommitError } from './reconcile'
|
|
4
|
+
import { REACT_RECOVERABLE_TYPE } from '../core/browser'
|
|
5
|
+
import { queueCommitEffects } from './commit'
|
|
6
|
+
import { deferTransitionPassive } from './features/view-transition'
|
|
4
7
|
|
|
5
8
|
function getCurrentFiber(): Fiber {
|
|
6
9
|
const f = ReactSharedInternals.F
|
|
@@ -14,32 +17,9 @@ function getCurrentFiber(): Fiber {
|
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
function nextHook(): Hook {
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
let prev = ReactSharedInternals.K
|
|
21
|
-
|
|
22
|
-
if (idx === 0) {
|
|
23
|
-
if (fiber.hooks) {
|
|
24
|
-
ReactSharedInternals.K = fiber.hooks
|
|
25
|
-
return fiber.hooks
|
|
26
|
-
}
|
|
27
|
-
const h: Hook = { s: undefined, q: undefined, d: undefined, c: undefined, n: null }
|
|
28
|
-
fiber.hooks = h
|
|
29
|
-
ReactSharedInternals.K = h
|
|
30
|
-
return h
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (prev && prev.n) {
|
|
34
|
-
ReactSharedInternals.K = prev.n
|
|
35
|
-
return prev.n
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const h: Hook = { s: undefined, q: undefined, d: undefined, c: undefined, n: null }
|
|
39
|
-
if (prev) prev.n = h
|
|
40
|
-
else fiber.hooks = h
|
|
41
|
-
ReactSharedInternals.K = h
|
|
42
|
-
return h
|
|
20
|
+
const hooks = getCurrentFiber().hooks ||= []
|
|
21
|
+
const index = ReactSharedInternals.I++
|
|
22
|
+
return hooks[index] ||= { s: undefined, q: undefined, d: undefined, c: undefined }
|
|
43
23
|
}
|
|
44
24
|
|
|
45
25
|
function depsEqual(
|
|
@@ -57,110 +37,185 @@ function depsEqual(
|
|
|
57
37
|
|
|
58
38
|
type BasicStateAction<S> = S | ((p: S) => S)
|
|
59
39
|
|
|
40
|
+
function initializeReducer(hook: Hook, fiber: Fiber, initialArg: any, init?: (arg: any) => any): void {
|
|
41
|
+
hook.s = init ? init(initialArg) : initialArg
|
|
42
|
+
hook.c = null
|
|
43
|
+
hook.q = (action: any) => {
|
|
44
|
+
if (fiber.um || fiber.pd) return
|
|
45
|
+
;(hook.c ||= []).push(action)
|
|
46
|
+
scheduleUpdate(fiber)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Reducer slots reuse the effect-cleanup field for pending actions. Zero marks
|
|
51
|
+
// eager state work, null means no update. Replacing arrays lets retries restore
|
|
52
|
+
// pending actions without copying or shifting them.
|
|
53
|
+
function reducePending(hook: Hook, reducer: (state: any, action: any) => any, previous = hook.s): void {
|
|
54
|
+
const actions = hook.c
|
|
55
|
+
if (actions == null) return
|
|
56
|
+
hook.c = null
|
|
57
|
+
let state = hook.s
|
|
58
|
+
if (actions) for (const action of actions) state = reducer(state, action)
|
|
59
|
+
hookFlags |= Object.is(state, previous) ? 2 : 3
|
|
60
|
+
hook.s = state
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let hookEffects: any[] | undefined
|
|
64
|
+
// Bit 1 records a changed value; bit 2 records a processed reducer queue.
|
|
65
|
+
let hookFlags = 0
|
|
66
|
+
export const HOOK_BAILOUT = Symbol()
|
|
67
|
+
|
|
68
|
+
function resetHookEffects(effects: any[]): void {
|
|
69
|
+
for (let index = 0; index < effects.length; index += 4) effects[index].d = effects[index + 1]
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function renderWithHooks(
|
|
73
|
+
fiber: Fiber,
|
|
74
|
+
render: (props: any, ref?: any) => ReactNode,
|
|
75
|
+
props: any,
|
|
76
|
+
ref?: any,
|
|
77
|
+
canBail = false,
|
|
78
|
+
): ReactNode | typeof HOOK_BAILOUT {
|
|
79
|
+
const previousDispatcher = ReactSharedInternals.H, previousFiber = ReactSharedInternals.F, previousIndex = ReactSharedInternals.I
|
|
80
|
+
const previousEffects = hookEffects, previousFlags = hookFlags
|
|
81
|
+
hookEffects = undefined
|
|
82
|
+
hookFlags = 0
|
|
83
|
+
ReactSharedInternals.H = DISPATCHER
|
|
84
|
+
ReactSharedInternals.F = fiber
|
|
85
|
+
try {
|
|
86
|
+
let rendered: ReactNode, attempts = 0
|
|
87
|
+
do {
|
|
88
|
+
if (++attempts > 25) throw new Error(process.env.NODE_ENV !== 'production' ? 'Too many re-renders.' : '')
|
|
89
|
+
if (hookEffects) {
|
|
90
|
+
resetHookEffects(hookEffects)
|
|
91
|
+
hookEffects = undefined
|
|
92
|
+
}
|
|
93
|
+
ReactSharedInternals.I = 0
|
|
94
|
+
fiber.dy = false
|
|
95
|
+
rendered = render(props, ref)
|
|
96
|
+
} while (fiber.dy)
|
|
97
|
+
if (canBail && hookFlags === 2) {
|
|
98
|
+
// React accepts the rendered dependencies on a reducer bailout, but
|
|
99
|
+
// keeps the previous committed effect descriptions until real work.
|
|
100
|
+
hookEffects = undefined
|
|
101
|
+
return HOOK_BAILOUT
|
|
102
|
+
}
|
|
103
|
+
if (hookEffects) {
|
|
104
|
+
const effects: any[] = hookEffects
|
|
105
|
+
for (let index = 0; index < effects.length; index += 4) {
|
|
106
|
+
const hook = effects[index], effect = effects[index + 2]
|
|
107
|
+
rememberActivityEffect(fiber, hook, effect)
|
|
108
|
+
if (effects[index + 3]) enqueueEffect(fiber, effect)
|
|
109
|
+
}
|
|
110
|
+
hookEffects = undefined
|
|
111
|
+
}
|
|
112
|
+
return rendered
|
|
113
|
+
} finally {
|
|
114
|
+
if (hookEffects) resetHookEffects(hookEffects)
|
|
115
|
+
hookEffects = previousEffects
|
|
116
|
+
hookFlags = previousFlags
|
|
117
|
+
ReactSharedInternals.H = previousDispatcher
|
|
118
|
+
ReactSharedInternals.F = previousFiber
|
|
119
|
+
ReactSharedInternals.I = previousIndex
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function cleanupEffect(hook: Hook, fiber: Fiber): void {
|
|
124
|
+
if (!hook.c) return
|
|
125
|
+
const cleanup = hook.c
|
|
126
|
+
hook.c = null
|
|
127
|
+
if (fiber.cu) {
|
|
128
|
+
const index = fiber.cu.indexOf(cleanup)
|
|
129
|
+
if (index >= 0) fiber.cu.splice(index, 1)
|
|
130
|
+
}
|
|
131
|
+
try { cleanup() } catch (error) { handleCommitError(fiber, error) }
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function useEffectImpl(type: Effect['t'], create: () => any, deps?: ReadonlyArray<unknown>): void {
|
|
135
|
+
const hook = nextHook()
|
|
136
|
+
const fiber = getCurrentFiber()
|
|
137
|
+
const changed = hook.d === undefined || !depsEqual(hook.d, deps)
|
|
138
|
+
if (!changed && !fiber.root?.a && !(type === 1 && fiber.root?.sp)) return
|
|
139
|
+
const previous = hook.d
|
|
140
|
+
hook.d = deps
|
|
141
|
+
const effect: Effect = {
|
|
142
|
+
t: type,
|
|
143
|
+
c: () => {
|
|
144
|
+
cleanupEffect(hook, fiber)
|
|
145
|
+
const cleanup = create()
|
|
146
|
+
// Each effect owns its cleanup even when hooks return the same function.
|
|
147
|
+
hook.c = typeof cleanup === 'function' ? () => {
|
|
148
|
+
if (type === 0) {
|
|
149
|
+
const dispose = () => {
|
|
150
|
+
try { cleanup() } catch (error) { handleCommitError(fiber, error) }
|
|
151
|
+
}
|
|
152
|
+
if (!deferTransitionPassive(dispose)) queueCommitEffects(dispose)
|
|
153
|
+
} else cleanup()
|
|
154
|
+
} : null
|
|
155
|
+
return hook.c
|
|
156
|
+
},
|
|
157
|
+
}
|
|
158
|
+
if (type === 1) effect.d = () => cleanupEffect(hook, fiber)
|
|
159
|
+
;(hookEffects ||= []).push(hook, previous, effect, changed)
|
|
160
|
+
}
|
|
161
|
+
|
|
60
162
|
// Singleton — every method reads render context via ReactSharedInternals,
|
|
61
163
|
// and per-hook closures live on the hook itself, so nothing is render-local
|
|
62
164
|
// to capture. Allocating a fresh wrapper + 17 method closures per function-
|
|
63
165
|
// component render was pure GC pressure.
|
|
64
166
|
const DISPATCHER = makeDispatcherImpl()
|
|
65
167
|
|
|
66
|
-
export function makeDispatcher() {
|
|
67
|
-
return DISPATCHER
|
|
68
|
-
}
|
|
69
|
-
|
|
70
168
|
function makeDispatcherImpl() {
|
|
71
169
|
return {
|
|
72
170
|
useState<S>(initial: S | (() => S)): [S, (a: BasicStateAction<S>) => void] {
|
|
73
|
-
|
|
74
|
-
basicReducer as (state: S, action: BasicStateAction<S>) => S,
|
|
75
|
-
typeof initial == 'function' ? (initial as () => S)() : initial,
|
|
76
|
-
)
|
|
77
|
-
},
|
|
78
|
-
|
|
79
|
-
useReducer<S, A>(reducer: (s: S, a: A) => S, initialArg: any, init?: (a: any) => S) {
|
|
80
|
-
const hook = nextHook()
|
|
81
|
-
const fiber = getCurrentFiber()
|
|
171
|
+
const hook = nextHook(), fiber = getCurrentFiber()
|
|
82
172
|
if (hook.q === undefined) {
|
|
83
|
-
hook.s =
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
173
|
+
hook.s = hook.d = typeof initial === 'function' ? (initial as () => S)() : initial
|
|
174
|
+
hook.c = null
|
|
175
|
+
hook.q = (action: BasicStateAction<S>) => {
|
|
176
|
+
if (fiber.um || fiber.pd) return
|
|
177
|
+
if (ReactSharedInternals.F !== fiber && !hook.c) {
|
|
178
|
+
let next: S
|
|
179
|
+
try {
|
|
180
|
+
next = basicReducer(hook.s, action)
|
|
181
|
+
} catch {
|
|
182
|
+
hook.c = [action]
|
|
183
|
+
scheduleUpdate(fiber)
|
|
184
|
+
return
|
|
185
|
+
}
|
|
186
|
+
if (Object.is(next, hook.s)) return
|
|
89
187
|
hook.s = next
|
|
188
|
+
hook.c = 0
|
|
90
189
|
scheduleUpdate(fiber)
|
|
190
|
+
return
|
|
91
191
|
}
|
|
192
|
+
;(hook.c ||= []).push(action)
|
|
193
|
+
scheduleUpdate(fiber)
|
|
92
194
|
}
|
|
93
|
-
queue.d = dispatch
|
|
94
|
-
hook.q = queue
|
|
95
|
-
} else {
|
|
96
|
-
hook.q.r = reducer
|
|
97
195
|
}
|
|
98
|
-
|
|
196
|
+
reducePending(hook, basicReducer, hook.d)
|
|
197
|
+
hook.d = hook.s
|
|
198
|
+
return [hook.s, hook.q]
|
|
99
199
|
},
|
|
100
200
|
|
|
101
|
-
|
|
201
|
+
useReducer<S, A>(reducer: (s: S, a: A) => S, initialArg: any, init?: (a: any) => S) {
|
|
102
202
|
const hook = nextHook()
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
hook.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
// dispatch/render phase. If render A → B → C all happen back-to-
|
|
112
|
-
// back before the passive microtask drains, dispatch-time cleanup
|
|
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
|
|
115
|
-
// it here, at effect-run time, means every new create first tears
|
|
116
|
-
// down whatever cleanup is currently live on the hook.
|
|
117
|
-
if (hook.c) {
|
|
118
|
-
try { hook.c() } catch {}
|
|
119
|
-
// The prior cleanup was also pushed onto fiber.cu; remove
|
|
120
|
-
// it so unmount doesn't double-call it.
|
|
121
|
-
if (fiber.cu) {
|
|
122
|
-
const i = fiber.cu.indexOf(hook.c)
|
|
123
|
-
if (i >= 0) fiber.cu.splice(i, 1)
|
|
124
|
-
}
|
|
125
|
-
hook.c = null
|
|
126
|
-
}
|
|
127
|
-
const c = create()
|
|
128
|
-
hook.c = typeof c == 'function' ? c : null
|
|
129
|
-
return hook.c
|
|
130
|
-
},
|
|
131
|
-
}
|
|
132
|
-
enqueueEffect(fiber, effect)
|
|
203
|
+
if (hook.q === undefined) initializeReducer(hook, getCurrentFiber(), initialArg, init)
|
|
204
|
+
reducePending(hook, reducer)
|
|
205
|
+
hook.d = reducer
|
|
206
|
+
return [hook.s, hook.q] as [S, (a: A) => void]
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
useEffect(create: () => any, deps?: ReadonlyArray<unknown>) {
|
|
210
|
+
useEffectImpl(0, create, deps)
|
|
133
211
|
},
|
|
134
212
|
|
|
135
213
|
useLayoutEffect(create: () => any, deps?: ReadonlyArray<unknown>) {
|
|
136
|
-
|
|
137
|
-
const fiber = getCurrentFiber()
|
|
138
|
-
const prevDeps = hook.d
|
|
139
|
-
if (prevDeps !== undefined && depsEqual(prevDeps, deps)) return
|
|
140
|
-
hook.d = deps
|
|
141
|
-
const effect: Effect = {
|
|
142
|
-
t: 1,
|
|
143
|
-
c: () => {
|
|
144
|
-
// Mirror useEffect: tear down the prior cleanup at run time so
|
|
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)
|
|
151
|
-
}
|
|
152
|
-
hook.c = null
|
|
153
|
-
}
|
|
154
|
-
const c = create()
|
|
155
|
-
hook.c = typeof c == 'function' ? c : null
|
|
156
|
-
return hook.c
|
|
157
|
-
},
|
|
158
|
-
}
|
|
159
|
-
enqueueEffect(fiber, effect)
|
|
214
|
+
useEffectImpl(1, create, deps)
|
|
160
215
|
},
|
|
161
216
|
|
|
162
217
|
useInsertionEffect(create: () => any, deps?: ReadonlyArray<unknown>) {
|
|
163
|
-
|
|
218
|
+
useEffectImpl(2, create, deps)
|
|
164
219
|
},
|
|
165
220
|
|
|
166
221
|
useRef<T>(initial: T) {
|
|
@@ -190,14 +245,16 @@ function makeDispatcherImpl() {
|
|
|
190
245
|
},
|
|
191
246
|
|
|
192
247
|
useImperativeHandle<T>(ref: any, factory: () => T, deps?: ReadonlyArray<unknown>) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
248
|
+
useEffectImpl(1, () => {
|
|
249
|
+
if (!ref) return
|
|
250
|
+
const value = factory()
|
|
251
|
+
if (typeof ref === 'function') {
|
|
252
|
+
const cleanup = ref(value)
|
|
253
|
+
return typeof cleanup === 'function' ? cleanup : () => ref(null)
|
|
254
|
+
}
|
|
255
|
+
ref.current = value
|
|
256
|
+
return () => { ref.current = null }
|
|
257
|
+
}, deps == null ? undefined : [...deps, ref])
|
|
201
258
|
},
|
|
202
259
|
|
|
203
260
|
useDebugValue<T>(_value: T, _formatter?: (v: T) => any): void {
|
|
@@ -217,13 +274,19 @@ function makeDispatcherImpl() {
|
|
|
217
274
|
},
|
|
218
275
|
|
|
219
276
|
useTransition(): [boolean, (fn: () => void) => void] {
|
|
220
|
-
return [false,
|
|
277
|
+
return [false, startTransition]
|
|
221
278
|
},
|
|
222
279
|
|
|
223
280
|
useDeferredValue<T>(v: T): T {
|
|
224
281
|
return v
|
|
225
282
|
},
|
|
226
283
|
|
|
284
|
+
useCacheRefresh(): () => void {
|
|
285
|
+
// There is no client cache to invalidate. Preserve hook identity and
|
|
286
|
+
// leave state and scheduling alone, as with the uncached client cache().
|
|
287
|
+
return this.useCallback(() => {}, [])
|
|
288
|
+
},
|
|
289
|
+
|
|
227
290
|
useSyncExternalStore<T>(
|
|
228
291
|
subscribe: (cb: () => void) => () => void,
|
|
229
292
|
getSnapshot: () => T,
|
|
@@ -251,26 +314,19 @@ function makeDispatcherImpl() {
|
|
|
251
314
|
const isHydrating = Boolean(root?.h)
|
|
252
315
|
const value =
|
|
253
316
|
isHydrating && getServerSnapshot ? getServerSnapshot() : getSnapshot()
|
|
317
|
+
if (!Object.is(hook.s, value)) hookFlags |= 1
|
|
254
318
|
hook.s = value
|
|
255
319
|
|
|
256
320
|
const deps = [subscribe]
|
|
257
|
-
|
|
321
|
+
const changed = hook.d === undefined || !depsEqual(hook.d, deps)
|
|
322
|
+
if (changed || fiber.root?.a) {
|
|
323
|
+
const previous = hook.d
|
|
258
324
|
hook.d = deps
|
|
259
325
|
const effect: Effect = {
|
|
260
326
|
t: 1,
|
|
327
|
+
s: true,
|
|
261
328
|
c: () => {
|
|
262
|
-
|
|
263
|
-
try {
|
|
264
|
-
hook.c()
|
|
265
|
-
} catch {
|
|
266
|
-
// ignore cleanup failures
|
|
267
|
-
}
|
|
268
|
-
if (fiber.cu) {
|
|
269
|
-
const i = fiber.cu.indexOf(hook.c)
|
|
270
|
-
if (i >= 0) fiber.cu.splice(i, 1)
|
|
271
|
-
}
|
|
272
|
-
hook.c = null
|
|
273
|
-
}
|
|
329
|
+
cleanupEffect(hook, fiber)
|
|
274
330
|
|
|
275
331
|
let unsubscribed = false
|
|
276
332
|
const cleanup = () => {
|
|
@@ -293,7 +349,6 @@ function makeDispatcherImpl() {
|
|
|
293
349
|
}
|
|
294
350
|
|
|
295
351
|
if (!Object.is(hook.s, next)) {
|
|
296
|
-
hook.s = next
|
|
297
352
|
scheduleUpdate(fiber)
|
|
298
353
|
}
|
|
299
354
|
}
|
|
@@ -311,12 +366,13 @@ function makeDispatcherImpl() {
|
|
|
311
366
|
return cleanup
|
|
312
367
|
},
|
|
313
368
|
}
|
|
314
|
-
|
|
369
|
+
;(hookEffects ||= []).push(hook, previous, effect, changed)
|
|
315
370
|
}
|
|
316
371
|
return value
|
|
317
372
|
},
|
|
318
373
|
|
|
319
374
|
use<T>(resource: any): T {
|
|
375
|
+
if (resource?.$$typeof === REACT_RECOVERABLE_TYPE) return undefined as T
|
|
320
376
|
if (resource == null) {
|
|
321
377
|
if (process.env.NODE_ENV !== 'production') {
|
|
322
378
|
throw new Error('use() received null or undefined')
|
|
@@ -372,7 +428,7 @@ let idCounter = 0
|
|
|
372
428
|
function findRootFromFiber(fiber: Fiber): FiberRoot | null {
|
|
373
429
|
let f: Fiber | null = fiber
|
|
374
430
|
while (f) {
|
|
375
|
-
if (f.root) return f.root
|
|
431
|
+
if (f.root) return fiber.root = f.root
|
|
376
432
|
f = f.parent
|
|
377
433
|
}
|
|
378
434
|
return null
|