@vidact/runtime 0.2.0-beta.0 → 0.2.0-beta.11
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 +73 -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 +148 -147
- package/dist/compiled/core.d.ts.map +1 -1
- package/dist/compiled/core.js +3064 -2987
- 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 +279 -222
- 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 +8 -2
- package/dist/dom/events.d.ts.map +1 -1
- package/dist/dom/events.js +118 -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 +17 -14
- package/dist/keyed-list.d.ts.map +1 -1
- package/dist/keyed-list.js +244 -161
- 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 +28 -22
- package/dist/renderable.d.ts.map +1 -1
- package/dist/renderable.js +152 -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 +10 -6
- package/dist/source-mask.d.ts.map +1 -1
- package/dist/source-mask.js +60 -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 +29 -15
- package/dist/state-slot.d.ts.map +1 -1
- package/dist/state-slot.js +73 -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 +4647 -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 +491 -0
- package/src/dom/attributes.ts +55 -0
- package/src/dom/events.ts +179 -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 +202 -0
- package/src/hydration.ts +644 -0
- package/src/index.ts +94 -0
- package/src/indexed-list.ts +20 -0
- package/src/jsx-runtime.ts +55 -0
- package/src/keyed-list.ts +379 -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 +313 -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 +103 -0
- package/src/spread.ts +131 -0
- package/src/state-slot.ts +132 -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,313 @@
|
|
|
1
|
+
import { binding, isCompiledBinding } from './compiled/core.ts'
|
|
2
|
+
import type { CompiledBinding, CompiledRenderValue, CompiledScope } from './compiled/types.ts'
|
|
3
|
+
import { compiledComponentSpread } from './component-spread.ts'
|
|
4
|
+
import { Fragment, h, type DirectComponent } from './direct-dom.ts'
|
|
5
|
+
import {
|
|
6
|
+
installRenderableClone,
|
|
7
|
+
isRenderableProtocol,
|
|
8
|
+
RENDERABLE,
|
|
9
|
+
type RenderableClone,
|
|
10
|
+
} from './renderable-protocol.ts'
|
|
11
|
+
import type { SourceMask } from './source-mask.ts'
|
|
12
|
+
import { unionSources } from './source-mask.ts'
|
|
13
|
+
import { compiledSpread } from './spread.ts'
|
|
14
|
+
|
|
15
|
+
const DEV = typeof __VIDACT_DEV__ === 'undefined' || __VIDACT_DEV__
|
|
16
|
+
const SPECIAL_PROPS = new Set(['children', 'key', 'ref'])
|
|
17
|
+
|
|
18
|
+
type Props = Record<string, unknown>
|
|
19
|
+
export type RenderablePropsInput = Props | CompiledBinding<Props>
|
|
20
|
+
|
|
21
|
+
type RenderableInternals = {
|
|
22
|
+
readonly identity: unknown
|
|
23
|
+
readonly input: RenderablePropsInput
|
|
24
|
+
readonly reconcile: boolean
|
|
25
|
+
readonly construct: (input: RenderablePropsInput) => CompiledRenderValue
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface CompiledRenderable {
|
|
29
|
+
readonly props: Props
|
|
30
|
+
readonly [RENDERABLE]: RenderableInternals
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function createRenderable(
|
|
34
|
+
input: RenderablePropsInput,
|
|
35
|
+
construct: (input: RenderablePropsInput) => CompiledRenderValue,
|
|
36
|
+
identity: unknown = construct,
|
|
37
|
+
reconcile = false,
|
|
38
|
+
): CompiledRenderable {
|
|
39
|
+
installRenderableClone(cloneRenderable as RenderableClone)
|
|
40
|
+
readPropsInput(input)
|
|
41
|
+
const capability = {
|
|
42
|
+
props: propsView(input),
|
|
43
|
+
} as CompiledRenderable
|
|
44
|
+
Object.defineProperty(capability, RENDERABLE, {
|
|
45
|
+
configurable: false,
|
|
46
|
+
enumerable: false,
|
|
47
|
+
value: { identity, input, reconcile, construct } satisfies RenderableInternals,
|
|
48
|
+
})
|
|
49
|
+
return capability
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function createComponentRenderable(
|
|
53
|
+
type: DirectComponent,
|
|
54
|
+
input: RenderablePropsInput,
|
|
55
|
+
identity: unknown = type,
|
|
56
|
+
): CompiledRenderable {
|
|
57
|
+
return createRenderable(
|
|
58
|
+
input,
|
|
59
|
+
(currentInput) =>
|
|
60
|
+
h(
|
|
61
|
+
type,
|
|
62
|
+
{ ...renderableComponentProps(currentInput), ref: renderableRef(currentInput) },
|
|
63
|
+
renderableChildren(currentInput),
|
|
64
|
+
),
|
|
65
|
+
identity,
|
|
66
|
+
true,
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function renderableComponentProps(input: RenderablePropsInput): Record<string, unknown> {
|
|
71
|
+
const ordinary = projectInput<Record<string, unknown>>(input, (props) =>
|
|
72
|
+
Object.fromEntries(
|
|
73
|
+
Reflect.ownKeys(props)
|
|
74
|
+
.filter((name) => typeof name !== 'string' || !SPECIAL_PROPS.has(name))
|
|
75
|
+
.map((name) => [name, Reflect.get(props, name)]),
|
|
76
|
+
),
|
|
77
|
+
)
|
|
78
|
+
return isCompiledBinding(ordinary) ? compiledComponentSpread(ordinary, []) : ordinary
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function isRenderable(value: unknown): value is CompiledRenderable {
|
|
82
|
+
return isRenderableProtocol(value)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function createReactElement(
|
|
86
|
+
type: string | typeof Fragment | DirectComponent | CompiledRenderable,
|
|
87
|
+
props: Props | null,
|
|
88
|
+
...children: CompiledRenderValue[]
|
|
89
|
+
): CompiledRenderable {
|
|
90
|
+
const input: Props = { ...props }
|
|
91
|
+
if (children.length === 1) input.children = children[0]
|
|
92
|
+
else if (children.length > 1) input.children = children
|
|
93
|
+
|
|
94
|
+
if (typeof type === 'string') return createIntrinsicRenderable(type, input)
|
|
95
|
+
|
|
96
|
+
return createRenderable(
|
|
97
|
+
input,
|
|
98
|
+
(currentInput) => {
|
|
99
|
+
if (isRenderable(type)) return cloneRenderable(type, currentInput)
|
|
100
|
+
const resolved = readPropsInput(currentInput)
|
|
101
|
+
const { children: currentChildren, key: _key, ...currentProps } = resolved
|
|
102
|
+
return Object.hasOwn(resolved, 'children')
|
|
103
|
+
? h(type, currentProps, currentChildren as CompiledRenderValue)
|
|
104
|
+
: h(type, currentProps)
|
|
105
|
+
},
|
|
106
|
+
type,
|
|
107
|
+
false,
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function renderableToArray(value: unknown): [CompiledRenderable] {
|
|
112
|
+
if (!isRenderable(value)) {
|
|
113
|
+
throw new TypeError(
|
|
114
|
+
DEV ? 'Children.toArray requires one compiled renderable capability' : 'V107',
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
return [value]
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function renderableMarker(value: unknown): undefined {
|
|
121
|
+
if (!isRenderable(value)) {
|
|
122
|
+
throw new TypeError(
|
|
123
|
+
DEV ? 'React element metadata requires a compiled renderable capability' : 'V107',
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
return undefined
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function cloneRenderable(
|
|
130
|
+
value: unknown,
|
|
131
|
+
overrides?: RenderablePropsInput | null,
|
|
132
|
+
childrenOverride?: CompiledRenderValue | CompiledBinding<CompiledRenderValue>,
|
|
133
|
+
): CompiledRenderValue {
|
|
134
|
+
if (!isRenderable(value)) {
|
|
135
|
+
throw new TypeError(DEV ? 'cloneRenderable requires a compiled renderable capability' : 'V107')
|
|
136
|
+
}
|
|
137
|
+
const internals = value[RENDERABLE]
|
|
138
|
+
let input = mergeInputs(internals.input, overrides)
|
|
139
|
+
if (arguments.length >= 3) input = mergeInputs(input, childrenInput(childrenOverride))
|
|
140
|
+
return createRenderable(
|
|
141
|
+
input,
|
|
142
|
+
internals.construct,
|
|
143
|
+
internals.identity,
|
|
144
|
+
internals.reconcile,
|
|
145
|
+
) as unknown as CompiledRenderValue
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function cloneRenderableComponent(props: Record<string, unknown>): CompiledRenderValue {
|
|
149
|
+
const value = isCompiledBinding(props.value) ? props.value[1]() : props.value
|
|
150
|
+
if (Object.hasOwn(props, 'childrenOverride')) {
|
|
151
|
+
return cloneRenderable(
|
|
152
|
+
value,
|
|
153
|
+
props.overrides as RenderablePropsInput | null | undefined,
|
|
154
|
+
props.childrenOverride as CompiledRenderValue | CompiledBinding<CompiledRenderValue>,
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
return cloneRenderable(value, props.overrides as RenderablePropsInput | null | undefined)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function keyedFragmentComponent(props: Record<string, unknown>): CompiledRenderValue {
|
|
161
|
+
return props.children as CompiledRenderValue
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function renderableProps(input: RenderablePropsInput): Record<string, unknown> {
|
|
165
|
+
const ordinary = projectInput(input, (props) =>
|
|
166
|
+
Object.fromEntries(
|
|
167
|
+
Reflect.ownKeys(props)
|
|
168
|
+
.filter((name) => typeof name !== 'string' || !SPECIAL_PROPS.has(name))
|
|
169
|
+
.map((name) => [name, Reflect.get(props, name)]),
|
|
170
|
+
),
|
|
171
|
+
)
|
|
172
|
+
return isCompiledBinding(ordinary) ? compiledSpread(ordinary, []) : ordinary
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export function renderableChildren(input: RenderablePropsInput): CompiledRenderValue {
|
|
176
|
+
return projectInput(input, (props) => props.children) as CompiledRenderValue
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function renderableRef(input: RenderablePropsInput): unknown {
|
|
180
|
+
return projectInput(input, (props) => props.ref)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function forwardedRef(props: Record<string, unknown>): unknown {
|
|
184
|
+
return props.ref
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export function dynamicIntrinsicComponent(props: Record<string, unknown>): CompiledRenderValue {
|
|
188
|
+
const tag = isCompiledBinding(props.tag) ? props.tag[1]() : props.tag
|
|
189
|
+
if (typeof tag !== 'string') {
|
|
190
|
+
throw new TypeError(DEV ? 'dynamic intrinsic construction requires a string tag' : 'V107')
|
|
191
|
+
}
|
|
192
|
+
let input = props.props as RenderablePropsInput
|
|
193
|
+
if (Object.hasOwn(props, 'childrenOverride')) {
|
|
194
|
+
input = mergeInputs(
|
|
195
|
+
input,
|
|
196
|
+
childrenInput(
|
|
197
|
+
props.childrenOverride as CompiledRenderValue | CompiledBinding<CompiledRenderValue>,
|
|
198
|
+
),
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
return createIntrinsicRenderable(tag, input) as unknown as CompiledRenderValue
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function createIntrinsicRenderable(tag: string, input: RenderablePropsInput): CompiledRenderable {
|
|
205
|
+
return createRenderable(
|
|
206
|
+
input,
|
|
207
|
+
(currentInput) =>
|
|
208
|
+
h(
|
|
209
|
+
tag,
|
|
210
|
+
{ ...renderableProps(currentInput), ref: renderableRef(currentInput) },
|
|
211
|
+
renderableChildren(currentInput),
|
|
212
|
+
),
|
|
213
|
+
tag,
|
|
214
|
+
true,
|
|
215
|
+
)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function propsView(input: RenderablePropsInput): Props {
|
|
219
|
+
return new Proxy(
|
|
220
|
+
{},
|
|
221
|
+
{
|
|
222
|
+
get(_target, property) {
|
|
223
|
+
const value = Reflect.get(readPropsInput(input), property)
|
|
224
|
+
return isCompiledBinding(value) ? value[1]() : value
|
|
225
|
+
},
|
|
226
|
+
getOwnPropertyDescriptor(_target, property) {
|
|
227
|
+
return Object.hasOwn(readPropsInput(input), property)
|
|
228
|
+
? { configurable: true, enumerable: true }
|
|
229
|
+
: undefined
|
|
230
|
+
},
|
|
231
|
+
has(_target, property) {
|
|
232
|
+
return Reflect.has(readPropsInput(input), property)
|
|
233
|
+
},
|
|
234
|
+
ownKeys() {
|
|
235
|
+
return Reflect.ownKeys(readPropsInput(input))
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function childrenInput(
|
|
242
|
+
value: CompiledRenderValue | CompiledBinding<CompiledRenderValue> | undefined,
|
|
243
|
+
): RenderablePropsInput {
|
|
244
|
+
if (!isCompiledBinding(value)) return { children: value }
|
|
245
|
+
return binding(value[2], value[3], () => ({ children: value[1]() }), value[4], value[5])
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function mergeInputs(
|
|
249
|
+
authored: RenderablePropsInput,
|
|
250
|
+
overrides: RenderablePropsInput | null | undefined,
|
|
251
|
+
): RenderablePropsInput {
|
|
252
|
+
if (overrides == null) return authored
|
|
253
|
+
if (!isCompiledBinding(authored) && !isCompiledBinding(overrides)) {
|
|
254
|
+
return { ...readPropsInput(authored), ...readPropsInput(overrides) }
|
|
255
|
+
}
|
|
256
|
+
const inputs = [authored, overrides]
|
|
257
|
+
const subscriptions = collectSubscriptions(inputs)
|
|
258
|
+
const evaluate = (): Props => ({
|
|
259
|
+
...readPropsInput(authored),
|
|
260
|
+
...readPropsInput(overrides),
|
|
261
|
+
})
|
|
262
|
+
return binding(
|
|
263
|
+
subscriptions[0]![0],
|
|
264
|
+
subscriptions[0]![1],
|
|
265
|
+
evaluate,
|
|
266
|
+
subscriptions[1]?.[0],
|
|
267
|
+
subscriptions[1]?.[1],
|
|
268
|
+
)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function projectInput<Value>(
|
|
272
|
+
input: RenderablePropsInput,
|
|
273
|
+
project: (props: Props) => Value,
|
|
274
|
+
): Value | CompiledBinding<Value> {
|
|
275
|
+
if (!isCompiledBinding(input)) return project(readPropsInput(input))
|
|
276
|
+
return binding(input[2], input[3], () => project(readPropsInput(input)), input[4], input[5])
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function collectSubscriptions(
|
|
280
|
+
inputs: readonly RenderablePropsInput[],
|
|
281
|
+
): Array<[CompiledScope, SourceMask]> {
|
|
282
|
+
const subscriptions = new Map<CompiledScope, SourceMask>()
|
|
283
|
+
for (const input of inputs) {
|
|
284
|
+
if (!isCompiledBinding(input)) continue
|
|
285
|
+
addSubscription(subscriptions, input[2], input[3])
|
|
286
|
+
if (input[4] !== undefined && input[5] !== undefined) {
|
|
287
|
+
addSubscription(subscriptions, input[4], input[5])
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (subscriptions.size > 2) {
|
|
291
|
+
throw new TypeError(
|
|
292
|
+
DEV ? 'a compiled renderable can combine reactive props from at most two scopes' : 'V107',
|
|
293
|
+
)
|
|
294
|
+
}
|
|
295
|
+
return [...subscriptions]
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function addSubscription(
|
|
299
|
+
subscriptions: Map<CompiledScope, SourceMask>,
|
|
300
|
+
scope: CompiledScope,
|
|
301
|
+
reads: SourceMask,
|
|
302
|
+
): void {
|
|
303
|
+
const current = subscriptions.get(scope)
|
|
304
|
+
subscriptions.set(scope, current === undefined ? reads : unionSources(current, reads))
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function readPropsInput(input: RenderablePropsInput): Props {
|
|
308
|
+
const value = isCompiledBinding(input) ? input[1]() : input
|
|
309
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
310
|
+
throw new TypeError(DEV ? 'compiled renderable props must evaluate to an object' : 'V107')
|
|
311
|
+
}
|
|
312
|
+
return value
|
|
313
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { enableRetainedUi, retainedActivity } from './compiled/core.ts'
|
|
2
|
+
import type { CompiledBinding, CompiledRenderValue, StructuralBinding } from './compiled/types.ts'
|
|
3
|
+
import { enableRetainedUiStyles } from './dom/styles.ts'
|
|
4
|
+
|
|
5
|
+
export interface ActivityProps {
|
|
6
|
+
readonly children?: (() => CompiledRenderValue) | readonly [() => CompiledRenderValue]
|
|
7
|
+
readonly mode: 'visible' | 'hidden' | CompiledBinding<'visible' | 'hidden'>
|
|
8
|
+
readonly name?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function Activity(props: ActivityProps): StructuralBinding {
|
|
12
|
+
const render = Array.isArray(props.children) ? props.children[0] : props.children
|
|
13
|
+
if (typeof render !== 'function') {
|
|
14
|
+
throw new TypeError('Activity children must be a compiler-generated render function')
|
|
15
|
+
}
|
|
16
|
+
enableRetainedUi()
|
|
17
|
+
enableRetainedUiStyles()
|
|
18
|
+
return retainedActivity(props.mode, render)
|
|
19
|
+
}
|
package/src/root.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { hydrateCompiled, mountCompiled, type MountCompiledOptions } from './compiled/core.ts'
|
|
2
|
+
import type { CompiledComponentResult } from './compiled/types.ts'
|
|
3
|
+
|
|
4
|
+
const DEV = typeof __VIDACT_DEV__ === 'undefined' || __VIDACT_DEV__
|
|
5
|
+
|
|
6
|
+
export interface CompiledRoot {
|
|
7
|
+
readonly mount: (application: () => CompiledComponentResult) => void
|
|
8
|
+
readonly replace: (application: () => CompiledComponentResult) => void
|
|
9
|
+
readonly unmount: () => void
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface HotContext {
|
|
13
|
+
readonly data: Record<string, unknown>
|
|
14
|
+
readonly accept: () => void
|
|
15
|
+
readonly dispose: (callback: (data: Record<string, unknown>) => void) => void
|
|
16
|
+
readonly prune: (callback: () => void) => void
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const HOT_ROOT = '__vidactHotRoot'
|
|
20
|
+
|
|
21
|
+
export function createRoot(host: ParentNode, options?: MountCompiledOptions): CompiledRoot {
|
|
22
|
+
let dispose: (() => void) | undefined
|
|
23
|
+
let terminal = false
|
|
24
|
+
return {
|
|
25
|
+
mount(application) {
|
|
26
|
+
if (terminal) throw new Error(DEV ? 'cannot mount an unmounted root' : 'V024')
|
|
27
|
+
if (dispose !== undefined) {
|
|
28
|
+
throw new Error(DEV ? 'compiled root already has a mounted application' : 'V025')
|
|
29
|
+
}
|
|
30
|
+
dispose = mountCompiled(application, host, options).dispose
|
|
31
|
+
},
|
|
32
|
+
replace(nextApplication) {
|
|
33
|
+
if (terminal) throw new Error(DEV ? 'cannot replace an unmounted root' : 'V030')
|
|
34
|
+
const previous = dispose
|
|
35
|
+
const next = mountCompiled(nextApplication, host, options).dispose
|
|
36
|
+
dispose = next
|
|
37
|
+
previous?.()
|
|
38
|
+
},
|
|
39
|
+
unmount() {
|
|
40
|
+
if (terminal) return
|
|
41
|
+
terminal = true
|
|
42
|
+
dispose?.()
|
|
43
|
+
dispose = undefined
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function hydrateRoot(
|
|
49
|
+
host: ParentNode,
|
|
50
|
+
application: () => CompiledComponentResult,
|
|
51
|
+
options?: MountCompiledOptions,
|
|
52
|
+
): CompiledRoot {
|
|
53
|
+
let dispose: (() => void) | undefined = hydrateCompiled(application, host, options).dispose
|
|
54
|
+
let terminal = false
|
|
55
|
+
return {
|
|
56
|
+
mount() {
|
|
57
|
+
throw new Error(DEV ? 'hydration roots are mounted during creation' : 'V029')
|
|
58
|
+
},
|
|
59
|
+
replace(nextApplication) {
|
|
60
|
+
if (terminal) throw new Error(DEV ? 'cannot replace an unmounted root' : 'V030')
|
|
61
|
+
const previous = dispose
|
|
62
|
+
const next = mountCompiled(nextApplication, host, options).dispose
|
|
63
|
+
dispose = next
|
|
64
|
+
previous?.()
|
|
65
|
+
},
|
|
66
|
+
unmount() {
|
|
67
|
+
if (terminal) return
|
|
68
|
+
terminal = true
|
|
69
|
+
dispose?.()
|
|
70
|
+
dispose = undefined
|
|
71
|
+
},
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function mountHotRoot(
|
|
76
|
+
hot: HotContext,
|
|
77
|
+
host: ParentNode,
|
|
78
|
+
application: () => CompiledComponentResult,
|
|
79
|
+
options?: MountCompiledOptions,
|
|
80
|
+
): CompiledRoot {
|
|
81
|
+
const previous = hot.data[HOT_ROOT]
|
|
82
|
+
const root = isCompiledRoot(previous) ? previous : createRoot(host, options)
|
|
83
|
+
if (isCompiledRoot(previous)) root.replace(application)
|
|
84
|
+
else root.mount(application)
|
|
85
|
+
registerHotRoot(hot, root)
|
|
86
|
+
return root
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function hydrateHotRoot(
|
|
90
|
+
hot: HotContext,
|
|
91
|
+
host: ParentNode,
|
|
92
|
+
application: () => CompiledComponentResult,
|
|
93
|
+
options?: MountCompiledOptions,
|
|
94
|
+
): CompiledRoot {
|
|
95
|
+
const previous = hot.data[HOT_ROOT]
|
|
96
|
+
const root = isCompiledRoot(previous) ? previous : hydrateRoot(host, application, options)
|
|
97
|
+
if (isCompiledRoot(previous)) root.replace(application)
|
|
98
|
+
registerHotRoot(hot, root)
|
|
99
|
+
return root
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function registerHotRoot(hot: HotContext, root: CompiledRoot): void {
|
|
103
|
+
hot.data[HOT_ROOT] = root
|
|
104
|
+
hot.accept()
|
|
105
|
+
hot.dispose((data) => {
|
|
106
|
+
data[HOT_ROOT] = root
|
|
107
|
+
})
|
|
108
|
+
hot.prune(() => {
|
|
109
|
+
if (hot.data[HOT_ROOT] !== root) return
|
|
110
|
+
delete hot.data[HOT_ROOT]
|
|
111
|
+
root.unmount()
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function isCompiledRoot(value: unknown): value is CompiledRoot {
|
|
116
|
+
return (
|
|
117
|
+
typeof value === 'object' &&
|
|
118
|
+
value !== null &&
|
|
119
|
+
typeof Reflect.get(value, 'replace') === 'function' &&
|
|
120
|
+
typeof Reflect.get(value, 'unmount') === 'function'
|
|
121
|
+
)
|
|
122
|
+
}
|
package/src/scheduler.ts
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
type ScheduledTask = () => void
|
|
2
|
+
export type CancelScheduledTask = () => void
|
|
3
|
+
|
|
4
|
+
type DeferredTask = {
|
|
5
|
+
readonly run: ScheduledTask
|
|
6
|
+
canceled: boolean
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let tasks: ScheduledTask[] = []
|
|
10
|
+
let deferredTasks: DeferredTask[] = []
|
|
11
|
+
let microtaskScheduled = false
|
|
12
|
+
let deferredTurnScheduled = false
|
|
13
|
+
let flushing = false
|
|
14
|
+
let actDepth = 0
|
|
15
|
+
|
|
16
|
+
export function scheduleTask(task: ScheduledTask): void {
|
|
17
|
+
tasks.push(task)
|
|
18
|
+
requestFlush()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function scheduleDeferredTask(task: ScheduledTask): CancelScheduledTask {
|
|
22
|
+
const entry: DeferredTask = { run: task, canceled: false }
|
|
23
|
+
deferredTasks.push(entry)
|
|
24
|
+
requestDeferredTurn()
|
|
25
|
+
return () => {
|
|
26
|
+
entry.canceled = true
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function flushScheduledTasks(): number {
|
|
31
|
+
if (flushing) return 0
|
|
32
|
+
flushing = true
|
|
33
|
+
microtaskScheduled = false
|
|
34
|
+
let firstError: unknown
|
|
35
|
+
let failed = false
|
|
36
|
+
let count = 0
|
|
37
|
+
try {
|
|
38
|
+
const queued = tasks
|
|
39
|
+
const deferred = deferredTasks
|
|
40
|
+
tasks = []
|
|
41
|
+
deferredTasks = []
|
|
42
|
+
for (const task of queued) {
|
|
43
|
+
count += 1
|
|
44
|
+
try {
|
|
45
|
+
task()
|
|
46
|
+
} catch (error) {
|
|
47
|
+
if (!failed) {
|
|
48
|
+
firstError = error
|
|
49
|
+
failed = true
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
for (const task of deferred) {
|
|
54
|
+
if (task.canceled) continue
|
|
55
|
+
count += 1
|
|
56
|
+
try {
|
|
57
|
+
task.run()
|
|
58
|
+
} catch (error) {
|
|
59
|
+
if (!failed) {
|
|
60
|
+
firstError = error
|
|
61
|
+
failed = true
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
} finally {
|
|
66
|
+
flushing = false
|
|
67
|
+
requestFlush()
|
|
68
|
+
requestDeferredTurn()
|
|
69
|
+
}
|
|
70
|
+
if (failed) throw firstError
|
|
71
|
+
return count
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function hasScheduledTasks(): boolean {
|
|
75
|
+
return tasks.length > 0 || deferredTasks.some((task) => !task.canceled)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function beginActScope(): void {
|
|
79
|
+
actDepth += 1
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function endActScope(): void {
|
|
83
|
+
actDepth -= 1
|
|
84
|
+
requestFlush()
|
|
85
|
+
requestDeferredTurn()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function requestFlush(): void {
|
|
89
|
+
if (tasks.length === 0 || microtaskScheduled || flushing || actDepth > 0) return
|
|
90
|
+
microtaskScheduled = true
|
|
91
|
+
queueMicrotask(() => {
|
|
92
|
+
microtaskScheduled = false
|
|
93
|
+
if (actDepth === 0) flushScheduledTasks()
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function requestDeferredTurn(): void {
|
|
98
|
+
if (
|
|
99
|
+
deferredTasks.every((task) => task.canceled) ||
|
|
100
|
+
deferredTurnScheduled ||
|
|
101
|
+
flushing ||
|
|
102
|
+
actDepth > 0
|
|
103
|
+
) {
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
deferredTurnScheduled = true
|
|
107
|
+
const channel = new MessageChannel()
|
|
108
|
+
channel.port1.addEventListener(
|
|
109
|
+
'message',
|
|
110
|
+
() => {
|
|
111
|
+
channel.port1.close()
|
|
112
|
+
channel.port2.close()
|
|
113
|
+
deferredTurnScheduled = false
|
|
114
|
+
if (actDepth > 0 || flushing) {
|
|
115
|
+
requestDeferredTurn()
|
|
116
|
+
return
|
|
117
|
+
}
|
|
118
|
+
flushOneDeferredTask()
|
|
119
|
+
},
|
|
120
|
+
{ once: true },
|
|
121
|
+
)
|
|
122
|
+
channel.port1.start()
|
|
123
|
+
channel.port2.postMessage(undefined)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function flushOneDeferredTask(): void {
|
|
127
|
+
let task: DeferredTask | undefined
|
|
128
|
+
while ((task = deferredTasks.shift()) !== undefined && task.canceled) {}
|
|
129
|
+
if (task === undefined) return
|
|
130
|
+
try {
|
|
131
|
+
task.run()
|
|
132
|
+
} finally {
|
|
133
|
+
requestFlush()
|
|
134
|
+
requestDeferredTurn()
|
|
135
|
+
}
|
|
136
|
+
}
|