@vidact/runtime 0.2.0-beta.0 → 0.2.0-beta.10

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.
Files changed (244) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/README.md +1 -1
  3. package/dist/actions.d.ts +32 -30
  4. package/dist/actions.d.ts.map +1 -1
  5. package/dist/actions.js +251 -266
  6. package/dist/actions.js.map +1 -1
  7. package/dist/async.d.ts +20 -17
  8. package/dist/async.d.ts.map +1 -1
  9. package/dist/async.js +18 -17
  10. package/dist/async.js.map +1 -1
  11. package/dist/compiled/async-resource.d.ts +9 -6
  12. package/dist/compiled/async-resource.d.ts.map +1 -1
  13. package/dist/compiled/async-resource.js +69 -77
  14. package/dist/compiled/async-resource.js.map +1 -1
  15. package/dist/compiled/core.d.ts +148 -147
  16. package/dist/compiled/core.d.ts.map +1 -1
  17. package/dist/compiled/core.js +3064 -2987
  18. package/dist/compiled/core.js.map +1 -1
  19. package/dist/compiled/types.d.ts +44 -56
  20. package/dist/compiled/types.d.ts.map +1 -1
  21. package/dist/compiled/types.js +10 -6
  22. package/dist/compiled/types.js.map +1 -1
  23. package/dist/compiled/validation.d.ts +4 -1
  24. package/dist/compiled/validation.d.ts.map +1 -1
  25. package/dist/compiled/validation.js +17 -20
  26. package/dist/compiled/validation.js.map +1 -1
  27. package/dist/component-spread.d.ts +5 -3
  28. package/dist/component-spread.d.ts.map +1 -1
  29. package/dist/component-spread.js +49 -67
  30. package/dist/component-spread.js.map +1 -1
  31. package/dist/concurrent.d.ts +20 -18
  32. package/dist/concurrent.d.ts.map +1 -1
  33. package/dist/concurrent.js +191 -210
  34. package/dist/concurrent.js.map +1 -1
  35. package/dist/direct-dom.d.ts +17 -12
  36. package/dist/direct-dom.d.ts.map +1 -1
  37. package/dist/direct-dom.js +279 -222
  38. package/dist/direct-dom.js.map +1 -1
  39. package/dist/dom/attributes.d.ts +9 -6
  40. package/dist/dom/attributes.d.ts.map +1 -1
  41. package/dist/dom/attributes.js +65 -47
  42. package/dist/dom/attributes.js.map +1 -1
  43. package/dist/dom/events.d.ts +8 -2
  44. package/dist/dom/events.d.ts.map +1 -1
  45. package/dist/dom/events.js +118 -65
  46. package/dist/dom/events.js.map +1 -1
  47. package/dist/dom/forms.d.ts +9 -6
  48. package/dist/dom/forms.d.ts.map +1 -1
  49. package/dist/dom/forms.js +152 -198
  50. package/dist/dom/forms.js.map +1 -1
  51. package/dist/dom/intrinsic.d.ts +17 -15
  52. package/dist/dom/intrinsic.d.ts.map +1 -1
  53. package/dist/dom/intrinsic.js +48 -50
  54. package/dist/dom/intrinsic.js.map +1 -1
  55. package/dist/dom/namespace.d.ts +4 -1
  56. package/dist/dom/namespace.d.ts.map +1 -1
  57. package/dist/dom/namespace.js +25 -28
  58. package/dist/dom/namespace.js.map +1 -1
  59. package/dist/dom/namespaces.d.ts +11 -8
  60. package/dist/dom/namespaces.d.ts.map +1 -1
  61. package/dist/dom/namespaces.js +14 -12
  62. package/dist/dom/namespaces.js.map +1 -1
  63. package/dist/dom/properties.d.ts +18 -16
  64. package/dist/dom/properties.d.ts.map +1 -1
  65. package/dist/dom/properties.js +273 -296
  66. package/dist/dom/properties.js.map +1 -1
  67. package/dist/dom/style-properties.d.ts +4 -1
  68. package/dist/dom/style-properties.d.ts.map +1 -1
  69. package/dist/dom/style-properties.js +49 -45
  70. package/dist/dom/style-properties.js.map +1 -1
  71. package/dist/dom/styles.d.ts +5 -2
  72. package/dist/dom/styles.d.ts.map +1 -1
  73. package/dist/dom/styles.js +47 -67
  74. package/dist/dom/styles.js.map +1 -1
  75. package/dist/dom-forms.d.ts +4 -1
  76. package/dist/dom-forms.d.ts.map +1 -1
  77. package/dist/dom-forms.js +16 -13
  78. package/dist/dom-forms.js.map +1 -1
  79. package/dist/dom-styles.d.ts +4 -1
  80. package/dist/dom-styles.d.ts.map +1 -1
  81. package/dist/dom-styles.js +10 -7
  82. package/dist/dom-styles.js.map +1 -1
  83. package/dist/framework-hydrate.d.ts +20 -17
  84. package/dist/framework-hydrate.d.ts.map +1 -1
  85. package/dist/framework-hydrate.js +128 -146
  86. package/dist/framework-hydrate.js.map +1 -1
  87. package/dist/framework-protocol.d.ts +27 -25
  88. package/dist/framework-protocol.d.ts.map +1 -1
  89. package/dist/framework-protocol.js +173 -211
  90. package/dist/framework-protocol.js.map +1 -1
  91. package/dist/framework.d.ts +34 -32
  92. package/dist/framework.d.ts.map +1 -1
  93. package/dist/framework.js +74 -93
  94. package/dist/framework.js.map +1 -1
  95. package/dist/hydrate.d.ts +11 -8
  96. package/dist/hydrate.d.ts.map +1 -1
  97. package/dist/hydrate.js +13 -9
  98. package/dist/hydrate.js.map +1 -1
  99. package/dist/hydration-bridge.d.ts +70 -58
  100. package/dist/hydration-bridge.d.ts.map +1 -1
  101. package/dist/hydration-bridge.js +77 -66
  102. package/dist/hydration-bridge.js.map +1 -1
  103. package/dist/hydration.d.ts +54 -28
  104. package/dist/hydration.d.ts.map +1 -1
  105. package/dist/hydration.js +450 -463
  106. package/dist/hydration.js.map +1 -1
  107. package/dist/index.d.ts +13 -13
  108. package/dist/index.js +11 -13
  109. package/dist/indexed-list.d.ts +8 -5
  110. package/dist/indexed-list.d.ts.map +1 -1
  111. package/dist/indexed-list.js +14 -7
  112. package/dist/indexed-list.js.map +1 -1
  113. package/dist/jsx-runtime.d.ts +10 -8
  114. package/dist/jsx-runtime.d.ts.map +1 -1
  115. package/dist/jsx-runtime.js +28 -23
  116. package/dist/jsx-runtime.js.map +1 -1
  117. package/dist/keyed-list.d.ts +17 -14
  118. package/dist/keyed-list.d.ts.map +1 -1
  119. package/dist/keyed-list.js +244 -161
  120. package/dist/keyed-list.js.map +1 -1
  121. package/dist/metadata.d.ts +6 -3
  122. package/dist/metadata.d.ts.map +1 -1
  123. package/dist/metadata.js +131 -164
  124. package/dist/metadata.js.map +1 -1
  125. package/dist/nested-prop.d.ts +4 -2
  126. package/dist/nested-prop.d.ts.map +1 -1
  127. package/dist/nested-prop.js +17 -16
  128. package/dist/nested-prop.js.map +1 -1
  129. package/dist/profiling.d.ts +11 -8
  130. package/dist/profiling.d.ts.map +1 -1
  131. package/dist/profiling.js +17 -17
  132. package/dist/profiling.js.map +1 -1
  133. package/dist/protocol.d.ts +5 -2
  134. package/dist/protocol.d.ts.map +1 -1
  135. package/dist/protocol.js +8 -5
  136. package/dist/protocol.js.map +1 -1
  137. package/dist/raw-html.d.ts +5 -2
  138. package/dist/raw-html.d.ts.map +1 -1
  139. package/dist/raw-html.js +86 -146
  140. package/dist/raw-html.js.map +1 -1
  141. package/dist/ref.d.ts +8 -3
  142. package/dist/ref.d.ts.map +1 -1
  143. package/dist/ref.js +10 -2
  144. package/dist/ref.js.map +1 -1
  145. package/dist/renderable-protocol.d.ts +26 -8
  146. package/dist/renderable-protocol.d.ts.map +1 -1
  147. package/dist/renderable-protocol.js +30 -9
  148. package/dist/renderable-protocol.js.map +1 -1
  149. package/dist/renderable.d.ts +28 -22
  150. package/dist/renderable.d.ts.map +1 -1
  151. package/dist/renderable.js +152 -133
  152. package/dist/renderable.js.map +1 -1
  153. package/dist/retained-ui.d.ts +9 -6
  154. package/dist/retained-ui.d.ts.map +1 -1
  155. package/dist/retained-ui.js +12 -10
  156. package/dist/retained-ui.js.map +1 -1
  157. package/dist/root.d.ts +18 -15
  158. package/dist/root.d.ts.map +1 -1
  159. package/dist/root.js +73 -85
  160. package/dist/root.js.map +1 -1
  161. package/dist/scheduler.d.ts +10 -8
  162. package/dist/scheduler.d.ts.map +1 -1
  163. package/dist/scheduler.js +97 -105
  164. package/dist/scheduler.js.map +1 -1
  165. package/dist/server-framework.d.ts +45 -42
  166. package/dist/server-framework.d.ts.map +1 -1
  167. package/dist/server-framework.js +209 -217
  168. package/dist/server-framework.js.map +1 -1
  169. package/dist/server.d.ts +130 -128
  170. package/dist/server.d.ts.map +1 -1
  171. package/dist/server.js +603 -710
  172. package/dist/server.js.map +1 -1
  173. package/dist/shared/promise.d.ts +6 -3
  174. package/dist/shared/promise.d.ts.map +1 -1
  175. package/dist/shared/promise.js +21 -19
  176. package/dist/shared/promise.js.map +1 -1
  177. package/dist/source-mask.d.ts +10 -6
  178. package/dist/source-mask.d.ts.map +1 -1
  179. package/dist/source-mask.js +60 -63
  180. package/dist/source-mask.js.map +1 -1
  181. package/dist/spread.d.ts +5 -2
  182. package/dist/spread.d.ts.map +1 -1
  183. package/dist/spread.js +79 -99
  184. package/dist/spread.js.map +1 -1
  185. package/dist/state-slot.d.ts +29 -15
  186. package/dist/state-slot.d.ts.map +1 -1
  187. package/dist/state-slot.js +73 -42
  188. package/dist/state-slot.js.map +1 -1
  189. package/dist/testing.d.ts +9 -6
  190. package/dist/testing.d.ts.map +1 -1
  191. package/dist/testing.js +16 -12
  192. package/dist/testing.js.map +1 -1
  193. package/package.json +8 -7
  194. package/src/actions.ts +415 -0
  195. package/src/async.ts +78 -0
  196. package/src/compiled/async-resource.ts +113 -0
  197. package/src/compiled/core.ts +4647 -0
  198. package/src/compiled/types.ts +96 -0
  199. package/src/compiled/validation.ts +23 -0
  200. package/src/component-spread.ts +86 -0
  201. package/src/concurrent.ts +310 -0
  202. package/src/direct-dom.ts +491 -0
  203. package/src/dom/attributes.ts +55 -0
  204. package/src/dom/events.ts +179 -0
  205. package/src/dom/forms.ts +220 -0
  206. package/src/dom/intrinsic.ts +94 -0
  207. package/src/dom/namespace.ts +30 -0
  208. package/src/dom/namespaces.ts +14 -0
  209. package/src/dom/properties.ts +355 -0
  210. package/src/dom/style-properties.ts +46 -0
  211. package/src/dom/styles.ts +86 -0
  212. package/src/dom-forms.ts +23 -0
  213. package/src/dom-styles.ts +11 -0
  214. package/src/env.d.ts +6 -0
  215. package/src/framework-hydrate.ts +224 -0
  216. package/src/framework-protocol.ts +335 -0
  217. package/src/framework.ts +161 -0
  218. package/src/hydrate.ts +38 -0
  219. package/src/hydration-bridge.ts +202 -0
  220. package/src/hydration.ts +644 -0
  221. package/src/index.ts +94 -0
  222. package/src/indexed-list.ts +20 -0
  223. package/src/jsx-runtime.ts +55 -0
  224. package/src/keyed-list.ts +379 -0
  225. package/src/metadata.ts +212 -0
  226. package/src/nested-prop.ts +27 -0
  227. package/src/profiling.ts +43 -0
  228. package/src/protocol.ts +8 -0
  229. package/src/raw-html.ts +206 -0
  230. package/src/ref.ts +13 -0
  231. package/src/renderable-protocol.ts +63 -0
  232. package/src/renderable.ts +313 -0
  233. package/src/retained-ui.ts +19 -0
  234. package/src/root.ts +122 -0
  235. package/src/scheduler.ts +136 -0
  236. package/src/server-framework.ts +397 -0
  237. package/src/server.ts +1160 -0
  238. package/src/shared/promise.ts +28 -0
  239. package/src/source-mask.ts +103 -0
  240. package/src/spread.ts +131 -0
  241. package/src/state-slot.ts +132 -0
  242. package/src/testing.ts +27 -0
  243. package/dist/index.d.ts.map +0 -1
  244. package/dist/index.js.map +0 -1
@@ -0,0 +1,491 @@
1
+ import {
2
+ isCompiledBinding,
3
+ isCompiledEventHandler,
4
+ isStructuralBinding,
5
+ adoptCompiledRoot,
6
+ constructCompiledComponent,
7
+ mountCompiledBinding,
8
+ mountCompiledProp,
9
+ mountCompiledRef,
10
+ mountCompiledPropTransition,
11
+ queueElementRef,
12
+ registerCompiledCleanup,
13
+ } from './compiled/core.ts'
14
+ import type {
15
+ CompiledBinding,
16
+ CompiledContext,
17
+ CompiledRenderValue,
18
+ StructuralBinding,
19
+ } from './compiled/types.ts'
20
+ import { hasInvalidChild } from './compiled/validation.ts'
21
+ import { attachCompiledEventProp, attachEventProp, isEventProp } from './dom/events.ts'
22
+ import {
23
+ type IntrinsicNamespace,
24
+ INTERNAL_NAMESPACE_PROP,
25
+ createComponentProps,
26
+ createIntrinsicElement,
27
+ currentIntrinsicNamespace,
28
+ intrinsicChildrenNamespace,
29
+ readIntrinsicNamespace,
30
+ resolveIntrinsicNamespace,
31
+ withIntrinsicNamespace,
32
+ } from './dom/intrinsic.ts'
33
+ import { intrinsicNamespaceUrl } from './dom/namespaces.ts'
34
+ import {
35
+ applyDomProp,
36
+ ensureControlledFormRestoration,
37
+ isControlledFormProp,
38
+ restoreControlledFormState,
39
+ } from './dom/properties.ts'
40
+ import {
41
+ claimHydrationElement,
42
+ claimHydrationArrayRange,
43
+ claimHydrationNode,
44
+ claimHydrationText,
45
+ createHydrationFragment,
46
+ finishHydrationArrayRange,
47
+ hydrationFragmentChildren,
48
+ isHydrating,
49
+ } from './hydration-bridge.ts'
50
+ import { mountRawHtmlProp } from './raw-html.ts'
51
+ import {
52
+ isRenderableProtocol,
53
+ materializeRenderable,
54
+ type RenderableProtocol,
55
+ } from './renderable-protocol.ts'
56
+
57
+ const DEV = typeof __VIDACT_DEV__ === 'undefined' || __VIDACT_DEV__
58
+ const UNSAFE_HTML = typeof __VIDACT_UNSAFE_HTML__ === 'undefined' || __VIDACT_UNSAFE_HTML__
59
+
60
+ export type DirectChild =
61
+ | Node
62
+ | string
63
+ | number
64
+ | bigint
65
+ | boolean
66
+ | null
67
+ | undefined
68
+ | readonly DirectChild[]
69
+ | CompiledBinding<unknown>
70
+ | StructuralBinding
71
+ | RenderableProtocol
72
+ export type DirectProps = Record<string, unknown> | null
73
+ export type DirectComponent = (props: Record<string, unknown>) => CompiledRenderValue
74
+
75
+ export const Fragment: symbol = Symbol.for('vidact.v1.Fragment')
76
+ let frameworkMetadataHandler: ((element: Element, props: DirectProps) => Node) | undefined
77
+ const staticIntrinsicShells = new Map<string, Element>()
78
+ const cloneSafeHtmlTags = new Set([
79
+ 'a',
80
+ 'article',
81
+ 'aside',
82
+ 'button',
83
+ 'div',
84
+ 'footer',
85
+ 'h1',
86
+ 'h2',
87
+ 'h3',
88
+ 'h4',
89
+ 'h5',
90
+ 'h6',
91
+ 'header',
92
+ 'li',
93
+ 'main',
94
+ 'nav',
95
+ 'ol',
96
+ 'p',
97
+ 'section',
98
+ 'span',
99
+ 'table',
100
+ 'tbody',
101
+ 'td',
102
+ 'tfoot',
103
+ 'th',
104
+ 'thead',
105
+ 'tr',
106
+ 'ul',
107
+ ])
108
+
109
+ /** @internal */
110
+ export function installFrameworkMetadata(
111
+ handler: (element: Element, props: DirectProps) => Node,
112
+ ): void {
113
+ frameworkMetadataHandler = handler
114
+ }
115
+
116
+ export function h<Tag extends keyof HTMLElementTagNameMap>(
117
+ type: Tag,
118
+ props: DirectProps,
119
+ ...children: DirectChild[]
120
+ ): HTMLElementTagNameMap[Tag]
121
+ export function h<Tag extends keyof MathMLElementTagNameMap>(
122
+ type: Tag,
123
+ props: DirectProps,
124
+ ...children: DirectChild[]
125
+ ): MathMLElementTagNameMap[Tag]
126
+ export function h(
127
+ type: typeof Fragment,
128
+ props: DirectProps,
129
+ ...children: DirectChild[]
130
+ ): DocumentFragment
131
+ export function h(
132
+ type: DirectComponent,
133
+ props: DirectProps,
134
+ ...children: DirectChild[]
135
+ ): DirectChild
136
+ export function h<T>(
137
+ type: CompiledContext<T>,
138
+ props: DirectProps,
139
+ ...children: DirectChild[]
140
+ ): DirectChild
141
+ export function h(
142
+ type: string | typeof Fragment | DirectComponent | CompiledContext<unknown>,
143
+ props: DirectProps,
144
+ ...children: DirectChild[]
145
+ ): DirectChild
146
+ export function h(
147
+ type: string | typeof Fragment | DirectComponent | CompiledContext<unknown>,
148
+ props: DirectProps,
149
+ ...children: DirectChild[]
150
+ ): DirectChild {
151
+ if (typeof type === 'symbol') {
152
+ if (isHydrating()) return createHydrationFragment(children)
153
+ const fragment = document.createDocumentFragment()
154
+ appendChildren(fragment, children)
155
+ return fragment
156
+ }
157
+ if (typeof type === 'function') {
158
+ const namespace = readIntrinsicNamespace(props)
159
+ const component = type as DirectComponent
160
+ const root = constructCompiledComponent(
161
+ () =>
162
+ withIntrinsicNamespace(namespace, () => component(createComponentProps(props, children))),
163
+ type,
164
+ )
165
+ adoptCompiledRoot(root)
166
+ return root
167
+ }
168
+
169
+ const namespace = resolveIntrinsicNamespace(type, readIntrinsicNamespace(props))
170
+ const namespaceUrl = intrinsicNamespaceUrl(namespace)
171
+ const hydratedElement = claimHydrationElement(type, namespaceUrl, (candidate) =>
172
+ matchesHydrationElement(candidate, props, children),
173
+ )
174
+ const shellKey =
175
+ hydratedElement === undefined ? staticIntrinsicShellKey(type, namespace, props) : undefined
176
+ let shell = shellKey === undefined ? undefined : staticIntrinsicShells.get(shellKey)
177
+ if (shellKey !== undefined && shell === undefined) {
178
+ shell = createIntrinsicElement(document, type, namespace)
179
+ applyStaticShellProps(shell, props)
180
+ if (staticIntrinsicShells.size >= 128) staticIntrinsicShells.clear()
181
+ staticIntrinsicShells.set(shellKey, shell)
182
+ }
183
+ const element =
184
+ hydratedElement ??
185
+ (shell?.cloneNode(false) as Element | undefined) ??
186
+ createIntrinsicElement(document, type, namespace)
187
+ const restoreAfterChildren = applyProps(element, props, children, shell !== undefined)
188
+ const childrenNamespace = intrinsicChildrenNamespace(type, namespace)
189
+ if (currentIntrinsicNamespace() === childrenNamespace) appendChildren(element, children)
190
+ else withIntrinsicNamespace(childrenNamespace, () => appendChildren(element, children))
191
+ if (restoreAfterChildren) restoreControlledFormState(element)
192
+ if (frameworkMetadataHandler !== undefined && namespace === 'html') {
193
+ return frameworkMetadataHandler(element, props)
194
+ }
195
+ return element
196
+ }
197
+
198
+ function staticIntrinsicShellKey(
199
+ type: string,
200
+ namespace: IntrinsicNamespace,
201
+ props: DirectProps,
202
+ ): string | undefined {
203
+ if (namespace !== 'html' || !cloneSafeHtmlTags.has(type)) return undefined
204
+ let key = type
205
+ if (props === null) return key
206
+ for (const name in props) {
207
+ if (!Object.hasOwn(props, name)) continue
208
+ if (name === 'key' || name === 'children' || name === INTERNAL_NAMESPACE_PROP) continue
209
+ const value = props[name]
210
+ if (!isStaticShellProp(name, value)) continue
211
+ key += `\0${name}\0${typeof value}\0${String(value)}`
212
+ }
213
+ return key
214
+ }
215
+
216
+ function isStaticShellProp(name: string, value: unknown): boolean {
217
+ if (
218
+ name !== 'className' &&
219
+ name !== 'id' &&
220
+ name !== 'href' &&
221
+ name !== 'rel' &&
222
+ name !== 'role' &&
223
+ name !== 'target' &&
224
+ name !== 'title' &&
225
+ name !== 'type' &&
226
+ !name.startsWith('aria-') &&
227
+ !name.startsWith('data-')
228
+ ) {
229
+ return false
230
+ }
231
+ return (
232
+ value === null ||
233
+ value === undefined ||
234
+ typeof value === 'string' ||
235
+ typeof value === 'number' ||
236
+ typeof value === 'boolean'
237
+ )
238
+ }
239
+
240
+ function applyStaticShellProps(element: Element, props: DirectProps): void {
241
+ if (props === null) return
242
+ for (const name in props) {
243
+ if (!Object.hasOwn(props, name)) continue
244
+ const value = props[name]
245
+ if (isStaticShellProp(name, value)) applyDomProp(element, name, value)
246
+ }
247
+ }
248
+
249
+ export function createElement(
250
+ type: string | typeof Fragment | DirectComponent,
251
+ props: DirectProps,
252
+ ...children: DirectChild[]
253
+ ): DirectChild {
254
+ if (children.length === 0 && props !== null && Object.hasOwn(props, 'children')) {
255
+ return h(type, props, props.children as DirectChild)
256
+ }
257
+ return h(type, props, ...children)
258
+ }
259
+
260
+ function matchesHydrationElement(
261
+ element: Element,
262
+ props: DirectProps,
263
+ children: readonly DirectChild[],
264
+ ): boolean {
265
+ const classInput = props?.className
266
+ const expectedClass = isCompiledBinding(classInput) ? classInput[1]() : classInput
267
+ if (typeof expectedClass === 'string' && element.getAttribute('class') !== expectedClass) {
268
+ return false
269
+ }
270
+ const idInput = props?.id
271
+ const expectedId = isCompiledBinding(idInput) ? idInput[1]() : idInput
272
+ if (typeof expectedId === 'string' && element.getAttribute('id') !== expectedId) return false
273
+
274
+ const expectedNodes: Node[] = []
275
+ collectHydrationChildNodes(children, expectedNodes)
276
+ if (expectedNodes.some((node) => !element.contains(node))) return false
277
+
278
+ const expectedText = staticHydrationText(children)
279
+ return expectedText === undefined || element.textContent === expectedText
280
+ }
281
+
282
+ function collectHydrationChildNodes(children: readonly DirectChild[], nodes: Node[]): void {
283
+ for (const child of children) {
284
+ if (Array.isArray(child)) {
285
+ collectHydrationChildNodes(child, nodes)
286
+ continue
287
+ }
288
+ if (child instanceof DocumentFragment) {
289
+ const fragmentChildren = hydrationFragmentChildren(child)
290
+ if (fragmentChildren !== undefined) {
291
+ collectHydrationChildNodes(fragmentChildren as readonly DirectChild[], nodes)
292
+ }
293
+ continue
294
+ }
295
+ if (child instanceof Node) nodes.push(child)
296
+ }
297
+ }
298
+
299
+ function staticHydrationText(children: readonly DirectChild[]): string | undefined {
300
+ let text = ''
301
+ for (const child of children) {
302
+ if (Array.isArray(child)) {
303
+ const nested = staticHydrationText(child)
304
+ if (nested === undefined) return undefined
305
+ text += nested
306
+ continue
307
+ }
308
+ if (child === null || child === undefined || typeof child === 'boolean') continue
309
+ if (isCompiledBinding(child)) {
310
+ const value = child[1]()
311
+ if (value === null || value === undefined || typeof value === 'boolean') continue
312
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'bigint') {
313
+ text += String(value)
314
+ continue
315
+ }
316
+ return undefined
317
+ }
318
+ if (typeof child === 'string' || typeof child === 'number' || typeof child === 'bigint') {
319
+ text += String(child)
320
+ continue
321
+ }
322
+ return undefined
323
+ }
324
+ return text
325
+ }
326
+
327
+ function applyProps(
328
+ element: Element,
329
+ props: DirectProps,
330
+ children: readonly DirectChild[],
331
+ skipStaticShellProps = false,
332
+ ): boolean {
333
+ if (props === null) return false
334
+ const rawHtml = props.dangerouslySetInnerHTML
335
+ let restoreAfterChildren = false
336
+ let hasControlledRestoration = false
337
+ for (const name in props) {
338
+ if (!Object.hasOwn(props, name)) continue
339
+ const value = props[name]
340
+ if (name.startsWith('__vidactSpread') && typeof value === 'function') {
341
+ restoreAfterChildren = Boolean(value(element)) || restoreAfterChildren
342
+ continue
343
+ }
344
+ if (name === 'key' || name === 'children' || name === INTERNAL_NAMESPACE_PROP) continue
345
+ if (name === 'dangerouslySetInnerHTML') continue
346
+ if (skipStaticShellProps && isStaticShellProp(name, value)) continue
347
+ if (!hasControlledRestoration && isControlledFormProp(element, name)) {
348
+ registerCompiledCleanup(ensureControlledFormRestoration(element))
349
+ hasControlledRestoration = true
350
+ }
351
+ if (name === 'value' && element instanceof HTMLSelectElement) restoreAfterChildren = true
352
+ if (name === 'ref') {
353
+ if (isCompiledBinding(value)) {
354
+ mountCompiledRef(element, value)
355
+ continue
356
+ }
357
+ // A generated renderable wrapper always projects a `ref` field, even when
358
+ // its input does not own one. Do not let that nullish projection replace a
359
+ // pending ref mounted by an earlier reactive spread. Authored overrides
360
+ // are already excluded from that spread by `compiledSpread`.
361
+ if (value !== null && value !== undefined) queueElementRef(element, value)
362
+ continue
363
+ }
364
+ if (isCompiledBinding(value)) {
365
+ if (isEventProp(name)) {
366
+ mountCompiledProp(value, (next) => attachCompiledEventProp(element, name, next))
367
+ continue
368
+ }
369
+ if (element instanceof HTMLSelectElement && name === 'multiple') {
370
+ mountCompiledPropTransition(
371
+ value,
372
+ (initial) => applyDomProp(element, name, initial),
373
+ // oxlint-disable no-sparse-arrays -- Preserve the compact positional ABI.
374
+ (next, previous) => [
375
+ () => applyDomProp(element, name, next),
376
+ () => {
377
+ applyDomProp(element, name, previous)
378
+ restoreControlledFormState(element)
379
+ },
380
+ ,
381
+ () => restoreControlledFormState(element),
382
+ -1,
383
+ ],
384
+ // oxlint-enable no-sparse-arrays
385
+ )
386
+ continue
387
+ }
388
+ mountCompiledProp(value, applyDomProp, element, name)
389
+ continue
390
+ }
391
+ if (isEventProp(name)) {
392
+ if (isCompiledEventHandler(value)) {
393
+ attachCompiledEventProp(element, name, value)
394
+ continue
395
+ }
396
+ registerCompiledCleanup(attachEventProp(element, name, value))
397
+ continue
398
+ }
399
+ applyDomProp(element, name, value)
400
+ }
401
+ if (rawHtml === null || rawHtml === undefined) return restoreAfterChildren
402
+ if (!(element instanceof HTMLElement)) {
403
+ throw new Error(
404
+ DEV ? 'dangerouslySetInnerHTML on SVG and MathML elements is not supported' : 'V102',
405
+ )
406
+ }
407
+ if (!UNSAFE_HTML) {
408
+ throw new Error(
409
+ DEV ? 'dangerouslySetInnerHTML requires the unsafe-html compiler feature' : 'V104',
410
+ )
411
+ }
412
+ mountRawHtmlProp(element, rawHtml, children)
413
+ return restoreAfterChildren
414
+ }
415
+
416
+ function appendChildren(parent: Node, children: readonly DirectChild[]): void {
417
+ if (!isHydrating()) {
418
+ if (children.length === 0) return
419
+ if (children.length === 1) {
420
+ const child = children[0]
421
+ if (child === null || child === undefined || typeof child === 'boolean') return
422
+ if (child instanceof Node) {
423
+ parent.appendChild(child)
424
+ return
425
+ }
426
+ if (typeof child === 'string' || typeof child === 'number' || typeof child === 'bigint') {
427
+ parent.appendChild(document.createTextNode(String(child)))
428
+ return
429
+ }
430
+ }
431
+ if (
432
+ children.length > 1 &&
433
+ parent instanceof Element &&
434
+ children.every((child): child is Node => child instanceof Node)
435
+ ) {
436
+ parent.append(...children)
437
+ return
438
+ }
439
+ }
440
+ if (hasInvalidChild(children)) {
441
+ throw new TypeError(
442
+ DEV ? 'unsupported direct child value; expected a DOM node or owned block' : 'V103',
443
+ )
444
+ }
445
+ for (const child of children) appendChild(parent, child)
446
+ }
447
+
448
+ function appendChild(parent: Node, child: DirectChild): void {
449
+ if (child === null || child === undefined || typeof child === 'boolean') {
450
+ claimHydrationText(parent, '')
451
+ return
452
+ }
453
+ if (isStructuralBinding(child)) {
454
+ child[1](parent, null)
455
+ return
456
+ }
457
+ if (isCompiledBinding(child)) {
458
+ mountCompiledBinding(parent, child)
459
+ return
460
+ }
461
+ if (isRenderableProtocol(child)) {
462
+ appendChild(parent, materializeRenderable(child) as DirectChild)
463
+ return
464
+ }
465
+ if (Array.isArray(child)) {
466
+ const hydratedRange = claimHydrationArrayRange(parent)
467
+ for (const item of child) appendChild(parent, item)
468
+ if (hydratedRange !== undefined) finishHydrationArrayRange(parent, hydratedRange[1])
469
+ return
470
+ }
471
+ if (child instanceof Node) {
472
+ if (child instanceof DocumentFragment) {
473
+ const hydrationChildren = hydrationFragmentChildren(child)
474
+ if (hydrationChildren !== undefined) {
475
+ for (const item of hydrationChildren) appendChild(parent, item as DirectChild)
476
+ return
477
+ }
478
+ }
479
+ if (!claimHydrationNode(parent, child)) parent.appendChild(child)
480
+ return
481
+ }
482
+ if (typeof child === 'object' || typeof child === 'function' || typeof child === 'symbol') {
483
+ throw new TypeError(
484
+ DEV ? 'unsupported direct child value; expected a DOM node or owned block' : 'V103',
485
+ )
486
+ }
487
+ const content = String(child)
488
+ if (claimHydrationText(parent, content) === undefined) {
489
+ parent.appendChild(document.createTextNode(content))
490
+ }
491
+ }
@@ -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
+ }