@oscarpalmer/abydon 0.13.0 → 0.15.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 +790 -763
- package/dist/constants.js +10 -0
- package/dist/fragment.js +38 -17
- package/dist/fragments.js +74 -0
- package/dist/helpers/dom.js +4 -4
- package/dist/helpers/index.js +4 -1
- package/dist/index.js +5 -1
- package/dist/node/attribute/index.js +19 -14
- package/dist/node/attribute/value.js +10 -12
- package/dist/node/event.js +7 -9
- package/dist/node/index.js +9 -4
- package/dist/node/value.js +84 -64
- package/dist/parse.js +7 -7
- package/package.json +14 -16
- package/src/constants.ts +20 -0
- package/src/fragment.ts +92 -29
- package/src/fragments.ts +134 -0
- package/src/helpers/dom.ts +3 -3
- package/src/helpers/index.ts +10 -0
- package/src/index.ts +16 -1
- package/src/models.ts +18 -4
- package/src/node/attribute/index.ts +24 -19
- package/src/node/attribute/value.ts +31 -28
- package/src/node/event.ts +11 -12
- package/src/node/index.ts +15 -6
- package/src/node/value.ts +186 -116
- package/src/parse.ts +10 -3
- package/types/constants.d.ts +9 -0
- package/types/fragment.d.ts +26 -8
- package/types/fragments.d.ts +13 -0
- package/types/helpers/index.d.ts +2 -0
- package/types/index.d.ts +5 -1
- package/types/models.d.ts +16 -4
- package/types/fragment.d.cts +0 -27
- package/types/helpers/dom.d.cts +0 -7
- package/types/helpers/index.d.cts +0 -29
- package/types/index.d.cts +0 -302
- package/types/models.d.cts +0 -107
- package/types/node/attribute/index.d.cts +0 -109
- package/types/node/attribute/value.d.cts +0 -109
- package/types/node/event.d.cts +0 -7
- package/types/node/index.d.cts +0 -108
- package/types/node/value.d.cts +0 -108
- package/types/parse.d.cts +0 -108
|
@@ -6,12 +6,14 @@ import {
|
|
|
6
6
|
setAttribute as setAttr,
|
|
7
7
|
} from '@oscarpalmer/toretto/attribute';
|
|
8
8
|
import type {HTMLOrSVGElement} from '@oscarpalmer/toretto/models';
|
|
9
|
+
import {
|
|
10
|
+
ATTRIBUTE_CLASS_PREFIX_LENGTH,
|
|
11
|
+
EXPRESSION_ATTRIBUTE_CLASS,
|
|
12
|
+
EXPRESSION_ATTRIBUTE_STYLE_FULL,
|
|
13
|
+
EXPRESSION_ATTRIBUTE_STYLE_PREFIX,
|
|
14
|
+
} from '../../constants';
|
|
9
15
|
import type {FragmentData} from '../../models';
|
|
10
16
|
|
|
11
|
-
const classExpression = /^class\./;
|
|
12
|
-
const styleFullExpression = /^style\.([\w-]+)(?:\.([\w-]+))?$/;
|
|
13
|
-
const stylePrefixExpression = /^style\./;
|
|
14
|
-
|
|
15
17
|
export function setAttribute(
|
|
16
18
|
data: FragmentData,
|
|
17
19
|
element: HTMLOrSVGElement,
|
|
@@ -21,11 +23,11 @@ export function setAttribute(
|
|
|
21
23
|
element.removeAttribute(name);
|
|
22
24
|
|
|
23
25
|
switch (true) {
|
|
24
|
-
case
|
|
26
|
+
case EXPRESSION_ATTRIBUTE_CLASS.test(name):
|
|
25
27
|
setClasses(data, element, name, value);
|
|
26
28
|
return;
|
|
27
29
|
|
|
28
|
-
case
|
|
30
|
+
case EXPRESSION_ATTRIBUTE_STYLE_PREFIX.test(name):
|
|
29
31
|
setStyle(data, element, name, value);
|
|
30
32
|
return;
|
|
31
33
|
|
|
@@ -49,7 +51,7 @@ function setClasses(
|
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
const classes = name.slice(
|
|
54
|
+
const classes = name.slice(ATTRIBUTE_CLASS_PREFIX_LENGTH).split('.');
|
|
53
55
|
|
|
54
56
|
if (isReactive(value)) {
|
|
55
57
|
data.mora.subscribers.add(value.subscribe(update));
|
|
@@ -64,6 +66,12 @@ function setStyle(
|
|
|
64
66
|
name: string,
|
|
65
67
|
value: unknown,
|
|
66
68
|
): void {
|
|
69
|
+
const [, property, unit] = EXPRESSION_ATTRIBUTE_STYLE_FULL.exec(name) ?? [];
|
|
70
|
+
|
|
71
|
+
if (property == null) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
67
75
|
function update(value: unknown): void {
|
|
68
76
|
if (value == null || value === false || (value === true && unit == null)) {
|
|
69
77
|
element.style.removeProperty(property);
|
|
@@ -75,14 +83,10 @@ function setStyle(
|
|
|
75
83
|
}
|
|
76
84
|
}
|
|
77
85
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
data.mora.subscribers.add(value.subscribe(update));
|
|
83
|
-
} else {
|
|
84
|
-
update(value);
|
|
85
|
-
}
|
|
86
|
+
if (isReactive(value)) {
|
|
87
|
+
data.mora.subscribers.add(value.subscribe(update));
|
|
88
|
+
} else {
|
|
89
|
+
update(value);
|
|
86
90
|
}
|
|
87
91
|
}
|
|
88
92
|
|
|
@@ -92,12 +96,17 @@ function setValue(
|
|
|
92
96
|
name: string,
|
|
93
97
|
value: unknown,
|
|
94
98
|
): void {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
let callback: (
|
|
100
|
+
element: HTMLOrSVGElement,
|
|
101
|
+
name: string,
|
|
102
|
+
value: unknown,
|
|
103
|
+
) => void;
|
|
104
|
+
|
|
105
|
+
if (isBooleanAttribute(name) && name in element) {
|
|
106
|
+
callback = name === 'selected' ? updateSelected : updateProperty;
|
|
107
|
+
} else {
|
|
108
|
+
callback = setAttr;
|
|
109
|
+
}
|
|
101
110
|
|
|
102
111
|
if (isReactive(value)) {
|
|
103
112
|
data.mora.subscribers.add(
|
|
@@ -110,12 +119,6 @@ function setValue(
|
|
|
110
119
|
}
|
|
111
120
|
}
|
|
112
121
|
|
|
113
|
-
function triggerSelectChange(select: HTMLSelectElement): void {
|
|
114
|
-
if (select != null) {
|
|
115
|
-
select.dispatchEvent(new Event('change', {bubbles: true}));
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
122
|
function updateProperty(
|
|
120
123
|
element: HTMLOrSVGElement,
|
|
121
124
|
name: string,
|
|
@@ -133,7 +136,7 @@ function updateSelected(
|
|
|
133
136
|
const options = [...(select?.options ?? [])];
|
|
134
137
|
|
|
135
138
|
if (select != null && options.includes(element as HTMLOptionElement)) {
|
|
136
|
-
|
|
139
|
+
select.dispatchEvent(new Event('change', {bubbles: true}));
|
|
137
140
|
}
|
|
138
141
|
|
|
139
142
|
updateProperty(element, name, value);
|
package/src/node/event.ts
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import type {HTMLOrSVGElement} from '@oscarpalmer/toretto/models';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const reason = 'Event removed as element was removed from document by Abydon';
|
|
2
|
+
import {
|
|
3
|
+
ABORT_CONTROLLERS,
|
|
4
|
+
EXPRESSION_EVENT_NAME,
|
|
5
|
+
REASON_EVENT_REMOVED,
|
|
6
|
+
} from '../constants';
|
|
8
7
|
|
|
9
8
|
function getController(element: HTMLOrSVGElement): AbortController {
|
|
10
|
-
let controller =
|
|
9
|
+
let controller = ABORT_CONTROLLERS.get(element);
|
|
11
10
|
|
|
12
11
|
if (controller == null) {
|
|
13
12
|
controller = new AbortController();
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
ABORT_CONTROLLERS.set(element, controller);
|
|
16
15
|
}
|
|
17
16
|
|
|
18
17
|
return controller;
|
|
@@ -24,7 +23,7 @@ function getOptions(options: string): AddEventListenerOptions {
|
|
|
24
23
|
return {
|
|
25
24
|
capture: parts.includes('c') || parts.includes('capture'),
|
|
26
25
|
once: parts.includes('o') || parts.includes('once'),
|
|
27
|
-
passive: !parts.includes('a')
|
|
26
|
+
passive: !(parts.includes('a') || parts.includes('active')),
|
|
28
27
|
};
|
|
29
28
|
}
|
|
30
29
|
|
|
@@ -35,7 +34,7 @@ export function mapEvent(
|
|
|
35
34
|
): void {
|
|
36
35
|
element.removeAttribute(name);
|
|
37
36
|
|
|
38
|
-
const [, type, options] =
|
|
37
|
+
const [, type, options] = EXPRESSION_EVENT_NAME.exec(name) ?? [];
|
|
39
38
|
|
|
40
39
|
if (typeof value === 'function' && type != null) {
|
|
41
40
|
element.addEventListener(type, value as EventListener, {
|
|
@@ -46,6 +45,6 @@ export function mapEvent(
|
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
export function removeEvents(element: HTMLOrSVGElement): void {
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
ABORT_CONTROLLERS.get(element)?.abort(REASON_EVENT_REMOVED);
|
|
49
|
+
ABORT_CONTROLLERS.delete(element);
|
|
51
50
|
}
|
package/src/node/index.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import type {GenericCallback} from '@oscarpalmer/atoms/models';
|
|
2
|
-
import {computed, isReactive} from '@oscarpalmer/mora';
|
|
2
|
+
import {computed, isReactive, Reactive} from '@oscarpalmer/mora';
|
|
3
3
|
import {isHTMLOrSVGElement} from '@oscarpalmer/toretto/is';
|
|
4
|
-
import {
|
|
4
|
+
import {EXPRESSION_COMMENT_CONTENT} from '../constants';
|
|
5
|
+
import {handleFragments} from '../fragments';
|
|
6
|
+
import {isFragment, isFragments} from '../helpers';
|
|
5
7
|
import {createNodes} from '../helpers/dom';
|
|
6
8
|
import type {FragmentData} from '../models';
|
|
7
9
|
import {mapAttributes} from './attribute';
|
|
8
10
|
import {setReactiveValue} from './value';
|
|
9
11
|
|
|
10
|
-
const commentExpression = /^abydon\.(\d+)$/;
|
|
11
|
-
|
|
12
12
|
function mapNode(data: FragmentData, comment: Comment): void {
|
|
13
|
-
const matches =
|
|
13
|
+
const matches = EXPRESSION_COMMENT_CONTENT.exec(comment.textContent ?? '');
|
|
14
14
|
const value = matches == null ? null : data.values[+matches[1]];
|
|
15
15
|
|
|
16
16
|
if (value != null) {
|
|
@@ -46,6 +46,15 @@ function mapValue(data: FragmentData, comment: Comment, value: unknown): void {
|
|
|
46
46
|
setComputedValue(data, comment, value as GenericCallback);
|
|
47
47
|
break;
|
|
48
48
|
|
|
49
|
+
case isFragments(value):
|
|
50
|
+
handleFragments(value, false);
|
|
51
|
+
setReactiveValue(
|
|
52
|
+
data,
|
|
53
|
+
comment,
|
|
54
|
+
value.items as Reactive<unknown[], unknown>,
|
|
55
|
+
);
|
|
56
|
+
break;
|
|
57
|
+
|
|
49
58
|
case isReactive(value):
|
|
50
59
|
setReactiveValue(data, comment, value);
|
|
51
60
|
break;
|
|
@@ -61,7 +70,7 @@ function replaceComment(
|
|
|
61
70
|
comment: Comment,
|
|
62
71
|
value: unknown,
|
|
63
72
|
): void {
|
|
64
|
-
const item = data.items.find(item => item.nodes
|
|
73
|
+
const item = data.items.find(item => item.nodes?.includes(comment));
|
|
65
74
|
const nodes = createNodes(value);
|
|
66
75
|
|
|
67
76
|
if (item != null) {
|
package/src/node/value.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {isNullableOrWhitespace} from '@oscarpalmer/atoms/is';
|
|
2
|
-
import type {Key} from '@oscarpalmer/atoms/models';
|
|
3
2
|
import {getString} from '@oscarpalmer/atoms/string';
|
|
4
3
|
import type {Reactive} from '@oscarpalmer/mora';
|
|
5
4
|
import {isChildNode} from '@oscarpalmer/toretto/is';
|
|
@@ -8,6 +7,94 @@ import {compareArrays, isFragment} from '../helpers';
|
|
|
8
7
|
import {createNodes, replaceNodes} from '../helpers/dom';
|
|
9
8
|
import type {FragmentData, FragmentItem} from '../models';
|
|
10
9
|
|
|
10
|
+
//
|
|
11
|
+
|
|
12
|
+
type Identifiers = {
|
|
13
|
+
next: unknown[];
|
|
14
|
+
previous: (unknown | undefined)[];
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type BaseItems = {
|
|
18
|
+
fragments: Fragment[];
|
|
19
|
+
templates: Fragment[];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type ExtendedItems = {
|
|
23
|
+
next: Fragment[];
|
|
24
|
+
} & BaseItems;
|
|
25
|
+
|
|
26
|
+
//
|
|
27
|
+
|
|
28
|
+
function addToArray(
|
|
29
|
+
identifiers: Identifiers,
|
|
30
|
+
items: ExtendedItems,
|
|
31
|
+
nodes: ChildNode[],
|
|
32
|
+
added: boolean,
|
|
33
|
+
): void {
|
|
34
|
+
let position = nodes[0];
|
|
35
|
+
|
|
36
|
+
const before =
|
|
37
|
+
added && !identifiers.previous.includes(items.templates[0].identifier);
|
|
38
|
+
|
|
39
|
+
const next = items.next.flatMap(fragment =>
|
|
40
|
+
fragment.get().flatMap(node => ({
|
|
41
|
+
identifier: fragment.identifier,
|
|
42
|
+
value: node,
|
|
43
|
+
})),
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const {length} = next;
|
|
47
|
+
|
|
48
|
+
for (let index = 0; index < length; index += 1) {
|
|
49
|
+
const node = next[index];
|
|
50
|
+
|
|
51
|
+
if (!(added && identifiers.previous.includes(node.identifier))) {
|
|
52
|
+
if (index === 0 && before) {
|
|
53
|
+
position.before(node.value);
|
|
54
|
+
} else {
|
|
55
|
+
position.after(node.value);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
position = node.value;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function handleArray(
|
|
64
|
+
identifiers: Identifiers,
|
|
65
|
+
items: BaseItems,
|
|
66
|
+
nodes: ChildNode[],
|
|
67
|
+
): Partial<FragmentItem> {
|
|
68
|
+
const next = items.templates.map(
|
|
69
|
+
template =>
|
|
70
|
+
items.fragments?.find(
|
|
71
|
+
fragment => fragment.identifier === template.identifier,
|
|
72
|
+
) ?? template,
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const comparison = compareArrays(items.fragments ?? [], items.templates);
|
|
76
|
+
|
|
77
|
+
if (comparison !== 'removed') {
|
|
78
|
+
addToArray(identifiers, {...items, next}, nodes, comparison === 'added');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const toRemove =
|
|
82
|
+
items.fragments?.filter(
|
|
83
|
+
fragment => !identifiers.next.includes(fragment.identifier),
|
|
84
|
+
) ?? [];
|
|
85
|
+
|
|
86
|
+
const {length} = toRemove;
|
|
87
|
+
|
|
88
|
+
for (let index = 0; index < length; index += 1) {
|
|
89
|
+
toRemove[index].remove();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
fragments: next,
|
|
94
|
+
nodes: next.flatMap(fragment => fragment.get()),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
11
98
|
function removeFragments(fragments: Fragment[] | undefined): void {
|
|
12
99
|
if (fragments != null) {
|
|
13
100
|
const {length} = fragments;
|
|
@@ -18,16 +105,30 @@ function removeFragments(fragments: Fragment[] | undefined): void {
|
|
|
18
105
|
}
|
|
19
106
|
}
|
|
20
107
|
|
|
108
|
+
function replaceText(
|
|
109
|
+
item: FragmentItem,
|
|
110
|
+
comment: Comment,
|
|
111
|
+
isNullable: boolean,
|
|
112
|
+
): void {
|
|
113
|
+
let to: ChildNode[];
|
|
114
|
+
|
|
115
|
+
if (isNullable) {
|
|
116
|
+
to = [comment];
|
|
117
|
+
} else {
|
|
118
|
+
to = item.text == null ? [] : [item.text];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
replaceNodes(item.nodes ?? [], to);
|
|
122
|
+
}
|
|
123
|
+
|
|
21
124
|
function setArray(
|
|
22
|
-
|
|
23
|
-
nodes: ChildNode[] | undefined,
|
|
125
|
+
item: FragmentItem,
|
|
24
126
|
comment: Comment,
|
|
25
|
-
text: Text,
|
|
26
127
|
value: unknown[],
|
|
27
128
|
): Partial<FragmentItem> | boolean {
|
|
28
129
|
if (value.length === 0) {
|
|
29
130
|
return {
|
|
30
|
-
nodes: setText(
|
|
131
|
+
nodes: setText(item, comment, value),
|
|
31
132
|
};
|
|
32
133
|
}
|
|
33
134
|
|
|
@@ -35,10 +136,10 @@ function setArray(
|
|
|
35
136
|
item => isFragment(item) && item.identifier != null,
|
|
36
137
|
) as Fragment[];
|
|
37
138
|
|
|
38
|
-
const
|
|
39
|
-
const
|
|
139
|
+
const next = templates.map(fragment => fragment.identifier) as unknown[];
|
|
140
|
+
const previous = item.fragments?.map(fragment => fragment.identifier) ?? [];
|
|
40
141
|
|
|
41
|
-
if (new Set(
|
|
142
|
+
if (new Set(next).size !== templates.length) {
|
|
42
143
|
templates = [];
|
|
43
144
|
}
|
|
44
145
|
|
|
@@ -46,16 +147,14 @@ function setArray(
|
|
|
46
147
|
|
|
47
148
|
if (
|
|
48
149
|
noTemplates ||
|
|
49
|
-
nodes == null ||
|
|
50
|
-
|
|
150
|
+
item.nodes == null ||
|
|
151
|
+
previous.some(identifier => identifier == null)
|
|
51
152
|
) {
|
|
52
153
|
return {
|
|
53
154
|
fragments: noTemplates ? undefined : templates,
|
|
54
155
|
nodes: setNodes(
|
|
55
|
-
|
|
56
|
-
nodes,
|
|
156
|
+
item,
|
|
57
157
|
comment,
|
|
58
|
-
text,
|
|
59
158
|
noTemplates
|
|
60
159
|
? value.flatMap(item => createNodes(item))
|
|
61
160
|
: templates.flatMap(template => template.get()),
|
|
@@ -63,84 +162,35 @@ function setArray(
|
|
|
63
162
|
};
|
|
64
163
|
}
|
|
65
164
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
165
|
+
return handleArray(
|
|
166
|
+
{
|
|
167
|
+
next,
|
|
168
|
+
previous,
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
templates,
|
|
172
|
+
fragments: item.fragments ?? [],
|
|
173
|
+
},
|
|
174
|
+
item.nodes,
|
|
71
175
|
);
|
|
72
|
-
|
|
73
|
-
const comparison = compareArrays(fragments ?? [], templates);
|
|
74
|
-
|
|
75
|
-
if (comparison !== 'removed') {
|
|
76
|
-
let position = nodes[0];
|
|
77
|
-
|
|
78
|
-
const before =
|
|
79
|
-
comparison === 'added' &&
|
|
80
|
-
!oldIdentifiers.includes(templates[0].identifier);
|
|
81
|
-
|
|
82
|
-
const items = next.flatMap(fragment =>
|
|
83
|
-
fragment.get().flatMap(node => ({
|
|
84
|
-
identifier: fragment.identifier,
|
|
85
|
-
value: node,
|
|
86
|
-
})),
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
const {length} = items;
|
|
90
|
-
|
|
91
|
-
for (let index = 0; index < length; index += 1) {
|
|
92
|
-
const item = items[index];
|
|
93
|
-
|
|
94
|
-
if (
|
|
95
|
-
comparison === 'dissimilar' ||
|
|
96
|
-
!oldIdentifiers.includes(item.identifier)
|
|
97
|
-
) {
|
|
98
|
-
if (index === 0 && before) {
|
|
99
|
-
position.before(item.value);
|
|
100
|
-
} else {
|
|
101
|
-
position.after(item.value);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
position = item.value;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const toRemove =
|
|
110
|
-
fragments?.filter(
|
|
111
|
-
fragment => !identifiers.includes(fragment.identifier as Key),
|
|
112
|
-
) ?? [];
|
|
113
|
-
|
|
114
|
-
const {length} = toRemove;
|
|
115
|
-
|
|
116
|
-
for (let index = 0; index < length; index += 1) {
|
|
117
|
-
toRemove[index].remove();
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
fragments: next,
|
|
122
|
-
nodes: next.flatMap(fragment => fragment.get()),
|
|
123
|
-
};
|
|
124
176
|
}
|
|
125
177
|
|
|
126
178
|
function setNodes(
|
|
127
|
-
|
|
128
|
-
nodes: ChildNode[] | undefined,
|
|
179
|
+
item: FragmentItem,
|
|
129
180
|
comment: Comment,
|
|
130
|
-
text: Text,
|
|
131
181
|
next: ChildNode[],
|
|
132
182
|
): ChildNode[] {
|
|
133
|
-
if (nodes == null) {
|
|
183
|
+
if (item.nodes == null) {
|
|
134
184
|
if (comment.parentNode != null) {
|
|
135
185
|
replaceNodes([comment], next);
|
|
136
|
-
} else if (text
|
|
137
|
-
replaceNodes([text], next);
|
|
186
|
+
} else if (item.text?.parentNode != null) {
|
|
187
|
+
replaceNodes([item.text], next);
|
|
138
188
|
}
|
|
139
189
|
} else {
|
|
140
|
-
replaceNodes(nodes, next);
|
|
190
|
+
replaceNodes(item.nodes, next);
|
|
141
191
|
}
|
|
142
192
|
|
|
143
|
-
removeFragments(fragments);
|
|
193
|
+
removeFragments(item.fragments);
|
|
144
194
|
|
|
145
195
|
return next;
|
|
146
196
|
}
|
|
@@ -150,71 +200,91 @@ export function setReactiveValue(
|
|
|
150
200
|
comment: Comment,
|
|
151
201
|
reactive: Reactive<unknown>,
|
|
152
202
|
): void {
|
|
153
|
-
|
|
154
|
-
|
|
203
|
+
let item = data.items.find(item => item.nodes?.includes(comment));
|
|
204
|
+
|
|
205
|
+
item ??= {};
|
|
155
206
|
|
|
156
|
-
|
|
157
|
-
let nodes: ChildNode[] | undefined;
|
|
207
|
+
item.text = new Text();
|
|
158
208
|
|
|
159
209
|
data.mora.subscribers.add(
|
|
160
210
|
reactive.subscribe(value => {
|
|
161
211
|
if (Array.isArray(value)) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
fragments = typeof result === 'boolean' ? undefined : result?.fragments;
|
|
165
|
-
|
|
166
|
-
nodes =
|
|
167
|
-
typeof result === 'boolean'
|
|
168
|
-
? result
|
|
169
|
-
? [text]
|
|
170
|
-
: undefined
|
|
171
|
-
: result?.nodes;
|
|
212
|
+
setReactiveValueForArray(item, comment, value);
|
|
172
213
|
} else {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
fragments = valueIsFragment ? [value] : undefined;
|
|
176
|
-
|
|
177
|
-
if (valueIsFragment || isChildNode(value)) {
|
|
178
|
-
nodes = setNodes(fragments, nodes, comment, text, createNodes(value));
|
|
179
|
-
} else {
|
|
180
|
-
nodes = setText(fragments, nodes, comment, text, value);
|
|
181
|
-
}
|
|
214
|
+
setReactiveValueForSingle(item, comment, value);
|
|
182
215
|
}
|
|
183
216
|
|
|
184
|
-
|
|
185
|
-
item.fragments = fragments;
|
|
186
|
-
item.nodes = [...(nodes ?? [comment])];
|
|
187
|
-
}
|
|
217
|
+
item.nodes = [...(item.nodes ?? [comment])];
|
|
188
218
|
}),
|
|
189
219
|
);
|
|
190
220
|
}
|
|
191
221
|
|
|
222
|
+
function setReactiveValueForArray(
|
|
223
|
+
item: FragmentItem,
|
|
224
|
+
comment: Comment,
|
|
225
|
+
value: unknown[],
|
|
226
|
+
): void {
|
|
227
|
+
const result = setArray(item, comment, value);
|
|
228
|
+
|
|
229
|
+
item.fragments = typeof result === 'boolean' ? undefined : result?.fragments;
|
|
230
|
+
|
|
231
|
+
if (typeof result === 'boolean') {
|
|
232
|
+
if (result) {
|
|
233
|
+
item.nodes = item.text == null ? [] : [item.text];
|
|
234
|
+
} else {
|
|
235
|
+
item.nodes = undefined;
|
|
236
|
+
}
|
|
237
|
+
} else {
|
|
238
|
+
item.nodes = result?.nodes;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function setReactiveValueForSingle(
|
|
243
|
+
item: FragmentItem,
|
|
244
|
+
comment: Comment,
|
|
245
|
+
value: unknown,
|
|
246
|
+
): void {
|
|
247
|
+
const valueIsFragment = isFragment(value);
|
|
248
|
+
|
|
249
|
+
item.fragments = valueIsFragment ? [value] : undefined;
|
|
250
|
+
|
|
251
|
+
if (valueIsFragment || isChildNode(value)) {
|
|
252
|
+
item.nodes = setNodes(item, comment, createNodes(value));
|
|
253
|
+
} else {
|
|
254
|
+
item.nodes = setText(item, comment, value);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
192
258
|
function setText(
|
|
193
|
-
|
|
194
|
-
nodes: ChildNode[] | undefined,
|
|
259
|
+
item: FragmentItem,
|
|
195
260
|
comment: Comment,
|
|
196
|
-
text: Text,
|
|
197
261
|
value: unknown,
|
|
198
262
|
): ChildNode[] | undefined {
|
|
199
263
|
const isNullable = isNullableOrWhitespace(value);
|
|
200
264
|
|
|
201
|
-
text
|
|
265
|
+
if (item.text != null) {
|
|
266
|
+
item.text.textContent = isNullable ? '' : getString(value);
|
|
267
|
+
}
|
|
202
268
|
|
|
203
269
|
let result = false;
|
|
204
270
|
|
|
205
|
-
if (nodes != null) {
|
|
206
|
-
|
|
271
|
+
if (item.nodes != null) {
|
|
272
|
+
replaceText(item, comment, isNullable);
|
|
207
273
|
|
|
208
274
|
result = !isNullable;
|
|
209
275
|
} else if (isNullable && comment.parentNode == null) {
|
|
210
|
-
text
|
|
211
|
-
} else if (!isNullable && text
|
|
212
|
-
|
|
276
|
+
item.text?.replaceWith(comment);
|
|
277
|
+
} else if (!isNullable && item?.text?.parentNode == null) {
|
|
278
|
+
if (item.text != null) {
|
|
279
|
+
comment.replaceWith(item.text);
|
|
280
|
+
}
|
|
213
281
|
|
|
214
282
|
result = true;
|
|
215
283
|
}
|
|
216
284
|
|
|
217
|
-
removeFragments(fragments);
|
|
285
|
+
removeFragments(item.fragments);
|
|
218
286
|
|
|
219
|
-
|
|
287
|
+
if (result) {
|
|
288
|
+
return item.text == null ? [] : [item.text];
|
|
289
|
+
}
|
|
220
290
|
}
|
package/src/parse.ts
CHANGED
|
@@ -31,17 +31,24 @@ function handleExpression(
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
export function parse(data: FragmentData): string {
|
|
34
|
+
if (data.template != null) {
|
|
35
|
+
return data.template;
|
|
36
|
+
}
|
|
37
|
+
|
|
34
38
|
const {length} = data.strings;
|
|
35
39
|
|
|
36
|
-
|
|
40
|
+
data.template = '';
|
|
37
41
|
|
|
38
42
|
for (let index = 0; index < length; index += 1) {
|
|
39
|
-
template += handleExpression(
|
|
43
|
+
data.template += handleExpression(
|
|
40
44
|
data,
|
|
41
45
|
data.strings[index],
|
|
42
46
|
data.expressions[index],
|
|
43
47
|
);
|
|
44
48
|
}
|
|
45
49
|
|
|
46
|
-
|
|
50
|
+
data.expressions = [];
|
|
51
|
+
data.strings = [] as never;
|
|
52
|
+
|
|
53
|
+
return data.template;
|
|
47
54
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const ABORT_CONTROLLERS: WeakMap<HTMLOrSVGElement, AbortController>;
|
|
2
|
+
export declare const ATTRIBUTE_CLASS_PREFIX_LENGTH = 6;
|
|
3
|
+
export declare const EXPRESSION_ATTRIBUTE_CLASS: RegExp;
|
|
4
|
+
export declare const EXPRESSION_ATTRIBUTE_STYLE_FULL: RegExp;
|
|
5
|
+
export declare const EXPRESSION_ATTRIBUTE_STYLE_PREFIX: RegExp;
|
|
6
|
+
export declare const EXPRESSION_COMMENT_FULL: RegExp;
|
|
7
|
+
export declare const EXPRESSION_COMMENT_CONTENT: RegExp;
|
|
8
|
+
export declare const EXPRESSION_EVENT_NAME: RegExp;
|
|
9
|
+
export declare const REASON_EVENT_REMOVED = "Event removed as element was removed from document by Abydon";
|
package/types/fragment.d.ts
CHANGED
|
@@ -1,20 +1,38 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FragmentConfiguration } from './models';
|
|
2
2
|
export declare class Fragment {
|
|
3
|
-
private
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
#private;
|
|
4
|
+
/**
|
|
5
|
+
* Fragment identifier
|
|
6
|
+
*/
|
|
7
|
+
get identifier(): unknown;
|
|
6
8
|
constructor(strings: TemplateStringsArray, expressions: unknown[]);
|
|
7
9
|
/**
|
|
8
|
-
*
|
|
10
|
+
* Append the fragment to the given element
|
|
11
|
+
* @param element Element to append to
|
|
9
12
|
*/
|
|
10
13
|
appendTo(element: Element): void;
|
|
11
14
|
/**
|
|
12
|
-
*
|
|
15
|
+
* Configure the fragment
|
|
16
|
+
* @param configuration Configuration options
|
|
17
|
+
* @returns Fragment
|
|
18
|
+
*/
|
|
19
|
+
configure(configuration: FragmentConfiguration): Fragment;
|
|
20
|
+
/**
|
|
21
|
+
* Get a list of the fragment's nodes
|
|
22
|
+
* @returns List of nodes
|
|
13
23
|
*/
|
|
14
24
|
get(): ChildNode[];
|
|
15
|
-
identify(identifier: Key): Fragment;
|
|
16
25
|
/**
|
|
17
|
-
*
|
|
26
|
+
* Set an identifier for the fragment
|
|
27
|
+
*
|
|
28
|
+
* _An identifier can be used to uniquely identify a fragment,
|
|
29
|
+
* which helps prevent re-rendering in certain scenarios._
|
|
30
|
+
* @param identifier Identifier
|
|
31
|
+
* @returns Fragment
|
|
32
|
+
*/
|
|
33
|
+
identify(identifier: unknown): Fragment;
|
|
34
|
+
/**
|
|
35
|
+
* Remove the fragment from the DOM
|
|
18
36
|
*/
|
|
19
37
|
remove(): void;
|
|
20
38
|
}
|