@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,365 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isCompiledBinding,
|
|
3
|
+
isStructuralBinding,
|
|
4
|
+
adoptCompiledRoot,
|
|
5
|
+
constructCompiledComponent,
|
|
6
|
+
mountCompiledBinding,
|
|
7
|
+
mountCompiledProp,
|
|
8
|
+
mountCompiledRef,
|
|
9
|
+
mountCompiledPropTransition,
|
|
10
|
+
queueElementRef,
|
|
11
|
+
registerCompiledCleanup,
|
|
12
|
+
} from './compiled/core.ts'
|
|
13
|
+
import type {
|
|
14
|
+
CompiledBinding,
|
|
15
|
+
CompiledContext,
|
|
16
|
+
CompiledRenderValue,
|
|
17
|
+
StructuralBinding,
|
|
18
|
+
} from './compiled/types.ts'
|
|
19
|
+
import { hasInvalidChild } from './compiled/validation.ts'
|
|
20
|
+
import { attachEventProp, isEventProp } from './dom/events.ts'
|
|
21
|
+
import {
|
|
22
|
+
INTERNAL_NAMESPACE_PROP,
|
|
23
|
+
createComponentProps,
|
|
24
|
+
createIntrinsicElement,
|
|
25
|
+
intrinsicChildrenNamespace,
|
|
26
|
+
readIntrinsicNamespace,
|
|
27
|
+
resolveIntrinsicNamespace,
|
|
28
|
+
withIntrinsicNamespace,
|
|
29
|
+
} from './dom/intrinsic.ts'
|
|
30
|
+
import { intrinsicNamespaceUrl } from './dom/namespaces.ts'
|
|
31
|
+
import {
|
|
32
|
+
applyDomProp,
|
|
33
|
+
ensureControlledFormRestoration,
|
|
34
|
+
isControlledFormProp,
|
|
35
|
+
restoreControlledFormState,
|
|
36
|
+
} from './dom/properties.ts'
|
|
37
|
+
import {
|
|
38
|
+
claimHydrationElement,
|
|
39
|
+
claimHydrationArrayRange,
|
|
40
|
+
claimHydrationNode,
|
|
41
|
+
claimHydrationText,
|
|
42
|
+
createHydrationFragment,
|
|
43
|
+
finishHydrationArrayRange,
|
|
44
|
+
hydrationFragmentChildren,
|
|
45
|
+
isHydrating,
|
|
46
|
+
} from './hydration-bridge.ts'
|
|
47
|
+
import { mountRawHtmlProp } from './raw-html.ts'
|
|
48
|
+
import {
|
|
49
|
+
isRenderableProtocol,
|
|
50
|
+
materializeRenderable,
|
|
51
|
+
type RenderableProtocol,
|
|
52
|
+
} from './renderable-protocol.ts'
|
|
53
|
+
|
|
54
|
+
const DEV = typeof __VIDACT_DEV__ === 'undefined' || __VIDACT_DEV__
|
|
55
|
+
const UNSAFE_HTML = typeof __VIDACT_UNSAFE_HTML__ === 'undefined' || __VIDACT_UNSAFE_HTML__
|
|
56
|
+
|
|
57
|
+
export type DirectChild =
|
|
58
|
+
| Node
|
|
59
|
+
| string
|
|
60
|
+
| number
|
|
61
|
+
| bigint
|
|
62
|
+
| boolean
|
|
63
|
+
| null
|
|
64
|
+
| undefined
|
|
65
|
+
| readonly DirectChild[]
|
|
66
|
+
| CompiledBinding<unknown>
|
|
67
|
+
| StructuralBinding
|
|
68
|
+
| RenderableProtocol
|
|
69
|
+
export type DirectProps = Record<string, unknown> | null
|
|
70
|
+
export type DirectComponent = (props: Record<string, unknown>) => CompiledRenderValue
|
|
71
|
+
|
|
72
|
+
export const Fragment: symbol = Symbol.for('vidact.v1.Fragment')
|
|
73
|
+
let frameworkMetadataHandler: ((element: Element, props: DirectProps) => Node) | undefined
|
|
74
|
+
|
|
75
|
+
/** @internal */
|
|
76
|
+
export function installFrameworkMetadata(
|
|
77
|
+
handler: (element: Element, props: DirectProps) => Node,
|
|
78
|
+
): void {
|
|
79
|
+
frameworkMetadataHandler = handler
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function h<Tag extends keyof HTMLElementTagNameMap>(
|
|
83
|
+
type: Tag,
|
|
84
|
+
props: DirectProps,
|
|
85
|
+
...children: DirectChild[]
|
|
86
|
+
): HTMLElementTagNameMap[Tag]
|
|
87
|
+
export function h<Tag extends keyof MathMLElementTagNameMap>(
|
|
88
|
+
type: Tag,
|
|
89
|
+
props: DirectProps,
|
|
90
|
+
...children: DirectChild[]
|
|
91
|
+
): MathMLElementTagNameMap[Tag]
|
|
92
|
+
export function h(
|
|
93
|
+
type: typeof Fragment,
|
|
94
|
+
props: DirectProps,
|
|
95
|
+
...children: DirectChild[]
|
|
96
|
+
): DocumentFragment
|
|
97
|
+
export function h(
|
|
98
|
+
type: DirectComponent,
|
|
99
|
+
props: DirectProps,
|
|
100
|
+
...children: DirectChild[]
|
|
101
|
+
): DirectChild
|
|
102
|
+
export function h<T>(
|
|
103
|
+
type: CompiledContext<T>,
|
|
104
|
+
props: DirectProps,
|
|
105
|
+
...children: DirectChild[]
|
|
106
|
+
): DirectChild
|
|
107
|
+
export function h(
|
|
108
|
+
type: string | typeof Fragment | DirectComponent | CompiledContext<unknown>,
|
|
109
|
+
props: DirectProps,
|
|
110
|
+
...children: DirectChild[]
|
|
111
|
+
): DirectChild
|
|
112
|
+
export function h(
|
|
113
|
+
type: string | typeof Fragment | DirectComponent | CompiledContext<unknown>,
|
|
114
|
+
props: DirectProps,
|
|
115
|
+
...children: DirectChild[]
|
|
116
|
+
): DirectChild {
|
|
117
|
+
if (typeof type === 'symbol') {
|
|
118
|
+
if (isHydrating()) return createHydrationFragment(children)
|
|
119
|
+
const fragment = document.createDocumentFragment()
|
|
120
|
+
appendChildren(fragment, children)
|
|
121
|
+
return fragment
|
|
122
|
+
}
|
|
123
|
+
if (typeof type === 'function') {
|
|
124
|
+
const namespace = readIntrinsicNamespace(props)
|
|
125
|
+
const component = type as DirectComponent
|
|
126
|
+
const root = constructCompiledComponent(
|
|
127
|
+
() =>
|
|
128
|
+
withIntrinsicNamespace(namespace, () => component(createComponentProps(props, children))),
|
|
129
|
+
type,
|
|
130
|
+
)
|
|
131
|
+
adoptCompiledRoot(root)
|
|
132
|
+
return root
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const namespace = resolveIntrinsicNamespace(type, readIntrinsicNamespace(props))
|
|
136
|
+
const namespaceUrl = intrinsicNamespaceUrl(namespace)
|
|
137
|
+
const element =
|
|
138
|
+
claimHydrationElement(type, namespaceUrl, (candidate) =>
|
|
139
|
+
matchesHydrationElement(candidate, props, children),
|
|
140
|
+
) ?? createIntrinsicElement(document, type, namespace)
|
|
141
|
+
const restoreAfterChildren = applyProps(element, props, children)
|
|
142
|
+
withIntrinsicNamespace(intrinsicChildrenNamespace(type, namespace), () =>
|
|
143
|
+
appendChildren(element, children),
|
|
144
|
+
)
|
|
145
|
+
if (restoreAfterChildren) restoreControlledFormState(element)
|
|
146
|
+
if (frameworkMetadataHandler !== undefined && namespace === 'html') {
|
|
147
|
+
return frameworkMetadataHandler(element, props)
|
|
148
|
+
}
|
|
149
|
+
return element
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function createElement(
|
|
153
|
+
type: string | typeof Fragment | DirectComponent,
|
|
154
|
+
props: DirectProps,
|
|
155
|
+
...children: DirectChild[]
|
|
156
|
+
): DirectChild {
|
|
157
|
+
if (children.length === 0 && props !== null && Object.hasOwn(props, 'children')) {
|
|
158
|
+
return h(type, props, props.children as DirectChild)
|
|
159
|
+
}
|
|
160
|
+
return h(type, props, ...children)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function matchesHydrationElement(
|
|
164
|
+
element: Element,
|
|
165
|
+
props: DirectProps,
|
|
166
|
+
children: readonly DirectChild[],
|
|
167
|
+
): boolean {
|
|
168
|
+
const classInput = props?.className
|
|
169
|
+
const expectedClass = isCompiledBinding(classInput) ? classInput[1]() : classInput
|
|
170
|
+
if (typeof expectedClass === 'string' && element.getAttribute('class') !== expectedClass) {
|
|
171
|
+
return false
|
|
172
|
+
}
|
|
173
|
+
const idInput = props?.id
|
|
174
|
+
const expectedId = isCompiledBinding(idInput) ? idInput[1]() : idInput
|
|
175
|
+
if (typeof expectedId === 'string' && element.getAttribute('id') !== expectedId) return false
|
|
176
|
+
|
|
177
|
+
const expectedNodes: Node[] = []
|
|
178
|
+
collectHydrationChildNodes(children, expectedNodes)
|
|
179
|
+
if (expectedNodes.some((node) => !element.contains(node))) return false
|
|
180
|
+
|
|
181
|
+
const expectedText = staticHydrationText(children)
|
|
182
|
+
return expectedText === undefined || element.textContent === expectedText
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function collectHydrationChildNodes(children: readonly DirectChild[], nodes: Node[]): void {
|
|
186
|
+
for (const child of children) {
|
|
187
|
+
if (Array.isArray(child)) {
|
|
188
|
+
collectHydrationChildNodes(child, nodes)
|
|
189
|
+
continue
|
|
190
|
+
}
|
|
191
|
+
if (child instanceof DocumentFragment) {
|
|
192
|
+
const fragmentChildren = hydrationFragmentChildren(child)
|
|
193
|
+
if (fragmentChildren !== undefined) {
|
|
194
|
+
collectHydrationChildNodes(fragmentChildren as readonly DirectChild[], nodes)
|
|
195
|
+
}
|
|
196
|
+
continue
|
|
197
|
+
}
|
|
198
|
+
if (child instanceof Node) nodes.push(child)
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function staticHydrationText(children: readonly DirectChild[]): string | undefined {
|
|
203
|
+
let text = ''
|
|
204
|
+
for (const child of children) {
|
|
205
|
+
if (Array.isArray(child)) {
|
|
206
|
+
const nested = staticHydrationText(child)
|
|
207
|
+
if (nested === undefined) return undefined
|
|
208
|
+
text += nested
|
|
209
|
+
continue
|
|
210
|
+
}
|
|
211
|
+
if (child === null || child === undefined || typeof child === 'boolean') continue
|
|
212
|
+
if (isCompiledBinding(child)) {
|
|
213
|
+
const value = child[1]()
|
|
214
|
+
if (value === null || value === undefined || typeof value === 'boolean') continue
|
|
215
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'bigint') {
|
|
216
|
+
text += String(value)
|
|
217
|
+
continue
|
|
218
|
+
}
|
|
219
|
+
return undefined
|
|
220
|
+
}
|
|
221
|
+
if (typeof child === 'string' || typeof child === 'number' || typeof child === 'bigint') {
|
|
222
|
+
text += String(child)
|
|
223
|
+
continue
|
|
224
|
+
}
|
|
225
|
+
return undefined
|
|
226
|
+
}
|
|
227
|
+
return text
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function applyProps(
|
|
231
|
+
element: Element,
|
|
232
|
+
props: DirectProps,
|
|
233
|
+
children: readonly DirectChild[],
|
|
234
|
+
): boolean {
|
|
235
|
+
if (props === null) return false
|
|
236
|
+
const rawHtml = props.dangerouslySetInnerHTML
|
|
237
|
+
let restoreAfterChildren = false
|
|
238
|
+
let hasControlledRestoration = false
|
|
239
|
+
for (const name in props) {
|
|
240
|
+
if (!Object.hasOwn(props, name)) continue
|
|
241
|
+
const value = props[name]
|
|
242
|
+
if (name.startsWith('__vidactSpread') && typeof value === 'function') {
|
|
243
|
+
restoreAfterChildren = Boolean(value(element)) || restoreAfterChildren
|
|
244
|
+
continue
|
|
245
|
+
}
|
|
246
|
+
if (name === 'key' || name === 'children' || name === INTERNAL_NAMESPACE_PROP) continue
|
|
247
|
+
if (name === 'dangerouslySetInnerHTML') continue
|
|
248
|
+
if (!hasControlledRestoration && isControlledFormProp(element, name)) {
|
|
249
|
+
registerCompiledCleanup(ensureControlledFormRestoration(element))
|
|
250
|
+
hasControlledRestoration = true
|
|
251
|
+
}
|
|
252
|
+
if (name === 'value' && element instanceof HTMLSelectElement) restoreAfterChildren = true
|
|
253
|
+
if (name === 'ref') {
|
|
254
|
+
if (isCompiledBinding(value)) {
|
|
255
|
+
mountCompiledRef(element, value)
|
|
256
|
+
continue
|
|
257
|
+
}
|
|
258
|
+
// A generated renderable wrapper always projects a `ref` field, even when
|
|
259
|
+
// its input does not own one. Do not let that nullish projection replace a
|
|
260
|
+
// pending ref mounted by an earlier reactive spread. Authored overrides
|
|
261
|
+
// are already excluded from that spread by `compiledSpread`.
|
|
262
|
+
if (value !== null && value !== undefined) queueElementRef(element, value)
|
|
263
|
+
continue
|
|
264
|
+
}
|
|
265
|
+
if (isCompiledBinding(value)) {
|
|
266
|
+
if (isEventProp(name)) {
|
|
267
|
+
mountCompiledProp(value, (next) => attachEventProp(element, name, next))
|
|
268
|
+
continue
|
|
269
|
+
}
|
|
270
|
+
if (element instanceof HTMLSelectElement && name === 'multiple') {
|
|
271
|
+
mountCompiledPropTransition(
|
|
272
|
+
value,
|
|
273
|
+
(initial) => applyDomProp(element, name, initial),
|
|
274
|
+
// oxlint-disable no-sparse-arrays -- Preserve the compact positional ABI.
|
|
275
|
+
(next, previous) => [
|
|
276
|
+
() => applyDomProp(element, name, next),
|
|
277
|
+
() => {
|
|
278
|
+
applyDomProp(element, name, previous)
|
|
279
|
+
restoreControlledFormState(element)
|
|
280
|
+
},
|
|
281
|
+
,
|
|
282
|
+
() => restoreControlledFormState(element),
|
|
283
|
+
-1,
|
|
284
|
+
],
|
|
285
|
+
// oxlint-enable no-sparse-arrays
|
|
286
|
+
)
|
|
287
|
+
continue
|
|
288
|
+
}
|
|
289
|
+
mountCompiledProp(value, (next) => applyDomProp(element, name, next))
|
|
290
|
+
continue
|
|
291
|
+
}
|
|
292
|
+
if (isEventProp(name)) {
|
|
293
|
+
registerCompiledCleanup(attachEventProp(element, name, value))
|
|
294
|
+
continue
|
|
295
|
+
}
|
|
296
|
+
applyDomProp(element, name, value)
|
|
297
|
+
}
|
|
298
|
+
if (rawHtml === null || rawHtml === undefined) return restoreAfterChildren
|
|
299
|
+
if (!(element instanceof HTMLElement)) {
|
|
300
|
+
throw new Error(
|
|
301
|
+
DEV ? 'dangerouslySetInnerHTML on SVG and MathML elements is not supported' : 'V102',
|
|
302
|
+
)
|
|
303
|
+
}
|
|
304
|
+
if (!UNSAFE_HTML) {
|
|
305
|
+
throw new Error(
|
|
306
|
+
DEV ? 'dangerouslySetInnerHTML requires the unsafe-html compiler feature' : 'V104',
|
|
307
|
+
)
|
|
308
|
+
}
|
|
309
|
+
mountRawHtmlProp(element, rawHtml, children)
|
|
310
|
+
return restoreAfterChildren
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function appendChildren(parent: Node, children: readonly DirectChild[]): void {
|
|
314
|
+
if (hasInvalidChild(children)) {
|
|
315
|
+
throw new TypeError(
|
|
316
|
+
DEV ? 'unsupported direct child value; expected a DOM node or owned block' : 'V103',
|
|
317
|
+
)
|
|
318
|
+
}
|
|
319
|
+
for (const child of children) appendChild(parent, child)
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function appendChild(parent: Node, child: DirectChild): void {
|
|
323
|
+
if (child === null || child === undefined || typeof child === 'boolean') {
|
|
324
|
+
claimHydrationText(parent, '')
|
|
325
|
+
return
|
|
326
|
+
}
|
|
327
|
+
if (isStructuralBinding(child)) {
|
|
328
|
+
child[1](parent, null)
|
|
329
|
+
return
|
|
330
|
+
}
|
|
331
|
+
if (isCompiledBinding(child)) {
|
|
332
|
+
mountCompiledBinding(parent, child)
|
|
333
|
+
return
|
|
334
|
+
}
|
|
335
|
+
if (isRenderableProtocol(child)) {
|
|
336
|
+
appendChild(parent, materializeRenderable(child) as DirectChild)
|
|
337
|
+
return
|
|
338
|
+
}
|
|
339
|
+
if (Array.isArray(child)) {
|
|
340
|
+
const hydratedRange = claimHydrationArrayRange(parent)
|
|
341
|
+
for (const item of child) appendChild(parent, item)
|
|
342
|
+
if (hydratedRange !== undefined) finishHydrationArrayRange(parent, hydratedRange[1])
|
|
343
|
+
return
|
|
344
|
+
}
|
|
345
|
+
if (child instanceof Node) {
|
|
346
|
+
if (child instanceof DocumentFragment) {
|
|
347
|
+
const hydrationChildren = hydrationFragmentChildren(child)
|
|
348
|
+
if (hydrationChildren !== undefined) {
|
|
349
|
+
for (const item of hydrationChildren) appendChild(parent, item as DirectChild)
|
|
350
|
+
return
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
if (!claimHydrationNode(parent, child)) parent.appendChild(child)
|
|
354
|
+
return
|
|
355
|
+
}
|
|
356
|
+
if (typeof child === 'object' || typeof child === 'function' || typeof child === 'symbol') {
|
|
357
|
+
throw new TypeError(
|
|
358
|
+
DEV ? 'unsupported direct child value; expected a DOM node or owned block' : 'V103',
|
|
359
|
+
)
|
|
360
|
+
}
|
|
361
|
+
const content = String(child)
|
|
362
|
+
if (claimHydrationText(parent, content) === undefined) {
|
|
363
|
+
parent.appendChild(document.createTextNode(content))
|
|
364
|
+
}
|
|
365
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export const SERVER_BOOLEAN_ATTRIBUTES: ReadonlySet<string> = new Set([
|
|
2
|
+
'allowFullScreen',
|
|
3
|
+
'async',
|
|
4
|
+
'autoFocus',
|
|
5
|
+
'autoPlay',
|
|
6
|
+
'checked',
|
|
7
|
+
'controls',
|
|
8
|
+
'default',
|
|
9
|
+
'defaultChecked',
|
|
10
|
+
'defer',
|
|
11
|
+
'disabled',
|
|
12
|
+
'disablePictureInPicture',
|
|
13
|
+
'disableRemotePlayback',
|
|
14
|
+
'formNoValidate',
|
|
15
|
+
'hidden',
|
|
16
|
+
'inert',
|
|
17
|
+
'itemScope',
|
|
18
|
+
'loop',
|
|
19
|
+
'multiple',
|
|
20
|
+
'muted',
|
|
21
|
+
'noModule',
|
|
22
|
+
'noValidate',
|
|
23
|
+
'open',
|
|
24
|
+
'playsInline',
|
|
25
|
+
'readOnly',
|
|
26
|
+
'required',
|
|
27
|
+
'reversed',
|
|
28
|
+
'selected',
|
|
29
|
+
])
|
|
30
|
+
|
|
31
|
+
const SERVER_ATTRIBUTE_ALIASES: Readonly<Record<string, string>> = {
|
|
32
|
+
acceptCharset: 'accept-charset',
|
|
33
|
+
className: 'class',
|
|
34
|
+
crossOrigin: 'crossorigin',
|
|
35
|
+
defaultChecked: 'checked',
|
|
36
|
+
defaultValue: 'value',
|
|
37
|
+
formAction: 'formaction',
|
|
38
|
+
htmlFor: 'for',
|
|
39
|
+
httpEquiv: 'http-equiv',
|
|
40
|
+
itemID: 'itemid',
|
|
41
|
+
itemProp: 'itemprop',
|
|
42
|
+
itemRef: 'itemref',
|
|
43
|
+
itemScope: 'itemscope',
|
|
44
|
+
itemType: 'itemtype',
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const VALID_ATTRIBUTE_NAME = /^[A-Za-z_:][A-Za-z0-9:._-]*$/
|
|
48
|
+
|
|
49
|
+
export const META_IDENTITY_PROPS = ['charSet', 'name', 'property', 'httpEquiv'] as const
|
|
50
|
+
export const LINK_IDENTITY_PROPS = ['rel', 'href', 'as'] as const
|
|
51
|
+
export const META_IDENTITY_ATTRIBUTES = ['charset', 'name', 'property', 'http-equiv'] as const
|
|
52
|
+
|
|
53
|
+
export function serverHtmlAttributeName(name: string): string {
|
|
54
|
+
return SERVER_ATTRIBUTE_ALIASES[name] ?? name
|
|
55
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { isReactFormChangeEvent, restoreControlledFormState } from './properties.ts'
|
|
2
|
+
|
|
3
|
+
const DEV = typeof __VIDACT_DEV__ === 'undefined' || __VIDACT_DEV__
|
|
4
|
+
|
|
5
|
+
function isSupportedReactEventName(name: string): boolean {
|
|
6
|
+
return '|Abort|AnimationEnd|AnimationIteration|AnimationStart|AuxClick|BeforeInput|BeforeToggle|Blur|CanPlay|CanPlayThrough|Cancel|Change|Click|Close|CompositionEnd|CompositionStart|CompositionUpdate|ContextMenu|Copy|Cut|DoubleClick|Drag|DragEnd|DragEnter|DragExit|DragLeave|DragOver|DragStart|Drop|DurationChange|Emptied|Encrypted|Ended|Error|Focus|GotPointerCapture|Input|Invalid|KeyDown|KeyPress|KeyUp|Load|LoadedData|LoadedMetadata|LoadStart|LostPointerCapture|MouseDown|MouseEnter|MouseLeave|MouseMove|MouseOut|MouseOver|MouseUp|Paste|Pause|Play|Playing|PointerCancel|PointerDown|PointerEnter|PointerLeave|PointerMove|PointerOut|PointerOver|PointerUp|Progress|RateChange|Reset|Resize|Scroll|ScrollEnd|Seeked|Seeking|Select|Stalled|Submit|Suspend|TimeUpdate|Toggle|TouchCancel|TouchEnd|TouchMove|TouchStart|TransitionCancel|TransitionEnd|TransitionRun|TransitionStart|VolumeChange|Waiting|Wheel|'.includes(
|
|
7
|
+
`|${name}|`,
|
|
8
|
+
)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function attachEventProp(element: Element, name: string, value: unknown): () => void {
|
|
12
|
+
if (value === null || value === undefined) return () => {}
|
|
13
|
+
if (typeof value !== 'function') {
|
|
14
|
+
throw new TypeError(DEV ? `event prop ${name} must be a function, null, or undefined` : 'V201')
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const reactEventName = name.slice(2)
|
|
18
|
+
const capture = reactEventName.endsWith('Capture') && !reactEventName.endsWith('PointerCapture')
|
|
19
|
+
const eventNameWithoutPhase = capture
|
|
20
|
+
? reactEventName.slice(0, -'Capture'.length)
|
|
21
|
+
: reactEventName
|
|
22
|
+
if (DEV && !isSupportedReactEventName(eventNameWithoutPhase)) {
|
|
23
|
+
throw new TypeError(DEV ? `unsupported event prop ${name}` : 'V202')
|
|
24
|
+
}
|
|
25
|
+
if (eventNameWithoutPhase === 'Change') {
|
|
26
|
+
return attachReactChangeEvent(element, value as EventListener, capture)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const eventName = nativeEventName(eventNameWithoutPhase)
|
|
30
|
+
if (eventName === 'input') {
|
|
31
|
+
const dispatch = (event: Event): void =>
|
|
32
|
+
invokeFormListener(element, value as EventListener, event)
|
|
33
|
+
element.addEventListener(eventName, dispatch, capture)
|
|
34
|
+
return () => element.removeEventListener(eventName, dispatch, capture)
|
|
35
|
+
}
|
|
36
|
+
const dispatch = (event: Event): void => (value as EventListener)(reactShapedEvent(event))
|
|
37
|
+
element.addEventListener(eventName, dispatch, capture)
|
|
38
|
+
return () => element.removeEventListener(eventName, dispatch, capture)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function isEventProp(name: string): boolean {
|
|
42
|
+
return /^on[A-Z]/.test(name)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function attachReactChangeEvent(
|
|
46
|
+
element: Element,
|
|
47
|
+
listener: EventListener,
|
|
48
|
+
capture: boolean,
|
|
49
|
+
): () => void {
|
|
50
|
+
const dispatch = (event: Event): void => {
|
|
51
|
+
const target = event.target
|
|
52
|
+
if (!(target instanceof Element) || !isReactFormChangeEvent(target, event.type)) return
|
|
53
|
+
invokeFormListener(element, listener, event)
|
|
54
|
+
}
|
|
55
|
+
element.addEventListener('input', dispatch, capture)
|
|
56
|
+
element.addEventListener('change', dispatch, capture)
|
|
57
|
+
return () => {
|
|
58
|
+
element.removeEventListener('input', dispatch, capture)
|
|
59
|
+
element.removeEventListener('change', dispatch, capture)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function invokeFormListener(element: Element, listener: EventListener, event: Event): void {
|
|
64
|
+
try {
|
|
65
|
+
listener(reactShapedEvent(event))
|
|
66
|
+
} finally {
|
|
67
|
+
const target = event.target as Element
|
|
68
|
+
if (isReactFormChangeEvent(target, event.type) && (target === element || event.cancelBubble)) {
|
|
69
|
+
restoreControlledFormState(target)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function reactShapedEvent(event: Event): Event {
|
|
75
|
+
const shaped = event as Event & {
|
|
76
|
+
nativeEvent?: Event
|
|
77
|
+
isDefaultPrevented?: () => boolean
|
|
78
|
+
isPropagationStopped?: () => boolean
|
|
79
|
+
persist?: () => void
|
|
80
|
+
}
|
|
81
|
+
shaped.nativeEvent ??= event
|
|
82
|
+
shaped.isDefaultPrevented ??= () => event.defaultPrevented
|
|
83
|
+
shaped.isPropagationStopped ??= () => event.cancelBubble
|
|
84
|
+
shaped.persist ??= () => {}
|
|
85
|
+
return shaped
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function nativeEventName(reactEventName: string): string {
|
|
89
|
+
if (reactEventName === 'DoubleClick') return 'dblclick'
|
|
90
|
+
if (reactEventName === 'Focus') return 'focusin'
|
|
91
|
+
if (reactEventName === 'Blur') return 'focusout'
|
|
92
|
+
return reactEventName.toLowerCase()
|
|
93
|
+
}
|