onejs-core 3.0.2 → 3.0.3
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/.gitattributes +2 -2
- package/.prettierrc +5 -5
- package/.vscode/settings.json +5 -5
- package/LICENSE +20 -20
- package/README.md +102 -102
- package/definitions/Assemblies/OneJS.Runtime.Ext.d.ts +6 -6
- package/definitions/Assemblies/OneJS.Runtime.d.ts +826 -826
- package/definitions/Assemblies/OneJS.Samples.d.ts +20 -20
- package/definitions/Assemblies/Unity.Mathematics.d.ts +9221 -9221
- package/definitions/Assemblies/UnityEditor.CoreModule.d.ts +32614 -32614
- package/definitions/Assemblies/UnityEngine.AIModule.d.ts +998 -998
- package/definitions/Assemblies/UnityEngine.AnimationModule.d.ts +3308 -3308
- package/definitions/Assemblies/UnityEngine.AssetBundleModule.d.ts +337 -337
- package/definitions/Assemblies/UnityEngine.AudioModule.d.ts +1154 -1154
- package/definitions/Assemblies/UnityEngine.CoreModule.d.ts +29587 -29587
- package/definitions/Assemblies/UnityEngine.PhysicsModule.d.ts +3137 -3137
- package/definitions/Assemblies/UnityEngine.TerrainModule.d.ts +1270 -1270
- package/definitions/Assemblies/UnityEngine.UIElementsModule.d.ts +32718 -32718
- package/definitions/Assemblies/UnityEngine.UnityAnalyticsCommonModule.d.ts +274 -274
- package/definitions/Assemblies/index.d.ts +16 -16
- package/definitions/Assemblies/mscorlib.d.ts +19416 -19416
- package/definitions/augments.d.ts +66 -66
- package/definitions/globals.d.ts +53 -53
- package/definitions/index.d.ts +11 -11
- package/definitions/jsx.d.ts +570 -570
- package/definitions/modules.d.ts +32 -32
- package/definitions/onejs.d.ts +171 -171
- package/definitions/preact.jsx.d.ts +6 -6
- package/definitions/proto-overrides.d.ts +41 -41
- package/definitions/puerts.d.ts +30 -30
- package/definitions/unity-engine.d.ts +22 -22
- package/dom/document.ts +115 -115
- package/dom/dom-style.ts +36 -36
- package/dom/dom.ts +376 -376
- package/dom/index.ts +3 -3
- package/index.ts +59 -59
- package/jsr.json +9 -9
- package/math/README.md +212 -212
- package/math/index.ts +487 -487
- package/package.json +33 -33
- package/preloads/inject.ts +43 -43
- package/scripts/esbuild/copy-assets.mjs +94 -94
- package/scripts/esbuild/decorator-fix.mjs +17 -17
- package/scripts/esbuild/import-transform.mjs +100 -100
- package/scripts/esbuild/index.mjs +3 -3
- package/scripts/esbuild/watch-output.mjs +38 -38
- package/scripts/postcss/cleanup-plugin.cjs +89 -89
- package/scripts/postcss/onejs-tw-config.cjs +252 -252
- package/scripts/postcss/optional-import-plugin.cjs +26 -26
- package/scripts/postcss/tailwind-logging-plugin.cjs +11 -11
- package/scripts/postcss/unwrap-is-plugin.cjs +16 -16
- package/scripts/postcss/uss-transform-plugin.cjs +92 -92
- package/scripts/switch.cjs +290 -290
- package/styling/index.tsx +32 -32
- package/styling/utils/generateAlphabeticName.ts +20 -20
- package/styling/utils/generateComponentId.ts +5 -5
- package/styling/utils/hash.ts +46 -46
- package/tsconfig.json +24 -24
- package/typings.d.ts +5 -5
- package/utils/arrays.ts +10 -10
- package/utils/color-palettes.ts +2 -2
- package/utils/color-parser.ts +248 -248
- package/utils/float-parser.ts +30 -30
- package/utils/index.ts +15 -15
- package/utils/subscribe.ts +16 -16
- package/utils/system.ts +16 -16
- package/dist/csharp/index.d.ts +0 -3
- package/dist/csharp/index.js +0 -3
- package/dist/dom/document.d.ts +0 -30
- package/dist/dom/document.js +0 -89
- package/dist/dom/dom-style.d.ts +0 -9
- package/dist/dom/dom-style.js +0 -27
- package/dist/dom/dom.d.ts +0 -83
- package/dist/dom/dom.js +0 -313
- package/dist/dom/index.d.ts +0 -4
- package/dist/dom/index.js +0 -4
- package/dist/dom/selector.d.ts +0 -0
- package/dist/dom/selector.js +0 -0
- package/dist/index.d.ts +0 -25
- package/dist/index.js +0 -45
- package/dist/math/index.d.ts +0 -86
- package/dist/math/index.js +0 -361
- package/dist/preloads/inject.d.ts +0 -3
- package/dist/preloads/inject.js +0 -36
- package/dist/styling/index.d.ts +0 -10
- package/dist/styling/index.js +0 -28
- package/dist/styling/utils/generateAlphabeticName.d.ts +0 -1
- package/dist/styling/utils/generateAlphabeticName.js +0 -16
- package/dist/styling/utils/generateComponentId.d.ts +0 -1
- package/dist/styling/utils/generateComponentId.js +0 -5
- package/dist/styling/utils/hash.d.ts +0 -5
- package/dist/styling/utils/hash.js +0 -34
- package/dist/utils/arrays.d.ts +0 -1
- package/dist/utils/arrays.js +0 -10
- package/dist/utils/color-palettes.d.ts +0 -2
- package/dist/utils/color-palettes.js +0 -2
- package/dist/utils/color-parser.d.ts +0 -161
- package/dist/utils/color-parser.js +0 -241
- package/dist/utils/float-parser.d.ts +0 -7
- package/dist/utils/float-parser.js +0 -23
- package/dist/utils/index.d.ts +0 -12
- package/dist/utils/index.js +0 -15
- package/dist/utils/responsive.d.ts +0 -4
- package/dist/utils/responsive.js +0 -23
- package/dist/utils/subscribe.d.ts +0 -4
- package/dist/utils/subscribe.js +0 -10
- package/dist/utils/system.d.ts +0 -1
- package/dist/utils/system.js +0 -16
- package/dist/utils/toJsArray.d.ts +0 -1
- package/dist/utils/toJsArray.js +0 -10
package/dom/dom.ts
CHANGED
|
@@ -1,377 +1,377 @@
|
|
|
1
|
-
import { EventBase } from "UnityEngine/UIElements"
|
|
2
|
-
import { DomStyleWrapper } from "./dom-style"
|
|
3
|
-
|
|
4
|
-
export class DomWrapper {
|
|
5
|
-
public get _dom(): CS.OneJS.Dom.Dom { return this.dom }
|
|
6
|
-
public get ve(): CS.UnityEngine.UIElements.VisualElement { return this.dom.ve }
|
|
7
|
-
public get childNodes(): DomWrapper[] {
|
|
8
|
-
if (this.cachedChildNodes) return this.cachedChildNodes
|
|
9
|
-
this.cachedChildNodes = new Array(this.dom.childNodes.Length) as DomWrapper[]
|
|
10
|
-
var i = this.dom.childNodes.Length
|
|
11
|
-
while (i--) {
|
|
12
|
-
this.cachedChildNodes[i] = new DomWrapper(this.dom.childNodes.get_Item(i))
|
|
13
|
-
}
|
|
14
|
-
return this.cachedChildNodes
|
|
15
|
-
}
|
|
16
|
-
public get firstChild(): DomWrapper | null {
|
|
17
|
-
return this.dom.firstChild ? new DomWrapper(this.dom.firstChild) : null
|
|
18
|
-
}
|
|
19
|
-
public get parentNode(): DomWrapper | null {
|
|
20
|
-
return this.dom.parentNode ? new DomWrapper(this.dom.parentNode) : null
|
|
21
|
-
}
|
|
22
|
-
public get nextSibling(): DomWrapper | null {
|
|
23
|
-
return this.dom.nextSibling ? new DomWrapper(this.dom.nextSibling) : null
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
public get nodeType(): number { return this.dom.nodeType }
|
|
27
|
-
public get style(): DomStyleWrapper { return this.domStyleWrapper }
|
|
28
|
-
public get Id(): string { return this.dom.Id }
|
|
29
|
-
public set Id(value: string) { this.dom.Id = value }
|
|
30
|
-
public get key(): string { return this.dom.key }
|
|
31
|
-
public set key(value: string) { this.dom.key = value }
|
|
32
|
-
public get value(): any { return this.dom.value }
|
|
33
|
-
public get checked(): boolean { return this.dom.checked }
|
|
34
|
-
public get data(): any { return this.dom.data }
|
|
35
|
-
public set data(value: any) { this.dom.data = value }
|
|
36
|
-
|
|
37
|
-
public get className(): string { return this.dom.className }
|
|
38
|
-
public set className(value: string) { this.dom.className = value }
|
|
39
|
-
public get classList(): DomTokenList { return this.domTokenList }
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Not using private fields because of issues with the `#private;` line
|
|
43
|
-
* generated by tsc
|
|
44
|
-
*/
|
|
45
|
-
dom: CS.OneJS.Dom.Dom
|
|
46
|
-
domStyleWrapper: DomStyleWrapper
|
|
47
|
-
domTokenList: DomTokenList
|
|
48
|
-
|
|
49
|
-
cachedChildNodes: DomWrapper[] | null = null
|
|
50
|
-
boundListeners = new WeakMap();
|
|
51
|
-
|
|
52
|
-
constructor(dom: CS.OneJS.Dom.Dom) {
|
|
53
|
-
this.dom = dom
|
|
54
|
-
this.domStyleWrapper = new DomStyleWrapper(dom.style)
|
|
55
|
-
this.domTokenList = new DomTokenList(dom)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// MARK: Manipulation
|
|
59
|
-
|
|
60
|
-
appendChild(child: DomWrapper) {
|
|
61
|
-
if (!child) return
|
|
62
|
-
this.dom.appendChild(child.dom)
|
|
63
|
-
this.cachedChildNodes = null
|
|
64
|
-
return child
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
removeChild(child: DomWrapper) {
|
|
68
|
-
if (!child) return
|
|
69
|
-
this.dom.removeChild(child.dom)
|
|
70
|
-
this.cachedChildNodes = null
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
insertBefore(a: DomWrapper, b: DomWrapper) {
|
|
74
|
-
this.dom.insertBefore(a?._dom, b?._dom)
|
|
75
|
-
this.cachedChildNodes = null
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
insertAfter(a: DomWrapper, b: DomWrapper) {
|
|
79
|
-
this.dom.insertAfter(a?._dom, b?._dom)
|
|
80
|
-
this.cachedChildNodes = null
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
before(other: DomWrapper) { // TODO: variable length args
|
|
84
|
-
if (this.parentNode) {
|
|
85
|
-
this.parentNode.insertBefore(other, this)
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
clearChildren() {
|
|
90
|
-
this.dom.clearChildren()
|
|
91
|
-
this.cachedChildNodes = null
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
setAttribute(name: string, value: any) {
|
|
95
|
-
this.dom.setAttribute(name, value)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
removeAttribute(name: string) {
|
|
99
|
-
this.dom.removeAttribute(name)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// MARK: Node.prototype
|
|
103
|
-
|
|
104
|
-
append(child: DomWrapper) {
|
|
105
|
-
if (!child) return
|
|
106
|
-
this.dom.appendChild(child.dom)
|
|
107
|
-
this.cachedChildNodes = null
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
cloneNode(deep: boolean = false): DomWrapper {
|
|
111
|
-
return this
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
remove() {
|
|
115
|
-
if (this.parentNode) {
|
|
116
|
-
this.parentNode.removeChild(this)
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// MARK: Misc
|
|
121
|
-
|
|
122
|
-
contains(child: DomWrapper) {
|
|
123
|
-
if (!child) return false
|
|
124
|
-
return this.dom.contains(child._dom)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
focus() {
|
|
128
|
-
this.dom.focus()
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// MARK: Event
|
|
132
|
-
|
|
133
|
-
addEventListener(type: string, listener: (event: EventBase) => void, options?: boolean | { once?: boolean }) {
|
|
134
|
-
let boundListener = this.boundListeners.get(listener)
|
|
135
|
-
if (!boundListener) {
|
|
136
|
-
boundListener = listener.bind(this)
|
|
137
|
-
this.boundListeners.set(listener, boundListener)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (typeof options === 'object' && options.once) {
|
|
141
|
-
const onceWrapper = (event: EventBase) => {
|
|
142
|
-
boundListener(event)
|
|
143
|
-
this.dom.removeEventListener(type, onceWrapper, false)
|
|
144
|
-
}
|
|
145
|
-
this.dom.addEventListener(type, onceWrapper, false)
|
|
146
|
-
} else {
|
|
147
|
-
this.dom.addEventListener(type, boundListener, options ? true : false)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
removeEventListener(type: string, listener: (event: EventBase) => void, useCapture?: boolean) {
|
|
152
|
-
const boundListener = this.boundListeners.get(listener)
|
|
153
|
-
if (boundListener) {
|
|
154
|
-
this.dom.removeEventListener(type, boundListener, useCapture ? true : false)
|
|
155
|
-
this.boundListeners.delete(listener) // isn't strictly necessary for WeakMap, but still good practice
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Returns all elements matching the specified selector.
|
|
161
|
-
* Supports basic selectors:
|
|
162
|
-
* - Tag names: 'div'
|
|
163
|
-
* - IDs: '#myId'
|
|
164
|
-
* - Classes: '.myClass'
|
|
165
|
-
* - Combinations: 'div.myClass#myId'
|
|
166
|
-
*/
|
|
167
|
-
querySelectorAll(selector: string): DomWrapper[] {
|
|
168
|
-
const selectorInfo = parseSelector(selector)
|
|
169
|
-
const results: DomWrapper[] = []
|
|
170
|
-
|
|
171
|
-
function traverse(element: DomWrapper) {
|
|
172
|
-
if (elementMatchesSelector(element, selectorInfo)) {
|
|
173
|
-
results.push(element)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
for (const child of element.childNodes) {
|
|
177
|
-
traverse(child)
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
traverse(this)
|
|
182
|
-
return results
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Returns the first element matching the specified selector.
|
|
187
|
-
* Supports the same basic selectors as querySelectorAll.
|
|
188
|
-
*/
|
|
189
|
-
querySelector(selector: string): DomWrapper | null {
|
|
190
|
-
const selectorInfo = parseSelector(selector)
|
|
191
|
-
|
|
192
|
-
function traverse(element: DomWrapper): DomWrapper | null {
|
|
193
|
-
if (elementMatchesSelector(element, selectorInfo)) {
|
|
194
|
-
return element
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
for (const child of element.childNodes) {
|
|
198
|
-
const match = traverse(child)
|
|
199
|
-
if (match) {
|
|
200
|
-
return match
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
return null
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
return traverse(this)
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
interface SelectorInfo {
|
|
212
|
-
tag?: string
|
|
213
|
-
id?: string
|
|
214
|
-
classes: string[]
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
function parseSelector(selector: string): SelectorInfo {
|
|
218
|
-
const selectorInfo: SelectorInfo = {
|
|
219
|
-
classes: []
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Handle ID
|
|
223
|
-
const idMatch = selector.match(/#([^.#\s]+)/)
|
|
224
|
-
if (idMatch) {
|
|
225
|
-
selectorInfo.id = idMatch[1]
|
|
226
|
-
selector = selector.replace(idMatch[0], '')
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Handle classes
|
|
230
|
-
const classMatches = selector.match(/\.([^.#\s]+)/g)
|
|
231
|
-
if (classMatches) {
|
|
232
|
-
selectorInfo.classes = classMatches.map(c => c.substring(1))
|
|
233
|
-
selector = selector.replace(/\.[^.#\s]+/g, '')
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Handle tag name (what's left after removing id and classes)
|
|
237
|
-
const tagName = selector.trim()
|
|
238
|
-
if (tagName) {
|
|
239
|
-
selectorInfo.tag = tagName.toLowerCase()
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return selectorInfo
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
function elementMatchesSelector(element: DomWrapper, selectorInfo: SelectorInfo): boolean {
|
|
246
|
-
// Check tag name
|
|
247
|
-
if (selectorInfo.tag && element.ve.GetType().Name.toLowerCase() !== selectorInfo.tag) {
|
|
248
|
-
return false
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// Check ID
|
|
252
|
-
if (selectorInfo.id && element.Id !== selectorInfo.id) {
|
|
253
|
-
return false
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Check classes
|
|
257
|
-
if (selectorInfo.classes.length > 0) {
|
|
258
|
-
const elementClasses = element.className.split(' ').filter(c => c)
|
|
259
|
-
for (const className of selectorInfo.classes) {
|
|
260
|
-
if (!elementClasses.includes(className)) {
|
|
261
|
-
return false
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
return true
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
export function querySelectorAll(root: DomWrapper, selector: string): DomWrapper[] {
|
|
270
|
-
const results: DomWrapper[] = []
|
|
271
|
-
const selectorInfo = parseSelector(selector)
|
|
272
|
-
|
|
273
|
-
function traverse(element: DomWrapper) {
|
|
274
|
-
// Check if current element matches
|
|
275
|
-
if (elementMatchesSelector(element, selectorInfo)) {
|
|
276
|
-
results.push(element)
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// Recursively check children
|
|
280
|
-
for (const child of element.childNodes) {
|
|
281
|
-
traverse(child)
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
traverse(root)
|
|
286
|
-
return results
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
export function querySelector(root: DomWrapper, selector: string): DomWrapper | null {
|
|
290
|
-
const selectorInfo = parseSelector(selector)
|
|
291
|
-
|
|
292
|
-
function traverse(element: DomWrapper): DomWrapper | null {
|
|
293
|
-
// Check if current element matches
|
|
294
|
-
if (elementMatchesSelector(element, selectorInfo)) {
|
|
295
|
-
return element
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// Recursively check children
|
|
299
|
-
for (const child of element.childNodes) {
|
|
300
|
-
const match = traverse(child)
|
|
301
|
-
if (match) {
|
|
302
|
-
return match
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
return null
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
return traverse(root)
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
class DomTokenList {
|
|
313
|
-
dom: CS.OneJS.Dom.Dom
|
|
314
|
-
|
|
315
|
-
constructor(dom: CS.OneJS.Dom.Dom) {
|
|
316
|
-
this.dom = dom
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
_tokens(): string[] {
|
|
320
|
-
return this.dom.className.trim().split(/\s+/).filter(Boolean)
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
_update(tokens: string[]) {
|
|
324
|
-
this.dom.className = tokens.join(' ')
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
add(...tokens: string[]) {
|
|
328
|
-
const set = new Set(this._tokens())
|
|
329
|
-
tokens.forEach(t => t && set.add(t))
|
|
330
|
-
this._update(Array.from(set))
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
remove(...tokens: string[]) {
|
|
334
|
-
const set = new Set(this._tokens())
|
|
335
|
-
tokens.forEach(t => set.delete(t))
|
|
336
|
-
this._update(Array.from(set))
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
toggle(token: string, force?: boolean): boolean {
|
|
340
|
-
if (!token) return false
|
|
341
|
-
const has = this.contains(token)
|
|
342
|
-
if (force === true || (!has && force !== false)) {
|
|
343
|
-
this.add(token)
|
|
344
|
-
return true
|
|
345
|
-
}
|
|
346
|
-
if (has && (force === false || force === undefined)) {
|
|
347
|
-
this.remove(token)
|
|
348
|
-
return false
|
|
349
|
-
}
|
|
350
|
-
return has
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
contains(token: string): boolean {
|
|
354
|
-
return this._tokens().includes(token)
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
replace(oldToken: string, newToken: string): boolean {
|
|
358
|
-
if (!this.contains(oldToken)) return false
|
|
359
|
-
const tokens = this._tokens().map(t => (t === oldToken ? newToken : t))
|
|
360
|
-
this._update(tokens)
|
|
361
|
-
return true
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
toString(): string {
|
|
365
|
-
return this.dom.className
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
get length(): number { return this._tokens().length }
|
|
369
|
-
item(index: number): string | null {
|
|
370
|
-
const t = this._tokens()
|
|
371
|
-
return index >= 0 && index < t.length ? t[index] : null
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
[Symbol.iterator](): Iterator<string> {
|
|
375
|
-
return this._tokens()[Symbol.iterator]()
|
|
376
|
-
}
|
|
1
|
+
import { EventBase } from "UnityEngine/UIElements"
|
|
2
|
+
import { DomStyleWrapper } from "./dom-style"
|
|
3
|
+
|
|
4
|
+
export class DomWrapper {
|
|
5
|
+
public get _dom(): CS.OneJS.Dom.Dom { return this.dom }
|
|
6
|
+
public get ve(): CS.UnityEngine.UIElements.VisualElement { return this.dom.ve }
|
|
7
|
+
public get childNodes(): DomWrapper[] {
|
|
8
|
+
if (this.cachedChildNodes) return this.cachedChildNodes
|
|
9
|
+
this.cachedChildNodes = new Array(this.dom.childNodes.Length) as DomWrapper[]
|
|
10
|
+
var i = this.dom.childNodes.Length
|
|
11
|
+
while (i--) {
|
|
12
|
+
this.cachedChildNodes[i] = new DomWrapper(this.dom.childNodes.get_Item(i))
|
|
13
|
+
}
|
|
14
|
+
return this.cachedChildNodes
|
|
15
|
+
}
|
|
16
|
+
public get firstChild(): DomWrapper | null {
|
|
17
|
+
return this.dom.firstChild ? new DomWrapper(this.dom.firstChild) : null
|
|
18
|
+
}
|
|
19
|
+
public get parentNode(): DomWrapper | null {
|
|
20
|
+
return this.dom.parentNode ? new DomWrapper(this.dom.parentNode) : null
|
|
21
|
+
}
|
|
22
|
+
public get nextSibling(): DomWrapper | null {
|
|
23
|
+
return this.dom.nextSibling ? new DomWrapper(this.dom.nextSibling) : null
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public get nodeType(): number { return this.dom.nodeType }
|
|
27
|
+
public get style(): DomStyleWrapper { return this.domStyleWrapper }
|
|
28
|
+
public get Id(): string { return this.dom.Id }
|
|
29
|
+
public set Id(value: string) { this.dom.Id = value }
|
|
30
|
+
public get key(): string { return this.dom.key }
|
|
31
|
+
public set key(value: string) { this.dom.key = value }
|
|
32
|
+
public get value(): any { return this.dom.value }
|
|
33
|
+
public get checked(): boolean { return this.dom.checked }
|
|
34
|
+
public get data(): any { return this.dom.data }
|
|
35
|
+
public set data(value: any) { this.dom.data = value }
|
|
36
|
+
|
|
37
|
+
public get className(): string { return this.dom.className }
|
|
38
|
+
public set className(value: string) { this.dom.className = value }
|
|
39
|
+
public get classList(): DomTokenList { return this.domTokenList }
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Not using private fields because of issues with the `#private;` line
|
|
43
|
+
* generated by tsc
|
|
44
|
+
*/
|
|
45
|
+
dom: CS.OneJS.Dom.Dom
|
|
46
|
+
domStyleWrapper: DomStyleWrapper
|
|
47
|
+
domTokenList: DomTokenList
|
|
48
|
+
|
|
49
|
+
cachedChildNodes: DomWrapper[] | null = null
|
|
50
|
+
boundListeners = new WeakMap();
|
|
51
|
+
|
|
52
|
+
constructor(dom: CS.OneJS.Dom.Dom) {
|
|
53
|
+
this.dom = dom
|
|
54
|
+
this.domStyleWrapper = new DomStyleWrapper(dom.style)
|
|
55
|
+
this.domTokenList = new DomTokenList(dom)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// MARK: Manipulation
|
|
59
|
+
|
|
60
|
+
appendChild(child: DomWrapper) {
|
|
61
|
+
if (!child) return
|
|
62
|
+
this.dom.appendChild(child.dom)
|
|
63
|
+
this.cachedChildNodes = null
|
|
64
|
+
return child
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
removeChild(child: DomWrapper) {
|
|
68
|
+
if (!child) return
|
|
69
|
+
this.dom.removeChild(child.dom)
|
|
70
|
+
this.cachedChildNodes = null
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
insertBefore(a: DomWrapper, b: DomWrapper) {
|
|
74
|
+
this.dom.insertBefore(a?._dom, b?._dom)
|
|
75
|
+
this.cachedChildNodes = null
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
insertAfter(a: DomWrapper, b: DomWrapper) {
|
|
79
|
+
this.dom.insertAfter(a?._dom, b?._dom)
|
|
80
|
+
this.cachedChildNodes = null
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
before(other: DomWrapper) { // TODO: variable length args
|
|
84
|
+
if (this.parentNode) {
|
|
85
|
+
this.parentNode.insertBefore(other, this)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
clearChildren() {
|
|
90
|
+
this.dom.clearChildren()
|
|
91
|
+
this.cachedChildNodes = null
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
setAttribute(name: string, value: any) {
|
|
95
|
+
this.dom.setAttribute(name, value)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
removeAttribute(name: string) {
|
|
99
|
+
this.dom.removeAttribute(name)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// MARK: Node.prototype
|
|
103
|
+
|
|
104
|
+
append(child: DomWrapper) {
|
|
105
|
+
if (!child) return
|
|
106
|
+
this.dom.appendChild(child.dom)
|
|
107
|
+
this.cachedChildNodes = null
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
cloneNode(deep: boolean = false): DomWrapper {
|
|
111
|
+
return this
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
remove() {
|
|
115
|
+
if (this.parentNode) {
|
|
116
|
+
this.parentNode.removeChild(this)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// MARK: Misc
|
|
121
|
+
|
|
122
|
+
contains(child: DomWrapper) {
|
|
123
|
+
if (!child) return false
|
|
124
|
+
return this.dom.contains(child._dom)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
focus() {
|
|
128
|
+
this.dom.focus()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// MARK: Event
|
|
132
|
+
|
|
133
|
+
addEventListener(type: string, listener: (event: EventBase) => void, options?: boolean | { once?: boolean }) {
|
|
134
|
+
let boundListener = this.boundListeners.get(listener)
|
|
135
|
+
if (!boundListener) {
|
|
136
|
+
boundListener = listener.bind(this)
|
|
137
|
+
this.boundListeners.set(listener, boundListener)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (typeof options === 'object' && options.once) {
|
|
141
|
+
const onceWrapper = (event: EventBase) => {
|
|
142
|
+
boundListener(event)
|
|
143
|
+
this.dom.removeEventListener(type, onceWrapper, false)
|
|
144
|
+
}
|
|
145
|
+
this.dom.addEventListener(type, onceWrapper, false)
|
|
146
|
+
} else {
|
|
147
|
+
this.dom.addEventListener(type, boundListener, options ? true : false)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
removeEventListener(type: string, listener: (event: EventBase) => void, useCapture?: boolean) {
|
|
152
|
+
const boundListener = this.boundListeners.get(listener)
|
|
153
|
+
if (boundListener) {
|
|
154
|
+
this.dom.removeEventListener(type, boundListener, useCapture ? true : false)
|
|
155
|
+
this.boundListeners.delete(listener) // isn't strictly necessary for WeakMap, but still good practice
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Returns all elements matching the specified selector.
|
|
161
|
+
* Supports basic selectors:
|
|
162
|
+
* - Tag names: 'div'
|
|
163
|
+
* - IDs: '#myId'
|
|
164
|
+
* - Classes: '.myClass'
|
|
165
|
+
* - Combinations: 'div.myClass#myId'
|
|
166
|
+
*/
|
|
167
|
+
querySelectorAll(selector: string): DomWrapper[] {
|
|
168
|
+
const selectorInfo = parseSelector(selector)
|
|
169
|
+
const results: DomWrapper[] = []
|
|
170
|
+
|
|
171
|
+
function traverse(element: DomWrapper) {
|
|
172
|
+
if (elementMatchesSelector(element, selectorInfo)) {
|
|
173
|
+
results.push(element)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
for (const child of element.childNodes) {
|
|
177
|
+
traverse(child)
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
traverse(this)
|
|
182
|
+
return results
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Returns the first element matching the specified selector.
|
|
187
|
+
* Supports the same basic selectors as querySelectorAll.
|
|
188
|
+
*/
|
|
189
|
+
querySelector(selector: string): DomWrapper | null {
|
|
190
|
+
const selectorInfo = parseSelector(selector)
|
|
191
|
+
|
|
192
|
+
function traverse(element: DomWrapper): DomWrapper | null {
|
|
193
|
+
if (elementMatchesSelector(element, selectorInfo)) {
|
|
194
|
+
return element
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
for (const child of element.childNodes) {
|
|
198
|
+
const match = traverse(child)
|
|
199
|
+
if (match) {
|
|
200
|
+
return match
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return null
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return traverse(this)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
interface SelectorInfo {
|
|
212
|
+
tag?: string
|
|
213
|
+
id?: string
|
|
214
|
+
classes: string[]
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function parseSelector(selector: string): SelectorInfo {
|
|
218
|
+
const selectorInfo: SelectorInfo = {
|
|
219
|
+
classes: []
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Handle ID
|
|
223
|
+
const idMatch = selector.match(/#([^.#\s]+)/)
|
|
224
|
+
if (idMatch) {
|
|
225
|
+
selectorInfo.id = idMatch[1]
|
|
226
|
+
selector = selector.replace(idMatch[0], '')
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Handle classes
|
|
230
|
+
const classMatches = selector.match(/\.([^.#\s]+)/g)
|
|
231
|
+
if (classMatches) {
|
|
232
|
+
selectorInfo.classes = classMatches.map(c => c.substring(1))
|
|
233
|
+
selector = selector.replace(/\.[^.#\s]+/g, '')
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Handle tag name (what's left after removing id and classes)
|
|
237
|
+
const tagName = selector.trim()
|
|
238
|
+
if (tagName) {
|
|
239
|
+
selectorInfo.tag = tagName.toLowerCase()
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return selectorInfo
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function elementMatchesSelector(element: DomWrapper, selectorInfo: SelectorInfo): boolean {
|
|
246
|
+
// Check tag name
|
|
247
|
+
if (selectorInfo.tag && element.ve.GetType().Name.toLowerCase() !== selectorInfo.tag) {
|
|
248
|
+
return false
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Check ID
|
|
252
|
+
if (selectorInfo.id && element.Id !== selectorInfo.id) {
|
|
253
|
+
return false
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Check classes
|
|
257
|
+
if (selectorInfo.classes.length > 0) {
|
|
258
|
+
const elementClasses = element.className.split(' ').filter(c => c)
|
|
259
|
+
for (const className of selectorInfo.classes) {
|
|
260
|
+
if (!elementClasses.includes(className)) {
|
|
261
|
+
return false
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return true
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function querySelectorAll(root: DomWrapper, selector: string): DomWrapper[] {
|
|
270
|
+
const results: DomWrapper[] = []
|
|
271
|
+
const selectorInfo = parseSelector(selector)
|
|
272
|
+
|
|
273
|
+
function traverse(element: DomWrapper) {
|
|
274
|
+
// Check if current element matches
|
|
275
|
+
if (elementMatchesSelector(element, selectorInfo)) {
|
|
276
|
+
results.push(element)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Recursively check children
|
|
280
|
+
for (const child of element.childNodes) {
|
|
281
|
+
traverse(child)
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
traverse(root)
|
|
286
|
+
return results
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export function querySelector(root: DomWrapper, selector: string): DomWrapper | null {
|
|
290
|
+
const selectorInfo = parseSelector(selector)
|
|
291
|
+
|
|
292
|
+
function traverse(element: DomWrapper): DomWrapper | null {
|
|
293
|
+
// Check if current element matches
|
|
294
|
+
if (elementMatchesSelector(element, selectorInfo)) {
|
|
295
|
+
return element
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Recursively check children
|
|
299
|
+
for (const child of element.childNodes) {
|
|
300
|
+
const match = traverse(child)
|
|
301
|
+
if (match) {
|
|
302
|
+
return match
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return null
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return traverse(root)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
class DomTokenList {
|
|
313
|
+
dom: CS.OneJS.Dom.Dom
|
|
314
|
+
|
|
315
|
+
constructor(dom: CS.OneJS.Dom.Dom) {
|
|
316
|
+
this.dom = dom
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
_tokens(): string[] {
|
|
320
|
+
return this.dom.className.trim().split(/\s+/).filter(Boolean)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
_update(tokens: string[]) {
|
|
324
|
+
this.dom.className = tokens.join(' ')
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
add(...tokens: string[]) {
|
|
328
|
+
const set = new Set(this._tokens())
|
|
329
|
+
tokens.forEach(t => t && set.add(t))
|
|
330
|
+
this._update(Array.from(set))
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
remove(...tokens: string[]) {
|
|
334
|
+
const set = new Set(this._tokens())
|
|
335
|
+
tokens.forEach(t => set.delete(t))
|
|
336
|
+
this._update(Array.from(set))
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
toggle(token: string, force?: boolean): boolean {
|
|
340
|
+
if (!token) return false
|
|
341
|
+
const has = this.contains(token)
|
|
342
|
+
if (force === true || (!has && force !== false)) {
|
|
343
|
+
this.add(token)
|
|
344
|
+
return true
|
|
345
|
+
}
|
|
346
|
+
if (has && (force === false || force === undefined)) {
|
|
347
|
+
this.remove(token)
|
|
348
|
+
return false
|
|
349
|
+
}
|
|
350
|
+
return has
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
contains(token: string): boolean {
|
|
354
|
+
return this._tokens().includes(token)
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
replace(oldToken: string, newToken: string): boolean {
|
|
358
|
+
if (!this.contains(oldToken)) return false
|
|
359
|
+
const tokens = this._tokens().map(t => (t === oldToken ? newToken : t))
|
|
360
|
+
this._update(tokens)
|
|
361
|
+
return true
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
toString(): string {
|
|
365
|
+
return this.dom.className
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
get length(): number { return this._tokens().length }
|
|
369
|
+
item(index: number): string | null {
|
|
370
|
+
const t = this._tokens()
|
|
371
|
+
return index >= 0 && index < t.length ? t[index] : null
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
[Symbol.iterator](): Iterator<string> {
|
|
375
|
+
return this._tokens()[Symbol.iterator]()
|
|
376
|
+
}
|
|
377
377
|
}
|