UNPKG

2.94 kBJavaScriptView Raw
1export const last = (v = []) => v[v.length - 1]
2
3export const isWhitespace = (node) => {
4 return node.nodeType === node.TEXT_NODE && node.nodeValue.trim() === ""
5}
6
7export const walk = (node, callback, deep = true) => {
8 if (!node) return
9 if (!isWhitespace(node)) {
10 let v = callback(node)
11 if (v === false) return
12 if (v?.nodeName) return walk(v, callback, deep)
13 }
14 if (deep) walk(node.firstChild, callback, deep)
15 walk(node.nextSibling, callback, deep)
16}
17
18const transformBrackets = (str = "") => {
19 let parts = str.split(/(\[[^\]]+\])/).filter((v) => v)
20 return parts.reduce((a, part) => {
21 let v = part.charAt(0) === "[" ? "." + part.replace(/\./g, ":") : part
22 return a + v
23 }, "")
24}
25
26const getTarget = (path, target) => {
27 let parts = transformBrackets(path)
28 .split(".")
29 .map((k) => {
30 if (k.charAt(0) === "[") {
31 let p = k.slice(1, -1).replace(/:/g, ".")
32 return getValueAtPath(p, target)
33 } else {
34 return k
35 }
36 })
37
38 let t =
39 parts.slice(0, -1).reduce((o, k) => {
40 return o && o[k]
41 }, target) || target
42 return [t, last(parts)]
43}
44
45export const getValueAtPath = (path, target) => {
46 let [a, b] = getTarget(path, target)
47 let v = a?.[b]
48 if (typeof v === "function") return v.bind(a)
49 return v
50}
51
52export const fragmentFromTemplate = (v) => {
53 if (typeof v === "string") {
54 let tpl = document.createElement("template")
55 tpl.innerHTML = v.trim()
56 return tpl.content
57 }
58 if (v.nodeName === "TEMPLATE") return v.cloneNode(true).content
59 if (v.nodeName === "defs") return v.firstElementChild.cloneNode(true)
60}
61
62export const debounce = (fn) => {
63 let wait = false
64 let invoke = false
65 return () => {
66 if (wait) {
67 invoke = true
68 } else {
69 wait = true
70 fn()
71 requestAnimationFrame(() => {
72 if (invoke) fn()
73 wait = false
74 })
75 }
76 }
77}
78
79export const isPrimitive = (v) => v === null || typeof v !== "object"
80
81export const typeOf = (v) =>
82 Object.prototype.toString.call(v).match(/\s(.+[^\]])/)[1]
83
84export const pascalToKebab = (string) =>
85 string.replace(/[\w]([A-Z])/g, function (m) {
86 return m[0] + "-" + m[1].toLowerCase()
87 })
88
89export const kebabToPascal = (string) =>
90 string.replace(/[\w]-([\w])/g, function (m) {
91 return m[0] + m[2].toUpperCase()
92 })
93
94export const applyAttribute = (node, name, value) => {
95 name = pascalToKebab(name)
96
97 if (typeof value === "boolean") {
98 if (name.startsWith("aria-")) {
99 value = "" + value
100 } else if (value) {
101 value = ""
102 }
103 }
104
105 if (typeof value === "string" || typeof value === "number") {
106 node.setAttribute(name, value)
107 } else {
108 node.removeAttribute(name)
109 }
110}
111
112export const attributeToProp = (k, v) => {
113 let name = kebabToPascal(k)
114 if (v === "") v = true
115 if (k.startsWith("aria-")) {
116 if (v === "true") v = true
117 if (v === "false") v = false
118 }
119 return {
120 name,
121 value: v,
122 }
123}