@oscarpalmer/abydon 0.10.0 → 0.12.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/fragment.mjs +27 -10
- package/dist/helpers/dom.mjs +3 -3
- package/dist/helpers/index.mjs +6 -6
- package/dist/index.js +369 -261
- package/dist/index.mjs +1 -0
- package/dist/node/attribute/index.mjs +9 -4
- package/dist/node/attribute/value.mjs +13 -13
- package/dist/node/event.mjs +3 -4
- package/dist/node/index.mjs +10 -5
- package/dist/node/value.mjs +6 -6
- package/package.json +1 -1
- package/src/fragment.ts +53 -11
- package/src/helpers/dom.ts +13 -16
- package/src/helpers/index.ts +25 -6
- package/src/index.ts +1 -0
- package/src/models.ts +12 -5
- package/src/node/attribute/index.ts +24 -6
- package/src/node/attribute/value.ts +37 -19
- package/src/node/event.ts +9 -9
- package/src/node/index.ts +21 -9
- package/src/node/value.ts +173 -39
- package/types/fragment.d.ts +4 -2
- package/types/helpers/dom.d.ts +3 -4
- package/types/helpers/index.d.ts +4 -3
- package/types/index.d.cts +5 -2
- package/types/index.d.ts +1 -0
- package/types/models.d.ts +12 -4
- package/types/node/attribute/index.d.ts +2 -2
- package/types/node/attribute/value.d.ts +2 -2
- package/types/node/event.d.ts +3 -3
- package/types/node/index.d.ts +2 -2
- package/types/node/value.d.ts +1 -1
package/dist/index.mjs
CHANGED
|
@@ -15,20 +15,25 @@ function mapAttributes(data, element) {
|
|
|
15
15
|
if (name.startsWith("@")) {
|
|
16
16
|
mapEvent(element, name, actual);
|
|
17
17
|
} else if (name.includes(".") || typeof value2 === "function" || isReactive(actual)) {
|
|
18
|
-
mapValue(element, name, actual);
|
|
18
|
+
mapValue(data, element, name, actual);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
-
function mapValue(element, name, value2) {
|
|
22
|
+
function mapValue(data, element, name, value2) {
|
|
23
23
|
switch (true) {
|
|
24
24
|
case typeof value2 === "function":
|
|
25
|
-
|
|
25
|
+
setComputedAttribute(data, element, name, value2);
|
|
26
26
|
break;
|
|
27
27
|
default:
|
|
28
|
-
setAttribute(element, name, value2);
|
|
28
|
+
setAttribute(data, element, name, value2);
|
|
29
29
|
break;
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
+
function setComputedAttribute(data, element, name, callback) {
|
|
33
|
+
const value2 = computed(callback);
|
|
34
|
+
data.sentinel.values.add(value2);
|
|
35
|
+
setAttribute(data, element, name, value2);
|
|
36
|
+
}
|
|
32
37
|
var commentExpression = /^<!--abydon\.(\d+)-->$/;
|
|
33
38
|
export {
|
|
34
39
|
mapAttributes
|
|
@@ -5,21 +5,21 @@ import {
|
|
|
5
5
|
isBooleanAttribute,
|
|
6
6
|
setAttribute as setAttr
|
|
7
7
|
} from "@oscarpalmer/toretto/attribute";
|
|
8
|
-
function setAttribute(element, name, value) {
|
|
8
|
+
function setAttribute(data, element, name, value) {
|
|
9
9
|
element.removeAttribute(name);
|
|
10
10
|
switch (true) {
|
|
11
11
|
case classExpression.test(name):
|
|
12
|
-
setClasses(element, name, value);
|
|
12
|
+
setClasses(data, element, name, value);
|
|
13
13
|
return;
|
|
14
14
|
case stylePrefixExpression.test(name):
|
|
15
|
-
setStyle(element, name, value);
|
|
15
|
+
setStyle(data, element, name, value);
|
|
16
16
|
return;
|
|
17
17
|
default:
|
|
18
|
-
setValue(element, name, value);
|
|
18
|
+
setValue(data, element, name, value);
|
|
19
19
|
break;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
-
function setClasses(element, name, value) {
|
|
22
|
+
function setClasses(data, element, name, value) {
|
|
23
23
|
function update(value2) {
|
|
24
24
|
if (value2 === true) {
|
|
25
25
|
element.classList.add(...classes);
|
|
@@ -29,14 +29,14 @@ function setClasses(element, name, value) {
|
|
|
29
29
|
}
|
|
30
30
|
const classes = name.slice(6).split(".");
|
|
31
31
|
if (isReactive(value)) {
|
|
32
|
-
effect(() => {
|
|
32
|
+
data.sentinel.effects.add(effect(() => {
|
|
33
33
|
update(value.get());
|
|
34
|
-
});
|
|
34
|
+
}));
|
|
35
35
|
} else {
|
|
36
36
|
update(value);
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
function setStyle(element, name, value) {
|
|
39
|
+
function setStyle(data, element, name, value) {
|
|
40
40
|
function update(value2) {
|
|
41
41
|
if (value2 == null || value2 === false || value2 === true && unit == null) {
|
|
42
42
|
element.style.removeProperty(property);
|
|
@@ -47,20 +47,20 @@ function setStyle(element, name, value) {
|
|
|
47
47
|
const [, property, unit] = styleFullExpression.exec(name) ?? [];
|
|
48
48
|
if (property != null) {
|
|
49
49
|
if (isReactive(value)) {
|
|
50
|
-
effect(() => {
|
|
50
|
+
data.sentinel.effects.add(effect(() => {
|
|
51
51
|
update(value.get());
|
|
52
|
-
});
|
|
52
|
+
}));
|
|
53
53
|
} else {
|
|
54
54
|
update(value);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
function setValue(element, name, value) {
|
|
58
|
+
function setValue(data, element, name, value) {
|
|
59
59
|
const callback = isBooleanAttribute(name) && name in element ? name === "selected" ? updateSelected : updateProperty : setAttr;
|
|
60
60
|
if (isReactive(value)) {
|
|
61
|
-
effect(() => {
|
|
61
|
+
data.sentinel.effects.add(effect(() => {
|
|
62
62
|
callback(element, name, value.get());
|
|
63
|
-
});
|
|
63
|
+
}));
|
|
64
64
|
} else {
|
|
65
65
|
callback(element, name, value);
|
|
66
66
|
}
|
package/dist/node/event.mjs
CHANGED
|
@@ -26,13 +26,12 @@ function mapEvent(element, name, value) {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
function removeEvents(element) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
controllers.delete(element);
|
|
32
|
-
}
|
|
29
|
+
controllers.get(element)?.abort(reason);
|
|
30
|
+
controllers.delete(element);
|
|
33
31
|
}
|
|
34
32
|
var controllers = new WeakMap;
|
|
35
33
|
var eventNamePattern = /^@([\w-]+)(?::([a-z:]+))?$/i;
|
|
34
|
+
var reason = "Event removed as element was removed from document by Abydon";
|
|
36
35
|
export {
|
|
37
36
|
removeEvents,
|
|
38
37
|
mapEvent
|
package/dist/node/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// src/node/index.ts
|
|
2
2
|
import {computed, isReactive} from "@oscarpalmer/sentinel";
|
|
3
|
-
import {isFragment,
|
|
3
|
+
import {isFragment, isHTMLOrSVGElement} from "../helpers";
|
|
4
4
|
import {createNodes} from "../helpers/dom";
|
|
5
5
|
import {mapAttributes} from "./attribute";
|
|
6
|
-
import {
|
|
6
|
+
import {setReactiveValue} from "./value";
|
|
7
7
|
function mapNode(data, comment) {
|
|
8
8
|
const matches = commentExpression.exec(comment.textContent ?? "");
|
|
9
9
|
const value2 = matches == null ? null : data.values[+matches[1]];
|
|
@@ -19,7 +19,7 @@ function mapNodes(data, nodes) {
|
|
|
19
19
|
mapNode(data, node);
|
|
20
20
|
continue;
|
|
21
21
|
}
|
|
22
|
-
if (
|
|
22
|
+
if (isHTMLOrSVGElement(node)) {
|
|
23
23
|
mapAttributes(data, node);
|
|
24
24
|
}
|
|
25
25
|
if (node.hasChildNodes()) {
|
|
@@ -30,10 +30,10 @@ function mapNodes(data, nodes) {
|
|
|
30
30
|
function mapValue(data, comment, value2) {
|
|
31
31
|
switch (true) {
|
|
32
32
|
case typeof value2 === "function":
|
|
33
|
-
|
|
33
|
+
setComputedValue(data, comment, value2);
|
|
34
34
|
break;
|
|
35
35
|
case isReactive(value2):
|
|
36
|
-
|
|
36
|
+
setReactiveValue(data, comment, value2);
|
|
37
37
|
break;
|
|
38
38
|
default:
|
|
39
39
|
replaceComment(data, comment, value2);
|
|
@@ -49,6 +49,11 @@ function replaceComment(data, comment, value2) {
|
|
|
49
49
|
}
|
|
50
50
|
comment.replaceWith(...nodes);
|
|
51
51
|
}
|
|
52
|
+
function setComputedValue(data, comment, callback) {
|
|
53
|
+
const value2 = computed(callback);
|
|
54
|
+
data.sentinel.values.add(value2);
|
|
55
|
+
setReactiveValue(data, comment, value2);
|
|
56
|
+
}
|
|
52
57
|
var commentExpression = /^abydon\.(\d+)$/;
|
|
53
58
|
export {
|
|
54
59
|
mapNodes
|
package/dist/node/value.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {isNullableOrWhitespace} from "@oscarpalmer/atoms/is";
|
|
3
3
|
import {getString} from "@oscarpalmer/atoms/string";
|
|
4
4
|
import {effect} from "@oscarpalmer/sentinel";
|
|
5
|
-
import {compareArrays,
|
|
5
|
+
import {compareArrays, isChildNode, isFragment} from "../helpers";
|
|
6
6
|
import {createNodes, replaceNodes} from "../helpers/dom";
|
|
7
7
|
function removeFragments(fragments) {
|
|
8
8
|
if (fragments != null) {
|
|
@@ -76,12 +76,12 @@ function setNodes(fragments, nodes, comment, text, next) {
|
|
|
76
76
|
removeFragments(fragments);
|
|
77
77
|
return next;
|
|
78
78
|
}
|
|
79
|
-
function
|
|
79
|
+
function setReactiveValue(data, comment, reactive) {
|
|
80
80
|
const item = data.items.find((item2) => item2.nodes.includes(comment));
|
|
81
81
|
const text = new Text;
|
|
82
82
|
let fragments;
|
|
83
83
|
let nodes;
|
|
84
|
-
effect(() => {
|
|
84
|
+
data.sentinel.effects.add(effect(() => {
|
|
85
85
|
const value = reactive.get();
|
|
86
86
|
if (Array.isArray(value)) {
|
|
87
87
|
const result = setArray(fragments, nodes, comment, text, value);
|
|
@@ -90,7 +90,7 @@ function setReactiveNode(data, comment, reactive) {
|
|
|
90
90
|
} else {
|
|
91
91
|
const valueIsFragment = isFragment(value);
|
|
92
92
|
fragments = valueIsFragment ? [value] : undefined;
|
|
93
|
-
if (valueIsFragment ||
|
|
93
|
+
if (valueIsFragment || isChildNode(value)) {
|
|
94
94
|
nodes = setNodes(fragments, nodes, comment, text, createNodes(value));
|
|
95
95
|
} else {
|
|
96
96
|
nodes = setText(fragments, nodes, comment, text, value);
|
|
@@ -100,7 +100,7 @@ function setReactiveNode(data, comment, reactive) {
|
|
|
100
100
|
item.fragments = fragments;
|
|
101
101
|
item.nodes = [...nodes ?? [comment]];
|
|
102
102
|
}
|
|
103
|
-
});
|
|
103
|
+
}));
|
|
104
104
|
}
|
|
105
105
|
function setText(fragments, nodes, comment, text, value) {
|
|
106
106
|
const isNullable = isNullableOrWhitespace(value);
|
|
@@ -119,5 +119,5 @@ function setText(fragments, nodes, comment, text, value) {
|
|
|
119
119
|
return result ? [text] : undefined;
|
|
120
120
|
}
|
|
121
121
|
export {
|
|
122
|
-
|
|
122
|
+
setReactiveValue
|
|
123
123
|
};
|
package/package.json
CHANGED
package/src/fragment.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type {Key} from '@oscarpalmer/atoms/models';
|
|
1
2
|
import {html} from '@oscarpalmer/toretto/html';
|
|
2
3
|
import {parse} from './html';
|
|
3
|
-
import type {FragmentData
|
|
4
|
+
import type {FragmentData} from './models';
|
|
4
5
|
import {mapNodes} from './node';
|
|
5
6
|
import {removeNodes} from './helpers/dom';
|
|
6
7
|
|
|
@@ -8,11 +9,19 @@ export class Fragment {
|
|
|
8
9
|
private readonly $fragment = true;
|
|
9
10
|
private readonly data: FragmentData;
|
|
10
11
|
|
|
12
|
+
get identifier(): Key | undefined {
|
|
13
|
+
return this.data.identifier;
|
|
14
|
+
}
|
|
15
|
+
|
|
11
16
|
constructor(strings: TemplateStringsArray, expressions: unknown[]) {
|
|
12
17
|
this.data = {
|
|
13
18
|
expressions,
|
|
14
19
|
strings,
|
|
15
20
|
items: [],
|
|
21
|
+
sentinel: {
|
|
22
|
+
effects: new Set(),
|
|
23
|
+
values: new Set(),
|
|
24
|
+
},
|
|
16
25
|
values: [],
|
|
17
26
|
};
|
|
18
27
|
}
|
|
@@ -27,7 +36,7 @@ export class Fragment {
|
|
|
27
36
|
/**
|
|
28
37
|
* Gets a list of the fragment's nodes
|
|
29
38
|
*/
|
|
30
|
-
get():
|
|
39
|
+
get(): ChildNode[] {
|
|
31
40
|
if (this.data.items.length === 0) {
|
|
32
41
|
const parsed = parse(this.data);
|
|
33
42
|
|
|
@@ -39,35 +48,68 @@ export class Fragment {
|
|
|
39
48
|
0,
|
|
40
49
|
this.data.items.length,
|
|
41
50
|
...templated.map(node => ({
|
|
42
|
-
nodes: [node as
|
|
51
|
+
nodes: [node as ChildNode],
|
|
43
52
|
})),
|
|
44
53
|
);
|
|
45
54
|
|
|
46
55
|
mapNodes(
|
|
47
56
|
this.data,
|
|
48
|
-
this.data.items.flatMap(
|
|
57
|
+
this.data.items.flatMap(
|
|
58
|
+
item =>
|
|
59
|
+
item.fragments?.flatMap(fragment => fragment.get()) ?? item.nodes,
|
|
60
|
+
),
|
|
49
61
|
);
|
|
50
62
|
}
|
|
51
63
|
|
|
52
64
|
return [
|
|
53
|
-
...this.data.items.flatMap(
|
|
65
|
+
...this.data.items.flatMap(
|
|
66
|
+
item =>
|
|
67
|
+
item.fragments?.flatMap(fragment => fragment.get()) ?? item.nodes,
|
|
68
|
+
),
|
|
54
69
|
];
|
|
55
70
|
}
|
|
56
71
|
|
|
72
|
+
identify(identifier: Key): Fragment {
|
|
73
|
+
this.data.identifier = identifier;
|
|
74
|
+
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
|
|
57
78
|
/**
|
|
58
79
|
* Removes the fragment from the DOM
|
|
59
80
|
*/
|
|
60
81
|
remove(): void {
|
|
61
|
-
|
|
82
|
+
removeFragment(this.data);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
62
85
|
|
|
63
|
-
|
|
64
|
-
|
|
86
|
+
function removeFragment(data: FragmentData): void {
|
|
87
|
+
removeSentinels(data);
|
|
65
88
|
|
|
66
|
-
|
|
89
|
+
const {length} = data.items;
|
|
67
90
|
|
|
68
|
-
|
|
91
|
+
for (let index = 0; index < length; index += 1) {
|
|
92
|
+
const {fragments, nodes} = data.items[index];
|
|
93
|
+
const {length} = fragments ?? [];
|
|
94
|
+
|
|
95
|
+
for (let index = 0; index < length; index += 1) {
|
|
96
|
+
fragments?.[index]?.remove();
|
|
69
97
|
}
|
|
70
98
|
|
|
71
|
-
|
|
99
|
+
removeNodes(nodes);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
data.items.splice(0, length);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function removeSentinels(data: FragmentData): void {
|
|
106
|
+
const sentinels = [...data.sentinel.effects, ...data.sentinel.values];
|
|
107
|
+
const {length} = sentinels;
|
|
108
|
+
|
|
109
|
+
for (let index = 0; index < length; index += 1) {
|
|
110
|
+
sentinels[index].stop();
|
|
72
111
|
}
|
|
112
|
+
|
|
113
|
+
data.sentinel.effects.clear();
|
|
114
|
+
data.sentinel.values.clear();
|
|
73
115
|
}
|
package/src/helpers/dom.ts
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import {getString} from '@oscarpalmer/atoms/string';
|
|
2
|
-
import
|
|
3
|
-
import {isFragment, isProperElement, isProperNode} from './index';
|
|
2
|
+
import {isChildNode, isFragment, isHTMLOrSVGElement} from './index';
|
|
4
3
|
import {removeEvents} from '../node/event';
|
|
5
4
|
|
|
6
|
-
export function createNodes(value: unknown):
|
|
5
|
+
export function createNodes(value: unknown): ChildNode[] {
|
|
7
6
|
if (isFragment(value)) {
|
|
8
|
-
return value.get() as
|
|
7
|
+
return value.get() as ChildNode[];
|
|
9
8
|
}
|
|
10
9
|
|
|
11
|
-
if (
|
|
10
|
+
if (isChildNode(value)) {
|
|
12
11
|
return [value];
|
|
13
12
|
}
|
|
14
13
|
|
|
15
14
|
return [new Text(getString(value))];
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
export function removeNodes(nodes:
|
|
17
|
+
export function removeNodes(nodes: ChildNode[]): void {
|
|
19
18
|
sanitiseNodes(nodes);
|
|
20
19
|
|
|
21
20
|
const {length} = nodes;
|
|
@@ -25,30 +24,28 @@ export function removeNodes(nodes: ProperNode[]): void {
|
|
|
25
24
|
}
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
export function replaceNodes(from:
|
|
27
|
+
export function replaceNodes(from: ChildNode[], to: ChildNode[]): void {
|
|
28
|
+
from[0]?.replaceWith(...to);
|
|
29
|
+
|
|
29
30
|
const {length} = from;
|
|
30
31
|
|
|
31
|
-
for (let index =
|
|
32
|
-
|
|
33
|
-
from[index].replaceWith(...to);
|
|
34
|
-
} else {
|
|
35
|
-
from[index].remove();
|
|
36
|
-
}
|
|
32
|
+
for (let index = 1; index < length; index += 1) {
|
|
33
|
+
from[index].remove();
|
|
37
34
|
}
|
|
38
35
|
}
|
|
39
36
|
|
|
40
|
-
function sanitiseNodes(nodes:
|
|
37
|
+
function sanitiseNodes(nodes: ChildNode[]): void {
|
|
41
38
|
const {length} = nodes;
|
|
42
39
|
|
|
43
40
|
for (let index = 0; index < length; index += 1) {
|
|
44
41
|
const node = nodes[index];
|
|
45
42
|
|
|
46
|
-
if (
|
|
43
|
+
if (isHTMLOrSVGElement(node)) {
|
|
47
44
|
removeEvents(node);
|
|
48
45
|
}
|
|
49
46
|
|
|
50
47
|
if (node.hasChildNodes()) {
|
|
51
|
-
sanitiseNodes([...node.childNodes] as
|
|
48
|
+
sanitiseNodes([...node.childNodes] as ChildNode[]);
|
|
52
49
|
}
|
|
53
50
|
}
|
|
54
51
|
}
|
package/src/helpers/index.ts
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
import type {Fragment} from '../fragment';
|
|
2
|
-
import type {
|
|
2
|
+
import type {HTMLOrSVGElement} from '../models';
|
|
3
|
+
|
|
4
|
+
export function compareArrays(
|
|
5
|
+
first: unknown[],
|
|
6
|
+
second: unknown[],
|
|
7
|
+
): 'added' | 'dissimilar' | 'removed' {
|
|
8
|
+
const firstIsLarger = first.length > second.length;
|
|
9
|
+
const from = firstIsLarger ? first : second;
|
|
10
|
+
const to = firstIsLarger ? second : first;
|
|
11
|
+
|
|
12
|
+
if (
|
|
13
|
+
!from
|
|
14
|
+
.filter(key => to.includes(key))
|
|
15
|
+
.every((key, index) => to[index] === key)
|
|
16
|
+
) {
|
|
17
|
+
return 'dissimilar';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return firstIsLarger ? 'removed' : 'added';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function isChildNode(value: unknown): value is ChildNode {
|
|
24
|
+
return value instanceof CharacterData || value instanceof Element;
|
|
25
|
+
}
|
|
3
26
|
|
|
4
27
|
export function isFragment(value: unknown): value is Fragment {
|
|
5
28
|
return (
|
|
@@ -10,10 +33,6 @@ export function isFragment(value: unknown): value is Fragment {
|
|
|
10
33
|
);
|
|
11
34
|
}
|
|
12
35
|
|
|
13
|
-
export function
|
|
36
|
+
export function isHTMLOrSVGElement(value: unknown): value is HTMLOrSVGElement {
|
|
14
37
|
return value instanceof HTMLElement || value instanceof SVGElement;
|
|
15
38
|
}
|
|
16
|
-
|
|
17
|
-
export function isProperNode(value: unknown): value is ProperNode {
|
|
18
|
-
return value instanceof CharacterData || value instanceof Element;
|
|
19
|
-
}
|
package/src/index.ts
CHANGED
package/src/models.ts
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
|
+
import type {Key} from '@oscarpalmer/atoms/models';
|
|
2
|
+
import type {Effect, Reactive} from '@oscarpalmer/sentinel';
|
|
1
3
|
import type {Fragment} from './fragment';
|
|
2
4
|
|
|
3
5
|
export type FragmentData = {
|
|
4
6
|
expressions: unknown[];
|
|
7
|
+
identifier?: Key;
|
|
5
8
|
items: FragmentItem[];
|
|
9
|
+
sentinel: FragmentDataSentinel;
|
|
6
10
|
strings: TemplateStringsArray;
|
|
7
11
|
values: unknown[];
|
|
8
12
|
};
|
|
9
13
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
type FragmentDataSentinel = {
|
|
15
|
+
effects: Set<Effect>;
|
|
16
|
+
values: Set<Reactive>;
|
|
13
17
|
};
|
|
14
18
|
|
|
15
|
-
export type
|
|
19
|
+
export type FragmentItem = {
|
|
20
|
+
fragments?: Fragment[];
|
|
21
|
+
nodes: ChildNode[];
|
|
22
|
+
};
|
|
16
23
|
|
|
17
|
-
export type
|
|
24
|
+
export type HTMLOrSVGElement = HTMLElement | SVGElement;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type {GenericCallback} from '@oscarpalmer/atoms/models';
|
|
2
2
|
import {computed, isReactive} from '@oscarpalmer/sentinel';
|
|
3
|
-
import type {FragmentData,
|
|
3
|
+
import type {FragmentData, HTMLOrSVGElement} from '../../models';
|
|
4
4
|
import {mapEvent} from '../event';
|
|
5
5
|
import {setAttribute} from './value';
|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ function getValue(data: FragmentData, original: string): unknown {
|
|
|
14
14
|
|
|
15
15
|
export function mapAttributes(
|
|
16
16
|
data: FragmentData,
|
|
17
|
-
element:
|
|
17
|
+
element: HTMLOrSVGElement,
|
|
18
18
|
): void {
|
|
19
19
|
const attributes = [...element.attributes];
|
|
20
20
|
const {length} = attributes;
|
|
@@ -31,19 +31,37 @@ export function mapAttributes(
|
|
|
31
31
|
typeof value === 'function' ||
|
|
32
32
|
isReactive(actual)
|
|
33
33
|
) {
|
|
34
|
-
mapValue(element, name, actual);
|
|
34
|
+
mapValue(data, element, name, actual);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
function mapValue(
|
|
39
|
+
function mapValue(
|
|
40
|
+
data: FragmentData,
|
|
41
|
+
element: HTMLOrSVGElement,
|
|
42
|
+
name: string,
|
|
43
|
+
value: unknown,
|
|
44
|
+
): void {
|
|
40
45
|
switch (true) {
|
|
41
46
|
case typeof value === 'function':
|
|
42
|
-
|
|
47
|
+
setComputedAttribute(data, element, name, value as GenericCallback);
|
|
43
48
|
break;
|
|
44
49
|
|
|
45
50
|
default:
|
|
46
|
-
setAttribute(element, name, value);
|
|
51
|
+
setAttribute(data, element, name, value);
|
|
47
52
|
break;
|
|
48
53
|
}
|
|
49
54
|
}
|
|
55
|
+
|
|
56
|
+
function setComputedAttribute(
|
|
57
|
+
data: FragmentData,
|
|
58
|
+
element: HTMLOrSVGElement,
|
|
59
|
+
name: string,
|
|
60
|
+
callback: GenericCallback,
|
|
61
|
+
): void {
|
|
62
|
+
const value = computed(callback);
|
|
63
|
+
|
|
64
|
+
data.sentinel.values.add(value);
|
|
65
|
+
|
|
66
|
+
setAttribute(data, element, name, value);
|
|
67
|
+
}
|
|
@@ -5,14 +5,15 @@ import {
|
|
|
5
5
|
isBooleanAttribute,
|
|
6
6
|
setAttribute as setAttr,
|
|
7
7
|
} from '@oscarpalmer/toretto/attribute';
|
|
8
|
-
import type {
|
|
8
|
+
import type {FragmentData, HTMLOrSVGElement} from '../../models';
|
|
9
9
|
|
|
10
10
|
const classExpression = /^class\./;
|
|
11
11
|
const styleFullExpression = /^style\.([\w-]+)(?:\.([\w-]+))?$/;
|
|
12
12
|
const stylePrefixExpression = /^style\./;
|
|
13
13
|
|
|
14
14
|
export function setAttribute(
|
|
15
|
-
|
|
15
|
+
data: FragmentData,
|
|
16
|
+
element: HTMLOrSVGElement,
|
|
16
17
|
name: string,
|
|
17
18
|
value: unknown,
|
|
18
19
|
): void {
|
|
@@ -20,21 +21,22 @@ export function setAttribute(
|
|
|
20
21
|
|
|
21
22
|
switch (true) {
|
|
22
23
|
case classExpression.test(name):
|
|
23
|
-
setClasses(element, name, value);
|
|
24
|
+
setClasses(data, element, name, value);
|
|
24
25
|
return;
|
|
25
26
|
|
|
26
27
|
case stylePrefixExpression.test(name):
|
|
27
|
-
setStyle(element, name, value);
|
|
28
|
+
setStyle(data, element, name, value);
|
|
28
29
|
return;
|
|
29
30
|
|
|
30
31
|
default:
|
|
31
|
-
setValue(element, name, value);
|
|
32
|
+
setValue(data, element, name, value);
|
|
32
33
|
break;
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
function setClasses(
|
|
37
|
-
|
|
38
|
+
data: FragmentData,
|
|
39
|
+
element: HTMLOrSVGElement,
|
|
38
40
|
name: string,
|
|
39
41
|
value: unknown,
|
|
40
42
|
): void {
|
|
@@ -49,15 +51,22 @@ function setClasses(
|
|
|
49
51
|
const classes = name.slice(6).split('.');
|
|
50
52
|
|
|
51
53
|
if (isReactive(value)) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
data.sentinel.effects.add(
|
|
55
|
+
effect(() => {
|
|
56
|
+
update(value.get());
|
|
57
|
+
}),
|
|
58
|
+
);
|
|
55
59
|
} else {
|
|
56
60
|
update(value);
|
|
57
61
|
}
|
|
58
62
|
}
|
|
59
63
|
|
|
60
|
-
function setStyle(
|
|
64
|
+
function setStyle(
|
|
65
|
+
data: FragmentData,
|
|
66
|
+
element: HTMLOrSVGElement,
|
|
67
|
+
name: string,
|
|
68
|
+
value: unknown,
|
|
69
|
+
): void {
|
|
61
70
|
function update(value: unknown): void {
|
|
62
71
|
if (value == null || value === false || (value === true && unit == null)) {
|
|
63
72
|
element.style.removeProperty(property);
|
|
@@ -73,16 +82,23 @@ function setStyle(element: ProperElement, name: string, value: unknown): void {
|
|
|
73
82
|
|
|
74
83
|
if (property != null) {
|
|
75
84
|
if (isReactive(value)) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
85
|
+
data.sentinel.effects.add(
|
|
86
|
+
effect(() => {
|
|
87
|
+
update(value.get());
|
|
88
|
+
}),
|
|
89
|
+
);
|
|
79
90
|
} else {
|
|
80
91
|
update(value);
|
|
81
92
|
}
|
|
82
93
|
}
|
|
83
94
|
}
|
|
84
95
|
|
|
85
|
-
function setValue(
|
|
96
|
+
function setValue(
|
|
97
|
+
data: FragmentData,
|
|
98
|
+
element: HTMLOrSVGElement,
|
|
99
|
+
name: string,
|
|
100
|
+
value: unknown,
|
|
101
|
+
): void {
|
|
86
102
|
const callback =
|
|
87
103
|
isBooleanAttribute(name) && name in element
|
|
88
104
|
? name === 'selected'
|
|
@@ -91,9 +107,11 @@ function setValue(element: ProperElement, name: string, value: unknown): void {
|
|
|
91
107
|
: setAttr;
|
|
92
108
|
|
|
93
109
|
if (isReactive(value)) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
110
|
+
data.sentinel.effects.add(
|
|
111
|
+
effect(() => {
|
|
112
|
+
callback(element, name, value.get());
|
|
113
|
+
}),
|
|
114
|
+
);
|
|
97
115
|
} else {
|
|
98
116
|
callback(element, name, value);
|
|
99
117
|
}
|
|
@@ -106,7 +124,7 @@ function triggerSelectChange(select: HTMLSelectElement): void {
|
|
|
106
124
|
}
|
|
107
125
|
|
|
108
126
|
function updateProperty(
|
|
109
|
-
element:
|
|
127
|
+
element: HTMLOrSVGElement,
|
|
110
128
|
name: string,
|
|
111
129
|
value: unknown,
|
|
112
130
|
): void {
|
|
@@ -114,7 +132,7 @@ function updateProperty(
|
|
|
114
132
|
}
|
|
115
133
|
|
|
116
134
|
function updateSelected(
|
|
117
|
-
element:
|
|
135
|
+
element: HTMLOrSVGElement,
|
|
118
136
|
name: string,
|
|
119
137
|
value: unknown,
|
|
120
138
|
): void {
|