@oscarpalmer/abydon 0.5.0 → 0.7.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/dist/index.js +360 -49
- package/package.json +1 -1
- package/src/fragment.ts +9 -21
- package/src/helpers/dom.ts +30 -0
- package/src/helpers/index.ts +22 -0
- package/src/html.ts +3 -10
- package/src/index.ts +1 -1
- package/src/models.ts +16 -0
- package/src/node/attribute/index.ts +62 -0
- package/src/node/attribute/value.ts +159 -0
- package/src/node/event.ts +29 -0
- package/src/node/index.ts +13 -22
- package/src/node/value.ts +48 -0
- package/types/fragment.d.ts +1 -11
- package/types/helpers/dom.d.ts +3 -0
- package/types/helpers/index.d.ts +4 -0
- package/types/html.d.ts +1 -2
- package/types/index.d.ts +1 -1
- package/types/models.d.ts +13 -0
- package/types/node/attribute/index.d.ts +3 -0
- package/types/node/attribute/value.d.ts +2 -0
- package/types/node/event.d.ts +2 -0
- package/types/node/index.d.ts +1 -1
- package/types/node/value.d.ts +2 -0
package/dist/index.js
CHANGED
|
@@ -15,7 +15,27 @@ var isNullableOrWhitespace = function(value) {
|
|
|
15
15
|
return value == null || /^\s*$/.test(getString(value));
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
// src/helpers/index.ts
|
|
19
|
+
function isFragment(value) {
|
|
20
|
+
return typeof value === "object" && value != null && "$fragment" in value && value.$fragment === true;
|
|
21
|
+
}
|
|
22
|
+
function isFragmentElement(value) {
|
|
23
|
+
return value instanceof HTMLElement || value instanceof SVGElement;
|
|
24
|
+
}
|
|
25
|
+
function isFragmentNode(value) {
|
|
26
|
+
return value instanceof Comment || value instanceof Element || value instanceof Text;
|
|
27
|
+
}
|
|
28
|
+
|
|
18
29
|
// src/helpers/dom.ts
|
|
30
|
+
function createNodes(value) {
|
|
31
|
+
if (isFragmentNode(value)) {
|
|
32
|
+
return [value];
|
|
33
|
+
}
|
|
34
|
+
if (isFragment(value)) {
|
|
35
|
+
return value.get();
|
|
36
|
+
}
|
|
37
|
+
return [new Text(getString(value))];
|
|
38
|
+
}
|
|
19
39
|
function createTemplate(html) {
|
|
20
40
|
const template = document.createElement("template");
|
|
21
41
|
template.innerHTML = html;
|
|
@@ -33,6 +53,17 @@ function createTemplate(html) {
|
|
|
33
53
|
function getNodes(node) {
|
|
34
54
|
return /^documentfragment$/i.test(node.constructor.name) ? [...node.childNodes] : [node];
|
|
35
55
|
}
|
|
56
|
+
function replaceNodes(from, to) {
|
|
57
|
+
const { length } = from;
|
|
58
|
+
for (let index = 0;index < length; index += 1) {
|
|
59
|
+
const node = from[index];
|
|
60
|
+
if (index === 0) {
|
|
61
|
+
node.replaceWith(...to);
|
|
62
|
+
} else {
|
|
63
|
+
node.remove();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
36
67
|
|
|
37
68
|
// node_modules/@oscarpalmer/sentinel/node_modules/@oscarpalmer/atoms/dist/js/queue.mjs
|
|
38
69
|
if (globalThis._atomic_queued == null) {
|
|
@@ -54,6 +85,45 @@ if (globalThis._sentinels == null) {
|
|
|
54
85
|
});
|
|
55
86
|
}
|
|
56
87
|
|
|
88
|
+
// node_modules/@oscarpalmer/sentinel/dist/effect.mjs
|
|
89
|
+
var effect = function(callback) {
|
|
90
|
+
const state = {
|
|
91
|
+
callback,
|
|
92
|
+
active: false,
|
|
93
|
+
reactives: new Set
|
|
94
|
+
};
|
|
95
|
+
const instance = Object.create({
|
|
96
|
+
start() {
|
|
97
|
+
if (!state.active) {
|
|
98
|
+
state.active = true;
|
|
99
|
+
const index = globalThis._sentinels.push(state) - 1;
|
|
100
|
+
state.callback();
|
|
101
|
+
globalThis._sentinels.splice(index, 1);
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
stop() {
|
|
105
|
+
if (state.active) {
|
|
106
|
+
state.active = false;
|
|
107
|
+
for (const reactive of state.reactives) {
|
|
108
|
+
reactive.callbacks.any.delete(state);
|
|
109
|
+
for (const [key, keyed] of reactive.callbacks.values) {
|
|
110
|
+
keyed.delete(state);
|
|
111
|
+
if (keyed.size === 0) {
|
|
112
|
+
reactive.callbacks.keys.delete(key);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
state.reactives.clear();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
Object.defineProperty(instance, "$sentinel", {
|
|
121
|
+
value: "effect"
|
|
122
|
+
});
|
|
123
|
+
instance.start();
|
|
124
|
+
return instance;
|
|
125
|
+
};
|
|
126
|
+
|
|
57
127
|
// node_modules/@oscarpalmer/sentinel/dist/helpers/is.mjs
|
|
58
128
|
var isReactive = function(value) {
|
|
59
129
|
return isSentinel(value, /^array|computed|signal|store$/i);
|
|
@@ -78,77 +148,326 @@ var arrayOperations = new Set([
|
|
|
78
148
|
// node_modules/@oscarpalmer/sentinel/dist/reactive/index.mjs
|
|
79
149
|
var primitives = new Set(["boolean", "number", "string"]);
|
|
80
150
|
|
|
151
|
+
// src/node/value.ts
|
|
152
|
+
function setReactiveNode(comment, reactive3) {
|
|
153
|
+
const text = new Text;
|
|
154
|
+
let nodes;
|
|
155
|
+
effect(() => {
|
|
156
|
+
const value10 = reactive3.get();
|
|
157
|
+
if (isFragment(value10) || isFragmentNode(value10)) {
|
|
158
|
+
const next = createNodes(value10);
|
|
159
|
+
if (nodes == null) {
|
|
160
|
+
if (comment.parentNode != null) {
|
|
161
|
+
replaceNodes([comment], next);
|
|
162
|
+
} else if (text.parentNode != null) {
|
|
163
|
+
replaceNodes([text], next);
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
replaceNodes(nodes, next);
|
|
167
|
+
}
|
|
168
|
+
nodes = next;
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const isNullable = isNullableOrWhitespace(value10);
|
|
172
|
+
text.textContent = getString(value10);
|
|
173
|
+
if (nodes != null) {
|
|
174
|
+
replaceNodes(nodes, [isNullable ? comment : text]);
|
|
175
|
+
} else if (isNullable && comment.parentNode == null) {
|
|
176
|
+
text.replaceWith(comment);
|
|
177
|
+
} else if (!isNullable && text.parentNode == null) {
|
|
178
|
+
comment.replaceWith(text);
|
|
179
|
+
}
|
|
180
|
+
nodes = undefined;
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// src/node/event.ts
|
|
185
|
+
var getOptions = function(options) {
|
|
186
|
+
const parts = options.split(":");
|
|
187
|
+
return {
|
|
188
|
+
capture: parts.includes("c") || parts.includes("capture"),
|
|
189
|
+
once: parts.includes("o") || parts.includes("once"),
|
|
190
|
+
passive: !parts.includes("a") && !parts.includes("active")
|
|
191
|
+
};
|
|
192
|
+
};
|
|
193
|
+
function mapEvent(element, name, value10) {
|
|
194
|
+
element.removeAttribute(name);
|
|
195
|
+
const [, type, options] = /^@(\w+)(?::([a-z:]+))?$/.exec(name) ?? [];
|
|
196
|
+
if (typeof value10 === "function" && type != null) {
|
|
197
|
+
element.addEventListener(type, value10, getOptions(options ?? ""));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// node_modules/@oscarpalmer/atoms/dist/js/element/closest.mjs
|
|
202
|
+
var closest = function(origin, selector, context) {
|
|
203
|
+
const elements = [...(context ?? document).querySelectorAll(selector)];
|
|
204
|
+
const { length } = elements;
|
|
205
|
+
if (length === 0) {
|
|
206
|
+
return [];
|
|
207
|
+
}
|
|
208
|
+
const distances = [];
|
|
209
|
+
let minimum = null;
|
|
210
|
+
for (let index = 0;index < length; index += 1) {
|
|
211
|
+
const element = elements[index];
|
|
212
|
+
const distance = calculateDistance(origin, element);
|
|
213
|
+
if (distance < 0) {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (minimum == null || distance < minimum) {
|
|
217
|
+
minimum = distance;
|
|
218
|
+
}
|
|
219
|
+
distances.push({
|
|
220
|
+
distance,
|
|
221
|
+
element
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
return minimum == null ? [] : distances.filter((found) => found.distance === minimum).map((found) => found.element);
|
|
225
|
+
};
|
|
226
|
+
var calculateDistance = function(origin, target) {
|
|
227
|
+
const comparison = origin.compareDocumentPosition(target);
|
|
228
|
+
const children = [...origin.parentElement?.children ?? []];
|
|
229
|
+
switch (true) {
|
|
230
|
+
case children.includes(target):
|
|
231
|
+
return Math.abs(children.indexOf(origin) - children.indexOf(target));
|
|
232
|
+
case !!(comparison & 2 || comparison & 8):
|
|
233
|
+
return traverse(origin, target);
|
|
234
|
+
case !!(comparison & 4 || comparison & 16):
|
|
235
|
+
return traverse(target, origin);
|
|
236
|
+
default:
|
|
237
|
+
return -1;
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
var traverse = function(from, to) {
|
|
241
|
+
const children = [...to.children];
|
|
242
|
+
if (children.includes(from)) {
|
|
243
|
+
return children.indexOf(from) + 1;
|
|
244
|
+
}
|
|
245
|
+
let current = from;
|
|
246
|
+
let distance = 0;
|
|
247
|
+
let parent = from.parentElement;
|
|
248
|
+
while (parent != null) {
|
|
249
|
+
if (parent === to) {
|
|
250
|
+
return distance + 1;
|
|
251
|
+
}
|
|
252
|
+
const children2 = [...parent.children ?? []];
|
|
253
|
+
if (children2.includes(to)) {
|
|
254
|
+
return distance + Math.abs(children2.indexOf(current) - children2.indexOf(to));
|
|
255
|
+
}
|
|
256
|
+
const index = children2.findIndex((child) => child.contains(to));
|
|
257
|
+
if (index > -1) {
|
|
258
|
+
return distance + Math.abs(index - children2.indexOf(current)) + traverse(to, children2[index]);
|
|
259
|
+
}
|
|
260
|
+
current = parent;
|
|
261
|
+
distance += 1;
|
|
262
|
+
parent = parent.parentElement;
|
|
263
|
+
}
|
|
264
|
+
return -1e6;
|
|
265
|
+
};
|
|
266
|
+
// src/node/attribute/value.ts
|
|
267
|
+
function setAttribute(element2, name, value10) {
|
|
268
|
+
element2.removeAttribute(name);
|
|
269
|
+
switch (true) {
|
|
270
|
+
case classPattern.test(name):
|
|
271
|
+
setClasses(element2, name, value10);
|
|
272
|
+
return;
|
|
273
|
+
case stylePattern.test(name):
|
|
274
|
+
setStyle(element2, name, value10);
|
|
275
|
+
return;
|
|
276
|
+
default:
|
|
277
|
+
setValue2(element2, name, value10);
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
var setClasses = function(element2, name, value10) {
|
|
282
|
+
function update(value11) {
|
|
283
|
+
if (/^(|true)$/.test(getString(value11))) {
|
|
284
|
+
element2.classList.add(...classes);
|
|
285
|
+
} else {
|
|
286
|
+
element2.classList.remove(...classes);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
const classes = name.slice(6).split(".");
|
|
290
|
+
if (isReactive(value10)) {
|
|
291
|
+
effect(() => {
|
|
292
|
+
update(value10.get());
|
|
293
|
+
});
|
|
294
|
+
} else {
|
|
295
|
+
update(value10);
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
var setStyle = function(element2, name, value10) {
|
|
299
|
+
function update(value11) {
|
|
300
|
+
if (value11 == null || value11 === false || value11 === true && unit == null) {
|
|
301
|
+
element2.style.removeProperty(property);
|
|
302
|
+
} else {
|
|
303
|
+
element2.style.setProperty(property, value11 === true ? unit : getString(value11));
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
const [, property, unit] = /^\w+\.([a-z-]+)(?:\.(\w+))?$/i.exec(name) ?? [];
|
|
307
|
+
if (property == null) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (isReactive(value10)) {
|
|
311
|
+
effect(() => {
|
|
312
|
+
update(value10.get());
|
|
313
|
+
});
|
|
314
|
+
} else {
|
|
315
|
+
update(value10);
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
var setValue2 = function(element2, name, value10) {
|
|
319
|
+
const callback = booleanAttributes.has(name) && name in element2 ? name === "selected" ? updateSelected(element2) : updateProperty : updateAttribute;
|
|
320
|
+
if (isReactive(value10)) {
|
|
321
|
+
effect(() => {
|
|
322
|
+
callback(element2, name, value10.get());
|
|
323
|
+
});
|
|
324
|
+
} else {
|
|
325
|
+
callback(element2, name, value10);
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
var triggerSelectChange = function(select) {
|
|
329
|
+
if (select != null) {
|
|
330
|
+
select.dispatchEvent(new Event("change", { bubbles: true }));
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
var updateAttribute = function(element2, name, value10) {
|
|
334
|
+
if (value10 == null) {
|
|
335
|
+
element2.removeAttribute(name);
|
|
336
|
+
} else {
|
|
337
|
+
element2.setAttribute(name, getString(value10));
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
var updateProperty = function(element2, name, value10) {
|
|
341
|
+
element2[name] = /^(|true)$/.test(getString(value10));
|
|
342
|
+
};
|
|
343
|
+
var updateSelected = function(element2) {
|
|
344
|
+
const select = closest(element2, "select")[0];
|
|
345
|
+
const options = [...select?.options ?? []];
|
|
346
|
+
return (element3, name, value10) => {
|
|
347
|
+
if (select != null && options.includes(element3)) {
|
|
348
|
+
triggerSelectChange(select);
|
|
349
|
+
}
|
|
350
|
+
updateProperty(element3, name, value10);
|
|
351
|
+
};
|
|
352
|
+
};
|
|
353
|
+
var booleanAttributes = new Set([
|
|
354
|
+
"checked",
|
|
355
|
+
"disabled",
|
|
356
|
+
"hidden",
|
|
357
|
+
"inert",
|
|
358
|
+
"multiple",
|
|
359
|
+
"open",
|
|
360
|
+
"readOnly",
|
|
361
|
+
"required",
|
|
362
|
+
"selected"
|
|
363
|
+
]);
|
|
364
|
+
var classPattern = /^class\./;
|
|
365
|
+
var stylePattern = /^style\./;
|
|
366
|
+
|
|
367
|
+
// src/node/attribute/index.ts
|
|
368
|
+
var getValue2 = function(data2, original) {
|
|
369
|
+
const matches = commentExpression.exec(original ?? "");
|
|
370
|
+
return matches == null ? original : data2.values[+matches[1]];
|
|
371
|
+
};
|
|
372
|
+
function isBadAttribute(name, value11) {
|
|
373
|
+
return /^on/i.test(name) || /^(href|src|xlink:href)$/i.test(name) && /(data:text\/html|javascript:)/i.test(value11);
|
|
374
|
+
}
|
|
375
|
+
function mapAttributes(data2, element2) {
|
|
376
|
+
const attributes = [...element2.attributes];
|
|
377
|
+
const { length } = attributes;
|
|
378
|
+
for (let index = 0;index < length; index += 1) {
|
|
379
|
+
const { name, value: value11 } = attributes[index];
|
|
380
|
+
if (isBadAttribute(name, value11)) {
|
|
381
|
+
element2.removeAttribute(name);
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
const actual = getValue2(data2, value11);
|
|
385
|
+
if (name.startsWith("@")) {
|
|
386
|
+
mapEvent(element2, name, actual);
|
|
387
|
+
} else if (name.includes(".") || isReactive(actual)) {
|
|
388
|
+
mapValue(element2, name, actual);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
var mapValue = function(element2, name, value11) {
|
|
393
|
+
switch (true) {
|
|
394
|
+
case typeof value11 === "function":
|
|
395
|
+
mapValue(element2, name, value11());
|
|
396
|
+
return;
|
|
397
|
+
default:
|
|
398
|
+
setAttribute(element2, name, value11);
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
var commentExpression = /^<!--abydon\.(\d+)-->$/;
|
|
403
|
+
|
|
81
404
|
// src/node/index.ts
|
|
82
|
-
var mapNode = function(
|
|
83
|
-
const matches =
|
|
84
|
-
const
|
|
85
|
-
if (
|
|
86
|
-
|
|
405
|
+
var mapNode = function(data2, comment) {
|
|
406
|
+
const matches = commentExpression2.exec(comment.textContent ?? "");
|
|
407
|
+
const value12 = matches == null ? null : data2.values[+matches[1]];
|
|
408
|
+
if (value12 != null) {
|
|
409
|
+
mapValue2(comment, value12);
|
|
87
410
|
}
|
|
88
411
|
};
|
|
89
|
-
function mapNodes(
|
|
412
|
+
function mapNodes(data2, nodes) {
|
|
90
413
|
const { length } = nodes;
|
|
91
414
|
for (let index = 0;index < length; index += 1) {
|
|
92
415
|
const node = nodes[index];
|
|
93
416
|
if (node instanceof Comment) {
|
|
94
|
-
mapNode(
|
|
417
|
+
mapNode(data2, node);
|
|
95
418
|
continue;
|
|
96
419
|
}
|
|
97
|
-
if (node
|
|
420
|
+
if (isFragmentElement(node)) {
|
|
421
|
+
mapAttributes(data2, node);
|
|
98
422
|
}
|
|
99
423
|
if (node.hasChildNodes()) {
|
|
100
|
-
mapNodes(
|
|
424
|
+
mapNodes(data2, [...node.childNodes]);
|
|
101
425
|
}
|
|
102
426
|
}
|
|
103
427
|
}
|
|
104
|
-
var
|
|
105
|
-
};
|
|
106
|
-
var mapValue = function(comment, value10) {
|
|
428
|
+
var mapValue2 = function(comment, value12) {
|
|
107
429
|
switch (true) {
|
|
108
|
-
case
|
|
109
|
-
comment
|
|
430
|
+
case typeof value12 === "function":
|
|
431
|
+
mapValue2(comment, value12());
|
|
110
432
|
return;
|
|
111
|
-
case
|
|
112
|
-
comment
|
|
113
|
-
break;
|
|
114
|
-
case isReactive(value10):
|
|
115
|
-
mapReactive(comment, value10);
|
|
433
|
+
case isReactive(value12):
|
|
434
|
+
setReactiveNode(comment, value12);
|
|
116
435
|
break;
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
return;
|
|
120
|
-
case typeof value10 === "object":
|
|
121
|
-
comment.replaceWith(new Text(getString(value10)));
|
|
436
|
+
default:
|
|
437
|
+
comment.replaceWith(...createNodes(value12));
|
|
122
438
|
break;
|
|
123
439
|
}
|
|
124
440
|
};
|
|
125
|
-
var
|
|
441
|
+
var commentExpression2 = /^abydon\.(\d+)$/;
|
|
126
442
|
|
|
127
443
|
// src/fragment.ts
|
|
128
444
|
function createFragment(strings, expressions) {
|
|
129
|
-
const
|
|
445
|
+
const data2 = {
|
|
130
446
|
expressions,
|
|
131
447
|
strings,
|
|
132
448
|
nodes: [],
|
|
133
449
|
values: []
|
|
134
450
|
};
|
|
135
451
|
const instance = Object.create({
|
|
452
|
+
appendTo(element2) {
|
|
453
|
+
element2.append(...this.get());
|
|
454
|
+
},
|
|
136
455
|
get() {
|
|
137
|
-
if (
|
|
138
|
-
const parsed =
|
|
456
|
+
if (data2.nodes.length === 0) {
|
|
457
|
+
const parsed = parse2(data2);
|
|
139
458
|
const templated = createTemplate(parsed);
|
|
140
|
-
|
|
141
|
-
mapNodes(
|
|
459
|
+
data2.nodes.splice(0, data2.nodes.length, ...getNodes(templated));
|
|
460
|
+
mapNodes(data2, data2.nodes);
|
|
142
461
|
}
|
|
143
|
-
return
|
|
462
|
+
return [...data2.nodes];
|
|
144
463
|
},
|
|
145
464
|
remove() {
|
|
146
|
-
const { length } =
|
|
465
|
+
const { length } = data2.nodes;
|
|
147
466
|
for (let index = 0;index < length; index += 1) {
|
|
148
|
-
const node2 =
|
|
467
|
+
const node2 = data2.nodes[index];
|
|
149
468
|
node2.parentNode?.removeChild(node2);
|
|
150
469
|
}
|
|
151
|
-
|
|
470
|
+
data2.nodes.splice(0, data2.nodes.length);
|
|
152
471
|
}
|
|
153
472
|
});
|
|
154
473
|
Object.defineProperty(instance, "$fragment", {
|
|
@@ -156,17 +475,9 @@ function createFragment(strings, expressions) {
|
|
|
156
475
|
});
|
|
157
476
|
return instance;
|
|
158
477
|
}
|
|
159
|
-
function isFragment(value10) {
|
|
160
|
-
return typeof value10 === "object" && value10 != null && "$fragment" in value10;
|
|
161
|
-
}
|
|
162
478
|
|
|
163
479
|
// src/html.ts
|
|
164
|
-
function
|
|
165
|
-
const fragment3 = document.createDocumentFragment();
|
|
166
|
-
fragment3.append(...nodes);
|
|
167
|
-
return fragment3;
|
|
168
|
-
}
|
|
169
|
-
var handleExpression = function(data, prefix, expression) {
|
|
480
|
+
var handleExpression = function(data2, prefix, expression) {
|
|
170
481
|
if (isNullableOrWhitespace(expression)) {
|
|
171
482
|
return prefix;
|
|
172
483
|
}
|
|
@@ -174,12 +485,12 @@ var handleExpression = function(data, prefix, expression) {
|
|
|
174
485
|
const { length } = expression;
|
|
175
486
|
let expressions = "";
|
|
176
487
|
for (let index = 0;index < length; index += 1) {
|
|
177
|
-
expressions += handleExpression(
|
|
488
|
+
expressions += handleExpression(data2, "", expression[index]);
|
|
178
489
|
}
|
|
179
490
|
return `${prefix}${expressions}`;
|
|
180
491
|
}
|
|
181
|
-
if (typeof expression === "object") {
|
|
182
|
-
const index =
|
|
492
|
+
if (typeof expression === "function" || typeof expression === "object") {
|
|
493
|
+
const index = data2.values.push(expression) - 1;
|
|
183
494
|
return `${prefix}<!--abydon.${index}-->`;
|
|
184
495
|
}
|
|
185
496
|
return `${prefix}${expression}`;
|
|
@@ -187,11 +498,11 @@ var handleExpression = function(data, prefix, expression) {
|
|
|
187
498
|
function html2(strings, ...values) {
|
|
188
499
|
return createFragment(strings, values);
|
|
189
500
|
}
|
|
190
|
-
function
|
|
191
|
-
const { length } =
|
|
501
|
+
function parse2(data2) {
|
|
502
|
+
const { length } = data2.strings;
|
|
192
503
|
let template = "";
|
|
193
504
|
for (let index = 0;index < length; index += 1) {
|
|
194
|
-
template += handleExpression(
|
|
505
|
+
template += handleExpression(data2, data2.strings[index], data2.expressions[index]);
|
|
195
506
|
}
|
|
196
507
|
return template;
|
|
197
508
|
}
|
package/package.json
CHANGED
package/src/fragment.ts
CHANGED
|
@@ -1,19 +1,8 @@
|
|
|
1
1
|
import {createTemplate, getNodes} from './helpers/dom';
|
|
2
|
-
import {
|
|
2
|
+
import {parse} from './html';
|
|
3
|
+
import type {Fragment, FragmentData} from './models';
|
|
3
4
|
import {mapNodes} from './node';
|
|
4
5
|
|
|
5
|
-
export type Fragment = {
|
|
6
|
-
get(): DocumentFragment;
|
|
7
|
-
remove(): void;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export type FragmentData = {
|
|
11
|
-
expressions: unknown[];
|
|
12
|
-
nodes: Node[];
|
|
13
|
-
strings: TemplateStringsArray;
|
|
14
|
-
values: unknown[];
|
|
15
|
-
};
|
|
16
|
-
|
|
17
6
|
export function createFragment(
|
|
18
7
|
strings: TemplateStringsArray,
|
|
19
8
|
expressions: unknown[],
|
|
@@ -26,7 +15,10 @@ export function createFragment(
|
|
|
26
15
|
};
|
|
27
16
|
|
|
28
17
|
const instance = Object.create({
|
|
29
|
-
|
|
18
|
+
appendTo(element: Element) {
|
|
19
|
+
element.append(...this.get());
|
|
20
|
+
},
|
|
21
|
+
get() {
|
|
30
22
|
if (data.nodes.length === 0) {
|
|
31
23
|
const parsed = parse(data);
|
|
32
24
|
const templated = createTemplate(parsed);
|
|
@@ -36,9 +28,9 @@ export function createFragment(
|
|
|
36
28
|
mapNodes(data, data.nodes);
|
|
37
29
|
}
|
|
38
30
|
|
|
39
|
-
return
|
|
31
|
+
return [...data.nodes];
|
|
40
32
|
},
|
|
41
|
-
remove()
|
|
33
|
+
remove() {
|
|
42
34
|
const {length} = data.nodes;
|
|
43
35
|
|
|
44
36
|
for (let index = 0; index < length; index += 1) {
|
|
@@ -49,7 +41,7 @@ export function createFragment(
|
|
|
49
41
|
|
|
50
42
|
data.nodes.splice(0, data.nodes.length);
|
|
51
43
|
},
|
|
52
|
-
});
|
|
44
|
+
} as Fragment);
|
|
53
45
|
|
|
54
46
|
Object.defineProperty(instance, '$fragment', {
|
|
55
47
|
value: true,
|
|
@@ -57,7 +49,3 @@ export function createFragment(
|
|
|
57
49
|
|
|
58
50
|
return instance;
|
|
59
51
|
}
|
|
60
|
-
|
|
61
|
-
export function isFragment(value: unknown): value is Fragment {
|
|
62
|
-
return typeof value === 'object' && value != null && '$fragment' in value;
|
|
63
|
-
}
|
package/src/helpers/dom.ts
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
import {getString} from '@oscarpalmer/atoms/string';
|
|
2
|
+
import type {FragmentNode} from '../models';
|
|
3
|
+
import {isFragment, isFragmentNode} from './index';
|
|
4
|
+
|
|
5
|
+
export function createNodes(value: unknown): FragmentNode[] {
|
|
6
|
+
if (isFragmentNode(value)) {
|
|
7
|
+
return [value];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (isFragment(value)) {
|
|
11
|
+
return value.get();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return [new Text(getString(value))];
|
|
15
|
+
}
|
|
16
|
+
|
|
1
17
|
export function createTemplate(html: string): Node {
|
|
2
18
|
const template = document.createElement('template');
|
|
3
19
|
|
|
@@ -25,3 +41,17 @@ export function getNodes(node: Node): Node[] {
|
|
|
25
41
|
? [...node.childNodes]
|
|
26
42
|
: [node];
|
|
27
43
|
}
|
|
44
|
+
|
|
45
|
+
export function replaceNodes(from: FragmentNode[], to: FragmentNode[]): void {
|
|
46
|
+
const {length} = from;
|
|
47
|
+
|
|
48
|
+
for (let index = 0; index < length; index += 1) {
|
|
49
|
+
const node = from[index];
|
|
50
|
+
|
|
51
|
+
if (index === 0) {
|
|
52
|
+
node.replaceWith(...to);
|
|
53
|
+
} else {
|
|
54
|
+
node.remove();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type {Fragment, FragmentElement, FragmentNode} from '../models';
|
|
2
|
+
|
|
3
|
+
export function isFragment(value: unknown): value is Fragment {
|
|
4
|
+
return (
|
|
5
|
+
typeof value === 'object' &&
|
|
6
|
+
value != null &&
|
|
7
|
+
'$fragment' in value &&
|
|
8
|
+
value.$fragment === true
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function isFragmentElement(value: unknown): value is FragmentElement {
|
|
13
|
+
return value instanceof HTMLElement || value instanceof SVGElement;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function isFragmentNode(value: unknown): value is FragmentNode {
|
|
17
|
+
return (
|
|
18
|
+
value instanceof Comment ||
|
|
19
|
+
value instanceof Element ||
|
|
20
|
+
value instanceof Text
|
|
21
|
+
);
|
|
22
|
+
}
|
package/src/html.ts
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import {isNullableOrWhitespace} from '@oscarpalmer/atoms/is';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
export function getFragment(nodes: Node[]): DocumentFragment {
|
|
5
|
-
const fragment = document.createDocumentFragment();
|
|
6
|
-
|
|
7
|
-
fragment.append(...nodes);
|
|
8
|
-
|
|
9
|
-
return fragment;
|
|
10
|
-
}
|
|
2
|
+
import {createFragment} from './fragment';
|
|
3
|
+
import type {Fragment, FragmentData} from './models';
|
|
11
4
|
|
|
12
5
|
function handleExpression(
|
|
13
6
|
data: FragmentData,
|
|
@@ -30,7 +23,7 @@ function handleExpression(
|
|
|
30
23
|
return `${prefix}${expressions}`;
|
|
31
24
|
}
|
|
32
25
|
|
|
33
|
-
if (typeof expression === 'object') {
|
|
26
|
+
if (typeof expression === 'function' || typeof expression === 'object') {
|
|
34
27
|
const index = data.values.push(expression) - 1;
|
|
35
28
|
|
|
36
29
|
return `${prefix}<!--abydon.${index}-->`;
|
package/src/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type {Fragment} from './
|
|
1
|
+
export type {Fragment} from './models';
|
|
2
2
|
export {html} from './html';
|
package/src/models.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type Fragment = {
|
|
2
|
+
appendTo(element: Element): void;
|
|
3
|
+
get(): FragmentNode[];
|
|
4
|
+
remove(): void;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export type FragmentData = {
|
|
8
|
+
expressions: unknown[];
|
|
9
|
+
nodes: Node[];
|
|
10
|
+
strings: TemplateStringsArray;
|
|
11
|
+
values: unknown[];
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type FragmentElement = HTMLElement | SVGElement;
|
|
15
|
+
|
|
16
|
+
export type FragmentNode = Comment | Element | Text;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import {isReactive} from '@oscarpalmer/sentinel';
|
|
2
|
+
import type {FragmentData, FragmentElement} from '../../models';
|
|
3
|
+
import {mapEvent} from '../event';
|
|
4
|
+
import {setAttribute} from './value';
|
|
5
|
+
|
|
6
|
+
const commentExpression = /^<!--abydon\.(\d+)-->$/;
|
|
7
|
+
|
|
8
|
+
function getValue(data: FragmentData, original: string): unknown {
|
|
9
|
+
const matches = commentExpression.exec(original ?? '');
|
|
10
|
+
|
|
11
|
+
return matches == null ? original : data.values[+matches[1]];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function isBadAttribute(name: string, value: string): boolean {
|
|
15
|
+
return (
|
|
16
|
+
/^on/i.test(name) ||
|
|
17
|
+
(/^(href|src|xlink:href)$/i.test(name) &&
|
|
18
|
+
/(data:text\/html|javascript:)/i.test(value))
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function mapAttributes(
|
|
23
|
+
data: FragmentData,
|
|
24
|
+
element: FragmentElement,
|
|
25
|
+
): void {
|
|
26
|
+
const attributes = [...element.attributes];
|
|
27
|
+
const {length} = attributes;
|
|
28
|
+
|
|
29
|
+
for (let index = 0; index < length; index += 1) {
|
|
30
|
+
const {name, value} = attributes[index];
|
|
31
|
+
|
|
32
|
+
if (isBadAttribute(name, value)) {
|
|
33
|
+
element.removeAttribute(name);
|
|
34
|
+
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const actual = getValue(data, value);
|
|
39
|
+
|
|
40
|
+
if (name.startsWith('@')) {
|
|
41
|
+
mapEvent(element, name, actual);
|
|
42
|
+
} else if (name.includes('.') || isReactive(actual)) {
|
|
43
|
+
mapValue(element, name, actual);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function mapValue(
|
|
49
|
+
element: FragmentElement,
|
|
50
|
+
name: string,
|
|
51
|
+
value: unknown,
|
|
52
|
+
): void {
|
|
53
|
+
switch (true) {
|
|
54
|
+
case typeof value === 'function':
|
|
55
|
+
mapValue(element, name, value());
|
|
56
|
+
return;
|
|
57
|
+
|
|
58
|
+
default:
|
|
59
|
+
setAttribute(element, name, value);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import type {PlainObject} from '@oscarpalmer/atoms/models';
|
|
2
|
+
import {getString} from '@oscarpalmer/atoms/string';
|
|
3
|
+
import {effect, isReactive} from '@oscarpalmer/sentinel';
|
|
4
|
+
import type {FragmentElement} from '../../models';
|
|
5
|
+
import {closest} from '@oscarpalmer/atoms/element';
|
|
6
|
+
|
|
7
|
+
const booleanAttributes = new Set([
|
|
8
|
+
'checked',
|
|
9
|
+
'disabled',
|
|
10
|
+
'hidden',
|
|
11
|
+
'inert',
|
|
12
|
+
'multiple',
|
|
13
|
+
'open',
|
|
14
|
+
'readOnly',
|
|
15
|
+
'required',
|
|
16
|
+
'selected',
|
|
17
|
+
]);
|
|
18
|
+
|
|
19
|
+
const classPattern = /^class\./;
|
|
20
|
+
const stylePattern = /^style\./;
|
|
21
|
+
|
|
22
|
+
export function setAttribute(
|
|
23
|
+
element: FragmentElement,
|
|
24
|
+
name: string,
|
|
25
|
+
value: unknown,
|
|
26
|
+
): void {
|
|
27
|
+
element.removeAttribute(name);
|
|
28
|
+
|
|
29
|
+
switch (true) {
|
|
30
|
+
case classPattern.test(name):
|
|
31
|
+
setClasses(element, name, value);
|
|
32
|
+
return;
|
|
33
|
+
|
|
34
|
+
case stylePattern.test(name):
|
|
35
|
+
setStyle(element, name, value);
|
|
36
|
+
return;
|
|
37
|
+
|
|
38
|
+
default:
|
|
39
|
+
setValue(element, name, value);
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function setClasses(
|
|
45
|
+
element: FragmentElement,
|
|
46
|
+
name: string,
|
|
47
|
+
value: unknown,
|
|
48
|
+
): void {
|
|
49
|
+
function update(value: unknown): void {
|
|
50
|
+
if (/^(|true)$/.test(getString(value))) {
|
|
51
|
+
element.classList.add(...classes);
|
|
52
|
+
} else {
|
|
53
|
+
element.classList.remove(...classes);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const classes = name.slice(6).split('.');
|
|
58
|
+
|
|
59
|
+
if (isReactive(value)) {
|
|
60
|
+
effect(() => {
|
|
61
|
+
update(value.get());
|
|
62
|
+
});
|
|
63
|
+
} else {
|
|
64
|
+
update(value);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function setStyle(
|
|
69
|
+
element: FragmentElement,
|
|
70
|
+
name: string,
|
|
71
|
+
value: unknown,
|
|
72
|
+
): void {
|
|
73
|
+
function update(value: unknown): void {
|
|
74
|
+
if (value == null || value === false || (value === true && unit == null)) {
|
|
75
|
+
element.style.removeProperty(property);
|
|
76
|
+
} else {
|
|
77
|
+
element.style.setProperty(
|
|
78
|
+
property,
|
|
79
|
+
value === true ? unit : getString(value),
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const [, property, unit] = /^\w+\.([a-z-]+)(?:\.(\w+))?$/i.exec(name) ?? [];
|
|
85
|
+
|
|
86
|
+
if (property == null) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (isReactive(value)) {
|
|
91
|
+
effect(() => {
|
|
92
|
+
update(value.get());
|
|
93
|
+
});
|
|
94
|
+
} else {
|
|
95
|
+
update(value);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function setValue(
|
|
100
|
+
element: FragmentElement,
|
|
101
|
+
name: string,
|
|
102
|
+
value: unknown,
|
|
103
|
+
): void {
|
|
104
|
+
const callback =
|
|
105
|
+
booleanAttributes.has(name) && name in element
|
|
106
|
+
? name === 'selected'
|
|
107
|
+
? updateSelected(element)
|
|
108
|
+
: updateProperty
|
|
109
|
+
: updateAttribute;
|
|
110
|
+
|
|
111
|
+
if (isReactive(value)) {
|
|
112
|
+
effect(() => {
|
|
113
|
+
callback(element, name, value.get());
|
|
114
|
+
});
|
|
115
|
+
} else {
|
|
116
|
+
callback(element, name, value);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function triggerSelectChange(select: HTMLSelectElement): void {
|
|
121
|
+
if (select != null) {
|
|
122
|
+
select.dispatchEvent(new Event('change', {bubbles: true}));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function updateAttribute(
|
|
127
|
+
element: FragmentElement,
|
|
128
|
+
name: string,
|
|
129
|
+
value: unknown,
|
|
130
|
+
): void {
|
|
131
|
+
if (value == null) {
|
|
132
|
+
element.removeAttribute(name);
|
|
133
|
+
} else {
|
|
134
|
+
element.setAttribute(name, getString(value));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function updateProperty(
|
|
139
|
+
element: FragmentElement,
|
|
140
|
+
name: string,
|
|
141
|
+
value: unknown,
|
|
142
|
+
): void {
|
|
143
|
+
(element as unknown as PlainObject)[name] = /^(|true)$/.test(
|
|
144
|
+
getString(value),
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function updateSelected(element: FragmentElement) {
|
|
149
|
+
const select = closest(element, 'select')[0] as HTMLSelectElement;
|
|
150
|
+
const options = [...(select?.options ?? [])];
|
|
151
|
+
|
|
152
|
+
return (element: FragmentElement, name: string, value: unknown): void => {
|
|
153
|
+
if (select != null && options.includes(element as HTMLOptionElement)) {
|
|
154
|
+
triggerSelectChange(select);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
updateProperty(element, name, value);
|
|
158
|
+
};
|
|
159
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type {FragmentElement} from '../models';
|
|
2
|
+
|
|
3
|
+
function getOptions(options: string): AddEventListenerOptions {
|
|
4
|
+
const parts = options.split(':');
|
|
5
|
+
|
|
6
|
+
return {
|
|
7
|
+
capture: parts.includes('c') || parts.includes('capture'),
|
|
8
|
+
once: parts.includes('o') || parts.includes('once'),
|
|
9
|
+
passive: !parts.includes('a') && !parts.includes('active'),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function mapEvent(
|
|
14
|
+
element: FragmentElement,
|
|
15
|
+
name: string,
|
|
16
|
+
value: unknown,
|
|
17
|
+
): void {
|
|
18
|
+
element.removeAttribute(name);
|
|
19
|
+
|
|
20
|
+
const [, type, options] = /^@(\w+)(?::([a-z:]+))?$/.exec(name) ?? [];
|
|
21
|
+
|
|
22
|
+
if (typeof value === 'function' && type != null) {
|
|
23
|
+
element.addEventListener(
|
|
24
|
+
type,
|
|
25
|
+
value as EventListener,
|
|
26
|
+
getOptions(options ?? ''),
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|
package/src/node/index.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import {isReactive} from '@oscarpalmer/sentinel';
|
|
2
|
+
import {isFragmentElement} from '../helpers';
|
|
3
|
+
import {createNodes} from '../helpers/dom';
|
|
4
|
+
import type {FragmentData} from '../models';
|
|
5
|
+
import {setReactiveNode} from './value';
|
|
6
|
+
import {mapAttributes} from './attribute';
|
|
4
7
|
|
|
5
8
|
const commentExpression = /^abydon\.(\d+)$/;
|
|
6
9
|
|
|
@@ -25,8 +28,8 @@ export function mapNodes(data: FragmentData, nodes: Node[]): void {
|
|
|
25
28
|
continue;
|
|
26
29
|
}
|
|
27
30
|
|
|
28
|
-
if (node
|
|
29
|
-
|
|
31
|
+
if (isFragmentElement(node)) {
|
|
32
|
+
mapAttributes(data, node);
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
if (node.hasChildNodes()) {
|
|
@@ -35,30 +38,18 @@ export function mapNodes(data: FragmentData, nodes: Node[]): void {
|
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
|
|
38
|
-
function mapReactive(comment: Comment, value: Reactive): void {
|
|
39
|
-
// ?
|
|
40
|
-
}
|
|
41
|
-
|
|
42
41
|
function mapValue(comment: Comment, value: unknown): void {
|
|
43
42
|
switch (true) {
|
|
44
|
-
case value
|
|
45
|
-
comment
|
|
43
|
+
case typeof value === 'function':
|
|
44
|
+
mapValue(comment, value());
|
|
46
45
|
return;
|
|
47
46
|
|
|
48
|
-
case isFragment(value):
|
|
49
|
-
comment.replaceWith(value.get());
|
|
50
|
-
break;
|
|
51
|
-
|
|
52
47
|
case isReactive(value):
|
|
53
|
-
|
|
48
|
+
setReactiveNode(comment, value);
|
|
54
49
|
break;
|
|
55
50
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return;
|
|
59
|
-
|
|
60
|
-
case typeof value === 'object':
|
|
61
|
-
comment.replaceWith(new Text(getString(value)));
|
|
51
|
+
default:
|
|
52
|
+
comment.replaceWith(...createNodes(value));
|
|
62
53
|
break;
|
|
63
54
|
}
|
|
64
55
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import {isNullableOrWhitespace} from '@oscarpalmer/atoms/is';
|
|
2
|
+
import {getString} from '@oscarpalmer/atoms/string';
|
|
3
|
+
import {type Reactive, effect} from '@oscarpalmer/sentinel';
|
|
4
|
+
import {isFragment, isFragmentNode} from '../helpers';
|
|
5
|
+
import {createNodes, replaceNodes} from '../helpers/dom';
|
|
6
|
+
import type {FragmentNode} from '../models';
|
|
7
|
+
|
|
8
|
+
export function setReactiveNode(comment: Comment, reactive: Reactive): void {
|
|
9
|
+
const text = new Text();
|
|
10
|
+
|
|
11
|
+
let nodes: FragmentNode[] | undefined;
|
|
12
|
+
|
|
13
|
+
effect(() => {
|
|
14
|
+
const value = reactive.get();
|
|
15
|
+
|
|
16
|
+
if (isFragment(value) || isFragmentNode(value)) {
|
|
17
|
+
const next = createNodes(value);
|
|
18
|
+
|
|
19
|
+
if (nodes == null) {
|
|
20
|
+
if (comment.parentNode != null) {
|
|
21
|
+
replaceNodes([comment], next);
|
|
22
|
+
} else if (text.parentNode != null) {
|
|
23
|
+
replaceNodes([text], next);
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
replaceNodes(nodes, next);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
nodes = next;
|
|
30
|
+
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const isNullable = isNullableOrWhitespace(value);
|
|
35
|
+
|
|
36
|
+
text.textContent = getString(value);
|
|
37
|
+
|
|
38
|
+
if (nodes != null) {
|
|
39
|
+
replaceNodes(nodes, [isNullable ? comment : text]);
|
|
40
|
+
} else if (isNullable && comment.parentNode == null) {
|
|
41
|
+
text.replaceWith(comment);
|
|
42
|
+
} else if (!isNullable && text.parentNode == null) {
|
|
43
|
+
comment.replaceWith(text);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
nodes = undefined;
|
|
47
|
+
});
|
|
48
|
+
}
|
package/types/fragment.d.ts
CHANGED
|
@@ -1,12 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
get(): DocumentFragment;
|
|
3
|
-
remove(): void;
|
|
4
|
-
};
|
|
5
|
-
export type FragmentData = {
|
|
6
|
-
expressions: unknown[];
|
|
7
|
-
nodes: Node[];
|
|
8
|
-
strings: TemplateStringsArray;
|
|
9
|
-
values: unknown[];
|
|
10
|
-
};
|
|
1
|
+
import type { Fragment } from './models';
|
|
11
2
|
export declare function createFragment(strings: TemplateStringsArray, expressions: unknown[]): Fragment;
|
|
12
|
-
export declare function isFragment(value: unknown): value is Fragment;
|
package/types/helpers/dom.d.ts
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
+
import type { FragmentNode } from '../models';
|
|
2
|
+
export declare function createNodes(value: unknown): FragmentNode[];
|
|
1
3
|
export declare function createTemplate(html: string): Node;
|
|
2
4
|
export declare function getNodes(node: Node): Node[];
|
|
5
|
+
export declare function replaceNodes(from: FragmentNode[], to: FragmentNode[]): void;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Fragment, FragmentElement, FragmentNode } from '../models';
|
|
2
|
+
export declare function isFragment(value: unknown): value is Fragment;
|
|
3
|
+
export declare function isFragmentElement(value: unknown): value is FragmentElement;
|
|
4
|
+
export declare function isFragmentNode(value: unknown): value is FragmentNode;
|
package/types/html.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function getFragment(nodes: Node[]): DocumentFragment;
|
|
1
|
+
import type { Fragment, FragmentData } from './models';
|
|
3
2
|
export declare function html(strings: TemplateStringsArray, ...values: unknown[]): Fragment;
|
|
4
3
|
export declare function parse(data: FragmentData): string;
|
package/types/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type { Fragment } from './
|
|
1
|
+
export type { Fragment } from './models';
|
|
2
2
|
export { html } from './html';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type Fragment = {
|
|
2
|
+
appendTo(element: Element): void;
|
|
3
|
+
get(): FragmentNode[];
|
|
4
|
+
remove(): void;
|
|
5
|
+
};
|
|
6
|
+
export type FragmentData = {
|
|
7
|
+
expressions: unknown[];
|
|
8
|
+
nodes: Node[];
|
|
9
|
+
strings: TemplateStringsArray;
|
|
10
|
+
values: unknown[];
|
|
11
|
+
};
|
|
12
|
+
export type FragmentElement = HTMLElement | SVGElement;
|
|
13
|
+
export type FragmentNode = Comment | Element | Text;
|
package/types/node/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { FragmentData } from '../models';
|
|
2
2
|
export declare function mapNodes(data: FragmentData, nodes: Node[]): void;
|