@thi.ng/hdom 9.3.30 → 9.4.0

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/dom.js CHANGED
@@ -1,277 +1,238 @@
1
1
  import { implementsFunction } from "@thi.ng/checks/implements-function";
2
- import { isArray as isa } from "@thi.ng/checks/is-array";
3
- import { isNotStringAndIterable as isi } from "@thi.ng/checks/is-not-string-iterable";
4
- import { isString as iss } from "@thi.ng/checks/is-string";
5
- import { SVG_TAGS } from "@thi.ng/hiccup/api";
2
+ import { isArray } from "@thi.ng/checks/is-array";
3
+ import { isNotStringAndIterable } from "@thi.ng/checks/is-not-string-iterable";
4
+ import { isString } from "@thi.ng/checks/is-string";
5
+ import { ATTRIB_JOIN_DELIMS, SVG_TAGS } from "@thi.ng/hiccup/api";
6
6
  import { css } from "@thi.ng/hiccup/css";
7
7
  import { formatPrefixes } from "@thi.ng/hiccup/prefix";
8
8
  import { XML_SVG } from "@thi.ng/prefixes/xml";
9
- const isArray = isa;
10
- const isNotStringAndIterable = isi;
11
- const isString = iss;
12
9
  const maybeInitElement = (el, tree) => tree.__init && tree.__init.apply(tree.__this, [el, ...tree.__args]);
13
- /**
14
- * See {@link HDOMImplementation} interface for further details.
15
- *
16
- * @param opts - hdom config options
17
- * @param parent - DOM element
18
- * @param tree - component tree
19
- * @param insert - child index
20
- */
21
- export const createTree = (opts, impl, parent, tree, insert, init = true) => {
22
- if (isArray(tree)) {
23
- const tag = tree[0];
24
- if (typeof tag === "function") {
25
- return createTree(opts, impl, parent, tag.apply(null, [opts.ctx, ...tree.slice(1)]), insert);
26
- }
27
- const attribs = tree[1];
28
- if (attribs.__impl) {
29
- return attribs.__impl.createTree(opts, parent, tree, insert, init);
30
- }
31
- const el = impl.createElement(parent, tag, attribs, insert);
32
- if (tree.length > 2) {
33
- const n = tree.length;
34
- for (let i = 2; i < n; i++) {
35
- createTree(opts, impl, el, tree[i], undefined, init);
36
- }
37
- }
38
- init && maybeInitElement(el, tree);
39
- return el;
10
+ const createTree = (opts, impl, parent, tree, insert, init = true) => {
11
+ if (isArray(tree)) {
12
+ const tag = tree[0];
13
+ if (typeof tag === "function") {
14
+ return createTree(
15
+ opts,
16
+ impl,
17
+ parent,
18
+ tag.apply(null, [opts.ctx, ...tree.slice(1)]),
19
+ insert
20
+ );
40
21
  }
41
- if (isNotStringAndIterable(tree)) {
42
- const res = [];
43
- for (let t of tree) {
44
- res.push(createTree(opts, impl, parent, t, insert, init));
45
- }
46
- return res;
22
+ const attribs = tree[1];
23
+ if (attribs.__impl) {
24
+ return attribs.__impl.createTree(
25
+ opts,
26
+ parent,
27
+ tree,
28
+ insert,
29
+ init
30
+ );
47
31
  }
48
- if (tree == null) {
49
- return parent;
32
+ const el = impl.createElement(parent, tag, attribs, insert);
33
+ if (tree.length > 2) {
34
+ const n = tree.length;
35
+ for (let i = 2; i < n; i++) {
36
+ createTree(opts, impl, el, tree[i], void 0, init);
37
+ }
50
38
  }
51
- return impl.createTextElement(parent, tree);
39
+ init && maybeInitElement(el, tree);
40
+ return el;
41
+ }
42
+ if (isNotStringAndIterable(tree)) {
43
+ const res = [];
44
+ for (let t of tree) {
45
+ res.push(createTree(opts, impl, parent, t, insert, init));
46
+ }
47
+ return res;
48
+ }
49
+ if (tree == null) {
50
+ return parent;
51
+ }
52
+ return impl.createTextElement(parent, tree);
52
53
  };
53
- /**
54
- * See {@link HDOMImplementation} interface for further details.
55
- *
56
- * @param opts - hdom config options
57
- * @param parent - DOM element
58
- * @param tree - component tree
59
- * @param index - child index
60
- */
61
- export const hydrateTree = (opts, impl, parent, tree, index = 0) => {
62
- if (isArray(tree)) {
63
- const el = impl.getChild(parent, index);
64
- if (typeof tree[0] === "function") {
65
- hydrateTree(opts, impl, parent, tree[0].apply(null, [opts.ctx, ...tree.slice(1)]), index);
66
- }
67
- const attribs = tree[1];
68
- if (attribs.__impl) {
69
- return attribs.__impl.hydrateTree(opts, parent, tree, index);
70
- }
71
- maybeInitElement(el, tree);
72
- for (let a in attribs) {
73
- a[0] === "o" && a[1] === "n" && impl.setAttrib(el, a, attribs[a]);
74
- }
75
- for (let n = tree.length, i = 2; i < n; i++) {
76
- hydrateTree(opts, impl, el, tree[i], i - 2);
77
- }
54
+ const hydrateTree = (opts, impl, parent, tree, index = 0) => {
55
+ if (isArray(tree)) {
56
+ const el = impl.getChild(parent, index);
57
+ if (typeof tree[0] === "function") {
58
+ hydrateTree(
59
+ opts,
60
+ impl,
61
+ parent,
62
+ tree[0].apply(null, [opts.ctx, ...tree.slice(1)]),
63
+ index
64
+ );
65
+ }
66
+ const attribs = tree[1];
67
+ if (attribs.__impl) {
68
+ return attribs.__impl.hydrateTree(
69
+ opts,
70
+ parent,
71
+ tree,
72
+ index
73
+ );
78
74
  }
79
- else if (isNotStringAndIterable(tree)) {
80
- for (let t of tree) {
81
- hydrateTree(opts, impl, parent, t, index);
82
- index++;
83
- }
75
+ maybeInitElement(el, tree);
76
+ for (let a in attribs) {
77
+ a[0] === "o" && a[1] === "n" && impl.setAttrib(el, a, attribs[a]);
84
78
  }
79
+ for (let n = tree.length, i = 2; i < n; i++) {
80
+ hydrateTree(opts, impl, el, tree[i], i - 2);
81
+ }
82
+ } else if (isNotStringAndIterable(tree)) {
83
+ for (let t of tree) {
84
+ hydrateTree(opts, impl, parent, t, index);
85
+ index++;
86
+ }
87
+ }
85
88
  };
86
- /**
87
- * Creates a new DOM element of type `tag` with optional `attribs`. If
88
- * `parent` is not `null`, the new element will be inserted as child at
89
- * given `insert` index. If `insert` is missing, the element will be
90
- * appended to the `parent`'s list of children. Returns new DOM node.
91
- *
92
- * If `tag` is a known SVG element name, the new element will be created
93
- * with the proper SVG XML namespace.
94
- *
95
- * @param parent - DOM element
96
- * @param tag - component tree
97
- * @param attribs - attributes
98
- * @param insert - child index
99
- */
100
- export const createElement = (parent, tag, attribs, insert) => {
101
- const el = SVG_TAGS[tag]
102
- ? document.createElementNS(XML_SVG, tag)
103
- : document.createElement(tag);
104
- attribs && setAttribs(el, attribs);
105
- return addChild(parent, el, insert);
89
+ const createElement = (parent, tag, attribs, insert) => {
90
+ const el = SVG_TAGS[tag] ? document.createElementNS(XML_SVG, tag) : document.createElement(tag);
91
+ attribs && setAttribs(el, attribs);
92
+ return addChild(parent, el, insert);
106
93
  };
107
- export const createTextElement = (parent, content, insert) => addChild(parent, document.createTextNode(content), insert);
108
- export const addChild = (parent, child, insert) => parent
109
- ? insert === undefined
110
- ? parent.appendChild(child)
111
- : parent.insertBefore(child, parent.children[insert])
112
- : child;
113
- export const getChild = (parent, child) => parent.children[child];
114
- export const replaceChild = (opts, impl, parent, child, tree, init = true) => (impl.removeChild(parent, child),
115
- impl.createTree(opts, parent, tree, child, init));
116
- export const cloneWithNewAttribs = (el, attribs) => {
117
- const res = el.cloneNode(true);
118
- setAttribs(res, attribs);
119
- el.parentNode.replaceChild(res, el);
120
- return res;
94
+ const createTextElement = (parent, content, insert) => addChild(parent, document.createTextNode(content), insert);
95
+ const addChild = (parent, child, insert) => parent ? insert === void 0 ? parent.appendChild(child) : parent.insertBefore(child, parent.children[insert]) : child;
96
+ const getChild = (parent, child) => parent.children[child];
97
+ const replaceChild = (opts, impl, parent, child, tree, init = true) => (impl.removeChild(parent, child), impl.createTree(opts, parent, tree, child, init));
98
+ const cloneWithNewAttribs = (el, attribs) => {
99
+ const res = el.cloneNode(true);
100
+ setAttribs(res, attribs);
101
+ el.parentNode.replaceChild(res, el);
102
+ return res;
121
103
  };
122
- export const setContent = (el, body) => (el.textContent = body);
123
- export const setAttribs = (el, attribs) => {
124
- for (let k in attribs) {
125
- setAttrib(el, k, attribs[k], attribs);
126
- }
127
- return el;
104
+ const setContent = (el, body) => el.textContent = body;
105
+ const setAttribs = (el, attribs) => {
106
+ for (let k in attribs) {
107
+ setAttrib(el, k, attribs[k], attribs);
108
+ }
109
+ return el;
128
110
  };
129
- /**
130
- * Sets a single attribute on given element. If attrib name is NOT an
131
- * event name (prefix: "on") and its value is a function, it is called
132
- * with given `attribs` object (usually the full attrib object passed to
133
- * {@link setAttribs}) and the function's return value is used as the actual
134
- * attrib value.
135
- *
136
- * Special rules apply for certain attributes:
137
- *
138
- * - "style": delegated to {@link setStyle}
139
- * - "value": delegated to {@link updateValueAttrib}
140
- * - attrib IDs starting with "on" are treated as event listeners
141
- *
142
- * If the given (or computed) attrib value is `false` or `undefined` the
143
- * attrib is removed from the element.
144
- *
145
- * @param el - DOM element
146
- * @param id - attribute name
147
- * @param val - attribute value
148
- * @param attribs - object of all attribs
149
- */
150
- export const setAttrib = (el, id, val, attribs) => {
151
- implementsFunction(val, "deref") && (val = val.deref());
152
- if (id.startsWith("__"))
153
- return;
154
- const isListener = id[0] === "o" && id[1] === "n";
155
- if (!isListener && typeof val === "function") {
156
- val = val(attribs);
157
- }
158
- if (val !== undefined && val !== false) {
159
- switch (id) {
160
- case "style":
161
- setStyle(el, val);
162
- break;
163
- case "value":
164
- updateValueAttrib(el, val);
165
- break;
166
- case "prefix":
167
- el.setAttribute(id, isString(val) ? val : formatPrefixes(val));
168
- break;
169
- case "accesskey":
170
- el.accessKey = val;
171
- break;
172
- case "contenteditable":
173
- el.contentEditable = val;
174
- break;
175
- case "tabindex":
176
- el.tabIndex = val;
177
- break;
178
- case "align":
179
- case "autocapitalize":
180
- case "checked":
181
- case "dir":
182
- case "draggable":
183
- case "hidden":
184
- case "id":
185
- case "lang":
186
- case "namespaceURI":
187
- case "scrollTop":
188
- case "scrollLeft":
189
- case "title":
190
- // TODO add more properties / enumerated attribs?
191
- el[id] = val;
192
- break;
193
- default:
194
- isListener
195
- ? setListener(el, id.substring(2), val)
196
- : el.setAttribute(id, val === true ? "" : val);
197
- }
198
- }
199
- else {
200
- el.hasAttribute(id)
201
- ? el.removeAttribute("title")
202
- : el[id] && (el[id] = null);
111
+ const setAttrib = (el, id, val, attribs) => {
112
+ implementsFunction(val, "deref") && (val = val.deref());
113
+ if (id.startsWith("__"))
114
+ return;
115
+ const isListener = id[0] === "o" && id[1] === "n";
116
+ if (isListener) {
117
+ if (isString(val)) {
118
+ el.setAttribute(id, val);
119
+ } else {
120
+ id = id.substring(2);
121
+ isArray(val) ? el.addEventListener(id, val[0], val[1]) : el.addEventListener(id, val);
203
122
  }
204
123
  return el;
124
+ }
125
+ if (typeof val === "function")
126
+ val = val(attribs);
127
+ if (isArray(val))
128
+ val = val.join(ATTRIB_JOIN_DELIMS[id] || " ");
129
+ switch (id) {
130
+ case "style":
131
+ setStyle(el, val);
132
+ break;
133
+ case "value":
134
+ updateValueAttrib(el, val);
135
+ break;
136
+ case "prefix":
137
+ el.setAttribute(id, isString(val) ? val : formatPrefixes(val));
138
+ break;
139
+ case "accesskey":
140
+ case "accessKey":
141
+ el.accessKey = val;
142
+ break;
143
+ case "contenteditable":
144
+ case "contentEditable":
145
+ el.contentEditable = val;
146
+ break;
147
+ case "tabindex":
148
+ case "tabIndex":
149
+ el.tabIndex = val;
150
+ break;
151
+ case "align":
152
+ case "autocapitalize":
153
+ case "checked":
154
+ case "dir":
155
+ case "draggable":
156
+ case "hidden":
157
+ case "id":
158
+ case "indeterminate":
159
+ case "lang":
160
+ case "namespaceURI":
161
+ case "scrollLeft":
162
+ case "scrollTop":
163
+ case "selectionEnd":
164
+ case "selectionStart":
165
+ case "slot":
166
+ case "spellcheck":
167
+ case "title":
168
+ el[id] = val;
169
+ break;
170
+ default:
171
+ val === false || val == null ? el.removeAttribute(id) : el.setAttribute(id, val === true ? id : val);
172
+ }
173
+ return el;
205
174
  };
206
- /**
207
- * Updates an element's `value` property. For form elements it too
208
- * ensures the edit cursor retains its position.
209
- *
210
- * @param el - DOM element
211
- * @param value - value
212
- */
213
- export const updateValueAttrib = (el, value) => {
214
- let ev;
215
- switch (el.type) {
216
- case "text":
217
- case "textarea":
218
- case "password":
219
- case "search":
220
- case "number":
221
- case "email":
222
- case "url":
223
- case "tel":
224
- case "date":
225
- case "datetime-local":
226
- case "time":
227
- case "week":
228
- case "month":
229
- if ((ev = el.value) !== undefined && typeof value === "string") {
230
- const off = value.length - (ev.length - (el.selectionStart || 0));
231
- el.value = value;
232
- el.selectionStart = el.selectionEnd = off;
233
- break;
234
- }
235
- default:
236
- el.value = value;
237
- }
175
+ const updateValueAttrib = (el, value) => {
176
+ let ev;
177
+ switch (el.type) {
178
+ case "text":
179
+ case "textarea":
180
+ case "password":
181
+ case "search":
182
+ case "number":
183
+ case "email":
184
+ case "url":
185
+ case "tel":
186
+ case "date":
187
+ case "datetime-local":
188
+ case "time":
189
+ case "week":
190
+ case "month":
191
+ if ((ev = el.value) !== void 0 && typeof value === "string") {
192
+ const off = value.length - (ev.length - (el.selectionStart || 0));
193
+ el.value = value;
194
+ el.selectionStart = el.selectionEnd = off;
195
+ break;
196
+ }
197
+ default:
198
+ el.value = value;
199
+ }
238
200
  };
239
- export const removeAttribs = (el, attribs, prev) => {
240
- for (let i = attribs.length; i-- > 0;) {
241
- const a = attribs[i];
242
- if (a[0] === "o" && a[1] === "n") {
243
- removeListener(el, a.substring(2), prev[a]);
244
- }
245
- else {
246
- el.hasAttribute(a) ? el.removeAttribute(a) : (el[a] = null);
247
- }
201
+ const removeAttribs = (el, attribs, prev) => {
202
+ for (let i = attribs.length; i-- > 0; ) {
203
+ const a = attribs[i];
204
+ if (a[0] === "o" && a[1] === "n") {
205
+ removeListener(el, a.substring(2), prev[a]);
206
+ } else {
207
+ el.hasAttribute(a) ? el.removeAttribute(a) : el[a] = null;
248
208
  }
209
+ }
210
+ };
211
+ const setStyle = (el, styles) => (el.setAttribute("style", css(styles)), el);
212
+ const setListener = (el, id, listener) => isString(listener) ? el.setAttribute("on" + id, listener) : isArray(listener) ? el.addEventListener(id, ...listener) : el.addEventListener(id, listener);
213
+ const removeListener = (el, id, listener) => isArray(listener) ? el.removeEventListener(id, ...listener) : el.removeEventListener(id, listener);
214
+ const clearDOM = (el) => el.innerHTML = "";
215
+ const removeChild = (parent, childIdx) => {
216
+ const n = parent.children[childIdx];
217
+ n !== void 0 && parent.removeChild(n);
249
218
  };
250
- export const setStyle = (el, styles) => (el.setAttribute("style", css(styles)), el);
251
- /**
252
- * Adds event listener (possibly with options).
253
- *
254
- * @param el - DOM element
255
- * @param id - event name (w/o `on` prefix)
256
- * @param listener -
257
- */
258
- export const setListener = (el, id, listener) => isString(listener)
259
- ? el.setAttribute("on" + id, listener)
260
- : isArray(listener)
261
- ? el.addEventListener(id, ...listener)
262
- : el.addEventListener(id, listener);
263
- /**
264
- * Removes event listener (possibly with options).
265
- *
266
- * @param el - DOM element
267
- * @param id - event name (w/o `on` prefix)
268
- * @param listener -
269
- */
270
- export const removeListener = (el, id, listener) => isArray(listener)
271
- ? el.removeEventListener(id, ...listener)
272
- : el.removeEventListener(id, listener);
273
- export const clearDOM = (el) => (el.innerHTML = "");
274
- export const removeChild = (parent, childIdx) => {
275
- const n = parent.children[childIdx];
276
- n !== undefined && parent.removeChild(n);
219
+ export {
220
+ addChild,
221
+ clearDOM,
222
+ cloneWithNewAttribs,
223
+ createElement,
224
+ createTextElement,
225
+ createTree,
226
+ getChild,
227
+ hydrateTree,
228
+ removeAttribs,
229
+ removeChild,
230
+ removeListener,
231
+ replaceChild,
232
+ setAttrib,
233
+ setAttribs,
234
+ setContent,
235
+ setListener,
236
+ setStyle,
237
+ updateValueAttrib
277
238
  };
package/logger.js CHANGED
@@ -1,3 +1,7 @@
1
1
  import { NULL_LOGGER } from "@thi.ng/logger/null";
2
- export let LOGGER = NULL_LOGGER;
3
- export const setLogger = (logger) => (LOGGER = logger);
2
+ let LOGGER = NULL_LOGGER;
3
+ const setLogger = (logger) => LOGGER = logger;
4
+ export {
5
+ LOGGER,
6
+ setLogger
7
+ };