@oscarpalmer/abydon 0.13.0 → 0.14.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 +616 -710
- package/dist/constants.js +10 -0
- package/dist/fragment.js +12 -12
- package/dist/helpers/dom.js +3 -3
- 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 +2 -2
- package/dist/node/value.js +75 -60
- package/dist/parse.js +1 -4
- package/package.json +14 -16
- package/src/constants.ts +20 -0
- package/src/fragment.ts +50 -22
- package/src/helpers/dom.ts +3 -3
- package/src/index.ts +3 -2
- package/src/models.ts +8 -3
- 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 +3 -4
- package/src/node/value.ts +164 -116
- package/src/parse.ts +10 -3
- package/types/constants.d.ts +9 -0
- package/types/fragment.d.ts +3 -5
- package/types/models.d.ts +1 -2
- 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
package/src/helpers/dom.ts
CHANGED
|
@@ -16,7 +16,7 @@ export function createNodes(value: unknown): ChildNode[] {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export function removeNodes(nodes: ChildNode[]): void {
|
|
19
|
-
|
|
19
|
+
sanitizeNodes(nodes);
|
|
20
20
|
|
|
21
21
|
const {length} = nodes;
|
|
22
22
|
|
|
@@ -35,7 +35,7 @@ export function replaceNodes(from: ChildNode[], to: ChildNode[]): void {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
function
|
|
38
|
+
function sanitizeNodes(nodes: ChildNode[]): void {
|
|
39
39
|
const {length} = nodes;
|
|
40
40
|
|
|
41
41
|
for (let index = 0; index < length; index += 1) {
|
|
@@ -46,7 +46,7 @@ function sanitiseNodes(nodes: ChildNode[]): void {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
if (node.hasChildNodes()) {
|
|
49
|
-
|
|
49
|
+
sanitizeNodes([...node.childNodes] as ChildNode[]);
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import '@oscarpalmer/mora';
|
|
2
|
-
import {Fragment} from './fragment';
|
|
2
|
+
import { Fragment } from './fragment';
|
|
3
3
|
|
|
4
4
|
export function html(
|
|
5
5
|
strings: TemplateStringsArray,
|
|
@@ -9,4 +9,5 @@ export function html(
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export * from '@oscarpalmer/mora';
|
|
12
|
-
export type {Fragment} from './fragment';
|
|
12
|
+
export type { Fragment } from './fragment';
|
|
13
|
+
|
package/src/models.ts
CHANGED
|
@@ -1,19 +1,24 @@
|
|
|
1
|
-
import type {Key} from '@oscarpalmer/atoms/models';
|
|
2
1
|
import type {Reactive} from '@oscarpalmer/mora';
|
|
3
2
|
import type {Fragment} from './fragment';
|
|
4
3
|
|
|
4
|
+
export type FragmentConfiguration = {
|
|
5
|
+
identifier?: unknown;
|
|
6
|
+
ignoreCache?: boolean;
|
|
7
|
+
};
|
|
8
|
+
|
|
5
9
|
export type FragmentData = {
|
|
6
10
|
expressions: unknown[];
|
|
7
|
-
identifier?: Key;
|
|
8
11
|
items: FragmentItem[];
|
|
9
12
|
mora: MoraData;
|
|
10
13
|
strings: TemplateStringsArray;
|
|
14
|
+
template?: string;
|
|
11
15
|
values: unknown[];
|
|
12
16
|
};
|
|
13
17
|
|
|
14
18
|
export type FragmentItem = {
|
|
15
19
|
fragments?: Fragment[];
|
|
16
|
-
nodes
|
|
20
|
+
nodes?: ChildNode[];
|
|
21
|
+
text?: Text;
|
|
17
22
|
};
|
|
18
23
|
|
|
19
24
|
type MoraData = {
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import type {GenericCallback} from '@oscarpalmer/atoms/models';
|
|
2
2
|
import {computed, isReactive} from '@oscarpalmer/mora';
|
|
3
|
+
import {isBooleanAttribute, setProperty} from '@oscarpalmer/toretto/attribute';
|
|
3
4
|
import type {HTMLOrSVGElement} from '@oscarpalmer/toretto/models';
|
|
5
|
+
import {EXPRESSION_COMMENT_FULL} from '../../constants';
|
|
4
6
|
import type {FragmentData} from '../../models';
|
|
5
7
|
import {mapEvent} from '../event';
|
|
6
8
|
import {setAttribute} from './value';
|
|
7
9
|
|
|
8
|
-
const commentExpression = /^<!--abydon\.(\d+)-->$/;
|
|
9
|
-
|
|
10
10
|
function getValue(data: FragmentData, original: string): unknown {
|
|
11
|
-
const matches =
|
|
11
|
+
const matches = EXPRESSION_COMMENT_FULL.exec(original ?? '');
|
|
12
12
|
|
|
13
13
|
return matches == null ? original : data.values[+matches[1]];
|
|
14
14
|
}
|
|
@@ -25,14 +25,23 @@ export function mapAttributes(
|
|
|
25
25
|
|
|
26
26
|
const actual = getValue(data, value);
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
28
|
+
switch (true) {
|
|
29
|
+
case name.startsWith('@'):
|
|
30
|
+
mapEvent(element, name, actual);
|
|
31
|
+
break;
|
|
32
|
+
|
|
33
|
+
case name.includes('.') ||
|
|
34
|
+
typeof actual === 'function' ||
|
|
35
|
+
isReactive(actual):
|
|
36
|
+
mapValue(data, element, name, actual);
|
|
37
|
+
break;
|
|
38
|
+
|
|
39
|
+
case isBooleanAttribute(name):
|
|
40
|
+
setProperty(element, name, value);
|
|
41
|
+
break;
|
|
42
|
+
|
|
43
|
+
default:
|
|
44
|
+
break;
|
|
36
45
|
}
|
|
37
46
|
}
|
|
38
47
|
}
|
|
@@ -43,14 +52,10 @@ function mapValue(
|
|
|
43
52
|
name: string,
|
|
44
53
|
value: unknown,
|
|
45
54
|
): void {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
default:
|
|
52
|
-
setAttribute(data, element, name, value);
|
|
53
|
-
break;
|
|
55
|
+
if (typeof value === 'function') {
|
|
56
|
+
setComputedAttribute(data, element, name, value as GenericCallback);
|
|
57
|
+
} else {
|
|
58
|
+
setAttribute(data, element, name, value);
|
|
54
59
|
}
|
|
55
60
|
}
|
|
56
61
|
|
|
@@ -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,15 @@
|
|
|
1
1
|
import type {GenericCallback} from '@oscarpalmer/atoms/models';
|
|
2
2
|
import {computed, isReactive} from '@oscarpalmer/mora';
|
|
3
3
|
import {isHTMLOrSVGElement} from '@oscarpalmer/toretto/is';
|
|
4
|
+
import {EXPRESSION_COMMENT_CONTENT} from '../constants';
|
|
4
5
|
import {isFragment} from '../helpers';
|
|
5
6
|
import {createNodes} from '../helpers/dom';
|
|
6
7
|
import type {FragmentData} from '../models';
|
|
7
8
|
import {mapAttributes} from './attribute';
|
|
8
9
|
import {setReactiveValue} from './value';
|
|
9
10
|
|
|
10
|
-
const commentExpression = /^abydon\.(\d+)$/;
|
|
11
|
-
|
|
12
11
|
function mapNode(data: FragmentData, comment: Comment): void {
|
|
13
|
-
const matches =
|
|
12
|
+
const matches = EXPRESSION_COMMENT_CONTENT.exec(comment.textContent ?? '');
|
|
14
13
|
const value = matches == null ? null : data.values[+matches[1]];
|
|
15
14
|
|
|
16
15
|
if (value != null) {
|
|
@@ -61,7 +60,7 @@ function replaceComment(
|
|
|
61
60
|
comment: Comment,
|
|
62
61
|
value: unknown,
|
|
63
62
|
): void {
|
|
64
|
-
const item = data.items.find(item => item.nodes
|
|
63
|
+
const item = data.items.find(item => item.nodes?.includes(comment));
|
|
65
64
|
const nodes = createNodes(value);
|
|
66
65
|
|
|
67
66
|
if (item != null) {
|