@oscarpalmer/abydon 0.19.0 → 0.21.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.mjs +682 -145
- package/dist/constants.d.mts +3 -1
- package/dist/constants.mjs +3 -1
- package/dist/fragment.d.mts +41 -1
- package/dist/fragments.d.mts +2 -1
- package/dist/helpers/dom.d.mts +1 -1
- package/dist/helpers/dom.mjs +1 -1
- package/dist/helpers/index.d.mts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/models.d.mts +43 -1
- package/dist/node/attribute/index.d.mts +1 -1
- package/dist/node/attribute/index.mjs +8 -3
- package/dist/node/attribute/value.d.mts +1 -1
- package/dist/node/index.d.mts +1 -1
- package/dist/node/index.mjs +24 -2
- package/dist/node/value.d.mts +1 -1
- package/dist/parse.d.mts +1 -1
- package/package.json +7 -7
- package/src/constants.ts +4 -0
- package/src/helpers/dom.ts +2 -8
- package/src/node/attribute/index.ts +18 -2
- package/src/node/index.ts +54 -2
- package/dist/fragment-9qTBAvtR.d.mts +0 -82
package/dist/constants.d.mts
CHANGED
|
@@ -27,6 +27,8 @@ declare const EXPRESSION_EVENT_OPTIONS_CAPTURE: RegExp;
|
|
|
27
27
|
declare const EXPRESSION_EVENT_OPTIONS_ONCE: RegExp;
|
|
28
28
|
declare const EXPRESSION_EVENT_PREFIX: RegExp;
|
|
29
29
|
declare const EXPRESSION_PERIOD: RegExp;
|
|
30
|
+
declare const EXPRESSION_TEXTAREA_VALUE: RegExp;
|
|
31
|
+
declare const INPUT_TYPE_CHECKBOX = "checkbox";
|
|
30
32
|
declare const NAME_FRAGMENT = "$fragment";
|
|
31
33
|
declare const NAME_FRAGMENTS = "$fragments";
|
|
32
34
|
declare const PROPERTY_CHECKED = "checked";
|
|
@@ -34,4 +36,4 @@ declare const PROPERTY_IDENTIFIER = "identifier";
|
|
|
34
36
|
declare const PROPERTY_VALUE = "value";
|
|
35
37
|
declare const TEMPLATE_ITEM = "<>";
|
|
36
38
|
//#endregion
|
|
37
|
-
export { ARRAY_COMPARISON_ADDED, ARRAY_COMPARISON_DISSIMILAR, ARRAY_COMPARISON_REMOVED, ATTRIBUTE_CLASS_PREFIX_LENGTH, ATTRIBUTE_NAME_DELIMITER, ERROR_FRAGMENT, ERROR_IDENTIFIER_DUPLICATE, ERROR_IDENTIFIER_TYPE, EVENT_CHANGE, EVENT_DEFAULTS, EVENT_INPUT, EVENT_ON_PREFIXED, EVENT_ON_VALUE, EVENT_OPTIONS_DELIMITER, EVENT_SUBMIT, EXPRESSION_ABYDON_ATTRIBUTE_FULL, EXPRESSION_ABYDON_ATTRIBUTE_PREFIX, EXPRESSION_ABYDON_CONTENT, EXPRESSION_ATTRIBUTE_CLASS, EXPRESSION_ATTRIBUTE_STYLE_FULL, EXPRESSION_ATTRIBUTE_STYLE_PREFIX, EXPRESSION_EVENT_CHANGE_TYPES, EXPRESSION_EVENT_NAME, EXPRESSION_EVENT_OPTIONS_ACTIVE, EXPRESSION_EVENT_OPTIONS_CAPTURE, EXPRESSION_EVENT_OPTIONS_ONCE, EXPRESSION_EVENT_PREFIX, EXPRESSION_PERIOD, NAME_FRAGMENT, NAME_FRAGMENTS, PROPERTY_CHECKED, PROPERTY_IDENTIFIER, PROPERTY_VALUE, TEMPLATE_ITEM };
|
|
39
|
+
export { ARRAY_COMPARISON_ADDED, ARRAY_COMPARISON_DISSIMILAR, ARRAY_COMPARISON_REMOVED, ATTRIBUTE_CLASS_PREFIX_LENGTH, ATTRIBUTE_NAME_DELIMITER, ERROR_FRAGMENT, ERROR_IDENTIFIER_DUPLICATE, ERROR_IDENTIFIER_TYPE, EVENT_CHANGE, EVENT_DEFAULTS, EVENT_INPUT, EVENT_ON_PREFIXED, EVENT_ON_VALUE, EVENT_OPTIONS_DELIMITER, EVENT_SUBMIT, EXPRESSION_ABYDON_ATTRIBUTE_FULL, EXPRESSION_ABYDON_ATTRIBUTE_PREFIX, EXPRESSION_ABYDON_CONTENT, EXPRESSION_ATTRIBUTE_CLASS, EXPRESSION_ATTRIBUTE_STYLE_FULL, EXPRESSION_ATTRIBUTE_STYLE_PREFIX, EXPRESSION_EVENT_CHANGE_TYPES, EXPRESSION_EVENT_NAME, EXPRESSION_EVENT_OPTIONS_ACTIVE, EXPRESSION_EVENT_OPTIONS_CAPTURE, EXPRESSION_EVENT_OPTIONS_ONCE, EXPRESSION_EVENT_PREFIX, EXPRESSION_PERIOD, EXPRESSION_TEXTAREA_VALUE, INPUT_TYPE_CHECKBOX, NAME_FRAGMENT, NAME_FRAGMENTS, PROPERTY_CHECKED, PROPERTY_IDENTIFIER, PROPERTY_VALUE, TEMPLATE_ITEM };
|
package/dist/constants.mjs
CHANGED
|
@@ -34,6 +34,8 @@ const EXPRESSION_EVENT_OPTIONS_CAPTURE = /^c(apture)$/i;
|
|
|
34
34
|
const EXPRESSION_EVENT_OPTIONS_ONCE = /^o(nce)$/i;
|
|
35
35
|
const EXPRESSION_EVENT_PREFIX = /^@/;
|
|
36
36
|
const EXPRESSION_PERIOD = /\./;
|
|
37
|
+
const EXPRESSION_TEXTAREA_VALUE = /<!--abydon\.(\d+)-->/;
|
|
38
|
+
const INPUT_TYPE_CHECKBOX = "checkbox";
|
|
37
39
|
const NAME_FRAGMENT = "$fragment";
|
|
38
40
|
const NAME_FRAGMENTS = "$fragments";
|
|
39
41
|
const PROPERTY_CHECKED = "checked";
|
|
@@ -41,4 +43,4 @@ const PROPERTY_IDENTIFIER = "identifier";
|
|
|
41
43
|
const PROPERTY_VALUE = "value";
|
|
42
44
|
const TEMPLATE_ITEM = "<>";
|
|
43
45
|
//#endregion
|
|
44
|
-
export { ARRAY_COMPARISON_ADDED, ARRAY_COMPARISON_DISSIMILAR, ARRAY_COMPARISON_REMOVED, ATTRIBUTE_CLASS_PREFIX_LENGTH, ATTRIBUTE_NAME_DELIMITER, ERROR_FRAGMENT, ERROR_IDENTIFIER_DUPLICATE, ERROR_IDENTIFIER_TYPE, EVENT_CHANGE, EVENT_DEFAULTS, EVENT_INPUT, EVENT_ON_PREFIXED, EVENT_ON_VALUE, EVENT_OPTIONS_DELIMITER, EVENT_SUBMIT, EXPRESSION_ABYDON_ATTRIBUTE_FULL, EXPRESSION_ABYDON_ATTRIBUTE_PREFIX, EXPRESSION_ABYDON_CONTENT, EXPRESSION_ATTRIBUTE_CLASS, EXPRESSION_ATTRIBUTE_STYLE_FULL, EXPRESSION_ATTRIBUTE_STYLE_PREFIX, EXPRESSION_EVENT_CHANGE_TYPES, EXPRESSION_EVENT_NAME, EXPRESSION_EVENT_OPTIONS_ACTIVE, EXPRESSION_EVENT_OPTIONS_CAPTURE, EXPRESSION_EVENT_OPTIONS_ONCE, EXPRESSION_EVENT_PREFIX, EXPRESSION_PERIOD, NAME_FRAGMENT, NAME_FRAGMENTS, PROPERTY_CHECKED, PROPERTY_IDENTIFIER, PROPERTY_VALUE, TEMPLATE_ITEM };
|
|
46
|
+
export { ARRAY_COMPARISON_ADDED, ARRAY_COMPARISON_DISSIMILAR, ARRAY_COMPARISON_REMOVED, ATTRIBUTE_CLASS_PREFIX_LENGTH, ATTRIBUTE_NAME_DELIMITER, ERROR_FRAGMENT, ERROR_IDENTIFIER_DUPLICATE, ERROR_IDENTIFIER_TYPE, EVENT_CHANGE, EVENT_DEFAULTS, EVENT_INPUT, EVENT_ON_PREFIXED, EVENT_ON_VALUE, EVENT_OPTIONS_DELIMITER, EVENT_SUBMIT, EXPRESSION_ABYDON_ATTRIBUTE_FULL, EXPRESSION_ABYDON_ATTRIBUTE_PREFIX, EXPRESSION_ABYDON_CONTENT, EXPRESSION_ATTRIBUTE_CLASS, EXPRESSION_ATTRIBUTE_STYLE_FULL, EXPRESSION_ATTRIBUTE_STYLE_PREFIX, EXPRESSION_EVENT_CHANGE_TYPES, EXPRESSION_EVENT_NAME, EXPRESSION_EVENT_OPTIONS_ACTIVE, EXPRESSION_EVENT_OPTIONS_CAPTURE, EXPRESSION_EVENT_OPTIONS_ONCE, EXPRESSION_EVENT_PREFIX, EXPRESSION_PERIOD, EXPRESSION_TEXTAREA_VALUE, INPUT_TYPE_CHECKBOX, NAME_FRAGMENT, NAME_FRAGMENTS, PROPERTY_CHECKED, PROPERTY_IDENTIFIER, PROPERTY_VALUE, TEMPLATE_ITEM };
|
package/dist/fragment.d.mts
CHANGED
|
@@ -1,2 +1,42 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FragmentConfiguration } from "./models.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/fragment.d.ts
|
|
4
|
+
declare class Fragment {
|
|
5
|
+
#private;
|
|
6
|
+
/**
|
|
7
|
+
* Fragment identifier
|
|
8
|
+
*/
|
|
9
|
+
get identifier(): unknown;
|
|
10
|
+
constructor(strings: TemplateStringsArray, expressions: unknown[]);
|
|
11
|
+
/**
|
|
12
|
+
* Append the fragment to the given element
|
|
13
|
+
* @param element Element to append to
|
|
14
|
+
*/
|
|
15
|
+
appendTo(element: Element): void;
|
|
16
|
+
/**
|
|
17
|
+
* Configure the fragment
|
|
18
|
+
* @param configuration Configuration options
|
|
19
|
+
* @returns Fragment
|
|
20
|
+
*/
|
|
21
|
+
configure(configuration: FragmentConfiguration): Fragment;
|
|
22
|
+
/**
|
|
23
|
+
* Get a list of the fragment's nodes
|
|
24
|
+
* @returns List of nodes
|
|
25
|
+
*/
|
|
26
|
+
get(): ChildNode[];
|
|
27
|
+
/**
|
|
28
|
+
* Set an identifier for the fragment
|
|
29
|
+
*
|
|
30
|
+
* _An identifier can be used to uniquely identify a fragment,
|
|
31
|
+
* which helps prevent re-rendering in certain scenarios._
|
|
32
|
+
* @param identifier Identifier
|
|
33
|
+
* @returns Fragment
|
|
34
|
+
*/
|
|
35
|
+
identify(identifier: unknown): Fragment;
|
|
36
|
+
/**
|
|
37
|
+
* Remove the fragment from the DOM
|
|
38
|
+
*/
|
|
39
|
+
remove(): void;
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
2
42
|
export { Fragment };
|
package/dist/fragments.d.mts
CHANGED
package/dist/helpers/dom.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/helpers/dom.d.ts
|
|
2
2
|
declare function createNodes(value: unknown): ChildNode[];
|
|
3
|
-
declare function isInputElement(node: Node): node is HTMLInputElement | HTMLSelectElement
|
|
3
|
+
declare function isInputElement(node: Node): node is HTMLInputElement | HTMLSelectElement;
|
|
4
4
|
declare function removeNodes(nodes: ChildNode[]): void;
|
|
5
5
|
declare function replaceNodes(from: ChildNode[], to: ChildNode[]): void;
|
|
6
6
|
//#endregion
|
package/dist/helpers/dom.mjs
CHANGED
|
@@ -8,7 +8,7 @@ function createNodes(value) {
|
|
|
8
8
|
return [new Text(getString(value))];
|
|
9
9
|
}
|
|
10
10
|
function isInputElement(node) {
|
|
11
|
-
return node instanceof HTMLInputElement || node instanceof HTMLSelectElement
|
|
11
|
+
return node instanceof HTMLInputElement || node instanceof HTMLSelectElement;
|
|
12
12
|
}
|
|
13
13
|
function removeNodes(nodes) {
|
|
14
14
|
const { length } = nodes;
|
package/dist/helpers/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ARRAY_COMPARISON_ADDED, ARRAY_COMPARISON_DISSIMILAR, ARRAY_COMPARISON_REMOVED } from "../constants.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { Fragment } from "../fragment.mjs";
|
|
3
3
|
import { Fragments } from "../fragments.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/helpers/index.d.ts
|
package/dist/index.d.mts
CHANGED
package/dist/models.d.mts
CHANGED
|
@@ -1,2 +1,44 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Fragment } from "./fragment.mjs";
|
|
2
|
+
import { Reactive, ReactiveArray, Unsubscribe } from "@oscarpalmer/mora";
|
|
3
|
+
|
|
4
|
+
//#region src/models.d.ts
|
|
5
|
+
type FragmentConfiguration = {
|
|
6
|
+
/**
|
|
7
|
+
* Should the template be cached? _(defaults to `true`)_
|
|
8
|
+
*/
|
|
9
|
+
cache?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Identifier for the fragment
|
|
12
|
+
*
|
|
13
|
+
* _(An identifier can be used to uniquely identify a fragment,
|
|
14
|
+
* which helps prevent re-rendering in certain scenarios)_
|
|
15
|
+
*/
|
|
16
|
+
identifier?: unknown;
|
|
17
|
+
};
|
|
18
|
+
type FragmentData = {
|
|
19
|
+
expressions: unknown[];
|
|
20
|
+
items: FragmentItem[];
|
|
21
|
+
mora: MoraData;
|
|
22
|
+
strings: TemplateStringsArray;
|
|
23
|
+
template?: string;
|
|
24
|
+
values: unknown[];
|
|
25
|
+
};
|
|
26
|
+
type FragmentItem = {
|
|
27
|
+
fragments?: Fragment[];
|
|
28
|
+
nodes?: ChildNode[];
|
|
29
|
+
text?: Text;
|
|
30
|
+
};
|
|
31
|
+
type FragmentsState = {
|
|
32
|
+
array: ReactiveArray<unknown>;
|
|
33
|
+
fragment: (item: unknown) => Fragment;
|
|
34
|
+
identify: (item: unknown) => unknown;
|
|
35
|
+
instances: Record<string, Fragment>;
|
|
36
|
+
mapped: ReactiveArray<Fragment>;
|
|
37
|
+
subscriber: Unsubscribe | undefined;
|
|
38
|
+
};
|
|
39
|
+
type MoraData = {
|
|
40
|
+
subscribers: Set<() => void>;
|
|
41
|
+
values: Set<Reactive<unknown>>;
|
|
42
|
+
};
|
|
43
|
+
//#endregion
|
|
2
44
|
export { FragmentConfiguration, FragmentData, FragmentItem, FragmentsState };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EXPRESSION_ABYDON_ATTRIBUTE_PREFIX, EXPRESSION_ABYDON_CONTENT, EXPRESSION_EVENT_PREFIX, EXPRESSION_PERIOD } from "../../constants.mjs";
|
|
1
|
+
import { EXPRESSION_ABYDON_ATTRIBUTE_PREFIX, EXPRESSION_ABYDON_CONTENT, EXPRESSION_EVENT_PREFIX, EXPRESSION_PERIOD, PROPERTY_CHECKED, PROPERTY_VALUE } from "../../constants.mjs";
|
|
2
2
|
import { isInputElement } from "../../helpers/dom.mjs";
|
|
3
3
|
import { mapEvent } from "../event.mjs";
|
|
4
4
|
import { setAttribute } from "./value.mjs";
|
|
@@ -33,8 +33,13 @@ function mapAttributes(data, element) {
|
|
|
33
33
|
function mapValue(data, element, name, value) {
|
|
34
34
|
if (typeof value === "function") setComputedAttribute(data, element, name, value);
|
|
35
35
|
else setAttribute(data, element, name, value);
|
|
36
|
-
if (
|
|
37
|
-
|
|
36
|
+
if (!isInputElement(element) || !isSignal(value)) return;
|
|
37
|
+
let property;
|
|
38
|
+
if (name === "checked" && element.type === "checkbox") property = PROPERTY_CHECKED;
|
|
39
|
+
else if (name === "value") property = PROPERTY_VALUE;
|
|
40
|
+
if (property != null) mapEvent(element, "@on", () => {
|
|
41
|
+
const next = element[property];
|
|
42
|
+
value.set(parse(String(next)) ?? next);
|
|
38
43
|
});
|
|
39
44
|
}
|
|
40
45
|
function setComputedAttribute(data, element, name, callback) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FragmentData } from "../../models.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/node/attribute/value.d.ts
|
|
4
4
|
declare function setAttribute(data: FragmentData, element: HTMLElement | SVGElement, name: string, value: unknown): void;
|
package/dist/node/index.d.mts
CHANGED
package/dist/node/index.mjs
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { EXPRESSION_ABYDON_CONTENT } from "../constants.mjs";
|
|
1
|
+
import { EXPRESSION_ABYDON_CONTENT, EXPRESSION_TEXTAREA_VALUE } from "../constants.mjs";
|
|
2
2
|
import { isFragment, isFragments } from "../helpers/index.mjs";
|
|
3
3
|
import { handleFragments } from "../fragments.mjs";
|
|
4
4
|
import { createNodes } from "../helpers/dom.mjs";
|
|
5
|
+
import { mapEvent } from "./event.mjs";
|
|
5
6
|
import { mapAttributes } from "./attribute/index.mjs";
|
|
6
7
|
import { setReactiveValue } from "./value.mjs";
|
|
7
|
-
import { computed, isReactive } from "@oscarpalmer/mora";
|
|
8
|
+
import { computed, isComputed, isReactive, isSignal } from "@oscarpalmer/mora";
|
|
8
9
|
import { isHTMLOrSVGElement } from "@oscarpalmer/toretto/is";
|
|
9
10
|
//#region src/node/index.ts
|
|
10
11
|
function mapNode(data, comment) {
|
|
@@ -20,10 +21,31 @@ function mapNodes(data, nodes) {
|
|
|
20
21
|
mapNode(data, node);
|
|
21
22
|
continue;
|
|
22
23
|
}
|
|
24
|
+
if (node instanceof HTMLTextAreaElement) mapTextarea(data, node);
|
|
23
25
|
if (isHTMLOrSVGElement(node)) mapAttributes(data, node);
|
|
24
26
|
if (node.hasChildNodes()) mapNodes(data, [...node.childNodes]);
|
|
25
27
|
}
|
|
26
28
|
}
|
|
29
|
+
function mapTextarea(data, element) {
|
|
30
|
+
const [, index] = EXPRESSION_TEXTAREA_VALUE.exec(element.value) ?? [];
|
|
31
|
+
if (index == null) return;
|
|
32
|
+
element.value = "";
|
|
33
|
+
const value = data.values[Number.parseInt(index, 10)];
|
|
34
|
+
if (isSignal(value)) {
|
|
35
|
+
element.value = String(value.peek());
|
|
36
|
+
mapEvent(element, "@on", () => {
|
|
37
|
+
value.set(element.value);
|
|
38
|
+
});
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
let reactive;
|
|
42
|
+
if (typeof value === "function") reactive = computed(value);
|
|
43
|
+
else if (isComputed(value)) reactive = value;
|
|
44
|
+
if (reactive == null) element.value = String(value);
|
|
45
|
+
else data.mora.subscribers.add(reactive.subscribe((value) => {
|
|
46
|
+
element.value = String(value);
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
27
49
|
function mapValue(data, comment, value) {
|
|
28
50
|
switch (true) {
|
|
29
51
|
case typeof value === "function":
|
package/dist/node/value.d.mts
CHANGED
package/dist/parse.d.mts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oscarpalmer/abydon",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"components",
|
|
6
6
|
"dom",
|
|
@@ -42,15 +42,15 @@
|
|
|
42
42
|
"test:leak": "npx vp test run --detect-async-leaks --coverage"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@oscarpalmer/atoms": "^0.
|
|
46
|
-
"@oscarpalmer/mora": "^0.
|
|
47
|
-
"@oscarpalmer/toretto": "^0.
|
|
45
|
+
"@oscarpalmer/atoms": "^0.183",
|
|
46
|
+
"@oscarpalmer/mora": "^0.28",
|
|
47
|
+
"@oscarpalmer/toretto": "^0.42"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@oscarpalmer/oui": "^0.
|
|
51
|
-
"@types/node": "^25.
|
|
50
|
+
"@oscarpalmer/oui": "^0.20",
|
|
51
|
+
"@types/node": "^25.6",
|
|
52
52
|
"@vitest/coverage-istanbul": "^4.1",
|
|
53
|
-
"jsdom": "^
|
|
53
|
+
"jsdom": "^29",
|
|
54
54
|
"tsdown": "^0.21",
|
|
55
55
|
"typescript": "^5.9",
|
|
56
56
|
"vite": "npm:@voidzero-dev/vite-plus-core@latest",
|
package/src/constants.ts
CHANGED
|
@@ -61,6 +61,10 @@ export const EXPRESSION_EVENT_PREFIX = /^@/;
|
|
|
61
61
|
|
|
62
62
|
export const EXPRESSION_PERIOD = /\./;
|
|
63
63
|
|
|
64
|
+
export const EXPRESSION_TEXTAREA_VALUE = /<!--abydon\.(\d+)-->/;
|
|
65
|
+
|
|
66
|
+
export const INPUT_TYPE_CHECKBOX = 'checkbox';
|
|
67
|
+
|
|
64
68
|
export const NAME_FRAGMENT = '$fragment';
|
|
65
69
|
|
|
66
70
|
export const NAME_FRAGMENTS = '$fragments';
|
package/src/helpers/dom.ts
CHANGED
|
@@ -14,14 +14,8 @@ export function createNodes(value: unknown): ChildNode[] {
|
|
|
14
14
|
return [new Text(getString(value))];
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export function isInputElement(
|
|
18
|
-
node
|
|
19
|
-
): node is HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement {
|
|
20
|
-
return (
|
|
21
|
-
node instanceof HTMLInputElement ||
|
|
22
|
-
node instanceof HTMLSelectElement ||
|
|
23
|
-
node instanceof HTMLTextAreaElement
|
|
24
|
-
);
|
|
17
|
+
export function isInputElement(node: Node): node is HTMLInputElement | HTMLSelectElement {
|
|
18
|
+
return node instanceof HTMLInputElement || node instanceof HTMLSelectElement;
|
|
25
19
|
}
|
|
26
20
|
|
|
27
21
|
export function removeNodes(nodes: ChildNode[]): void {
|
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
EXPRESSION_ABYDON_CONTENT,
|
|
8
8
|
EXPRESSION_EVENT_PREFIX,
|
|
9
9
|
EXPRESSION_PERIOD,
|
|
10
|
+
INPUT_TYPE_CHECKBOX,
|
|
11
|
+
PROPERTY_CHECKED,
|
|
10
12
|
PROPERTY_VALUE,
|
|
11
13
|
} from '../../constants';
|
|
12
14
|
import {isInputElement} from '../../helpers/dom';
|
|
@@ -63,9 +65,23 @@ function mapValue(
|
|
|
63
65
|
setAttribute(data, element, name, value);
|
|
64
66
|
}
|
|
65
67
|
|
|
66
|
-
if (
|
|
68
|
+
if (!isInputElement(element) || !isSignal(value)) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let property: string | undefined;
|
|
73
|
+
|
|
74
|
+
if (name === PROPERTY_CHECKED && element.type === INPUT_TYPE_CHECKBOX) {
|
|
75
|
+
property = PROPERTY_CHECKED;
|
|
76
|
+
} else if (name === PROPERTY_VALUE) {
|
|
77
|
+
property = PROPERTY_VALUE;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (property != null) {
|
|
67
81
|
mapEvent(element, EVENT_ON_PREFIXED, () => {
|
|
68
|
-
|
|
82
|
+
const next = element[property as keyof typeof element];
|
|
83
|
+
|
|
84
|
+
value.set(parse(String(next)) ?? next);
|
|
69
85
|
});
|
|
70
86
|
}
|
|
71
87
|
}
|
package/src/node/index.ts
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import type {GenericCallback} from '@oscarpalmer/atoms/models';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
computed,
|
|
4
|
+
isComputed,
|
|
5
|
+
isReactive,
|
|
6
|
+
isSignal,
|
|
7
|
+
type Computed,
|
|
8
|
+
type Reactive,
|
|
9
|
+
} from '@oscarpalmer/mora';
|
|
3
10
|
import {isHTMLOrSVGElement} from '@oscarpalmer/toretto/is';
|
|
4
|
-
import {EXPRESSION_ABYDON_CONTENT} from '../constants';
|
|
11
|
+
import {EXPRESSION_ABYDON_CONTENT, EXPRESSION_TEXTAREA_VALUE} from '../constants';
|
|
5
12
|
import {handleFragments} from '../fragments';
|
|
6
13
|
import {isFragment, isFragments} from '../helpers';
|
|
7
14
|
import {createNodes} from '../helpers/dom';
|
|
8
15
|
import type {FragmentData} from '../models';
|
|
9
16
|
import {mapAttributes} from './attribute';
|
|
10
17
|
import {setReactiveValue} from './value';
|
|
18
|
+
import {mapEvent} from './event';
|
|
11
19
|
|
|
12
20
|
function mapNode(data: FragmentData, comment: Comment): void {
|
|
13
21
|
const matches = EXPRESSION_ABYDON_CONTENT.exec(comment.textContent ?? '');
|
|
@@ -30,6 +38,10 @@ export function mapNodes(data: FragmentData, nodes: ChildNode[]): void {
|
|
|
30
38
|
continue;
|
|
31
39
|
}
|
|
32
40
|
|
|
41
|
+
if (node instanceof HTMLTextAreaElement) {
|
|
42
|
+
mapTextarea(data, node);
|
|
43
|
+
}
|
|
44
|
+
|
|
33
45
|
if (isHTMLOrSVGElement(node)) {
|
|
34
46
|
mapAttributes(data, node);
|
|
35
47
|
}
|
|
@@ -40,6 +52,46 @@ export function mapNodes(data: FragmentData, nodes: ChildNode[]): void {
|
|
|
40
52
|
}
|
|
41
53
|
}
|
|
42
54
|
|
|
55
|
+
function mapTextarea(data: FragmentData, element: HTMLTextAreaElement): void {
|
|
56
|
+
const [, index] = EXPRESSION_TEXTAREA_VALUE.exec(element.value) ?? [];
|
|
57
|
+
|
|
58
|
+
if (index == null) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
element.value = '';
|
|
63
|
+
|
|
64
|
+
const value = data.values[Number.parseInt(index, 10)];
|
|
65
|
+
|
|
66
|
+
if (isSignal(value)) {
|
|
67
|
+
element.value = String(value.peek());
|
|
68
|
+
|
|
69
|
+
mapEvent(element, '@on', () => {
|
|
70
|
+
value.set(element.value);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let reactive: Computed<unknown> | undefined;
|
|
77
|
+
|
|
78
|
+
if (typeof value === 'function') {
|
|
79
|
+
reactive = computed(value as GenericCallback);
|
|
80
|
+
} else if (isComputed(value)) {
|
|
81
|
+
reactive = value;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (reactive == null) {
|
|
85
|
+
element.value = String(value);
|
|
86
|
+
} else {
|
|
87
|
+
data.mora.subscribers.add(
|
|
88
|
+
reactive.subscribe(value => {
|
|
89
|
+
element.value = String(value);
|
|
90
|
+
}),
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
43
95
|
function mapValue(data: FragmentData, comment: Comment, value: unknown): void {
|
|
44
96
|
switch (true) {
|
|
45
97
|
case typeof value === 'function':
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { Reactive, ReactiveArray, Unsubscribe } from "@oscarpalmer/mora";
|
|
2
|
-
|
|
3
|
-
//#region src/models.d.ts
|
|
4
|
-
type FragmentConfiguration = {
|
|
5
|
-
/**
|
|
6
|
-
* Should the template be cached? _(defaults to `true`)_
|
|
7
|
-
*/
|
|
8
|
-
cache?: boolean;
|
|
9
|
-
/**
|
|
10
|
-
* Identifier for the fragment
|
|
11
|
-
*
|
|
12
|
-
* _(An identifier can be used to uniquely identify a fragment,
|
|
13
|
-
* which helps prevent re-rendering in certain scenarios)_
|
|
14
|
-
*/
|
|
15
|
-
identifier?: unknown;
|
|
16
|
-
};
|
|
17
|
-
type FragmentData = {
|
|
18
|
-
expressions: unknown[];
|
|
19
|
-
items: FragmentItem[];
|
|
20
|
-
mora: MoraData;
|
|
21
|
-
strings: TemplateStringsArray;
|
|
22
|
-
template?: string;
|
|
23
|
-
values: unknown[];
|
|
24
|
-
};
|
|
25
|
-
type FragmentItem = {
|
|
26
|
-
fragments?: Fragment[];
|
|
27
|
-
nodes?: ChildNode[];
|
|
28
|
-
text?: Text;
|
|
29
|
-
};
|
|
30
|
-
type FragmentsState = {
|
|
31
|
-
array: ReactiveArray<unknown>;
|
|
32
|
-
fragment: (item: unknown) => Fragment;
|
|
33
|
-
identify: (item: unknown) => unknown;
|
|
34
|
-
instances: Record<string, Fragment>;
|
|
35
|
-
mapped: ReactiveArray<Fragment>;
|
|
36
|
-
subscriber: Unsubscribe | undefined;
|
|
37
|
-
};
|
|
38
|
-
type MoraData = {
|
|
39
|
-
subscribers: Set<() => void>;
|
|
40
|
-
values: Set<Reactive<unknown>>;
|
|
41
|
-
};
|
|
42
|
-
//#endregion
|
|
43
|
-
//#region src/fragment.d.ts
|
|
44
|
-
declare class Fragment {
|
|
45
|
-
#private;
|
|
46
|
-
/**
|
|
47
|
-
* Fragment identifier
|
|
48
|
-
*/
|
|
49
|
-
get identifier(): unknown;
|
|
50
|
-
constructor(strings: TemplateStringsArray, expressions: unknown[]);
|
|
51
|
-
/**
|
|
52
|
-
* Append the fragment to the given element
|
|
53
|
-
* @param element Element to append to
|
|
54
|
-
*/
|
|
55
|
-
appendTo(element: Element): void;
|
|
56
|
-
/**
|
|
57
|
-
* Configure the fragment
|
|
58
|
-
* @param configuration Configuration options
|
|
59
|
-
* @returns Fragment
|
|
60
|
-
*/
|
|
61
|
-
configure(configuration: FragmentConfiguration): Fragment;
|
|
62
|
-
/**
|
|
63
|
-
* Get a list of the fragment's nodes
|
|
64
|
-
* @returns List of nodes
|
|
65
|
-
*/
|
|
66
|
-
get(): ChildNode[];
|
|
67
|
-
/**
|
|
68
|
-
* Set an identifier for the fragment
|
|
69
|
-
*
|
|
70
|
-
* _An identifier can be used to uniquely identify a fragment,
|
|
71
|
-
* which helps prevent re-rendering in certain scenarios._
|
|
72
|
-
* @param identifier Identifier
|
|
73
|
-
* @returns Fragment
|
|
74
|
-
*/
|
|
75
|
-
identify(identifier: unknown): Fragment;
|
|
76
|
-
/**
|
|
77
|
-
* Remove the fragment from the DOM
|
|
78
|
-
*/
|
|
79
|
-
remove(): void;
|
|
80
|
-
}
|
|
81
|
-
//#endregion
|
|
82
|
-
export { FragmentsState as a, FragmentItem as i, FragmentConfiguration as n, FragmentData as r, Fragment as t };
|