@oscarpalmer/abydon 0.19.0 → 0.20.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.
@@ -948,6 +948,7 @@ const EXPRESSION_EVENT_OPTIONS_CAPTURE = /^c(apture)$/i;
948
948
  const EXPRESSION_EVENT_OPTIONS_ONCE = /^o(nce)$/i;
949
949
  const EXPRESSION_EVENT_PREFIX = /^@/;
950
950
  const EXPRESSION_PERIOD = /\./;
951
+ const EXPRESSION_TEXTAREA_VALUE = /<!--abydon\.(\d+)-->/;
951
952
  const NAME_FRAGMENT = "$fragment";
952
953
  const NAME_FRAGMENTS = "$fragments";
953
954
  const PROPERTY_CHECKED = "checked";
@@ -1068,7 +1069,7 @@ function createNodes(value) {
1068
1069
  return [new Text(getString(value))];
1069
1070
  }
1070
1071
  function isInputElement(node) {
1071
- return node instanceof HTMLInputElement || node instanceof HTMLSelectElement || node instanceof HTMLTextAreaElement;
1072
+ return node instanceof HTMLInputElement || node instanceof HTMLSelectElement;
1072
1073
  }
1073
1074
  function removeNodes(nodes) {
1074
1075
  const { length } = nodes;
@@ -1312,8 +1313,13 @@ function mapAttributes(data, element) {
1312
1313
  function mapValue$1(data, element, name, value) {
1313
1314
  if (typeof value === "function") setComputedAttribute(data, element, name, value);
1314
1315
  else setAttribute(data, element, name, value);
1315
- if (name === "value" && isInputElement(element) && isSignal(value)) mapEvent(element, "@on", () => {
1316
- value.set(parse$1(element.value) ?? element.value);
1316
+ if (!isInputElement(element) || !isSignal(value)) return;
1317
+ let property;
1318
+ if (name === "checked" && element.type === "checkbox") property = PROPERTY_CHECKED;
1319
+ else if (name === "value") property = PROPERTY_VALUE;
1320
+ if (property != null) mapEvent(element, "@on", () => {
1321
+ const next = element[property];
1322
+ value.set(parse$1(String(next)) ?? next);
1317
1323
  });
1318
1324
  }
1319
1325
  function setComputedAttribute(data, element, name, callback) {
@@ -1445,10 +1451,31 @@ function mapNodes(data, nodes) {
1445
1451
  mapNode(data, node);
1446
1452
  continue;
1447
1453
  }
1454
+ if (node instanceof HTMLTextAreaElement) mapTextarea(data, node);
1448
1455
  if (isHTMLOrSVGElement(node)) mapAttributes(data, node);
1449
1456
  if (node.hasChildNodes()) mapNodes(data, [...node.childNodes]);
1450
1457
  }
1451
1458
  }
1459
+ function mapTextarea(data, element) {
1460
+ const [, index] = EXPRESSION_TEXTAREA_VALUE.exec(element.value) ?? [];
1461
+ if (index == null) return;
1462
+ element.value = "";
1463
+ const value = data.values[Number.parseInt(index, 10)];
1464
+ if (isSignal(value)) {
1465
+ element.value = String(value.peek());
1466
+ mapEvent(element, "@on", () => {
1467
+ value.set(element.value);
1468
+ });
1469
+ return;
1470
+ }
1471
+ let reactive;
1472
+ if (typeof value === "function") reactive = computed(value);
1473
+ else if (isComputed(value)) reactive = value;
1474
+ if (reactive == null) element.value = String(value);
1475
+ else data.mora.subscribers.add(reactive.subscribe((value) => {
1476
+ element.value = String(value);
1477
+ }));
1478
+ }
1452
1479
  function mapValue(data, comment, value) {
1453
1480
  switch (true) {
1454
1481
  case typeof value === "function":
@@ -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 };
@@ -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 };
@@ -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 | HTMLTextAreaElement;
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
@@ -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 || node instanceof HTMLTextAreaElement;
11
+ return node instanceof HTMLInputElement || node instanceof HTMLSelectElement;
12
12
  }
13
13
  function removeNodes(nodes) {
14
14
  const { length } = nodes;
@@ -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 (name === "value" && isInputElement(element) && isSignal(value)) mapEvent(element, "@on", () => {
37
- value.set(parse(element.value) ?? element.value);
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,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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oscarpalmer/abydon",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "keywords": [
5
5
  "components",
6
6
  "dom",
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';
@@ -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: 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 (name === PROPERTY_VALUE && isInputElement(element) && isSignal(value)) {
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
- value.set(parse(element.value) ?? element.value);
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 {computed, isReactive, type Reactive} from '@oscarpalmer/mora';
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':