-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathselector.ts
107 lines (95 loc) · 3.02 KB
/
selector.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import { createProxy, ProxyNode } from './core'
/** @throws Error if the selector doesn't match any element */
export function queryElement<Selector extends string>(
selector: Selector,
parent: ParentNode = document.body,
) {
let element = parent.querySelector<SelectorElement<Selector>>(selector)
if (!element) throw new Error('failed to find element, selector: ' + selector)
return element
}
/** @throws Error if the selector doesn't match any element */
export function queryElementProxy<Selector extends string>(
selector: Selector,
parent?: ParentNode,
) {
return createProxy(queryElement<Selector>(selector, parent))
}
export function queryAllElements<Selector extends string>(
selector: Selector,
parent: ParentNode = document.body,
) {
let elements = parent.querySelectorAll<SelectorElement<Selector>>(selector)
return Array.from(elements)
}
export function queryAllElementProxies<Selector extends string>(
selector: Selector,
parent: ParentNode = document.body,
) {
let elements = parent.querySelectorAll<SelectorElement<Selector>>(selector)
return Array.from(elements, element => createProxy(element))
}
/** @throws Error if any selectors don't match any elements */
export function queryElements<
SelectorDict extends Dict<Selector>,
Selector extends string,
>(
selectors: SelectorDict,
parent: ParentNode = document.body,
): { [P in keyof SelectorDict]: SelectorElement<SelectorDict[P]> } {
let object: any = {}
for (let [key, selector] of Object.entries(selectors)) {
object[key] = queryElement(selector, parent)
}
return object
}
/** @throws Error if any selectors don't match any elements */
export function queryElementProxies<
SelectorDict extends Dict<Selector>,
Selector extends string,
>(
selectors: SelectorDict,
parent: ParentNode = document.body,
): { [P in keyof SelectorDict]: ProxyNode<SelectorElement<SelectorDict[P]>> } {
let object: any = {}
for (let [key, selector] of Object.entries(selectors)) {
object[key] = queryElementProxy(selector, parent)
}
return object
}
type SelectorElement<Selector extends string> =
GetTagName<Selector> extends `${infer TagName}`
? TagName extends keyof HTMLElementTagNameMap
? HTMLElementTagNameMap[TagName]
: TagName extends keyof SVGElementTagNameMap
? SVGElementTagNameMap[TagName]
: FallbackSelectorElement<Selector>
: FallbackSelectorElement<Selector>
type FallbackSelectorElement<Selector extends string> =
Selector extends `${string}[name=${string}]${string}`
? HTMLInputElement
: Element
type Dict<T> = {
[key: string]: T
}
type RemoveTail<
S extends String,
Tail extends string,
> = S extends `${infer Rest}${Tail}` ? Rest : S
type RemoveHead<
S extends String,
Head extends string,
> = S extends `${Head}${infer Rest}` ? Rest : S
type GetTagName<S extends string> = RemoveTail<
RemoveTail<
RemoveTail<
RemoveTail<
RemoveHead<RemoveHead<S, `${string} `>, `${string}>`>,
`:${string}`
>,
`[${string}`
>,
`.${string}`
>,
`#${string}`
>