@htmlplus/element 2.12.0 → 2.13.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.
Files changed (175) hide show
  1. package/README.md +2 -2
  2. package/bundlers.d.ts +20 -0
  3. package/{bundlers/vite.js → bundlers.js} +39 -3
  4. package/client-5FqNUiuz.d.ts +309 -0
  5. package/client-Dse96R-O.js +1805 -0
  6. package/client.d.ts +1 -0
  7. package/client.js +3 -0
  8. package/constants.d.ts +48 -0
  9. package/constants.js +60 -0
  10. package/internal.d.ts +1 -0
  11. package/internal.js +3 -0
  12. package/package.json +8 -4
  13. package/transformer.d.ts +139 -0
  14. package/transformer.js +1277 -0
  15. package/bundlers/rollup.d.ts +0 -7
  16. package/bundlers/rollup.js +0 -23
  17. package/bundlers/vite.d.ts +0 -8
  18. package/client/decorators/bind.d.ts +0 -8
  19. package/client/decorators/bind.js +0 -21
  20. package/client/decorators/context.d.ts +0 -3
  21. package/client/decorators/context.js +0 -121
  22. package/client/decorators/direction.d.ts +0 -5
  23. package/client/decorators/direction.js +0 -8
  24. package/client/decorators/element.d.ts +0 -7
  25. package/client/decorators/element.js +0 -65
  26. package/client/decorators/event.d.ts +0 -35
  27. package/client/decorators/event.js +0 -53
  28. package/client/decorators/host.d.ts +0 -4
  29. package/client/decorators/host.js +0 -7
  30. package/client/decorators/index.d.ts +0 -15
  31. package/client/decorators/index.js +0 -15
  32. package/client/decorators/isRTL.d.ts +0 -4
  33. package/client/decorators/isRTL.js +0 -7
  34. package/client/decorators/listen.d.ts +0 -52
  35. package/client/decorators/listen.js +0 -37
  36. package/client/decorators/method.d.ts +0 -6
  37. package/client/decorators/method.js +0 -15
  38. package/client/decorators/property.d.ts +0 -25
  39. package/client/decorators/property.js +0 -94
  40. package/client/decorators/query.d.ts +0 -9
  41. package/client/decorators/query.js +0 -12
  42. package/client/decorators/queryAll.d.ts +0 -12
  43. package/client/decorators/queryAll.js +0 -15
  44. package/client/decorators/slots.d.ts +0 -4
  45. package/client/decorators/slots.js +0 -7
  46. package/client/decorators/state.d.ts +0 -6
  47. package/client/decorators/state.js +0 -23
  48. package/client/decorators/watch.d.ts +0 -11
  49. package/client/decorators/watch.js +0 -31
  50. package/client/index.d.ts +0 -2
  51. package/client/index.js +0 -2
  52. package/client/utils/appendToMethod.d.ts +0 -1
  53. package/client/utils/appendToMethod.js +0 -15
  54. package/client/utils/attributes.d.ts +0 -2
  55. package/client/utils/attributes.js +0 -33
  56. package/client/utils/call.d.ts +0 -1
  57. package/client/utils/call.js +0 -3
  58. package/client/utils/classes.d.ts +0 -4
  59. package/client/utils/classes.js +0 -45
  60. package/client/utils/config.d.ts +0 -39
  61. package/client/utils/config.js +0 -28
  62. package/client/utils/defineProperty.d.ts +0 -1
  63. package/client/utils/defineProperty.js +0 -1
  64. package/client/utils/direction.d.ts +0 -6
  65. package/client/utils/direction.js +0 -8
  66. package/client/utils/event.d.ts +0 -13
  67. package/client/utils/event.js +0 -48
  68. package/client/utils/getFramework.d.ts +0 -2
  69. package/client/utils/getFramework.js +0 -20
  70. package/client/utils/getStyles.d.ts +0 -2
  71. package/client/utils/getStyles.js +0 -4
  72. package/client/utils/getTag.d.ts +0 -2
  73. package/client/utils/getTag.js +0 -4
  74. package/client/utils/host.d.ts +0 -5
  75. package/client/utils/host.js +0 -12
  76. package/client/utils/index.d.ts +0 -32
  77. package/client/utils/index.js +0 -32
  78. package/client/utils/isCSSColor.d.ts +0 -5
  79. package/client/utils/isCSSColor.js +0 -9
  80. package/client/utils/isEvent.d.ts +0 -1
  81. package/client/utils/isEvent.js +0 -3
  82. package/client/utils/isRTL.d.ts +0 -5
  83. package/client/utils/isRTL.js +0 -5
  84. package/client/utils/isServer.d.ts +0 -4
  85. package/client/utils/isServer.js +0 -6
  86. package/client/utils/merge.d.ts +0 -1
  87. package/client/utils/merge.js +0 -22
  88. package/client/utils/query.d.ts +0 -5
  89. package/client/utils/query.js +0 -7
  90. package/client/utils/queryAll.d.ts +0 -5
  91. package/client/utils/queryAll.js +0 -7
  92. package/client/utils/request.d.ts +0 -9
  93. package/client/utils/request.js +0 -106
  94. package/client/utils/shadowRoot.d.ts +0 -2
  95. package/client/utils/shadowRoot.js +0 -4
  96. package/client/utils/slots.d.ts +0 -9
  97. package/client/utils/slots.js +0 -18
  98. package/client/utils/styles.d.ts +0 -4
  99. package/client/utils/styles.js +0 -10
  100. package/client/utils/task.d.ts +0 -6
  101. package/client/utils/task.js +0 -34
  102. package/client/utils/toBoolean.d.ts +0 -1
  103. package/client/utils/toBoolean.js +0 -3
  104. package/client/utils/toDecorator.d.ts +0 -2
  105. package/client/utils/toDecorator.js +0 -10
  106. package/client/utils/toEvent.d.ts +0 -1
  107. package/client/utils/toEvent.js +0 -3
  108. package/client/utils/toProperty.d.ts +0 -1
  109. package/client/utils/toProperty.js +0 -55
  110. package/client/utils/toUnit.d.ts +0 -4
  111. package/client/utils/toUnit.js +0 -10
  112. package/client/utils/typeOf.d.ts +0 -3
  113. package/client/utils/typeOf.js +0 -6
  114. package/client/utils/uhtml.d.ts +0 -22
  115. package/client/utils/uhtml.js +0 -703
  116. package/client/utils/updateAttribute.d.ts +0 -2
  117. package/client/utils/updateAttribute.js +0 -10
  118. package/constants/index.d.ts +0 -48
  119. package/constants/index.js +0 -60
  120. package/transformer/index.d.ts +0 -3
  121. package/transformer/index.js +0 -3
  122. package/transformer/plugins/assets.d.ts +0 -7
  123. package/transformer/plugins/assets.js +0 -26
  124. package/transformer/plugins/copy.d.ts +0 -9
  125. package/transformer/plugins/copy.js +0 -29
  126. package/transformer/plugins/customElement.d.ts +0 -7
  127. package/transformer/plugins/customElement.js +0 -392
  128. package/transformer/plugins/document.d.ts +0 -7
  129. package/transformer/plugins/document.js +0 -206
  130. package/transformer/plugins/extract.d.ts +0 -2
  131. package/transformer/plugins/extract.js +0 -22
  132. package/transformer/plugins/index.d.ts +0 -12
  133. package/transformer/plugins/index.js +0 -12
  134. package/transformer/plugins/parse.d.ts +0 -6
  135. package/transformer/plugins/parse.js +0 -13
  136. package/transformer/plugins/read.d.ts +0 -7
  137. package/transformer/plugins/read.js +0 -19
  138. package/transformer/plugins/readme.d.ts +0 -6
  139. package/transformer/plugins/readme.js +0 -24
  140. package/transformer/plugins/style.d.ts +0 -6
  141. package/transformer/plugins/style.js +0 -42
  142. package/transformer/plugins/validate.d.ts +0 -2
  143. package/transformer/plugins/validate.js +0 -40
  144. package/transformer/plugins/visualStudioCode.d.ts +0 -8
  145. package/transformer/plugins/visualStudioCode.js +0 -73
  146. package/transformer/plugins/webTypes.d.ts +0 -10
  147. package/transformer/plugins/webTypes.js +0 -74
  148. package/transformer/transformer.d.ts +0 -8
  149. package/transformer/transformer.js +0 -78
  150. package/transformer/transformer.types.d.ts +0 -52
  151. package/transformer/transformer.types.js +0 -1
  152. package/transformer/utils/addDependency.d.ts +0 -7
  153. package/transformer/utils/addDependency.js +0 -64
  154. package/transformer/utils/extractAttribute.d.ts +0 -2
  155. package/transformer/utils/extractAttribute.js +0 -10
  156. package/transformer/utils/extractFromComment.d.ts +0 -4
  157. package/transformer/utils/extractFromComment.js +0 -51
  158. package/transformer/utils/getInitializer.d.ts +0 -2
  159. package/transformer/utils/getInitializer.js +0 -3
  160. package/transformer/utils/getType.d.ts +0 -2
  161. package/transformer/utils/getType.js +0 -89
  162. package/transformer/utils/getTypeReference.d.ts +0 -2
  163. package/transformer/utils/getTypeReference.js +0 -33
  164. package/transformer/utils/hasDecorator.d.ts +0 -1
  165. package/transformer/utils/hasDecorator.js +0 -5
  166. package/transformer/utils/index.d.ts +0 -10
  167. package/transformer/utils/index.js +0 -10
  168. package/transformer/utils/print.d.ts +0 -2
  169. package/transformer/utils/print.js +0 -5
  170. package/transformer/utils/printType.d.ts +0 -1
  171. package/transformer/utils/printType.js +0 -69
  172. package/transformer/utils/visitor.d.ts +0 -2
  173. package/transformer/utils/visitor.js +0 -5
  174. package/types/index.d.ts +0 -2
  175. package/types/index.js +0 -1
@@ -1,703 +0,0 @@
1
- class MapSet extends Map {
2
- set(key, value) {
3
- super.set(key, value);
4
- return value;
5
- }
6
- }
7
- class WeakMapSet extends WeakMap {
8
- set(key, value) {
9
- super.set(key, value);
10
- return value;
11
- }
12
- }
13
- /*! (c) Andrea Giammarchi - ISC */
14
- const empty = /^(?:area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr)$/i;
15
- const elements = /<([a-z]+[a-z0-9:._-]*)([^>]*?)(\/?)>/g;
16
- const attributes = /([^\s\\>"'=]+)\s*=\s*(['"]?)\x01/g;
17
- const holes = /[\x01\x02]/g;
18
- // \x01 Node.ELEMENT_NODE
19
- // \x02 Node.ATTRIBUTE_NODE
20
- /**
21
- * Given a template, find holes as both nodes and attributes and
22
- * return a string with holes as either comment nodes or named attributes.
23
- * @param {string[]} template a template literal tag array
24
- * @param {string} prefix prefix to use per each comment/attribute
25
- * @param {boolean} svg enforces self-closing tags
26
- * @returns {string} X/HTML with prefixed comments or attributes
27
- */
28
- var instrument = (template, prefix, svg) => {
29
- let i = 0;
30
- return template
31
- .join('\x01')
32
- .trim()
33
- .replace(elements, (_, name, attrs, selfClosing) => {
34
- let ml = name + attrs.replace(attributes, '\x02=$2$1').trimEnd();
35
- if (selfClosing.length)
36
- ml += svg || empty.test(name) ? ' /' : '></' + name;
37
- return '<' + ml + '>';
38
- })
39
- .replace(holes, (hole) => (hole === '\x01' ? '<!--' + prefix + i++ + '-->' : prefix + i++));
40
- };
41
- const ELEMENT_NODE = 1;
42
- const nodeType = 111;
43
- const remove = ({ firstChild, lastChild }) => {
44
- const range = document.createRange();
45
- range.setStartAfter(firstChild);
46
- range.setEndAfter(lastChild);
47
- range.deleteContents();
48
- return firstChild;
49
- };
50
- const diffable = (node, operation) => node.nodeType === nodeType
51
- ? 1 / operation < 0
52
- ? operation
53
- ? remove(node)
54
- : node.lastChild
55
- : operation
56
- ? node.valueOf()
57
- : node.firstChild
58
- : node;
59
- const persistent = (fragment) => {
60
- const { firstChild, lastChild } = fragment;
61
- if (firstChild === lastChild)
62
- return lastChild || fragment;
63
- const { childNodes } = fragment;
64
- const nodes = [...childNodes];
65
- return {
66
- ELEMENT_NODE,
67
- nodeType,
68
- firstChild,
69
- lastChild,
70
- valueOf() {
71
- if (childNodes.length !== nodes.length)
72
- fragment.append(...nodes);
73
- return fragment;
74
- }
75
- };
76
- };
77
- const { isArray: isArray$1 } = Array;
78
- const aria = (node) => (values) => {
79
- for (const key in values) {
80
- const name = key === 'role' ? key : `aria-${key}`;
81
- const value = values[key];
82
- if (value == null)
83
- node.removeAttribute(name);
84
- else
85
- node.setAttribute(name, value);
86
- }
87
- };
88
- const attribute = (node, name) => {
89
- let oldValue, orphan = true;
90
- const attributeNode = document.createAttributeNS(null, name);
91
- return (newValue) => {
92
- if (oldValue !== newValue) {
93
- oldValue = newValue;
94
- if (oldValue == null) {
95
- if (!orphan) {
96
- node.removeAttributeNode(attributeNode);
97
- orphan = true;
98
- }
99
- }
100
- else {
101
- const value = newValue;
102
- if (value == null) {
103
- if (!orphan)
104
- node.removeAttributeNode(attributeNode);
105
- orphan = true;
106
- }
107
- else {
108
- attributeNode.value = value;
109
- if (orphan) {
110
- node.setAttributeNodeNS(attributeNode);
111
- orphan = false;
112
- }
113
- }
114
- }
115
- }
116
- };
117
- };
118
- const boolean = (node, key, oldValue) => (newValue) => {
119
- if (oldValue !== !!newValue) {
120
- // when IE won't be around anymore ...
121
- // node.toggleAttribute(key, oldValue = !!newValue);
122
- if ((oldValue = !!newValue))
123
- node.setAttribute(key, '');
124
- else
125
- node.removeAttribute(key);
126
- }
127
- };
128
- const data = ({ dataset }) => (values) => {
129
- for (const key in values) {
130
- const value = values[key];
131
- if (value == null)
132
- delete dataset[key];
133
- else
134
- dataset[key] = value;
135
- }
136
- };
137
- const event = (node, name) => {
138
- let oldValue, lower, type = name.slice(2);
139
- if (!(name in node) && (lower = name.toLowerCase()) in node)
140
- type = lower.slice(2);
141
- return (newValue) => {
142
- const info = isArray$1(newValue) ? newValue : [newValue, false];
143
- if (oldValue !== info[0]) {
144
- if (oldValue)
145
- node.removeEventListener(type, oldValue, info[1]);
146
- if ((oldValue = info[0]))
147
- node.addEventListener(type, oldValue, info[1]);
148
- }
149
- };
150
- };
151
- const ref = (node) => {
152
- let oldValue;
153
- return (value) => {
154
- if (oldValue !== value) {
155
- oldValue = value;
156
- if (typeof value === 'function')
157
- value(node);
158
- else
159
- value.current = node;
160
- }
161
- };
162
- };
163
- const setter = (node, key) => key === 'dataset'
164
- ? data(node)
165
- : (value) => {
166
- node[key] = value;
167
- };
168
- const text = (node) => {
169
- let oldValue;
170
- return (newValue) => {
171
- if (oldValue != newValue) {
172
- oldValue = newValue;
173
- node.textContent = newValue == null ? '' : newValue;
174
- }
175
- };
176
- };
177
- /**
178
- * ISC License
179
- *
180
- * Copyright (c) 2020, Andrea Giammarchi, @WebReflection
181
- *
182
- * Permission to use, copy, modify, and/or distribute this software for any
183
- * purpose with or without fee is hereby granted, provided that the above
184
- * copyright notice and this permission notice appear in all copies.
185
- *
186
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
187
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
188
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
189
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
190
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
191
- * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
192
- * PERFORMANCE OF THIS SOFTWARE.
193
- */
194
- /**
195
- * @param {Node} parentNode The container where children live
196
- * @param {Node[]} a The list of current/live children
197
- * @param {Node[]} b The list of future children
198
- * @param {(entry: Node, action: number) => Node} get
199
- * The callback invoked per each entry related DOM operation.
200
- * @param {Node} [before] The optional node used as anchor to insert before.
201
- * @returns {Node[]} The same list of future children.
202
- */
203
- var udomdiff = (parentNode, a, b, get, before) => {
204
- const bLength = b.length;
205
- let aEnd = a.length;
206
- let bEnd = bLength;
207
- let aStart = 0;
208
- let bStart = 0;
209
- let map = null;
210
- while (aStart < aEnd || bStart < bEnd) {
211
- // append head, tail, or nodes in between: fast path
212
- if (aEnd === aStart) {
213
- // we could be in a situation where the rest of nodes that
214
- // need to be added are not at the end, and in such case
215
- // the node to `insertBefore`, if the index is more than 0
216
- // must be retrieved, otherwise it's gonna be the first item.
217
- const node = bEnd < bLength
218
- ? bStart
219
- ? get(b[bStart - 1], -0).nextSibling
220
- : get(b[bEnd - bStart], 0)
221
- : before;
222
- while (bStart < bEnd)
223
- parentNode.insertBefore(get(b[bStart++], 1), node);
224
- }
225
- // remove head or tail: fast path
226
- else if (bEnd === bStart) {
227
- while (aStart < aEnd) {
228
- // remove the node only if it's unknown or not live
229
- if (!map || !map.has(a[aStart]))
230
- parentNode.removeChild(get(a[aStart], -1));
231
- aStart++;
232
- }
233
- }
234
- // same node: fast path
235
- else if (a[aStart] === b[bStart]) {
236
- aStart++;
237
- bStart++;
238
- }
239
- // same tail: fast path
240
- else if (a[aEnd - 1] === b[bEnd - 1]) {
241
- aEnd--;
242
- bEnd--;
243
- }
244
- // The once here single last swap "fast path" has been removed in v1.1.0
245
- // https://github.com/WebReflection/udomdiff/blob/single-final-swap/esm/index.js#L69-L85
246
- // reverse swap: also fast path
247
- else if (a[aStart] === b[bEnd - 1] && b[bStart] === a[aEnd - 1]) {
248
- // this is a "shrink" operation that could happen in these cases:
249
- // [1, 2, 3, 4, 5]
250
- // [1, 4, 3, 2, 5]
251
- // or asymmetric too
252
- // [1, 2, 3, 4, 5]
253
- // [1, 2, 3, 5, 6, 4]
254
- const node = get(a[--aEnd], -1).nextSibling;
255
- parentNode.insertBefore(get(b[bStart++], 1), get(a[aStart++], -1).nextSibling);
256
- parentNode.insertBefore(get(b[--bEnd], 1), node);
257
- // mark the future index as identical (yeah, it's dirty, but cheap 👍)
258
- // The main reason to do this, is that when a[aEnd] will be reached,
259
- // the loop will likely be on the fast path, as identical to b[bEnd].
260
- // In the best case scenario, the next loop will skip the tail,
261
- // but in the worst one, this node will be considered as already
262
- // processed, bailing out pretty quickly from the map index check
263
- a[aEnd] = b[bEnd];
264
- }
265
- // map based fallback, "slow" path
266
- else {
267
- // the map requires an O(bEnd - bStart) operation once
268
- // to store all future nodes indexes for later purposes.
269
- // In the worst case scenario, this is a full O(N) cost,
270
- // and such scenario happens at least when all nodes are different,
271
- // but also if both first and last items of the lists are different
272
- if (!map) {
273
- map = new Map();
274
- let i = bStart;
275
- while (i < bEnd)
276
- map.set(b[i], i++);
277
- }
278
- // if it's a future node, hence it needs some handling
279
- if (map.has(a[aStart])) {
280
- // grab the index of such node, 'cause it might have been processed
281
- const index = map.get(a[aStart]);
282
- // if it's not already processed, look on demand for the next LCS
283
- if (bStart < index && index < bEnd) {
284
- let i = aStart;
285
- // counts the amount of nodes that are the same in the future
286
- let sequence = 1;
287
- while (++i < aEnd && i < bEnd && map.get(a[i]) === index + sequence)
288
- sequence++;
289
- // effort decision here: if the sequence is longer than replaces
290
- // needed to reach such sequence, which would brings again this loop
291
- // to the fast path, prepend the difference before a sequence,
292
- // and move only the future list index forward, so that aStart
293
- // and bStart will be aligned again, hence on the fast path.
294
- // An example considering aStart and bStart are both 0:
295
- // a: [1, 2, 3, 4]
296
- // b: [7, 1, 2, 3, 6]
297
- // this would place 7 before 1 and, from that time on, 1, 2, and 3
298
- // will be processed at zero cost
299
- if (sequence > index - bStart) {
300
- const node = get(a[aStart], 0);
301
- while (bStart < index)
302
- parentNode.insertBefore(get(b[bStart++], 1), node);
303
- }
304
- // if the effort wasn't good enough, fallback to a replace,
305
- // moving both source and target indexes forward, hoping that some
306
- // similar node will be found later on, to go back to the fast path
307
- else {
308
- parentNode.replaceChild(get(b[bStart++], 1), get(a[aStart++], -1));
309
- }
310
- }
311
- // otherwise move the source forward, 'cause there's nothing to do
312
- else
313
- aStart++;
314
- }
315
- // this node has no meaning in the future list, so it's more than safe
316
- // to remove it, and check the next live node out instead, meaning
317
- // that only the live list index should be forwarded
318
- else
319
- parentNode.removeChild(get(a[aStart++], -1));
320
- }
321
- }
322
- return b;
323
- };
324
- const { isArray, prototype } = Array;
325
- const { indexOf } = prototype;
326
- const { createDocumentFragment, createElement, createElementNS, createTextNode, createTreeWalker, importNode } = new Proxy(typeof window == 'undefined' ? {} : window.document, {
327
- get: (target, method) => (target[method] || function () { }).bind(target)
328
- });
329
- const createHTML = (html) => {
330
- const template = createElement('template');
331
- template.innerHTML = html;
332
- return template.content;
333
- };
334
- let xml;
335
- const createSVG = (svg) => {
336
- if (!xml)
337
- xml = createElementNS('http://www.w3.org/2000/svg', 'svg');
338
- xml.innerHTML = svg;
339
- const content = createDocumentFragment();
340
- content.append(...xml.childNodes);
341
- return content;
342
- };
343
- const createContent = (text, svg) => (svg ? createSVG(text) : createHTML(text));
344
- // from a generic path, retrieves the exact targeted node
345
- const reducePath = ({ childNodes }, i) => childNodes[i];
346
- // this helper avoid code bloat around handleAnything() callback
347
- const diff = (comment, oldNodes, newNodes) => udomdiff(comment.parentNode,
348
- // TODO: there is a possible edge case where a node has been
349
- // removed manually, or it was a keyed one, attached
350
- // to a shared reference between renders.
351
- // In this case udomdiff might fail at removing such node
352
- // as its parent won't be the expected one.
353
- // The best way to avoid this issue is to filter oldNodes
354
- // in search of those not live, or not in the current parent
355
- // anymore, but this would require both a change to uwire,
356
- // exposing a parentNode from the firstChild, as example,
357
- // but also a filter per each diff that should exclude nodes
358
- // that are not in there, penalizing performance quite a lot.
359
- // As this has been also a potential issue with domdiff,
360
- // and both lighterhtml and hyperHTML might fail with this
361
- // very specific edge case, I might as well document this possible
362
- // "diffing shenanigan" and call it a day.
363
- oldNodes, newNodes, diffable, comment);
364
- // if an interpolation represents a comment, the whole
365
- // diffing will be related to such comment.
366
- // This helper is in charge of understanding how the new
367
- // content for such interpolation/hole should be updated
368
- const handleAnything = (comment) => {
369
- let oldValue, text, nodes = [];
370
- const anyContent = (newValue) => {
371
- switch (typeof newValue) {
372
- // primitives are handled as text content
373
- case 'string':
374
- case 'number':
375
- case 'boolean':
376
- if (oldValue !== newValue) {
377
- oldValue = newValue;
378
- if (!text)
379
- text = createTextNode('');
380
- text.data = newValue;
381
- nodes = diff(comment, nodes, [text]);
382
- }
383
- break;
384
- // null, and undefined are used to cleanup previous content
385
- case 'object':
386
- case 'undefined':
387
- if (newValue == null) {
388
- if (oldValue != newValue) {
389
- oldValue = newValue;
390
- nodes = diff(comment, nodes, []);
391
- }
392
- break;
393
- }
394
- // arrays and nodes have a special treatment
395
- if (isArray(newValue)) {
396
- oldValue = newValue;
397
- // arrays can be used to cleanup, if empty
398
- if (newValue.length === 0)
399
- nodes = diff(comment, nodes, []);
400
- // or diffed, if these contains nodes or "wires"
401
- else if (typeof newValue[0] === 'object')
402
- nodes = diff(comment, nodes, newValue);
403
- // in all other cases the content is stringified as is
404
- else
405
- anyContent(String(newValue));
406
- break;
407
- }
408
- // if the new value is a DOM node, or a wire, and it's
409
- // different from the one already live, then it's diffed.
410
- // if the node is a fragment, it's appended once via its childNodes
411
- // There is no `else` here, meaning if the content
412
- // is not expected one, nothing happens, as easy as that.
413
- if (oldValue !== newValue && 'ELEMENT_NODE' in newValue) {
414
- oldValue = newValue;
415
- nodes = diff(comment, nodes, newValue.nodeType === 11 ? [...newValue.childNodes] : [newValue]);
416
- }
417
- break;
418
- case 'function':
419
- anyContent(newValue(comment));
420
- break;
421
- }
422
- };
423
- return anyContent;
424
- };
425
- // attributes can be:
426
- // * ref=${...} for hooks and other purposes
427
- // * aria=${...} for aria attributes
428
- // * ?boolean=${...} for boolean attributes
429
- // * .dataset=${...} for dataset related attributes
430
- // * .setter=${...} for Custom Elements setters or nodes with setters
431
- // such as buttons, details, options, select, etc
432
- // * @event=${...} to explicitly handle event listeners
433
- // * onevent=${...} to automatically handle event listeners
434
- // * generic=${...} to handle an attribute just like an attribute
435
- const handleAttribute = (node, name /*, svg*/) => {
436
- switch (name[0]) {
437
- case '?':
438
- return boolean(node, name.slice(1), false);
439
- case '.':
440
- return setter(node, name.slice(1));
441
- case '@':
442
- return event(node, 'on' + name.slice(1));
443
- case 'o':
444
- if (name[1] === 'n')
445
- return event(node, name);
446
- }
447
- switch (name) {
448
- case 'ref':
449
- return ref(node);
450
- case 'aria':
451
- return aria(node);
452
- }
453
- return attribute(node, name /*, svg*/);
454
- };
455
- // each mapped update carries the update type and its path
456
- // the type is either node, attribute, or text, while
457
- // the path is how to retrieve the related node to update.
458
- // In the attribute case, the attribute name is also carried along.
459
- function handlers(options) {
460
- const { type, path } = options;
461
- const node = path.reduceRight(reducePath, this);
462
- return type === 'node'
463
- ? handleAnything(node)
464
- : type === 'attr'
465
- ? handleAttribute(node, options.name /*, options.svg*/)
466
- : text(node);
467
- }
468
- // from a fragment container, create an array of indexes
469
- // related to its child nodes, so that it's possible
470
- // to retrieve later on exact node via reducePath
471
- const createPath = (node) => {
472
- const path = [];
473
- let { parentNode } = node;
474
- while (parentNode) {
475
- path.push(indexOf.call(parentNode.childNodes, node));
476
- node = parentNode;
477
- ({ parentNode } = node);
478
- }
479
- return path;
480
- };
481
- // the prefix is used to identify either comments, attributes, or nodes
482
- // that contain the related unique id. In the attribute cases
483
- // isµX="attribute-name" will be used to map current X update to that
484
- // attribute name, while comments will be like <!--isµX-->, to map
485
- // the update to that specific comment node, hence its parent.
486
- // style and textarea will have <!--isµX--> text content, and are handled
487
- // directly through text-only updates.
488
- const prefix = 'isµ';
489
- // Template Literals are unique per scope and static, meaning a template
490
- // should be parsed once, and once only, as it will always represent the same
491
- // content, within the exact same amount of updates each time.
492
- // This cache relates each template to its unique content and updates.
493
- const cache$1 = new WeakMapSet();
494
- // a RegExp that helps checking nodes that cannot contain comments
495
- const textOnly = /^(?:textarea|script|style|title|plaintext|xmp)$/;
496
- const createCache = () => ({
497
- stack: [], // each template gets a stack for each interpolation "hole"
498
- entry: null, // each entry contains details, such as:
499
- // * the template that is representing
500
- // * the type of node it represents (html or svg)
501
- // * the content fragment with all nodes
502
- // * the list of updates per each node (template holes)
503
- // * the "wired" node or fragment that will get updates
504
- // if the template or type are different from the previous one
505
- // the entry gets re-created each time
506
- wire: null // each rendered node represent some wired content and
507
- // this reference to the latest one. If different, the node
508
- // will be cleaned up and the new "wire" will be appended
509
- });
510
- // the entry stored in the rendered node cache, and per each "hole"
511
- const createEntry = (type, template) => {
512
- const { content, updates } = mapUpdates(type, template);
513
- return { type, template, content, updates, wire: null };
514
- };
515
- // a template is instrumented to be able to retrieve where updates are needed.
516
- // Each unique template becomes a fragment, cloned once per each other
517
- // operation based on the same template, i.e. data => html`<p>${data}</p>`
518
- const mapTemplate = (type, template) => {
519
- const svg = type === 'svg';
520
- const text = instrument(template, prefix, svg);
521
- const content = createContent(text, svg);
522
- // once instrumented and reproduced as fragment, it's crawled
523
- // to find out where each update is in the fragment tree
524
- const tw = createTreeWalker(content, 1 | 128);
525
- const nodes = [];
526
- const length = template.length - 1;
527
- let i = 0;
528
- // updates are searched via unique names, linearly increased across the tree
529
- // <div isµ0="attr" isµ1="other"><!--isµ2--><style><!--isµ3--</style></div>
530
- let search = `${prefix}${i}`;
531
- while (i < length) {
532
- const node = tw.nextNode();
533
- // if not all updates are bound but there's nothing else to crawl
534
- // it means that there is something wrong with the template.
535
- if (!node)
536
- throw `bad template: ${text}`;
537
- // if the current node is a comment, and it contains isµX
538
- // it means the update should take care of any content
539
- if (node.nodeType === 8) {
540
- // The only comments to be considered are those
541
- // which content is exactly the same as the searched one.
542
- if (node.data === search) {
543
- nodes.push({ type: 'node', path: createPath(node) });
544
- search = `${prefix}${++i}`;
545
- }
546
- }
547
- else {
548
- // if the node is not a comment, loop through all its attributes
549
- // named isµX and relate attribute updates to this node and the
550
- // attribute name, retrieved through node.getAttribute("isµX")
551
- // the isµX attribute will be removed as irrelevant for the layout
552
- // let svg = -1;
553
- while (node.hasAttribute(search)) {
554
- nodes.push({
555
- type: 'attr',
556
- path: createPath(node),
557
- name: node.getAttribute(search)
558
- });
559
- node.removeAttribute(search);
560
- search = `${prefix}${++i}`;
561
- }
562
- // if the node was a style, textarea, or others, check its content
563
- // and if it is <!--isµX--> then update tex-only this node
564
- if (textOnly.test(node.localName) && node.textContent.trim() === `<!--${search}-->`) {
565
- node.textContent = '';
566
- nodes.push({ type: 'text', path: createPath(node) });
567
- search = `${prefix}${++i}`;
568
- }
569
- }
570
- }
571
- // once all nodes to update, or their attributes, are known, the content
572
- // will be cloned in the future to represent the template, and all updates
573
- // related to such content retrieved right away without needing to re-crawl
574
- // the exact same template, and its content, more than once.
575
- return { content, nodes };
576
- };
577
- // if a template is unknown, perform the previous mapping, otherwise grab
578
- // its details such as the fragment with all nodes, and updates info.
579
- const mapUpdates = (type, template) => {
580
- const { content, nodes } = cache$1.get(template) || cache$1.set(template, mapTemplate(type, template));
581
- // clone deeply the fragment
582
- const fragment = importNode(content, true);
583
- // and relate an update handler per each node that needs one
584
- const updates = nodes.map(handlers, fragment);
585
- // return the fragment and all updates to use within its nodes
586
- return { content: fragment, updates };
587
- };
588
- // as html and svg can be nested calls, but no parent node is known
589
- // until rendered somewhere, the unroll operation is needed to
590
- // discover what to do with each interpolation, which will result
591
- // into an update operation.
592
- const unroll = (info, { type, template, values }) => {
593
- // interpolations can contain holes and arrays, so these need
594
- // to be recursively discovered
595
- const length = unrollValues(info, values);
596
- let { entry } = info;
597
- // if the cache entry is either null or different from the template
598
- // and the type this unroll should resolve, create a new entry
599
- // assigning a new content fragment and the list of updates.
600
- if (!entry || entry.template !== template || entry.type !== type)
601
- info.entry = entry = createEntry(type, template);
602
- const { content, updates, wire } = entry;
603
- // even if the fragment and its nodes is not live yet,
604
- // it is already possible to update via interpolations values.
605
- for (let i = 0; i < length; i++)
606
- updates[i](values[i]);
607
- // if the entry was new, or representing a different template or type,
608
- // create a new persistent entity to use during diffing.
609
- // This is simply a DOM node, when the template has a single container,
610
- // as in `<p></p>`, or a "wire" in `<p></p><p></p>` and similar cases.
611
- return wire || (entry.wire = persistent(content));
612
- };
613
- // the stack retains, per each interpolation value, the cache
614
- // related to each interpolation value, or null, if the render
615
- // was conditional and the value is not special (Array or Hole)
616
- const unrollValues = ({ stack }, values) => {
617
- const { length } = values;
618
- for (let i = 0; i < length; i++) {
619
- const hole = values[i];
620
- // each Hole gets unrolled and re-assigned as value
621
- // so that domdiff will deal with a node/wire, not with a hole
622
- if (hole instanceof Hole)
623
- values[i] = unroll(stack[i] || (stack[i] = createCache()), hole);
624
- // arrays are recursively resolved so that each entry will contain
625
- // also a DOM node or a wire, hence it can be diffed if/when needed
626
- else if (isArray(hole))
627
- unrollValues(stack[i] || (stack[i] = createCache()), hole);
628
- // if the value is nothing special, the stack doesn't need to retain data
629
- // this is useful also to cleanup previously retained data, if the value
630
- // was a Hole, or an Array, but not anymore, i.e.:
631
- // const update = content => html`<div>${content}</div>`;
632
- // update(listOfItems); update(null); update(html`hole`)
633
- else
634
- stack[i] = null;
635
- }
636
- if (length < stack.length)
637
- stack.splice(length);
638
- return length;
639
- };
640
- /**
641
- * Holds all details wrappers needed to render the content further on.
642
- * @constructor
643
- * @param {string} type The hole type, either `html` or `svg`.
644
- * @param {string[]} template The template literals used to the define the content.
645
- * @param {Array} values Zero, one, or more interpolated values to render.
646
- */
647
- class Hole {
648
- constructor(type, template, values) {
649
- this.type = type;
650
- this.template = template;
651
- this.values = values;
652
- }
653
- }
654
- // both `html` and `svg` template literal tags are polluted
655
- // with a `for(ref[, id])` and a `node` tag too
656
- const tag = (type) => {
657
- // both `html` and `svg` tags have their own cache
658
- const keyed = new WeakMapSet();
659
- // keyed operations always re-use the same cache and unroll
660
- // the template and its interpolations right away
661
- const fixed = (cache) => (template, ...values) => unroll(cache, { type, template, values });
662
- return Object.assign(
663
- // non keyed operations are recognized as instance of Hole
664
- // during the "unroll", recursively resolved and updated
665
- (template, ...values) => new Hole(type, template, values), {
666
- // keyed operations need a reference object, usually the parent node
667
- // which is showing keyed results, and optionally a unique id per each
668
- // related node, handy with JSON results and mutable list of objects
669
- // that usually carry a unique identifier
670
- for(ref, id) {
671
- const memo = keyed.get(ref) || keyed.set(ref, new MapSet());
672
- return memo.get(id) || memo.set(id, fixed(createCache()));
673
- },
674
- // it is possible to create one-off content out of the box via node tag
675
- // this might return the single created node, or a fragment with all
676
- // nodes present at the root level and, of course, their child nodes
677
- node: (template, ...values) => unroll(createCache(), new Hole(type, template, values)).valueOf()
678
- });
679
- };
680
- // each rendered node gets its own cache
681
- const cache = new WeakMapSet();
682
- // rendering means understanding what `html` or `svg` tags returned
683
- // and it relates a specific node to its own unique cache.
684
- // Each time the content to render changes, the node is cleaned up
685
- // and the new new content is appended, and if such content is a Hole
686
- // then it's "unrolled" to resolve all its inner nodes.
687
- const render = (where, what) => {
688
- const hole = typeof what === 'function' ? what() : what;
689
- const info = cache.get(where) || cache.set(where, createCache());
690
- const wire = hole instanceof Hole ? unroll(info, hole) : hole;
691
- if (wire !== info.wire) {
692
- info.wire = wire;
693
- // valueOf() simply returns the node itself, but in case it was a "wire"
694
- // it will eventually re-append all nodes to its fragment so that such
695
- // fragment can be re-appended many times in a meaningful way
696
- // (wires are basically persistent fragments facades with special behavior)
697
- where.replaceChildren(wire.valueOf());
698
- }
699
- return where;
700
- };
701
- const html = tag('html');
702
- const svg = tag('svg');
703
- export { Hole, html, render, svg };