@oscarpalmer/abydon 0.12.0 → 0.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.
- package/dist/abydon.full.js +1247 -0
- package/dist/fragment.js +60 -0
- package/dist/helpers/dom.js +28 -0
- package/dist/helpers/index.js +11 -0
- package/dist/index.js +6 -911
- package/dist/node/attribute/index.js +34 -0
- package/dist/node/attribute/value.js +58 -0
- package/dist/node/event.js +32 -0
- package/dist/node/index.js +52 -0
- package/dist/node/value.js +93 -0
- package/dist/parse.js +21 -0
- package/package.json +41 -28
- package/src/fragment.ts +13 -14
- package/src/helpers/dom.ts +2 -1
- package/src/helpers/index.ts +0 -9
- package/src/index.ts +11 -2
- package/src/models.ts +6 -8
- package/src/node/attribute/index.ts +4 -3
- package/src/node/attribute/value.ts +8 -15
- package/src/node/event.ts +1 -1
- package/src/node/index.ts +4 -3
- package/src/node/value.ts +6 -7
- package/src/{html.ts → parse.ts} +5 -14
- package/types/fragment.d.cts +27 -0
- package/types/helpers/dom.d.cts +7 -0
- package/types/helpers/index.d.cts +29 -0
- package/types/helpers/index.d.ts +0 -3
- package/types/index.d.cts +278 -2
- package/types/index.d.ts +4 -2
- package/types/models.d.cts +107 -0
- package/types/models.d.ts +6 -7
- package/types/node/attribute/index.d.cts +109 -0
- package/types/node/attribute/index.d.ts +2 -1
- package/types/node/attribute/value.d.cts +109 -0
- package/types/node/attribute/value.d.ts +2 -1
- package/types/node/event.d.cts +7 -0
- package/types/node/event.d.ts +1 -1
- package/types/node/index.d.cts +108 -0
- package/types/node/value.d.cts +108 -0
- package/types/node/value.d.ts +2 -2
- package/types/parse.d.cts +108 -0
- package/types/parse.d.ts +2 -0
- package/dist/fragment.mjs +0 -75
- package/dist/helpers/dom.mjs +0 -44
- package/dist/helpers/index.mjs +0 -25
- package/dist/html.mjs +0 -36
- package/dist/index.mjs +0 -6
- package/dist/node/attribute/index.mjs +0 -40
- package/dist/node/attribute/value.mjs +0 -89
- package/dist/node/event.mjs +0 -38
- package/dist/node/index.mjs +0 -60
- package/dist/node/value.mjs +0 -123
- package/types/html.d.ts +0 -4
- /package/dist/{models.mjs → models.js} +0 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { mapEvent } from "../event.js";
|
|
2
|
+
import { setAttribute } from "./value.js";
|
|
3
|
+
import { computed, isReactive } from "@oscarpalmer/mora";
|
|
4
|
+
var commentExpression = /^<!--abydon\.(\d+)-->$/;
|
|
5
|
+
function getValue(data, original) {
|
|
6
|
+
const matches = commentExpression.exec(original ?? "");
|
|
7
|
+
return matches == null ? original : data.values[+matches[1]];
|
|
8
|
+
}
|
|
9
|
+
function mapAttributes(data, element) {
|
|
10
|
+
const attributes = [...element.attributes];
|
|
11
|
+
const { length } = attributes;
|
|
12
|
+
for (let index = 0; index < length; index += 1) {
|
|
13
|
+
const { name, value } = attributes[index];
|
|
14
|
+
const actual = getValue(data, value);
|
|
15
|
+
if (name.startsWith("@")) mapEvent(element, name, actual);
|
|
16
|
+
else if (name.includes(".") || typeof value === "function" || isReactive(actual)) mapValue(data, element, name, actual);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function mapValue(data, element, name, value) {
|
|
20
|
+
switch (true) {
|
|
21
|
+
case typeof value === "function":
|
|
22
|
+
setComputedAttribute(data, element, name, value);
|
|
23
|
+
break;
|
|
24
|
+
default:
|
|
25
|
+
setAttribute(data, element, name, value);
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function setComputedAttribute(data, element, name, callback) {
|
|
30
|
+
const value = computed(callback);
|
|
31
|
+
data.mora.values.add(value);
|
|
32
|
+
setAttribute(data, element, name, value);
|
|
33
|
+
}
|
|
34
|
+
export { mapAttributes };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { isReactive } from "@oscarpalmer/mora";
|
|
2
|
+
import { getString } from "@oscarpalmer/atoms/string";
|
|
3
|
+
import { isBooleanAttribute, setAttribute as setAttribute$1 } from "@oscarpalmer/toretto/attribute";
|
|
4
|
+
var classExpression = /^class\./;
|
|
5
|
+
var styleFullExpression = /^style\.([\w-]+)(?:\.([\w-]+))?$/;
|
|
6
|
+
var stylePrefixExpression = /^style\./;
|
|
7
|
+
function setAttribute(data, element, name, value) {
|
|
8
|
+
element.removeAttribute(name);
|
|
9
|
+
switch (true) {
|
|
10
|
+
case classExpression.test(name):
|
|
11
|
+
setClasses(data, element, name, value);
|
|
12
|
+
return;
|
|
13
|
+
case stylePrefixExpression.test(name):
|
|
14
|
+
setStyle(data, element, name, value);
|
|
15
|
+
return;
|
|
16
|
+
default:
|
|
17
|
+
setValue(data, element, name, value);
|
|
18
|
+
break;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function setClasses(data, element, name, value) {
|
|
22
|
+
function update(value$1) {
|
|
23
|
+
if (value$1 === true) element.classList.add(...classes);
|
|
24
|
+
else element.classList.remove(...classes);
|
|
25
|
+
}
|
|
26
|
+
const classes = name.slice(6).split(".");
|
|
27
|
+
if (isReactive(value)) data.mora.subscribers.add(value.subscribe(update));
|
|
28
|
+
else update(value);
|
|
29
|
+
}
|
|
30
|
+
function setStyle(data, element, name, value) {
|
|
31
|
+
function update(value$1) {
|
|
32
|
+
if (value$1 == null || value$1 === false || value$1 === true && unit == null) element.style.removeProperty(property);
|
|
33
|
+
else element.style.setProperty(property, value$1 === true ? unit : getString(value$1));
|
|
34
|
+
}
|
|
35
|
+
const [, property, unit] = styleFullExpression.exec(name) ?? [];
|
|
36
|
+
if (property != null) if (isReactive(value)) data.mora.subscribers.add(value.subscribe(update));
|
|
37
|
+
else update(value);
|
|
38
|
+
}
|
|
39
|
+
function setValue(data, element, name, value) {
|
|
40
|
+
const callback = isBooleanAttribute(name) && name in element ? name === "selected" ? updateSelected : updateProperty : setAttribute$1;
|
|
41
|
+
if (isReactive(value)) data.mora.subscribers.add(value.subscribe((next) => {
|
|
42
|
+
callback(element, name, next);
|
|
43
|
+
}));
|
|
44
|
+
else callback(element, name, value);
|
|
45
|
+
}
|
|
46
|
+
function triggerSelectChange(select) {
|
|
47
|
+
if (select != null) select.dispatchEvent(new Event("change", { bubbles: true }));
|
|
48
|
+
}
|
|
49
|
+
function updateProperty(element, name, value) {
|
|
50
|
+
element[name] = value === true;
|
|
51
|
+
}
|
|
52
|
+
function updateSelected(element, name, value) {
|
|
53
|
+
const select = element.closest("select");
|
|
54
|
+
const options = [...select?.options ?? []];
|
|
55
|
+
if (select != null && options.includes(element)) triggerSelectChange(select);
|
|
56
|
+
updateProperty(element, name, value);
|
|
57
|
+
}
|
|
58
|
+
export { setAttribute };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
var controllers = /* @__PURE__ */ new WeakMap();
|
|
2
|
+
var eventNamePattern = /^@([\w-]+)(?::([a-z:]+))?$/i;
|
|
3
|
+
var reason = "Event removed as element was removed from document by Abydon";
|
|
4
|
+
function getController(element) {
|
|
5
|
+
let controller = controllers.get(element);
|
|
6
|
+
if (controller == null) {
|
|
7
|
+
controller = new AbortController();
|
|
8
|
+
controllers.set(element, controller);
|
|
9
|
+
}
|
|
10
|
+
return controller;
|
|
11
|
+
}
|
|
12
|
+
function getOptions(options) {
|
|
13
|
+
const parts = options.split(":");
|
|
14
|
+
return {
|
|
15
|
+
capture: parts.includes("c") || parts.includes("capture"),
|
|
16
|
+
once: parts.includes("o") || parts.includes("once"),
|
|
17
|
+
passive: !parts.includes("a") && !parts.includes("active")
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function mapEvent(element, name, value) {
|
|
21
|
+
element.removeAttribute(name);
|
|
22
|
+
const [, type, options] = eventNamePattern.exec(name) ?? [];
|
|
23
|
+
if (typeof value === "function" && type != null) element.addEventListener(type, value, {
|
|
24
|
+
...getOptions(options ?? ""),
|
|
25
|
+
signal: getController(element).signal
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function removeEvents(element) {
|
|
29
|
+
controllers.get(element)?.abort(reason);
|
|
30
|
+
controllers.delete(element);
|
|
31
|
+
}
|
|
32
|
+
export { mapEvent, removeEvents };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { isFragment } from "../helpers/index.js";
|
|
2
|
+
import { createNodes } from "../helpers/dom.js";
|
|
3
|
+
import { mapAttributes } from "./attribute/index.js";
|
|
4
|
+
import { setReactiveValue } from "./value.js";
|
|
5
|
+
import { computed, isReactive } from "@oscarpalmer/mora";
|
|
6
|
+
import { isHTMLOrSVGElement } from "@oscarpalmer/toretto/is";
|
|
7
|
+
var commentExpression = /^abydon\.(\d+)$/;
|
|
8
|
+
function mapNode(data, comment) {
|
|
9
|
+
const matches = commentExpression.exec(comment.textContent ?? "");
|
|
10
|
+
const value = matches == null ? null : data.values[+matches[1]];
|
|
11
|
+
if (value != null) mapValue(data, comment, value);
|
|
12
|
+
}
|
|
13
|
+
function mapNodes(data, nodes) {
|
|
14
|
+
const { length } = nodes;
|
|
15
|
+
for (let index = 0; index < length; index += 1) {
|
|
16
|
+
const node = nodes[index];
|
|
17
|
+
if (node instanceof Comment) {
|
|
18
|
+
mapNode(data, node);
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (isHTMLOrSVGElement(node)) mapAttributes(data, node);
|
|
22
|
+
if (node.hasChildNodes()) mapNodes(data, [...node.childNodes]);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function mapValue(data, comment, value) {
|
|
26
|
+
switch (true) {
|
|
27
|
+
case typeof value === "function":
|
|
28
|
+
setComputedValue(data, comment, value);
|
|
29
|
+
break;
|
|
30
|
+
case isReactive(value):
|
|
31
|
+
setReactiveValue(data, comment, value);
|
|
32
|
+
break;
|
|
33
|
+
default:
|
|
34
|
+
replaceComment(data, comment, value);
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function replaceComment(data, comment, value) {
|
|
39
|
+
const item = data.items.find((item$1) => item$1.nodes.includes(comment));
|
|
40
|
+
const nodes = createNodes(value);
|
|
41
|
+
if (item != null) {
|
|
42
|
+
item.fragments = isFragment(value) ? [value] : void 0;
|
|
43
|
+
item.nodes = nodes;
|
|
44
|
+
}
|
|
45
|
+
comment.replaceWith(...nodes);
|
|
46
|
+
}
|
|
47
|
+
function setComputedValue(data, comment, callback) {
|
|
48
|
+
const value = computed(callback);
|
|
49
|
+
data.mora.values.add(value);
|
|
50
|
+
setReactiveValue(data, comment, value);
|
|
51
|
+
}
|
|
52
|
+
export { mapNodes };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { compareArrays, isFragment } from "../helpers/index.js";
|
|
2
|
+
import { createNodes, replaceNodes } from "../helpers/dom.js";
|
|
3
|
+
import { isNullableOrWhitespace } from "@oscarpalmer/atoms/is";
|
|
4
|
+
import { getString } from "@oscarpalmer/atoms/string";
|
|
5
|
+
import { isChildNode } from "@oscarpalmer/toretto/is";
|
|
6
|
+
function removeFragments(fragments) {
|
|
7
|
+
if (fragments != null) {
|
|
8
|
+
const { length } = fragments;
|
|
9
|
+
for (let index = 0; index < length; index += 1) fragments[index].remove();
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function setArray(fragments, nodes, comment, text, value) {
|
|
13
|
+
if (value.length === 0) return { nodes: setText(fragments, nodes, comment, text, value) };
|
|
14
|
+
let templates = value.filter((item) => isFragment(item) && item.identifier != null);
|
|
15
|
+
const identifiers = templates.map((fragment) => fragment.identifier);
|
|
16
|
+
const oldIdentifiers = fragments?.map((fragment) => fragment.identifier) ?? [];
|
|
17
|
+
if (new Set(identifiers).size !== templates.length) templates = [];
|
|
18
|
+
const noTemplates = templates.length === 0;
|
|
19
|
+
if (noTemplates || nodes == null || oldIdentifiers.some((identifier) => identifier == null)) return {
|
|
20
|
+
fragments: noTemplates ? void 0 : templates,
|
|
21
|
+
nodes: setNodes(fragments, nodes, comment, text, noTemplates ? value.flatMap((item) => createNodes(item)) : templates.flatMap((template) => template.get()))
|
|
22
|
+
};
|
|
23
|
+
const next = templates.map((template) => fragments?.find((fragment) => fragment.identifier === template.identifier) ?? template);
|
|
24
|
+
const comparison = compareArrays(fragments ?? [], templates);
|
|
25
|
+
if (comparison !== "removed") {
|
|
26
|
+
let position = nodes[0];
|
|
27
|
+
const before = comparison === "added" && !oldIdentifiers.includes(templates[0].identifier);
|
|
28
|
+
const items = next.flatMap((fragment) => fragment.get().flatMap((node) => ({
|
|
29
|
+
identifier: fragment.identifier,
|
|
30
|
+
value: node
|
|
31
|
+
})));
|
|
32
|
+
const { length: length$1 } = items;
|
|
33
|
+
for (let index = 0; index < length$1; index += 1) {
|
|
34
|
+
const item = items[index];
|
|
35
|
+
if (comparison === "dissimilar" || !oldIdentifiers.includes(item.identifier)) if (index === 0 && before) position.before(item.value);
|
|
36
|
+
else position.after(item.value);
|
|
37
|
+
position = item.value;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const toRemove = fragments?.filter((fragment) => !identifiers.includes(fragment.identifier)) ?? [];
|
|
41
|
+
const { length } = toRemove;
|
|
42
|
+
for (let index = 0; index < length; index += 1) toRemove[index].remove();
|
|
43
|
+
return {
|
|
44
|
+
fragments: next,
|
|
45
|
+
nodes: next.flatMap((fragment) => fragment.get())
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function setNodes(fragments, nodes, comment, text, next) {
|
|
49
|
+
if (nodes == null) {
|
|
50
|
+
if (comment.parentNode != null) replaceNodes([comment], next);
|
|
51
|
+
else if (text.parentNode != null) replaceNodes([text], next);
|
|
52
|
+
} else replaceNodes(nodes, next);
|
|
53
|
+
removeFragments(fragments);
|
|
54
|
+
return next;
|
|
55
|
+
}
|
|
56
|
+
function setReactiveValue(data, comment, reactive) {
|
|
57
|
+
const item = data.items.find((item$1) => item$1.nodes.includes(comment));
|
|
58
|
+
const text = new Text();
|
|
59
|
+
let fragments;
|
|
60
|
+
let nodes;
|
|
61
|
+
data.mora.subscribers.add(reactive.subscribe((value) => {
|
|
62
|
+
if (Array.isArray(value)) {
|
|
63
|
+
const result = setArray(fragments, nodes, comment, text, value);
|
|
64
|
+
fragments = typeof result === "boolean" ? void 0 : result?.fragments;
|
|
65
|
+
nodes = typeof result === "boolean" ? result ? [text] : void 0 : result?.nodes;
|
|
66
|
+
} else {
|
|
67
|
+
const valueIsFragment = isFragment(value);
|
|
68
|
+
fragments = valueIsFragment ? [value] : void 0;
|
|
69
|
+
if (valueIsFragment || isChildNode(value)) nodes = setNodes(fragments, nodes, comment, text, createNodes(value));
|
|
70
|
+
else nodes = setText(fragments, nodes, comment, text, value);
|
|
71
|
+
}
|
|
72
|
+
if (item != null) {
|
|
73
|
+
item.fragments = fragments;
|
|
74
|
+
item.nodes = [...nodes ?? [comment]];
|
|
75
|
+
}
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
function setText(fragments, nodes, comment, text, value) {
|
|
79
|
+
const isNullable = isNullableOrWhitespace(value);
|
|
80
|
+
text.textContent = isNullable ? "" : getString(value);
|
|
81
|
+
let result = false;
|
|
82
|
+
if (nodes != null) {
|
|
83
|
+
replaceNodes(nodes, [isNullable ? comment : text]);
|
|
84
|
+
result = !isNullable;
|
|
85
|
+
} else if (isNullable && comment.parentNode == null) text.replaceWith(comment);
|
|
86
|
+
else if (!isNullable && text.parentNode == null) {
|
|
87
|
+
comment.replaceWith(text);
|
|
88
|
+
result = true;
|
|
89
|
+
}
|
|
90
|
+
removeFragments(fragments);
|
|
91
|
+
return result ? [text] : void 0;
|
|
92
|
+
}
|
|
93
|
+
export { setReactiveValue };
|
package/dist/parse.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { isNullableOrWhitespace } from "@oscarpalmer/atoms/is";
|
|
2
|
+
function handleExpression(data, prefix, expression) {
|
|
3
|
+
if (Array.isArray(expression)) {
|
|
4
|
+
const { length } = expression;
|
|
5
|
+
let expressions = "";
|
|
6
|
+
for (let index = 0; index < length; index += 1) expressions += handleExpression(data, "", expression[index]);
|
|
7
|
+
return `${prefix}${expressions}`;
|
|
8
|
+
}
|
|
9
|
+
if (typeof expression === "function" || typeof expression === "object" && expression != null) {
|
|
10
|
+
const index = data.values.push(expression) - 1;
|
|
11
|
+
return `${prefix}<!--abydon.${index}-->`;
|
|
12
|
+
}
|
|
13
|
+
return isNullableOrWhitespace(expression) ? prefix : `${prefix}${expression}`;
|
|
14
|
+
}
|
|
15
|
+
function parse(data) {
|
|
16
|
+
const { length } = data.strings;
|
|
17
|
+
let template = "";
|
|
18
|
+
for (let index = 0; index < length; index += 1) template += handleExpression(data, data.strings[index], data.expressions[index]);
|
|
19
|
+
return template;
|
|
20
|
+
}
|
|
21
|
+
export { parse };
|
package/package.json
CHANGED
|
@@ -4,48 +4,61 @@
|
|
|
4
4
|
"url": "https://oscarpalmer.se"
|
|
5
5
|
},
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@oscarpalmer/atoms": "^0.
|
|
8
|
-
"@oscarpalmer/
|
|
9
|
-
"@oscarpalmer/toretto": "0.
|
|
7
|
+
"@oscarpalmer/atoms": "^0.108",
|
|
8
|
+
"@oscarpalmer/mora": "^0.21",
|
|
9
|
+
"@oscarpalmer/toretto": "^0.22"
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"@biomejs/biome": "^
|
|
13
|
-
"@
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
12
|
+
"@biomejs/biome": "^2.2",
|
|
13
|
+
"@oscarpalmer/oui": "^0.17",
|
|
14
|
+
"@rollup/plugin-node-resolve": "^16",
|
|
15
|
+
"@rollup/plugin-typescript": "^12.1",
|
|
16
|
+
"@types/node": "^24.3",
|
|
17
|
+
"@vitest/coverage-istanbul": "^3.2",
|
|
18
|
+
"dts-bundle-generator": "^9.5",
|
|
19
|
+
"glob": "^11",
|
|
20
|
+
"jsdom": "^26.1",
|
|
21
|
+
"rollup": "^4.50",
|
|
22
|
+
"tslib": "^2.8",
|
|
23
|
+
"typescript": "^5.9",
|
|
24
|
+
"vite": "npm:rolldown-vite@latest",
|
|
25
|
+
"vitest": "^3.2"
|
|
17
26
|
},
|
|
18
27
|
"exports": {
|
|
28
|
+
"./package.json": "./package.json",
|
|
19
29
|
".": {
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"types": "./types/index.d.ts",
|
|
23
|
-
"default": "./dist/index.mjs"
|
|
24
|
-
},
|
|
25
|
-
"require": {
|
|
26
|
-
"types": "./types/index.d.cts",
|
|
27
|
-
"default": "./dist/index.js"
|
|
28
|
-
}
|
|
30
|
+
"types": "./types/index.d.ts",
|
|
31
|
+
"default": "./dist/index.js"
|
|
29
32
|
}
|
|
30
33
|
},
|
|
31
|
-
"files": ["dist
|
|
34
|
+
"files": ["dist", "src", "types"],
|
|
35
|
+
"keywords": [
|
|
36
|
+
"components",
|
|
37
|
+
"dom",
|
|
38
|
+
"library",
|
|
39
|
+
"literals",
|
|
40
|
+
"reactive",
|
|
41
|
+
"signal",
|
|
42
|
+
"template",
|
|
43
|
+
"vanilla"
|
|
44
|
+
],
|
|
32
45
|
"license": "MIT",
|
|
33
|
-
"
|
|
34
|
-
"module": "dist/index.mjs",
|
|
46
|
+
"module": "dist/index.js",
|
|
35
47
|
"name": "@oscarpalmer/abydon",
|
|
36
48
|
"repository": {
|
|
37
49
|
"type": "git",
|
|
38
50
|
"url": "git+https://github.com/oscarpalmer/abydon.git"
|
|
39
51
|
},
|
|
40
52
|
"scripts": {
|
|
41
|
-
"build": "
|
|
42
|
-
"clean": "rm -rf ./dist && rm -rf ./types && rm -
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
53
|
+
"build": "npm run clean && npx vite build && npm run rollup:build && npm run types",
|
|
54
|
+
"clean": "rm -rf ./dist && rm -rf ./types && rm -f ./tsconfig.tsbuildinfo",
|
|
55
|
+
"rollup:build": "npx rollup -c",
|
|
56
|
+
"rollup:watch": "npx rollup -c --watch",
|
|
57
|
+
"test": "npx vitest --coverage",
|
|
58
|
+
"types": "npx tsc && npx dts-bundle-generator --config ./dts.config.cts --silent",
|
|
59
|
+
"watch": "npx vite build --watch"
|
|
47
60
|
},
|
|
48
61
|
"type": "module",
|
|
49
|
-
"types": "types/index.d.
|
|
50
|
-
"version": "0.
|
|
62
|
+
"types": "types/index.d.cts",
|
|
63
|
+
"version": "0.13.0"
|
|
51
64
|
}
|
package/src/fragment.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type {Key} from '@oscarpalmer/atoms/models';
|
|
2
2
|
import {html} from '@oscarpalmer/toretto/html';
|
|
3
|
-
import {
|
|
3
|
+
import {removeNodes} from './helpers/dom';
|
|
4
4
|
import type {FragmentData} from './models';
|
|
5
5
|
import {mapNodes} from './node';
|
|
6
|
-
import {
|
|
6
|
+
import {parse} from './parse';
|
|
7
7
|
|
|
8
8
|
export class Fragment {
|
|
9
9
|
private readonly $fragment = true;
|
|
@@ -18,8 +18,8 @@ export class Fragment {
|
|
|
18
18
|
expressions,
|
|
19
19
|
strings,
|
|
20
20
|
items: [],
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
mora: {
|
|
22
|
+
subscribers: new Set(),
|
|
23
23
|
values: new Set(),
|
|
24
24
|
},
|
|
25
25
|
values: [],
|
|
@@ -41,7 +41,7 @@ export class Fragment {
|
|
|
41
41
|
const parsed = parse(this.data);
|
|
42
42
|
|
|
43
43
|
const templated = html(parsed, {
|
|
44
|
-
|
|
44
|
+
sanitizeBooleanAttributes: false,
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
this.data.items.splice(
|
|
@@ -84,7 +84,7 @@ export class Fragment {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
function removeFragment(data: FragmentData): void {
|
|
87
|
-
|
|
87
|
+
removeMora(data);
|
|
88
88
|
|
|
89
89
|
const {length} = data.items;
|
|
90
90
|
|
|
@@ -102,14 +102,13 @@ function removeFragment(data: FragmentData): void {
|
|
|
102
102
|
data.items.splice(0, length);
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
function
|
|
106
|
-
const
|
|
107
|
-
const {length} = sentinels;
|
|
105
|
+
function removeMora(data: FragmentData): void {
|
|
106
|
+
const unsubscribers = [...data.mora.subscribers];
|
|
108
107
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
108
|
+
data.mora.subscribers.clear();
|
|
109
|
+
data.mora.values.clear();
|
|
112
110
|
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
for (const unsubscribe of unsubscribers) {
|
|
112
|
+
unsubscribe();
|
|
113
|
+
}
|
|
115
114
|
}
|
package/src/helpers/dom.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {getString} from '@oscarpalmer/atoms/string';
|
|
2
|
-
import {isChildNode,
|
|
2
|
+
import {isChildNode, isHTMLOrSVGElement} from '@oscarpalmer/toretto/is';
|
|
3
3
|
import {removeEvents} from '../node/event';
|
|
4
|
+
import {isFragment} from './index';
|
|
4
5
|
|
|
5
6
|
export function createNodes(value: unknown): ChildNode[] {
|
|
6
7
|
if (isFragment(value)) {
|
package/src/helpers/index.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type {Fragment} from '../fragment';
|
|
2
|
-
import type {HTMLOrSVGElement} from '../models';
|
|
3
2
|
|
|
4
3
|
export function compareArrays(
|
|
5
4
|
first: unknown[],
|
|
@@ -20,10 +19,6 @@ export function compareArrays(
|
|
|
20
19
|
return firstIsLarger ? 'removed' : 'added';
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
export function isChildNode(value: unknown): value is ChildNode {
|
|
24
|
-
return value instanceof CharacterData || value instanceof Element;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
22
|
export function isFragment(value: unknown): value is Fragment {
|
|
28
23
|
return (
|
|
29
24
|
typeof value === 'object' &&
|
|
@@ -32,7 +27,3 @@ export function isFragment(value: unknown): value is Fragment {
|
|
|
32
27
|
value.$fragment === true
|
|
33
28
|
);
|
|
34
29
|
}
|
|
35
|
-
|
|
36
|
-
export function isHTMLOrSVGElement(value: unknown): value is HTMLOrSVGElement {
|
|
37
|
-
return value instanceof HTMLElement || value instanceof SVGElement;
|
|
38
|
-
}
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
-
import '@oscarpalmer/
|
|
1
|
+
import '@oscarpalmer/mora';
|
|
2
|
+
import {Fragment} from './fragment';
|
|
3
|
+
|
|
4
|
+
export function html(
|
|
5
|
+
strings: TemplateStringsArray,
|
|
6
|
+
...values: unknown[]
|
|
7
|
+
): Fragment {
|
|
8
|
+
return new Fragment(strings, values);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export * from '@oscarpalmer/mora';
|
|
2
12
|
export type {Fragment} from './fragment';
|
|
3
|
-
export {html} from './html';
|
package/src/models.ts
CHANGED
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
import type {Key} from '@oscarpalmer/atoms/models';
|
|
2
|
-
import type {
|
|
2
|
+
import type {Reactive} from '@oscarpalmer/mora';
|
|
3
3
|
import type {Fragment} from './fragment';
|
|
4
4
|
|
|
5
5
|
export type FragmentData = {
|
|
6
6
|
expressions: unknown[];
|
|
7
7
|
identifier?: Key;
|
|
8
8
|
items: FragmentItem[];
|
|
9
|
-
|
|
9
|
+
mora: MoraData;
|
|
10
10
|
strings: TemplateStringsArray;
|
|
11
11
|
values: unknown[];
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
type FragmentDataSentinel = {
|
|
15
|
-
effects: Set<Effect>;
|
|
16
|
-
values: Set<Reactive>;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
14
|
export type FragmentItem = {
|
|
20
15
|
fragments?: Fragment[];
|
|
21
16
|
nodes: ChildNode[];
|
|
22
17
|
};
|
|
23
18
|
|
|
24
|
-
|
|
19
|
+
type MoraData = {
|
|
20
|
+
subscribers: Set<() => void>;
|
|
21
|
+
values: Set<Reactive<unknown>>;
|
|
22
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {GenericCallback} from '@oscarpalmer/atoms/models';
|
|
2
|
-
import {computed, isReactive} from '@oscarpalmer/
|
|
3
|
-
import type {
|
|
2
|
+
import {computed, isReactive} from '@oscarpalmer/mora';
|
|
3
|
+
import type {HTMLOrSVGElement} from '@oscarpalmer/toretto/models';
|
|
4
|
+
import type {FragmentData} from '../../models';
|
|
4
5
|
import {mapEvent} from '../event';
|
|
5
6
|
import {setAttribute} from './value';
|
|
6
7
|
|
|
@@ -61,7 +62,7 @@ function setComputedAttribute(
|
|
|
61
62
|
): void {
|
|
62
63
|
const value = computed(callback);
|
|
63
64
|
|
|
64
|
-
data.
|
|
65
|
+
data.mora.values.add(value);
|
|
65
66
|
|
|
66
67
|
setAttribute(data, element, name, value);
|
|
67
68
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type {PlainObject} from '@oscarpalmer/atoms/models';
|
|
2
2
|
import {getString} from '@oscarpalmer/atoms/string';
|
|
3
|
-
import {
|
|
3
|
+
import {isReactive} from '@oscarpalmer/mora';
|
|
4
4
|
import {
|
|
5
5
|
isBooleanAttribute,
|
|
6
6
|
setAttribute as setAttr,
|
|
7
7
|
} from '@oscarpalmer/toretto/attribute';
|
|
8
|
-
import type {
|
|
8
|
+
import type {HTMLOrSVGElement} from '@oscarpalmer/toretto/models';
|
|
9
|
+
import type {FragmentData} from '../../models';
|
|
9
10
|
|
|
10
11
|
const classExpression = /^class\./;
|
|
11
12
|
const styleFullExpression = /^style\.([\w-]+)(?:\.([\w-]+))?$/;
|
|
@@ -51,11 +52,7 @@ function setClasses(
|
|
|
51
52
|
const classes = name.slice(6).split('.');
|
|
52
53
|
|
|
53
54
|
if (isReactive(value)) {
|
|
54
|
-
data.
|
|
55
|
-
effect(() => {
|
|
56
|
-
update(value.get());
|
|
57
|
-
}),
|
|
58
|
-
);
|
|
55
|
+
data.mora.subscribers.add(value.subscribe(update));
|
|
59
56
|
} else {
|
|
60
57
|
update(value);
|
|
61
58
|
}
|
|
@@ -82,11 +79,7 @@ function setStyle(
|
|
|
82
79
|
|
|
83
80
|
if (property != null) {
|
|
84
81
|
if (isReactive(value)) {
|
|
85
|
-
data.
|
|
86
|
-
effect(() => {
|
|
87
|
-
update(value.get());
|
|
88
|
-
}),
|
|
89
|
-
);
|
|
82
|
+
data.mora.subscribers.add(value.subscribe(update));
|
|
90
83
|
} else {
|
|
91
84
|
update(value);
|
|
92
85
|
}
|
|
@@ -107,9 +100,9 @@ function setValue(
|
|
|
107
100
|
: setAttr;
|
|
108
101
|
|
|
109
102
|
if (isReactive(value)) {
|
|
110
|
-
data.
|
|
111
|
-
|
|
112
|
-
callback(element, name,
|
|
103
|
+
data.mora.subscribers.add(
|
|
104
|
+
value.subscribe(next => {
|
|
105
|
+
callback(element, name, next);
|
|
113
106
|
}),
|
|
114
107
|
);
|
|
115
108
|
} else {
|
package/src/node/event.ts
CHANGED
package/src/node/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {GenericCallback} from '@oscarpalmer/atoms/models';
|
|
2
|
-
import {computed, isReactive} from '@oscarpalmer/
|
|
3
|
-
import {
|
|
2
|
+
import {computed, isReactive} from '@oscarpalmer/mora';
|
|
3
|
+
import {isHTMLOrSVGElement} from '@oscarpalmer/toretto/is';
|
|
4
|
+
import {isFragment} from '../helpers';
|
|
4
5
|
import {createNodes} from '../helpers/dom';
|
|
5
6
|
import type {FragmentData} from '../models';
|
|
6
7
|
import {mapAttributes} from './attribute';
|
|
@@ -78,7 +79,7 @@ function setComputedValue(
|
|
|
78
79
|
): void {
|
|
79
80
|
const value = computed(callback);
|
|
80
81
|
|
|
81
|
-
data.
|
|
82
|
+
data.mora.values.add(value);
|
|
82
83
|
|
|
83
84
|
setReactiveValue(data, comment, value);
|
|
84
85
|
}
|
package/src/node/value.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {isNullableOrWhitespace} from '@oscarpalmer/atoms/is';
|
|
2
2
|
import type {Key} from '@oscarpalmer/atoms/models';
|
|
3
3
|
import {getString} from '@oscarpalmer/atoms/string';
|
|
4
|
-
import
|
|
4
|
+
import type {Reactive} from '@oscarpalmer/mora';
|
|
5
|
+
import {isChildNode} from '@oscarpalmer/toretto/is';
|
|
5
6
|
import type {Fragment} from '../fragment';
|
|
6
|
-
import {compareArrays,
|
|
7
|
+
import {compareArrays, isFragment} from '../helpers';
|
|
7
8
|
import {createNodes, replaceNodes} from '../helpers/dom';
|
|
8
9
|
import type {FragmentData, FragmentItem} from '../models';
|
|
9
10
|
|
|
@@ -147,7 +148,7 @@ function setNodes(
|
|
|
147
148
|
export function setReactiveValue(
|
|
148
149
|
data: FragmentData,
|
|
149
150
|
comment: Comment,
|
|
150
|
-
reactive: Reactive
|
|
151
|
+
reactive: Reactive<unknown>,
|
|
151
152
|
): void {
|
|
152
153
|
const item = data.items.find(item => item.nodes.includes(comment));
|
|
153
154
|
const text = new Text();
|
|
@@ -155,10 +156,8 @@ export function setReactiveValue(
|
|
|
155
156
|
let fragments: Fragment[] | undefined;
|
|
156
157
|
let nodes: ChildNode[] | undefined;
|
|
157
158
|
|
|
158
|
-
data.
|
|
159
|
-
|
|
160
|
-
const value = reactive.get();
|
|
161
|
-
|
|
159
|
+
data.mora.subscribers.add(
|
|
160
|
+
reactive.subscribe(value => {
|
|
162
161
|
if (Array.isArray(value)) {
|
|
163
162
|
const result = setArray(fragments, nodes, comment, text, value);
|
|
164
163
|
|