@vidact/runtime 0.2.0-beta.0 → 0.2.0-beta.5
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/CHANGELOG.md +52 -0
- package/README.md +1 -1
- package/dist/actions.d.ts +32 -30
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +251 -266
- package/dist/actions.js.map +1 -1
- package/dist/async.d.ts +20 -17
- package/dist/async.d.ts.map +1 -1
- package/dist/async.js +18 -17
- package/dist/async.js.map +1 -1
- package/dist/compiled/async-resource.d.ts +9 -6
- package/dist/compiled/async-resource.d.ts.map +1 -1
- package/dist/compiled/async-resource.js +69 -77
- package/dist/compiled/async-resource.js.map +1 -1
- package/dist/compiled/core.d.ts +136 -147
- package/dist/compiled/core.d.ts.map +1 -1
- package/dist/compiled/core.js +2672 -2985
- package/dist/compiled/core.js.map +1 -1
- package/dist/compiled/types.d.ts +44 -56
- package/dist/compiled/types.d.ts.map +1 -1
- package/dist/compiled/types.js +10 -6
- package/dist/compiled/types.js.map +1 -1
- package/dist/compiled/validation.d.ts +4 -1
- package/dist/compiled/validation.d.ts.map +1 -1
- package/dist/compiled/validation.js +17 -20
- package/dist/compiled/validation.js.map +1 -1
- package/dist/component-spread.d.ts +5 -3
- package/dist/component-spread.d.ts.map +1 -1
- package/dist/component-spread.js +49 -67
- package/dist/component-spread.js.map +1 -1
- package/dist/concurrent.d.ts +20 -18
- package/dist/concurrent.d.ts.map +1 -1
- package/dist/concurrent.js +191 -210
- package/dist/concurrent.js.map +1 -1
- package/dist/direct-dom.d.ts +17 -12
- package/dist/direct-dom.d.ts.map +1 -1
- package/dist/direct-dom.js +187 -221
- package/dist/direct-dom.js.map +1 -1
- package/dist/dom/attributes.d.ts +9 -6
- package/dist/dom/attributes.d.ts.map +1 -1
- package/dist/dom/attributes.js +65 -47
- package/dist/dom/attributes.js.map +1 -1
- package/dist/dom/events.d.ts +5 -2
- package/dist/dom/events.d.ts.map +1 -1
- package/dist/dom/events.js +53 -65
- package/dist/dom/events.js.map +1 -1
- package/dist/dom/forms.d.ts +9 -6
- package/dist/dom/forms.d.ts.map +1 -1
- package/dist/dom/forms.js +152 -198
- package/dist/dom/forms.js.map +1 -1
- package/dist/dom/intrinsic.d.ts +17 -15
- package/dist/dom/intrinsic.d.ts.map +1 -1
- package/dist/dom/intrinsic.js +48 -50
- package/dist/dom/intrinsic.js.map +1 -1
- package/dist/dom/namespace.d.ts +4 -1
- package/dist/dom/namespace.d.ts.map +1 -1
- package/dist/dom/namespace.js +25 -28
- package/dist/dom/namespace.js.map +1 -1
- package/dist/dom/namespaces.d.ts +11 -8
- package/dist/dom/namespaces.d.ts.map +1 -1
- package/dist/dom/namespaces.js +14 -12
- package/dist/dom/namespaces.js.map +1 -1
- package/dist/dom/properties.d.ts +18 -16
- package/dist/dom/properties.d.ts.map +1 -1
- package/dist/dom/properties.js +273 -296
- package/dist/dom/properties.js.map +1 -1
- package/dist/dom/style-properties.d.ts +4 -1
- package/dist/dom/style-properties.d.ts.map +1 -1
- package/dist/dom/style-properties.js +49 -45
- package/dist/dom/style-properties.js.map +1 -1
- package/dist/dom/styles.d.ts +5 -2
- package/dist/dom/styles.d.ts.map +1 -1
- package/dist/dom/styles.js +47 -67
- package/dist/dom/styles.js.map +1 -1
- package/dist/dom-forms.d.ts +4 -1
- package/dist/dom-forms.d.ts.map +1 -1
- package/dist/dom-forms.js +16 -13
- package/dist/dom-forms.js.map +1 -1
- package/dist/dom-styles.d.ts +4 -1
- package/dist/dom-styles.d.ts.map +1 -1
- package/dist/dom-styles.js +10 -7
- package/dist/dom-styles.js.map +1 -1
- package/dist/framework-hydrate.d.ts +20 -17
- package/dist/framework-hydrate.d.ts.map +1 -1
- package/dist/framework-hydrate.js +128 -146
- package/dist/framework-hydrate.js.map +1 -1
- package/dist/framework-protocol.d.ts +27 -25
- package/dist/framework-protocol.d.ts.map +1 -1
- package/dist/framework-protocol.js +173 -211
- package/dist/framework-protocol.js.map +1 -1
- package/dist/framework.d.ts +34 -32
- package/dist/framework.d.ts.map +1 -1
- package/dist/framework.js +74 -93
- package/dist/framework.js.map +1 -1
- package/dist/hydrate.d.ts +11 -8
- package/dist/hydrate.d.ts.map +1 -1
- package/dist/hydrate.js +13 -9
- package/dist/hydrate.js.map +1 -1
- package/dist/hydration-bridge.d.ts +70 -58
- package/dist/hydration-bridge.d.ts.map +1 -1
- package/dist/hydration-bridge.js +77 -66
- package/dist/hydration-bridge.js.map +1 -1
- package/dist/hydration.d.ts +54 -28
- package/dist/hydration.d.ts.map +1 -1
- package/dist/hydration.js +450 -463
- package/dist/hydration.js.map +1 -1
- package/dist/index.d.ts +13 -13
- package/dist/index.js +11 -13
- package/dist/indexed-list.d.ts +8 -5
- package/dist/indexed-list.d.ts.map +1 -1
- package/dist/indexed-list.js +14 -7
- package/dist/indexed-list.js.map +1 -1
- package/dist/jsx-runtime.d.ts +10 -8
- package/dist/jsx-runtime.d.ts.map +1 -1
- package/dist/jsx-runtime.js +28 -23
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/keyed-list.d.ts +13 -14
- package/dist/keyed-list.d.ts.map +1 -1
- package/dist/keyed-list.js +132 -160
- package/dist/keyed-list.js.map +1 -1
- package/dist/metadata.d.ts +6 -3
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js +131 -164
- package/dist/metadata.js.map +1 -1
- package/dist/nested-prop.d.ts +4 -2
- package/dist/nested-prop.d.ts.map +1 -1
- package/dist/nested-prop.js +17 -16
- package/dist/nested-prop.js.map +1 -1
- package/dist/profiling.d.ts +11 -8
- package/dist/profiling.d.ts.map +1 -1
- package/dist/profiling.js +17 -17
- package/dist/profiling.js.map +1 -1
- package/dist/protocol.d.ts +5 -2
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +8 -5
- package/dist/protocol.js.map +1 -1
- package/dist/raw-html.d.ts +5 -2
- package/dist/raw-html.d.ts.map +1 -1
- package/dist/raw-html.js +86 -146
- package/dist/raw-html.js.map +1 -1
- package/dist/ref.d.ts +8 -3
- package/dist/ref.d.ts.map +1 -1
- package/dist/ref.js +10 -2
- package/dist/ref.js.map +1 -1
- package/dist/renderable-protocol.d.ts +26 -8
- package/dist/renderable-protocol.d.ts.map +1 -1
- package/dist/renderable-protocol.js +30 -9
- package/dist/renderable-protocol.js.map +1 -1
- package/dist/renderable.d.ts +27 -22
- package/dist/renderable.d.ts.map +1 -1
- package/dist/renderable.js +141 -133
- package/dist/renderable.js.map +1 -1
- package/dist/retained-ui.d.ts +9 -6
- package/dist/retained-ui.d.ts.map +1 -1
- package/dist/retained-ui.js +12 -10
- package/dist/retained-ui.js.map +1 -1
- package/dist/root.d.ts +18 -15
- package/dist/root.d.ts.map +1 -1
- package/dist/root.js +73 -85
- package/dist/root.js.map +1 -1
- package/dist/scheduler.d.ts +10 -8
- package/dist/scheduler.d.ts.map +1 -1
- package/dist/scheduler.js +97 -105
- package/dist/scheduler.js.map +1 -1
- package/dist/server-framework.d.ts +45 -42
- package/dist/server-framework.d.ts.map +1 -1
- package/dist/server-framework.js +209 -217
- package/dist/server-framework.js.map +1 -1
- package/dist/server.d.ts +130 -128
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +603 -710
- package/dist/server.js.map +1 -1
- package/dist/shared/promise.d.ts +6 -3
- package/dist/shared/promise.d.ts.map +1 -1
- package/dist/shared/promise.js +21 -19
- package/dist/shared/promise.js.map +1 -1
- package/dist/source-mask.d.ts +9 -6
- package/dist/source-mask.d.ts.map +1 -1
- package/dist/source-mask.js +45 -63
- package/dist/source-mask.js.map +1 -1
- package/dist/spread.d.ts +5 -2
- package/dist/spread.d.ts.map +1 -1
- package/dist/spread.js +79 -99
- package/dist/spread.js.map +1 -1
- package/dist/state-slot.d.ts +18 -15
- package/dist/state-slot.d.ts.map +1 -1
- package/dist/state-slot.js +43 -42
- package/dist/state-slot.js.map +1 -1
- package/dist/testing.d.ts +9 -6
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +16 -12
- package/dist/testing.js.map +1 -1
- package/package.json +8 -7
- package/src/actions.ts +415 -0
- package/src/async.ts +78 -0
- package/src/compiled/async-resource.ts +113 -0
- package/src/compiled/core.ts +4041 -0
- package/src/compiled/types.ts +96 -0
- package/src/compiled/validation.ts +23 -0
- package/src/component-spread.ts +86 -0
- package/src/concurrent.ts +310 -0
- package/src/direct-dom.ts +365 -0
- package/src/dom/attributes.ts +55 -0
- package/src/dom/events.ts +93 -0
- package/src/dom/forms.ts +220 -0
- package/src/dom/intrinsic.ts +94 -0
- package/src/dom/namespace.ts +30 -0
- package/src/dom/namespaces.ts +14 -0
- package/src/dom/properties.ts +355 -0
- package/src/dom/style-properties.ts +46 -0
- package/src/dom/styles.ts +86 -0
- package/src/dom-forms.ts +23 -0
- package/src/dom-styles.ts +11 -0
- package/src/env.d.ts +6 -0
- package/src/framework-hydrate.ts +224 -0
- package/src/framework-protocol.ts +335 -0
- package/src/framework.ts +161 -0
- package/src/hydrate.ts +38 -0
- package/src/hydration-bridge.ts +196 -0
- package/src/hydration.ts +642 -0
- package/src/index.ts +92 -0
- package/src/indexed-list.ts +20 -0
- package/src/jsx-runtime.ts +55 -0
- package/src/keyed-list.ts +233 -0
- package/src/metadata.ts +212 -0
- package/src/nested-prop.ts +27 -0
- package/src/profiling.ts +43 -0
- package/src/protocol.ts +8 -0
- package/src/raw-html.ts +206 -0
- package/src/ref.ts +13 -0
- package/src/renderable-protocol.ts +63 -0
- package/src/renderable.ts +283 -0
- package/src/retained-ui.ts +19 -0
- package/src/root.ts +122 -0
- package/src/scheduler.ts +136 -0
- package/src/server-framework.ts +397 -0
- package/src/server.ts +1160 -0
- package/src/shared/promise.ts +28 -0
- package/src/source-mask.ts +83 -0
- package/src/spread.ts +131 -0
- package/src/state-slot.ts +76 -0
- package/src/testing.ts +27 -0
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { RenderableProtocol } from '../renderable-protocol.ts'
|
|
2
|
+
import type { SourceMask } from '../source-mask.ts'
|
|
3
|
+
|
|
4
|
+
export const BINDING = Symbol.for('vidact.v1.Binding')
|
|
5
|
+
export const STRUCTURAL = Symbol.for('vidact.v1.StructuralBinding')
|
|
6
|
+
export const CONTEXT = Symbol.for('vidact.v1.Context')
|
|
7
|
+
export const ASYNC_RESOURCE = Symbol.for('vidact.v1.AsyncResource')
|
|
8
|
+
export const SUSPENSION = Symbol.for('vidact.v1.Suspension')
|
|
9
|
+
export const COMPONENT_SPREAD_SOURCE = Symbol.for('vidact.v1.ComponentSpreadSource')
|
|
10
|
+
|
|
11
|
+
export type CompiledErrorHandler = (error: unknown) => void
|
|
12
|
+
|
|
13
|
+
export type ProfilerPhase = 'mount' | 'update' | 'nested-update'
|
|
14
|
+
|
|
15
|
+
export type ProfilerOnRender = (
|
|
16
|
+
id: string,
|
|
17
|
+
phase: ProfilerPhase,
|
|
18
|
+
actualDuration: number,
|
|
19
|
+
baseDuration: number,
|
|
20
|
+
startTime: number,
|
|
21
|
+
commitTime: number,
|
|
22
|
+
) => void
|
|
23
|
+
|
|
24
|
+
export type AsyncResourceState<Value> = {
|
|
25
|
+
status: 'pending' | 'fulfilled' | 'rejected'
|
|
26
|
+
value: Value | undefined
|
|
27
|
+
reason: unknown
|
|
28
|
+
readonly listeners: Set<() => void>
|
|
29
|
+
readonly cancel: (() => void) | undefined
|
|
30
|
+
subscribers: number
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface AsyncResource<Value> {
|
|
34
|
+
readonly [ASYNC_RESOURCE]: AsyncResourceState<Value>
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ResourceOptions {
|
|
38
|
+
readonly cancel?: () => void
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type Suspension = {
|
|
42
|
+
readonly [SUSPENSION]: true
|
|
43
|
+
readonly resource: AsyncResource<unknown>
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type LazyModule<Props extends Record<string, unknown>> = {
|
|
47
|
+
readonly default: (props: Props) => CompiledRenderValue
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type CompiledScope = readonly [
|
|
51
|
+
add: (reads: SourceMask, run: (active: SourceMask) => void, writes?: SourceMask) => () => void,
|
|
52
|
+
invalidate: (sources: SourceMask) => void,
|
|
53
|
+
batch: <T>(operation: () => T) => T,
|
|
54
|
+
dispose: () => void,
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
export type CompiledBinding<T> = readonly [
|
|
58
|
+
brand: typeof BINDING,
|
|
59
|
+
evaluate: () => T,
|
|
60
|
+
scope: CompiledScope,
|
|
61
|
+
reads: SourceMask,
|
|
62
|
+
additionalScope: CompiledScope | undefined,
|
|
63
|
+
additionalReads: SourceMask | undefined,
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
export type OwnedBlock = readonly [
|
|
67
|
+
brand: typeof STRUCTURAL,
|
|
68
|
+
mount: (parent: Node, before: Node | null) => void,
|
|
69
|
+
hydrationKind?: 'array' | 'slot' | 'transparent',
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
export type StructuralBinding = OwnedBlock
|
|
73
|
+
export type CompiledComponentResult = OwnedBlock
|
|
74
|
+
|
|
75
|
+
export type CompiledRenderValue =
|
|
76
|
+
| Node
|
|
77
|
+
| string
|
|
78
|
+
| number
|
|
79
|
+
| bigint
|
|
80
|
+
| boolean
|
|
81
|
+
| null
|
|
82
|
+
| undefined
|
|
83
|
+
| CompiledBinding<unknown>
|
|
84
|
+
| StructuralBinding
|
|
85
|
+
| RenderableProtocol
|
|
86
|
+
| readonly CompiledRenderValue[]
|
|
87
|
+
|
|
88
|
+
export interface CompiledContext<T> {
|
|
89
|
+
(props: {
|
|
90
|
+
readonly children?: CompiledRenderValue | readonly CompiledRenderValue[]
|
|
91
|
+
readonly value: T | CompiledBinding<T>
|
|
92
|
+
}): StructuralBinding
|
|
93
|
+
Provider: CompiledContext<T>
|
|
94
|
+
displayName?: string
|
|
95
|
+
readonly [CONTEXT]: T
|
|
96
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { isRenderableProtocol } from '../renderable-protocol.ts'
|
|
2
|
+
import { isCompiledBinding, isStructuralBinding } from './core.ts'
|
|
3
|
+
|
|
4
|
+
export function hasInvalidChild(children: readonly unknown[]): boolean {
|
|
5
|
+
for (const child of children) {
|
|
6
|
+
if (isStructuralBinding(child) || isCompiledBinding(child) || isRenderableProtocol(child)) {
|
|
7
|
+
continue
|
|
8
|
+
}
|
|
9
|
+
if (Array.isArray(child)) {
|
|
10
|
+
if (hasInvalidChild(child)) return true
|
|
11
|
+
continue
|
|
12
|
+
}
|
|
13
|
+
const type = typeof child
|
|
14
|
+
if (
|
|
15
|
+
type === 'function' ||
|
|
16
|
+
type === 'symbol' ||
|
|
17
|
+
(type === 'object' && child !== null && !(child instanceof Node))
|
|
18
|
+
) {
|
|
19
|
+
return true
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return false
|
|
23
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { COMPONENT_SPREAD_SOURCE, binding, mountCompiledProp } from './compiled/core.ts'
|
|
2
|
+
import type { CompiledBinding } from './compiled/types.ts'
|
|
3
|
+
import { INTERNAL_COMPONENT_SPREAD_PROP } from './dom/intrinsic.ts'
|
|
4
|
+
|
|
5
|
+
type Props = Record<string, unknown>
|
|
6
|
+
type ComponentSpreadDirective = (props: Props) => Props
|
|
7
|
+
const DEV = typeof __VIDACT_DEV__ === 'undefined' || __VIDACT_DEV__
|
|
8
|
+
|
|
9
|
+
function readSpreadValue(value: unknown): Props {
|
|
10
|
+
if (value === null || value === undefined) return {}
|
|
11
|
+
if (typeof value !== 'object') {
|
|
12
|
+
throw new TypeError(
|
|
13
|
+
DEV ? 'reactive component spread value must be an object or nullish' : 'V106',
|
|
14
|
+
)
|
|
15
|
+
}
|
|
16
|
+
if (Object.hasOwn(value, 'key')) {
|
|
17
|
+
throw new TypeError(DEV ? 'reactive component spreads cannot supply key' : 'V106')
|
|
18
|
+
}
|
|
19
|
+
return value as Props
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function compiledComponentSpread(
|
|
23
|
+
input: CompiledBinding<Props>,
|
|
24
|
+
overriddenNames: readonly string[],
|
|
25
|
+
): Record<PropertyKey, ComponentSpreadDirective> {
|
|
26
|
+
const overridden = new Set(overriddenNames)
|
|
27
|
+
const bindings = new Map<string, CompiledBinding<unknown>>()
|
|
28
|
+
const read = (): Props => readSpreadValue(input[1]())
|
|
29
|
+
const propBinding = (name: string): CompiledBinding<unknown> => {
|
|
30
|
+
let value = bindings.get(name)
|
|
31
|
+
if (value === undefined) {
|
|
32
|
+
value = binding(input[2], input[3], () => read()[name], input[4], input[5])
|
|
33
|
+
bindings.set(name, value)
|
|
34
|
+
}
|
|
35
|
+
return value
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
[INTERNAL_COMPONENT_SPREAD_PROP]: (explicitProps) => {
|
|
40
|
+
mountCompiledProp(input, (value) => {
|
|
41
|
+
readSpreadValue(value)
|
|
42
|
+
})
|
|
43
|
+
return new Proxy(explicitProps, {
|
|
44
|
+
get(target, property, receiver) {
|
|
45
|
+
if (property === COMPONENT_SPREAD_SOURCE) return input
|
|
46
|
+
if (
|
|
47
|
+
typeof property !== 'string' ||
|
|
48
|
+
overridden.has(property) ||
|
|
49
|
+
Object.hasOwn(target, property)
|
|
50
|
+
) {
|
|
51
|
+
return Reflect.get(target, property, receiver)
|
|
52
|
+
}
|
|
53
|
+
return propBinding(property)
|
|
54
|
+
},
|
|
55
|
+
getOwnPropertyDescriptor(target, property) {
|
|
56
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(target, property)
|
|
57
|
+
if (
|
|
58
|
+
descriptor !== undefined ||
|
|
59
|
+
typeof property !== 'string' ||
|
|
60
|
+
overridden.has(property) ||
|
|
61
|
+
!Object.hasOwn(read(), property)
|
|
62
|
+
) {
|
|
63
|
+
return descriptor
|
|
64
|
+
}
|
|
65
|
+
return { configurable: true, enumerable: true }
|
|
66
|
+
},
|
|
67
|
+
has(target, property) {
|
|
68
|
+
return (
|
|
69
|
+
Reflect.has(target, property) ||
|
|
70
|
+
(typeof property === 'string' &&
|
|
71
|
+
!overridden.has(property) &&
|
|
72
|
+
Object.hasOwn(read(), property))
|
|
73
|
+
)
|
|
74
|
+
},
|
|
75
|
+
ownKeys(target) {
|
|
76
|
+
return [
|
|
77
|
+
...new Set([
|
|
78
|
+
...Reflect.ownKeys(target),
|
|
79
|
+
...Object.keys(read()).filter((name) => !overridden.has(name)),
|
|
80
|
+
]),
|
|
81
|
+
]
|
|
82
|
+
},
|
|
83
|
+
})
|
|
84
|
+
},
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { createCompiledState, runCompiledTransaction } from './compiled/core.ts'
|
|
2
|
+
import type { CompiledScope } from './compiled/types.ts'
|
|
3
|
+
import { flushScheduledTasks, scheduleDeferredTask, type CancelScheduledTask } from './scheduler.ts'
|
|
4
|
+
import type { SourceMask } from './source-mask.ts'
|
|
5
|
+
import {
|
|
6
|
+
installStateWriteInterceptor,
|
|
7
|
+
type DeferredStateWrite,
|
|
8
|
+
type StateSlot,
|
|
9
|
+
type StateUpdate,
|
|
10
|
+
} from './state-slot.ts'
|
|
11
|
+
|
|
12
|
+
const DEV = typeof __VIDACT_DEV__ === 'undefined' || __VIDACT_DEV__
|
|
13
|
+
|
|
14
|
+
type TransitionAction = () => void | PromiseLike<void>
|
|
15
|
+
|
|
16
|
+
type StagedSlot = {
|
|
17
|
+
readonly revision: number
|
|
18
|
+
readonly currentRevision: () => number
|
|
19
|
+
readonly commit: (update: StateUpdate<unknown>) => void
|
|
20
|
+
readonly updates: StateUpdate<unknown>[]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type TransitionWork = {
|
|
24
|
+
readonly lane: TransitionLane
|
|
25
|
+
readonly generation: number
|
|
26
|
+
readonly slots: Map<object, StagedSlot>
|
|
27
|
+
readonly settled: Set<() => void>
|
|
28
|
+
readonly finalizers: Set<() => void>
|
|
29
|
+
readonly aborters: Set<() => void>
|
|
30
|
+
cancelTask: CancelScheduledTask | undefined
|
|
31
|
+
awaiting: number
|
|
32
|
+
committed: boolean
|
|
33
|
+
canceled: boolean
|
|
34
|
+
finished: boolean
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type TransitionLane = {
|
|
38
|
+
generation: number
|
|
39
|
+
current: TransitionWork | undefined
|
|
40
|
+
readonly pending: (value: boolean) => void
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface CompiledTransitionSlot {
|
|
44
|
+
readonly get: () => boolean
|
|
45
|
+
readonly set: (action: TransitionAction) => void
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let activeTransition: TransitionWork | undefined
|
|
49
|
+
let schedulerInstalled = false
|
|
50
|
+
const globalLane = createLane(() => {})
|
|
51
|
+
|
|
52
|
+
export function startTransition(action: TransitionAction): void {
|
|
53
|
+
ensureConcurrentScheduler()
|
|
54
|
+
startLaneTransition(globalLane, action)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function flushSync<Result>(operation?: () => Result): Result | undefined {
|
|
58
|
+
ensureConcurrentScheduler()
|
|
59
|
+
const previous = activeTransition
|
|
60
|
+
activeTransition = undefined
|
|
61
|
+
try {
|
|
62
|
+
const result = operation?.()
|
|
63
|
+
flushScheduledTasks()
|
|
64
|
+
return result
|
|
65
|
+
} finally {
|
|
66
|
+
activeTransition = previous
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function createCompiledTransition(
|
|
71
|
+
scope: CompiledScope,
|
|
72
|
+
sourceMask: SourceMask,
|
|
73
|
+
): CompiledTransitionSlot {
|
|
74
|
+
ensureConcurrentScheduler()
|
|
75
|
+
const pending = createCompiledState(scope, sourceMask, false)
|
|
76
|
+
const lane = createLane((value) => runUrgent(() => pending.replace(value)))
|
|
77
|
+
return {
|
|
78
|
+
get: pending.get,
|
|
79
|
+
set: (action) => startLaneTransition(lane, action),
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function createCompiledDeferred<Value>(
|
|
84
|
+
scope: CompiledScope,
|
|
85
|
+
reads: SourceMask,
|
|
86
|
+
writes: SourceMask,
|
|
87
|
+
evaluate: () => Value,
|
|
88
|
+
initialValue?: Value,
|
|
89
|
+
): StateSlot<Value> {
|
|
90
|
+
ensureConcurrentScheduler()
|
|
91
|
+
const slot = createCompiledState(
|
|
92
|
+
scope,
|
|
93
|
+
writes,
|
|
94
|
+
arguments.length >= 5 ? initialValue! : evaluate(),
|
|
95
|
+
)
|
|
96
|
+
const lane = createLane(() => {})
|
|
97
|
+
const update = (): void => {
|
|
98
|
+
startLaneTransition(lane, () => slot.replace(evaluate()))
|
|
99
|
+
}
|
|
100
|
+
scope[0](reads, update)
|
|
101
|
+
if (arguments.length >= 5) update()
|
|
102
|
+
return slot
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function useTransition(): never {
|
|
106
|
+
throw new Error(DEV ? 'useTransition requires compiler lowering' : 'V032')
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function useDeferredValue<Value>(_value: Value, _initialValue?: Value): never {
|
|
110
|
+
throw new Error(DEV ? 'useDeferredValue requires compiler lowering' : 'V033')
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** @internal */
|
|
114
|
+
export function registerTransitionSettlement(settle: () => void): boolean {
|
|
115
|
+
if (activeTransition === undefined) return false
|
|
116
|
+
activeTransition.settled.add(settle)
|
|
117
|
+
return true
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** @internal */
|
|
121
|
+
export function registerTransitionFinalizer(finalize: () => void): boolean {
|
|
122
|
+
if (activeTransition === undefined) return false
|
|
123
|
+
activeTransition.finalizers.add(finalize)
|
|
124
|
+
return true
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** @internal */
|
|
128
|
+
export function registerTransitionAborter(abort: () => void): boolean {
|
|
129
|
+
if (activeTransition === undefined) return false
|
|
130
|
+
activeTransition.aborters.add(abort)
|
|
131
|
+
return true
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** @internal */
|
|
135
|
+
export function runUrgentUpdate<Result>(operation: () => Result): Result {
|
|
136
|
+
return runUrgent(operation)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** @internal */
|
|
140
|
+
export function startIndependentTransition(action: TransitionAction): void {
|
|
141
|
+
ensureConcurrentScheduler()
|
|
142
|
+
const previous = activeTransition
|
|
143
|
+
activeTransition = undefined
|
|
144
|
+
try {
|
|
145
|
+
startLaneTransition(
|
|
146
|
+
createLane(() => {}),
|
|
147
|
+
action,
|
|
148
|
+
)
|
|
149
|
+
} finally {
|
|
150
|
+
activeTransition = previous
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function createLane(pending: (value: boolean) => void): TransitionLane {
|
|
155
|
+
return { generation: 0, current: undefined, pending }
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function ensureConcurrentScheduler(): void {
|
|
159
|
+
if (schedulerInstalled) return
|
|
160
|
+
schedulerInstalled = true
|
|
161
|
+
installStateWriteInterceptor(stageStateWrite)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function startLaneTransition(lane: TransitionLane, action: TransitionAction): void {
|
|
165
|
+
if (activeTransition !== undefined) {
|
|
166
|
+
lane.pending(true)
|
|
167
|
+
activeTransition.settled.add(() => lane.pending(false))
|
|
168
|
+
runTransitionAction(activeTransition, action)
|
|
169
|
+
return
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
cancelWork(lane.current, true)
|
|
173
|
+
lane.generation += 1
|
|
174
|
+
lane.pending(true)
|
|
175
|
+
const work: TransitionWork = {
|
|
176
|
+
lane,
|
|
177
|
+
generation: lane.generation,
|
|
178
|
+
slots: new Map(),
|
|
179
|
+
settled: new Set(),
|
|
180
|
+
finalizers: new Set(),
|
|
181
|
+
aborters: new Set(),
|
|
182
|
+
cancelTask: undefined,
|
|
183
|
+
awaiting: 0,
|
|
184
|
+
committed: false,
|
|
185
|
+
canceled: false,
|
|
186
|
+
finished: false,
|
|
187
|
+
}
|
|
188
|
+
lane.current = work
|
|
189
|
+
const previous = activeTransition
|
|
190
|
+
activeTransition = work
|
|
191
|
+
try {
|
|
192
|
+
runTransitionAction(work, action)
|
|
193
|
+
} catch (error) {
|
|
194
|
+
cancelWork(work)
|
|
195
|
+
throw error
|
|
196
|
+
} finally {
|
|
197
|
+
activeTransition = previous
|
|
198
|
+
}
|
|
199
|
+
work.cancelTask = scheduleDeferredTask(() => commitWork(work))
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function runTransitionAction(work: TransitionWork, action: TransitionAction): void {
|
|
203
|
+
const result = action()
|
|
204
|
+
if (!isPromiseLike(result)) return
|
|
205
|
+
work.awaiting += 1
|
|
206
|
+
void Promise.resolve(result).then(
|
|
207
|
+
() => {
|
|
208
|
+
work.awaiting -= 1
|
|
209
|
+
finishWork(work)
|
|
210
|
+
},
|
|
211
|
+
(error: unknown) => {
|
|
212
|
+
work.awaiting -= 1
|
|
213
|
+
cancelWork(work)
|
|
214
|
+
queueMicrotask(() => {
|
|
215
|
+
throw error
|
|
216
|
+
})
|
|
217
|
+
},
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function stageStateWrite<Value>(write: DeferredStateWrite<Value>): boolean {
|
|
222
|
+
const work = activeTransition
|
|
223
|
+
if (work === undefined || work.canceled) return false
|
|
224
|
+
let staged = work.slots.get(write.slot)
|
|
225
|
+
if (staged === undefined) {
|
|
226
|
+
staged = {
|
|
227
|
+
revision: write.revision,
|
|
228
|
+
currentRevision: write.currentRevision,
|
|
229
|
+
commit: write.commit as (update: StateUpdate<unknown>) => void,
|
|
230
|
+
updates: [],
|
|
231
|
+
}
|
|
232
|
+
work.slots.set(write.slot, staged)
|
|
233
|
+
}
|
|
234
|
+
staged.updates.push(write.update as StateUpdate<unknown>)
|
|
235
|
+
return true
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function commitWork(work: TransitionWork): void {
|
|
239
|
+
work.cancelTask = undefined
|
|
240
|
+
if (
|
|
241
|
+
work.canceled ||
|
|
242
|
+
work.lane.current !== work ||
|
|
243
|
+
work.lane.generation !== work.generation ||
|
|
244
|
+
[...work.slots.values()].some((slot) => slot.currentRevision() !== slot.revision)
|
|
245
|
+
) {
|
|
246
|
+
cancelWork(work)
|
|
247
|
+
return
|
|
248
|
+
}
|
|
249
|
+
const previous = activeTransition
|
|
250
|
+
activeTransition = undefined
|
|
251
|
+
try {
|
|
252
|
+
runCompiledTransaction(() => {
|
|
253
|
+
for (const slot of work.slots.values()) {
|
|
254
|
+
for (const update of slot.updates) slot.commit(update)
|
|
255
|
+
}
|
|
256
|
+
})
|
|
257
|
+
for (const finalize of work.finalizers) finalize()
|
|
258
|
+
work.finalizers.clear()
|
|
259
|
+
work.aborters.clear()
|
|
260
|
+
work.committed = true
|
|
261
|
+
} catch (error) {
|
|
262
|
+
cancelWork(work)
|
|
263
|
+
throw error
|
|
264
|
+
} finally {
|
|
265
|
+
activeTransition = previous
|
|
266
|
+
finishWork(work)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function cancelWork(work: TransitionWork | undefined, preserveLanePending = false): void {
|
|
271
|
+
if (work === undefined || work.finished) return
|
|
272
|
+
work.canceled = true
|
|
273
|
+
work.cancelTask?.()
|
|
274
|
+
work.cancelTask = undefined
|
|
275
|
+
work.finalizers.clear()
|
|
276
|
+
for (const abort of work.aborters) abort()
|
|
277
|
+
work.aborters.clear()
|
|
278
|
+
work.committed = true
|
|
279
|
+
work.awaiting = 0
|
|
280
|
+
if (preserveLanePending && work.lane.current === work) work.lane.current = undefined
|
|
281
|
+
finishWork(work)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function finishWork(work: TransitionWork): void {
|
|
285
|
+
if (work.finished || !work.committed || work.awaiting > 0) return
|
|
286
|
+
work.finished = true
|
|
287
|
+
if (work.lane.current === work) {
|
|
288
|
+
work.lane.current = undefined
|
|
289
|
+
work.lane.pending(false)
|
|
290
|
+
}
|
|
291
|
+
for (const settle of work.settled) settle()
|
|
292
|
+
work.settled.clear()
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function runUrgent<Result>(operation: () => Result): Result {
|
|
296
|
+
const previous = activeTransition
|
|
297
|
+
activeTransition = undefined
|
|
298
|
+
try {
|
|
299
|
+
return operation()
|
|
300
|
+
} finally {
|
|
301
|
+
activeTransition = previous
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function isPromiseLike(value: unknown): value is PromiseLike<void> {
|
|
306
|
+
return (
|
|
307
|
+
((typeof value === 'object' && value !== null) || typeof value === 'function') &&
|
|
308
|
+
typeof (value as PromiseLike<void>).then === 'function'
|
|
309
|
+
)
|
|
310
|
+
}
|