@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.
Files changed (244) hide show
  1. package/CHANGELOG.md +52 -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 +136 -147
  16. package/dist/compiled/core.d.ts.map +1 -1
  17. package/dist/compiled/core.js +2672 -2985
  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 +187 -221
  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 +5 -2
  44. package/dist/dom/events.d.ts.map +1 -1
  45. package/dist/dom/events.js +53 -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 +13 -14
  118. package/dist/keyed-list.d.ts.map +1 -1
  119. package/dist/keyed-list.js +132 -160
  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 +27 -22
  150. package/dist/renderable.d.ts.map +1 -1
  151. package/dist/renderable.js +141 -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 +9 -6
  178. package/dist/source-mask.d.ts.map +1 -1
  179. package/dist/source-mask.js +45 -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 +18 -15
  186. package/dist/state-slot.d.ts.map +1 -1
  187. package/dist/state-slot.js +43 -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 +4041 -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 +365 -0
  203. package/src/dom/attributes.ts +55 -0
  204. package/src/dom/events.ts +93 -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 +196 -0
  220. package/src/hydration.ts +642 -0
  221. package/src/index.ts +92 -0
  222. package/src/indexed-list.ts +20 -0
  223. package/src/jsx-runtime.ts +55 -0
  224. package/src/keyed-list.ts +233 -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 +283 -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 +83 -0
  240. package/src/spread.ts +131 -0
  241. package/src/state-slot.ts +76 -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,355 @@
1
+ import { validateRawHtmlRelatedProp } from '../raw-html.ts'
2
+ import {
3
+ MATHML_NAMESPACE,
4
+ SVG_NAMESPACE,
5
+ XLINK_NAMESPACE,
6
+ XML_NAMESPACE,
7
+ XMLNS_NAMESPACE,
8
+ } from './namespaces.ts'
9
+
10
+ const DEV = typeof __VIDACT_DEV__ === 'undefined' || __VIDACT_DEV__
11
+ const UNSAFE_HTML = typeof __VIDACT_UNSAFE_HTML__ === 'undefined' || __VIDACT_UNSAFE_HTML__
12
+
13
+ const booleanAttributes = new Set([
14
+ 'allowFullScreen',
15
+ 'async',
16
+ 'autoFocus',
17
+ 'autoPlay',
18
+ 'controls',
19
+ 'default',
20
+ 'defer',
21
+ 'disabled',
22
+ 'disablePictureInPicture',
23
+ 'disableRemotePlayback',
24
+ 'formNoValidate',
25
+ 'hidden',
26
+ 'inert',
27
+ 'itemScope',
28
+ 'loop',
29
+ 'noModule',
30
+ 'noValidate',
31
+ 'open',
32
+ 'playsInline',
33
+ 'readOnly',
34
+ 'required',
35
+ 'reversed',
36
+ ])
37
+ const booleanishStringAttributes = new Set(['contentEditable', 'draggable', 'spellCheck'])
38
+ const overloadedBooleanAttributes = new Set(['capture', 'download'])
39
+ const mathBooleanishStringAttributes = new Set([
40
+ 'accent',
41
+ 'accentunder',
42
+ 'displaystyle',
43
+ 'fence',
44
+ 'largeop',
45
+ 'movablelimits',
46
+ 'separator',
47
+ 'stretchy',
48
+ 'symmetric',
49
+ ])
50
+ const svgBooleanishStringAttributes = new Set(['focusable', 'preserveAlpha'])
51
+
52
+ const kebabCaseSvgAttributes = new Set([
53
+ 'accentHeight',
54
+ 'alignmentBaseline',
55
+ 'arabicForm',
56
+ 'baselineShift',
57
+ 'capHeight',
58
+ 'clipPath',
59
+ 'clipRule',
60
+ 'colorInterpolation',
61
+ 'colorInterpolationFilters',
62
+ 'colorProfile',
63
+ 'colorRendering',
64
+ 'dominantBaseline',
65
+ 'enableBackground',
66
+ 'fillOpacity',
67
+ 'fillRule',
68
+ 'floodColor',
69
+ 'floodOpacity',
70
+ 'fontFamily',
71
+ 'fontSize',
72
+ 'fontSizeAdjust',
73
+ 'fontStretch',
74
+ 'fontStyle',
75
+ 'fontVariant',
76
+ 'fontWeight',
77
+ 'glyphName',
78
+ 'glyphOrientationHorizontal',
79
+ 'glyphOrientationVertical',
80
+ 'horizAdvX',
81
+ 'horizOriginX',
82
+ 'imageRendering',
83
+ 'letterSpacing',
84
+ 'lightingColor',
85
+ 'markerEnd',
86
+ 'markerMid',
87
+ 'markerStart',
88
+ 'overlinePosition',
89
+ 'overlineThickness',
90
+ 'paintOrder',
91
+ 'pointerEvents',
92
+ 'renderingIntent',
93
+ 'shapeRendering',
94
+ 'stopColor',
95
+ 'stopOpacity',
96
+ 'strikethroughPosition',
97
+ 'strikethroughThickness',
98
+ 'strokeDasharray',
99
+ 'strokeDashoffset',
100
+ 'strokeLinecap',
101
+ 'strokeLinejoin',
102
+ 'strokeMiterlimit',
103
+ 'strokeOpacity',
104
+ 'strokeWidth',
105
+ 'textAnchor',
106
+ 'textDecoration',
107
+ 'textRendering',
108
+ 'transformOrigin',
109
+ 'underlinePosition',
110
+ 'underlineThickness',
111
+ 'unicodeBidi',
112
+ 'unicodeRange',
113
+ 'unitsPerEm',
114
+ 'vAlphabetic',
115
+ 'vHanging',
116
+ 'vIdeographic',
117
+ 'vMathematical',
118
+ 'vectorEffect',
119
+ 'vertAdvY',
120
+ 'vertOriginX',
121
+ 'vertOriginY',
122
+ 'wordSpacing',
123
+ 'writingMode',
124
+ 'xHeight',
125
+ ])
126
+
127
+ type DomPropHandler = (element: Element, name: string, value: unknown) => boolean
128
+
129
+ export interface FormDomCapability {
130
+ readonly applyProp: DomPropHandler
131
+ readonly ensureControlledRestoration: (element: Element) => () => void
132
+ readonly isControlledProp: (element: Element, name: string) => boolean
133
+ readonly isReactChangeEvent: (element: Element, eventName: string) => boolean
134
+ readonly restoreControlledState: (element: Element) => void
135
+ }
136
+
137
+ type StyleDomCapability = (element: Element, value: unknown) => void
138
+
139
+ let formCapability: FormDomCapability | undefined
140
+ let styleCapability: StyleDomCapability | undefined
141
+ const NOOP = (): void => {}
142
+
143
+ /** @internal */
144
+ export function installFormDomCapability(capability: FormDomCapability): void {
145
+ formCapability = capability
146
+ }
147
+
148
+ /** @internal */
149
+ export function installStyleDomCapability(capability: StyleDomCapability): void {
150
+ styleCapability = capability
151
+ }
152
+
153
+ /** @internal */
154
+ export function ensureControlledFormRestoration(element: Element): () => void {
155
+ return formCapability?.ensureControlledRestoration(element) ?? NOOP
156
+ }
157
+
158
+ /** @internal */
159
+ export function isControlledFormProp(element: Element, name: string): boolean {
160
+ return formCapability?.isControlledProp(element, name) ?? false
161
+ }
162
+
163
+ /** @internal */
164
+ export function isReactFormChangeEvent(element: Element, eventName: string): boolean {
165
+ return formCapability?.isReactChangeEvent(element, eventName) ?? false
166
+ }
167
+
168
+ /** @internal */
169
+ export function restoreControlledFormState(element: Element): void {
170
+ formCapability?.restoreControlledState(element)
171
+ }
172
+
173
+ export let applyDomProp = applyBaseDomProp
174
+
175
+ export function installDomPropHandler(handler: DomPropHandler): void {
176
+ const fallback = applyDomProp
177
+ applyDomProp = (element, name, value) => {
178
+ if (!handler(element, name, value)) fallback(element, name, value)
179
+ }
180
+ }
181
+
182
+ /** @internal Specialized capabilities may own a prop while reusing the base policy. */
183
+ export function applyBaseDomProp(element: Element, name: string, value: unknown): void {
184
+ if (typeof value === 'symbol') {
185
+ throw new TypeError(DEV ? `DOM prop ${name} cannot receive a symbol value` : 'V105')
186
+ }
187
+ if (name === 'dangerouslySetInnerHTML') {
188
+ throw new Error(
189
+ DEV ? 'dangerouslySetInnerHTML must be handled as an owned opaque subtree' : 'V401',
190
+ )
191
+ }
192
+ if (name === 'style') {
193
+ if (styleCapability === undefined) {
194
+ throw new Error(DEV ? 'style prop requires the DOM style capability' : 'V503')
195
+ }
196
+ styleCapability(element, value)
197
+ return
198
+ }
199
+ if (formCapability?.applyProp(element, name, value)) return
200
+ if (name.startsWith('data-') || name.startsWith('aria-')) {
201
+ applyStringAttribute(element, name, value)
202
+ return
203
+ }
204
+ if (element.namespaceURI === SVG_NAMESPACE || element.namespaceURI === MATHML_NAMESPACE) {
205
+ applyNamespacedAttribute(element, name, value)
206
+ return
207
+ }
208
+
209
+ const attribute = htmlAttributeName(name)
210
+ if (value === null || value === undefined) {
211
+ element.removeAttribute(attribute)
212
+ if (isCustomElement(element) && name in element) Reflect.set(element, name, null)
213
+ validateRawHtmlProp(element, name)
214
+ return
215
+ }
216
+ if (booleanishStringAttributes.has(name)) {
217
+ element.setAttribute(attribute, String(value))
218
+ return
219
+ }
220
+ if (overloadedBooleanAttributes.has(name)) {
221
+ if (value === false) element.removeAttribute(attribute)
222
+ else element.setAttribute(attribute, value === true ? '' : String(value))
223
+ return
224
+ }
225
+ if (booleanAttributes.has(name)) {
226
+ if (name in element) {
227
+ const next = Boolean(value)
228
+ if (!Object.is(Reflect.get(element, name), next)) Reflect.set(element, name, next)
229
+ } else if (value) element.setAttribute(attribute, '')
230
+ else element.removeAttribute(attribute)
231
+ return
232
+ }
233
+ if (typeof value === 'boolean') {
234
+ element.removeAttribute(attribute)
235
+ return
236
+ }
237
+ const serialized = String(value)
238
+ if (element.getAttribute(attribute) === serialized) {
239
+ validateRawHtmlProp(element, name)
240
+ return
241
+ }
242
+ if (name in element) {
243
+ const current = Reflect.get(element, name)
244
+ if (
245
+ !isCustomElement(element) &&
246
+ (Object.is(current, value) || String(current) === serialized)
247
+ ) {
248
+ validateRawHtmlProp(element, name)
249
+ return
250
+ }
251
+ if (Reflect.set(element, name, value)) {
252
+ validateRawHtmlProp(element, name)
253
+ return
254
+ }
255
+ }
256
+ if (element.getAttribute(attribute) !== serialized) {
257
+ element.setAttribute(attribute, serialized)
258
+ }
259
+ validateRawHtmlProp(element, name)
260
+ }
261
+
262
+ function applyStringAttribute(element: Element, name: string, value: unknown): void {
263
+ if (value === null || value === undefined) element.removeAttribute(name)
264
+ else {
265
+ if (typeof value === 'symbol') {
266
+ throw new TypeError(`cannot apply a Symbol value to DOM attribute ${name}`)
267
+ }
268
+ let serialized: string
269
+ try {
270
+ serialized = String(value)
271
+ } catch (cause) {
272
+ const detail = Array.isArray(value)
273
+ ? value.map((item) => (typeof item === 'symbol' ? String(item) : typeof item)).join(',')
274
+ : typeof value
275
+ throw new TypeError(`cannot serialize DOM attribute ${name} from ${detail}`, { cause })
276
+ }
277
+ if (element.getAttribute(name) !== serialized) element.setAttribute(name, serialized)
278
+ }
279
+ }
280
+
281
+ function applyNamespacedAttribute(element: Element, name: string, value: unknown): void {
282
+ const descriptor = namespacedAttribute(name)
283
+ if (value === null || value === undefined) {
284
+ if (descriptor.namespace === null) element.removeAttribute(descriptor.qualifiedName)
285
+ else element.removeAttributeNS(descriptor.namespace, descriptor.localName)
286
+ return
287
+ }
288
+ if (
289
+ (element.namespaceURI === MATHML_NAMESPACE && mathBooleanishStringAttributes.has(name)) ||
290
+ (element.namespaceURI === SVG_NAMESPACE && svgBooleanishStringAttributes.has(name))
291
+ ) {
292
+ element.setAttribute(descriptor.qualifiedName, String(value))
293
+ return
294
+ }
295
+ if (value === false) {
296
+ if (descriptor.namespace === null) element.removeAttribute(descriptor.qualifiedName)
297
+ else element.removeAttributeNS(descriptor.namespace, descriptor.localName)
298
+ return
299
+ }
300
+ const serialized = value === true ? '' : String(value)
301
+ if (descriptor.namespace === null) element.setAttribute(descriptor.qualifiedName, serialized)
302
+ else element.setAttributeNS(descriptor.namespace, descriptor.qualifiedName, serialized)
303
+ }
304
+
305
+ function namespacedAttribute(name: string): {
306
+ namespace: string | null
307
+ qualifiedName: string
308
+ localName: string
309
+ } {
310
+ if (name.startsWith('xlink') && name.length > 5) {
311
+ const localName = lowerInitial(name.slice(5))
312
+ return { namespace: XLINK_NAMESPACE, qualifiedName: `xlink:${localName}`, localName }
313
+ }
314
+ if (name === 'xmlnsXlink') {
315
+ return {
316
+ namespace: XMLNS_NAMESPACE,
317
+ qualifiedName: 'xmlns:xlink',
318
+ localName: 'xlink',
319
+ }
320
+ }
321
+ if (name.startsWith('xml') && name.length > 3) {
322
+ const localName = lowerInitial(name.slice(3))
323
+ return { namespace: XML_NAMESPACE, qualifiedName: `xml:${localName}`, localName }
324
+ }
325
+ const qualifiedName = svgAttributeName(name)
326
+ return { namespace: null, qualifiedName, localName: qualifiedName }
327
+ }
328
+
329
+ function svgAttributeName(name: string): string {
330
+ if (name === 'className') return 'class'
331
+ if (name === 'crossOrigin') return 'crossorigin'
332
+ if (name === 'tabIndex') return 'tabindex'
333
+ if (!kebabCaseSvgAttributes.has(name)) return name
334
+ return name.replace(/[A-Z]/g, (character) => `-${character.toLowerCase()}`)
335
+ }
336
+
337
+ function htmlAttributeName(name: string): string {
338
+ if (name === 'className') return 'class'
339
+ if (name === 'htmlFor') return 'for'
340
+ if (name === 'acceptCharset') return 'accept-charset'
341
+ if (name === 'httpEquiv') return 'http-equiv'
342
+ return name
343
+ }
344
+
345
+ function isCustomElement(element: Element): element is HTMLElement {
346
+ return element instanceof HTMLElement && element.localName.includes('-')
347
+ }
348
+
349
+ function validateRawHtmlProp(element: Element, name: string): void {
350
+ if (UNSAFE_HTML && element instanceof HTMLElement) validateRawHtmlRelatedProp(element, name)
351
+ }
352
+
353
+ function lowerInitial(value: string): string {
354
+ return `${value.charAt(0).toLowerCase()}${value.slice(1)}`
355
+ }
@@ -0,0 +1,46 @@
1
+ export const UNITLESS_STYLE_PROPERTIES: ReadonlySet<string> = new Set([
2
+ 'animationIterationCount',
3
+ 'aspectRatio',
4
+ 'borderImageOutset',
5
+ 'borderImageSlice',
6
+ 'borderImageWidth',
7
+ 'boxFlex',
8
+ 'boxFlexGroup',
9
+ 'boxOrdinalGroup',
10
+ 'columnCount',
11
+ 'columns',
12
+ 'fillOpacity',
13
+ 'flex',
14
+ 'flexGrow',
15
+ 'flexNegative',
16
+ 'flexOrder',
17
+ 'flexPositive',
18
+ 'flexShrink',
19
+ 'floodOpacity',
20
+ 'fontWeight',
21
+ 'gridArea',
22
+ 'gridColumn',
23
+ 'gridColumnEnd',
24
+ 'gridColumnSpan',
25
+ 'gridColumnStart',
26
+ 'gridRow',
27
+ 'gridRowEnd',
28
+ 'gridRowSpan',
29
+ 'gridRowStart',
30
+ 'lineClamp',
31
+ 'lineHeight',
32
+ 'opacity',
33
+ 'order',
34
+ 'orphans',
35
+ 'scale',
36
+ 'stopOpacity',
37
+ 'strokeDasharray',
38
+ 'strokeDashoffset',
39
+ 'strokeMiterlimit',
40
+ 'strokeOpacity',
41
+ 'strokeWidth',
42
+ 'tabSize',
43
+ 'widows',
44
+ 'zIndex',
45
+ 'zoom',
46
+ ])
@@ -0,0 +1,86 @@
1
+ import { isHydrating } from '../hydration-bridge.ts'
2
+ import { UNITLESS_STYLE_PROPERTIES } from './style-properties.ts'
3
+
4
+ const DEV = typeof __VIDACT_DEV__ === 'undefined' || __VIDACT_DEV__
5
+ let retainedUiEnabled = typeof __VIDACT_RETAINED_UI__ !== 'undefined' && __VIDACT_RETAINED_UI__
6
+
7
+ /** @internal */
8
+ export function enableRetainedUiStyles(): void {
9
+ retainedUiEnabled = true
10
+ }
11
+
12
+ const appliedStyleNames = new WeakMap<Element, Set<string>>()
13
+
14
+ export function applyStyleProp(element: Element, value: unknown): void {
15
+ const style = Reflect.get(element, 'style')
16
+ if (!(style instanceof CSSStyleDeclaration)) {
17
+ throw new TypeError(
18
+ DEV ? 'style is only supported on elements with CSS style declarations' : 'V501',
19
+ )
20
+ }
21
+ if (value !== null && value !== undefined && typeof value !== 'object') {
22
+ throw new TypeError(DEV ? 'style prop expects an object, null, or undefined' : 'V502')
23
+ }
24
+
25
+ const previous = appliedStyleNames.get(element) ?? new Set<string>()
26
+ const nextEntries =
27
+ value === null || value === undefined ? [] : Object.entries(value as Record<string, unknown>)
28
+ const nextNames = new Set<string>()
29
+ for (const [name] of nextEntries) nextNames.add(name)
30
+
31
+ for (const name of previous) {
32
+ if (!nextNames.has(name)) setStyleValue(style, name, '')
33
+ }
34
+ for (const [name, next] of nextEntries) {
35
+ const serialized = serializeStyleValue(name, next)
36
+ if (
37
+ !retainedUiEnabled ||
38
+ !isHydrating() ||
39
+ hydrationStyleValue(element, style, name) !== serialized
40
+ ) {
41
+ setStyleValue(style, name, serialized)
42
+ }
43
+ }
44
+
45
+ if (nextNames.size === 0) {
46
+ appliedStyleNames.delete(element)
47
+ if (element.getAttribute('style') === '') element.removeAttribute('style')
48
+ } else {
49
+ appliedStyleNames.set(element, nextNames)
50
+ }
51
+ }
52
+
53
+ function hydrationStyleValue(element: Element, style: CSSStyleDeclaration, name: string): string {
54
+ if (
55
+ name === 'display' &&
56
+ style.display === 'none' &&
57
+ style.getPropertyPriority('display') === 'important'
58
+ ) {
59
+ const cssText = element.getAttribute('style')
60
+ const hiddenDeclaration = 'display:none!important'
61
+ if (cssText?.endsWith(hiddenDeclaration)) {
62
+ const authored = document.createElement('div').style
63
+ authored.cssText = cssText.slice(0, -hiddenDeclaration.length)
64
+ return authored.display
65
+ }
66
+ }
67
+ if (name.startsWith('--') || name.includes('-')) return style.getPropertyValue(name)
68
+ return String(Reflect.get(style, name === 'float' ? 'cssFloat' : name) ?? '')
69
+ }
70
+
71
+ function serializeStyleValue(name: string, value: unknown): string {
72
+ if (value === null || value === undefined || typeof value === 'boolean' || value === '') return ''
73
+ if (name.startsWith('--')) return String(value).trim()
74
+ if (typeof value === 'number' && value !== 0 && !UNITLESS_STYLE_PROPERTIES.has(name)) {
75
+ return `${value}px`
76
+ }
77
+ return String(value).trim()
78
+ }
79
+
80
+ function setStyleValue(style: CSSStyleDeclaration, name: string, value: string): void {
81
+ if (name.startsWith('--') || name.includes('-')) {
82
+ style.setProperty(name, value)
83
+ return
84
+ }
85
+ Reflect.set(style, name === 'float' ? 'cssFloat' : name, value)
86
+ }
@@ -0,0 +1,23 @@
1
+ import {
2
+ applyFormProp,
3
+ ensureControlledFormRestoration,
4
+ isControlledFormProp,
5
+ isReactFormChangeEvent,
6
+ restoreControlledFormState,
7
+ } from './dom/forms.ts'
8
+ import { installFormDomCapability } from './dom/properties.ts'
9
+
10
+ let enabled = false
11
+
12
+ /** @internal Compiler-injected activation for form-specific DOM behavior. */
13
+ export function enableDomForms(): void {
14
+ if (enabled) return
15
+ enabled = true
16
+ installFormDomCapability({
17
+ applyProp: applyFormProp,
18
+ ensureControlledRestoration: ensureControlledFormRestoration,
19
+ isControlledProp: isControlledFormProp,
20
+ isReactChangeEvent: isReactFormChangeEvent,
21
+ restoreControlledState: restoreControlledFormState,
22
+ })
23
+ }
@@ -0,0 +1,11 @@
1
+ import { installStyleDomCapability } from './dom/properties.ts'
2
+ import { applyStyleProp } from './dom/styles.ts'
3
+
4
+ let enabled = false
5
+
6
+ /** @internal Compiler-injected activation for object-valued style props. */
7
+ export function enableDomStyles(): void {
8
+ if (enabled) return
9
+ enabled = true
10
+ installStyleDomCapability(applyStyleProp)
11
+ }
package/src/env.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ // oxlint-disable-next-line no-underscore-dangle -- Compiler/runtime production define.
2
+ /* oxlint-disable no-underscore-dangle -- Runtime build constants intentionally use reserved global names. */
3
+
4
+ declare const __VIDACT_DEV__: boolean
5
+ declare const __VIDACT_UNSAFE_HTML__: boolean
6
+ declare const __VIDACT_RETAINED_UI__: boolean