@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,220 @@
1
+ type ControlledFormState = [value?: unknown, checked?: boolean]
2
+
3
+ const controlledFormStates = new WeakMap<Element, ControlledFormState>()
4
+ const controlledRestorationCleanups = new WeakMap<Element, () => void>()
5
+ const DEV = typeof __VIDACT_DEV__ === 'undefined' || __VIDACT_DEV__
6
+
7
+ export function isControlledFormProp(element: Element, name: string): boolean {
8
+ return (
9
+ (name === 'value' &&
10
+ (element instanceof HTMLInputElement ||
11
+ element instanceof HTMLTextAreaElement ||
12
+ element instanceof HTMLSelectElement)) ||
13
+ (name === 'checked' && element instanceof HTMLInputElement)
14
+ )
15
+ }
16
+
17
+ export function ensureControlledFormRestoration(element: Element): () => void {
18
+ const existing = controlledRestorationCleanups.get(element)
19
+ if (existing !== undefined) return () => {}
20
+
21
+ const schedule = (event: Event): void => {
22
+ if (!isReactFormChangeEvent(element, event.type)) return
23
+ const root = element.getRootNode()
24
+ let restored = false
25
+ const restore = (): void => {
26
+ if (restored) return
27
+ restored = true
28
+ root.removeEventListener(event.type, restore)
29
+ restoreControlledFormState(element)
30
+ }
31
+ root.addEventListener(event.type, restore, { once: true })
32
+ setTimeout(restore, 0)
33
+ }
34
+ element.addEventListener('input', schedule)
35
+ element.addEventListener('change', schedule)
36
+ const cleanup = (): void => {
37
+ element.removeEventListener('input', schedule)
38
+ element.removeEventListener('change', schedule)
39
+ controlledRestorationCleanups.delete(element)
40
+ }
41
+ controlledRestorationCleanups.set(element, cleanup)
42
+ return cleanup
43
+ }
44
+
45
+ export function isReactFormChangeEvent(element: Element, eventName: string): boolean {
46
+ if (element instanceof HTMLTextAreaElement) return eventName === 'input'
47
+ if (element instanceof HTMLSelectElement) return eventName === 'change'
48
+ if (!(element instanceof HTMLInputElement)) return false
49
+ return element.type === 'checkbox' || element.type === 'radio' || element.type === 'file'
50
+ ? eventName === 'change'
51
+ : eventName === 'input'
52
+ }
53
+
54
+ export function applyFormProp(element: Element, name: string, value: unknown): boolean {
55
+ if (name === 'value') {
56
+ if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
57
+ if (value === undefined) {
58
+ delete remember(element)[0]
59
+ return true
60
+ }
61
+ const next = value === null || value === undefined ? '' : String(value)
62
+ remember(element)[0] = next
63
+ if (element.value !== next) element.value = next
64
+ return true
65
+ }
66
+ if (element instanceof HTMLSelectElement) {
67
+ if (value === undefined) {
68
+ delete remember(element)[0]
69
+ return true
70
+ }
71
+ const next = normalizeSelectValue(element, value)
72
+ remember(element)[0] = value
73
+ applySelectValue(element, next)
74
+ return true
75
+ }
76
+ }
77
+
78
+ if (name === 'checked' && element instanceof HTMLInputElement) {
79
+ if (value === undefined) {
80
+ delete remember(element)[1]
81
+ return true
82
+ }
83
+ const next = Boolean(value)
84
+ remember(element)[1] = next
85
+ if (element.checked !== next) element.checked = next
86
+ return true
87
+ }
88
+ if (name === 'defaultValue' && 'defaultValue' in element) {
89
+ const next = value === null || value === undefined ? '' : String(value)
90
+ if (Reflect.get(element, 'defaultValue') !== next) Reflect.set(element, 'defaultValue', next)
91
+ return true
92
+ }
93
+ if (name === 'defaultChecked' && element instanceof HTMLInputElement) {
94
+ element.defaultChecked = Boolean(value)
95
+ return true
96
+ }
97
+ if (name === 'selected' && element instanceof HTMLOptionElement) {
98
+ element.selected = Boolean(value)
99
+ return true
100
+ }
101
+ if (name === 'multiple' && element instanceof HTMLSelectElement) {
102
+ element.multiple = Boolean(value)
103
+ return true
104
+ }
105
+ if (name === 'muted' && element instanceof HTMLMediaElement) {
106
+ element.muted = Boolean(value)
107
+ return true
108
+ }
109
+ return false
110
+ }
111
+
112
+ function restoreControlledForm(form: HTMLFormElement): void {
113
+ for (const element of form.elements) {
114
+ if (element instanceof Element) restoreControlledFormState(element)
115
+ }
116
+ }
117
+
118
+ export function resetActionForm(form: HTMLFormElement): void {
119
+ for (const element of form.elements) {
120
+ const controlled = controlledFormStates.get(element)
121
+ if (controlled?.[0] !== undefined || controlled?.[1] !== undefined) continue
122
+ if (element instanceof HTMLInputElement) {
123
+ if (element.type === 'checkbox' || element.type === 'radio') {
124
+ element.checked = element.defaultChecked
125
+ } else {
126
+ element.value = element.type === 'file' ? '' : element.defaultValue
127
+ }
128
+ continue
129
+ }
130
+ if (element instanceof HTMLTextAreaElement) {
131
+ element.value = element.defaultValue
132
+ continue
133
+ }
134
+ if (element instanceof HTMLSelectElement) resetSelect(element)
135
+ }
136
+ restoreControlledForm(form)
137
+ }
138
+
139
+ export function restoreControlledFormState(element: Element): void {
140
+ restoreElement(element)
141
+ if (!(element instanceof HTMLInputElement) || element.type !== 'radio' || element.name === '') {
142
+ return
143
+ }
144
+
145
+ const root = element.getRootNode()
146
+ if (!(root instanceof Document || root instanceof ShadowRoot)) return
147
+ const escapedName = CSS.escape(element.name)
148
+ for (const candidate of root.querySelectorAll<HTMLInputElement>(
149
+ `input[type="radio"][name="${escapedName}"]`,
150
+ )) {
151
+ if (candidate !== element && candidate.form === element.form) restoreElement(candidate)
152
+ }
153
+ }
154
+
155
+ function restoreElement(element: Element): void {
156
+ const state = controlledFormStates.get(element)
157
+ if (state === undefined) return
158
+ if (state[0] !== undefined) {
159
+ if (element instanceof HTMLSelectElement) {
160
+ applySelectValue(element, normalizeSelectValue(element, state[0]))
161
+ } else if (
162
+ (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) &&
163
+ element.value !== state[0]
164
+ ) {
165
+ element.value = String(state[0])
166
+ }
167
+ }
168
+ if (
169
+ state[1] !== undefined &&
170
+ element instanceof HTMLInputElement &&
171
+ element.checked !== state[1]
172
+ ) {
173
+ element.checked = state[1]
174
+ }
175
+ }
176
+
177
+ function remember(element: Element): ControlledFormState {
178
+ const existing = controlledFormStates.get(element)
179
+ if (existing !== undefined) return existing
180
+ const state: ControlledFormState = []
181
+ controlledFormStates.set(element, state)
182
+ return state
183
+ }
184
+
185
+ function normalizeSelectValue(element: HTMLSelectElement, value: unknown): unknown {
186
+ if (!element.multiple) return value === null || value === undefined ? '' : String(value)
187
+ if (value === null || value === undefined) return []
188
+ if (!Array.isArray(value)) {
189
+ throw new TypeError(DEV ? 'a controlled <select multiple> value must be an array' : 'V301')
190
+ }
191
+ return value.map(String)
192
+ }
193
+
194
+ function applySelectValue(element: HTMLSelectElement, value: unknown): void {
195
+ if (!element.multiple) {
196
+ const selected = String(value)
197
+ let matched = false
198
+ for (const option of element.options) {
199
+ const next = option.value === selected
200
+ option.selected = next
201
+ matched ||= next
202
+ }
203
+ if (!matched) element.selectedIndex = -1
204
+ return
205
+ }
206
+
207
+ const selected = new Set(value as readonly string[])
208
+ for (const option of element.options) option.selected = selected.has(option.value)
209
+ }
210
+
211
+ function resetSelect(element: HTMLSelectElement): void {
212
+ let selected = false
213
+ for (const option of element.options) {
214
+ option.selected = option.defaultSelected
215
+ selected ||= option.selected
216
+ }
217
+ if (!element.multiple && !selected && element.options.length > 0) {
218
+ element.options[0]!.selected = true
219
+ }
220
+ }
@@ -0,0 +1,94 @@
1
+ const DEV = typeof __VIDACT_DEV__ === 'undefined' || __VIDACT_DEV__
2
+
3
+ export const INTERNAL_NAMESPACE_PROP = '__vidactNamespace'
4
+ export const INTERNAL_COMPONENT_SPREAD_PROP = Symbol(DEV ? 'Vidact.ComponentSpread' : undefined)
5
+
6
+ export type IntrinsicNamespace = 'html' | 'svg' | 'mathml'
7
+
8
+ interface NamespaceDomCapability {
9
+ readonly childrenNamespace: (type: string, namespace: IntrinsicNamespace) => IntrinsicNamespace
10
+ readonly createElement: (
11
+ document: Document,
12
+ type: string,
13
+ namespace: IntrinsicNamespace,
14
+ ) => Element
15
+ readonly resolveNamespace: (
16
+ type: string,
17
+ explicit: IntrinsicNamespace | undefined,
18
+ inherited: IntrinsicNamespace,
19
+ ) => IntrinsicNamespace
20
+ }
21
+
22
+ let activeNamespace: IntrinsicNamespace = 'html'
23
+ let namespaceCapability: NamespaceDomCapability | undefined
24
+
25
+ /** @internal */
26
+ export function installNamespaceDomCapability(capability: NamespaceDomCapability): void {
27
+ namespaceCapability = capability
28
+ }
29
+
30
+ export function currentIntrinsicNamespace(): IntrinsicNamespace {
31
+ return activeNamespace
32
+ }
33
+
34
+ export function readIntrinsicNamespace(
35
+ props: Record<string, unknown> | null,
36
+ ): IntrinsicNamespace | undefined {
37
+ const value = props?.[INTERNAL_NAMESPACE_PROP]
38
+ return value === 'html' || value === 'svg' || value === 'mathml' ? value : undefined
39
+ }
40
+
41
+ export function createComponentProps(
42
+ props: Record<string, unknown> | null,
43
+ children: readonly unknown[],
44
+ ): Record<string, unknown> {
45
+ const publicProps: Record<string, unknown> = { ...props }
46
+ if (children.length === 1) publicProps.children = children[0]
47
+ else if (children.length > 1) publicProps.children = children
48
+ delete publicProps[INTERNAL_NAMESPACE_PROP]
49
+ delete publicProps.key
50
+ if (publicProps.ref === undefined) delete publicProps.ref
51
+ const propsWithDirective = publicProps as Record<PropertyKey, unknown>
52
+ const directive = propsWithDirective[INTERNAL_COMPONENT_SPREAD_PROP]
53
+ delete propsWithDirective[INTERNAL_COMPONENT_SPREAD_PROP]
54
+ return typeof directive === 'function'
55
+ ? (directive(publicProps) as Record<string, unknown>)
56
+ : publicProps
57
+ }
58
+
59
+ export function withIntrinsicNamespace<Result>(
60
+ namespace: IntrinsicNamespace | undefined,
61
+ render: () => Result,
62
+ ): Result {
63
+ const previous = activeNamespace
64
+ activeNamespace = namespace ?? previous
65
+ try {
66
+ return render()
67
+ } finally {
68
+ activeNamespace = previous
69
+ }
70
+ }
71
+
72
+ export function createIntrinsicElement(
73
+ document: Document,
74
+ type: string,
75
+ namespace: IntrinsicNamespace,
76
+ ): Element {
77
+ return (
78
+ namespaceCapability?.createElement(document, type, namespace) ?? document.createElement(type)
79
+ )
80
+ }
81
+
82
+ export function resolveIntrinsicNamespace(
83
+ type: string,
84
+ namespace: IntrinsicNamespace | undefined,
85
+ ): IntrinsicNamespace {
86
+ return namespaceCapability?.resolveNamespace(type, namespace, activeNamespace) ?? activeNamespace
87
+ }
88
+
89
+ export function intrinsicChildrenNamespace(
90
+ type: string,
91
+ namespace: IntrinsicNamespace,
92
+ ): IntrinsicNamespace {
93
+ return namespaceCapability?.childrenNamespace(type, namespace) ?? namespace
94
+ }
@@ -0,0 +1,30 @@
1
+ import { installNamespaceDomCapability, type IntrinsicNamespace } from './intrinsic.ts'
2
+ import { MATHML_NAMESPACE, SVG_NAMESPACE } from './namespaces.ts'
3
+
4
+ let enabled = false
5
+
6
+ /** @internal Compiler-injected activation for SVG and MathML namespace behavior. */
7
+ export function enableDomNamespace(): void {
8
+ if (enabled) return
9
+ enabled = true
10
+ installNamespaceDomCapability({
11
+ childrenNamespace: (type, namespace) =>
12
+ namespace === 'svg' && type === 'foreignObject' ? 'html' : namespace,
13
+ createElement(document, type, namespace) {
14
+ if (namespace === 'svg') return document.createElementNS(SVG_NAMESPACE, type)
15
+ if (namespace === 'mathml') return document.createElementNS(MATHML_NAMESPACE, type)
16
+ return document.createElement(type)
17
+ },
18
+ resolveNamespace(type, explicit, inherited) {
19
+ if (explicit !== undefined) return explicit
20
+ return rootNamespace(type, inherited)
21
+ },
22
+ })
23
+ }
24
+
25
+ function rootNamespace(type: string, inherited: IntrinsicNamespace): IntrinsicNamespace {
26
+ if (inherited !== 'html') return inherited
27
+ if (type === 'svg') return 'svg'
28
+ if (type === 'math') return 'mathml'
29
+ return inherited
30
+ }
@@ -0,0 +1,14 @@
1
+ import type { IntrinsicNamespace } from './intrinsic.ts'
2
+
3
+ export const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml'
4
+ export const SVG_NAMESPACE = 'http://www.w3.org/2000/svg'
5
+ export const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML'
6
+ export const XLINK_NAMESPACE = 'http://www.w3.org/1999/xlink'
7
+ export const XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace'
8
+ export const XMLNS_NAMESPACE = 'http://www.w3.org/2000/xmlns/'
9
+
10
+ export function intrinsicNamespaceUrl(namespace: IntrinsicNamespace): string {
11
+ if (namespace === 'svg') return SVG_NAMESPACE
12
+ if (namespace === 'mathml') return MATHML_NAMESPACE
13
+ return HTML_NAMESPACE
14
+ }