@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
package/src/dom/forms.ts
ADDED
|
@@ -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
|
+
}
|