@oscarpalmer/abydon 0.10.0 → 0.11.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/index.js +109 -27
- package/package.json +1 -1
- package/src/fragment.ts +24 -4
- package/src/helpers/dom.ts +4 -6
- package/src/helpers/index.ts +19 -0
- package/src/models.ts +3 -1
- package/src/node/index.ts +1 -1
- package/src/node/value.ts +154 -22
- package/types/fragment.d.ts +3 -0
- package/types/helpers/index.d.ts +1 -0
- package/types/index.d.cts +4 -0
- package/types/models.d.ts +3 -1
package/dist/index.js
CHANGED
|
@@ -433,6 +433,15 @@ class Computed extends ReactiveValue {
|
|
|
433
433
|
var primitives = new Set(["boolean", "number", "string"]);
|
|
434
434
|
|
|
435
435
|
// src/helpers/index.ts
|
|
436
|
+
function compareArrays(first, second) {
|
|
437
|
+
const firstIsLarger = first.length > second.length;
|
|
438
|
+
const from = firstIsLarger ? first : second;
|
|
439
|
+
const to = firstIsLarger ? second : first;
|
|
440
|
+
if (!from.filter((key) => to.includes(key)).every((key, index) => to[index] === key)) {
|
|
441
|
+
return "dissimilar";
|
|
442
|
+
}
|
|
443
|
+
return firstIsLarger ? "removed" : "added";
|
|
444
|
+
}
|
|
436
445
|
function isFragment(value11) {
|
|
437
446
|
return typeof value11 === "object" && value11 != null && "$fragment" in value11 && value11.$fragment === true;
|
|
438
447
|
}
|
|
@@ -497,13 +506,10 @@ function removeNodes(nodes) {
|
|
|
497
506
|
}
|
|
498
507
|
}
|
|
499
508
|
function replaceNodes(from, to) {
|
|
509
|
+
from[0]?.replaceWith(...to);
|
|
500
510
|
const { length } = from;
|
|
501
|
-
for (let index =
|
|
502
|
-
|
|
503
|
-
from[index].replaceWith(...to);
|
|
504
|
-
} else {
|
|
505
|
-
from[index].remove();
|
|
506
|
-
}
|
|
511
|
+
for (let index = 1;index < length; index += 1) {
|
|
512
|
+
from[index].remove();
|
|
507
513
|
}
|
|
508
514
|
}
|
|
509
515
|
function sanitiseNodes2(nodes) {
|
|
@@ -631,8 +637,66 @@ function mapValue(element, name, value12) {
|
|
|
631
637
|
var commentExpression = /^<!--abydon\.(\d+)-->$/;
|
|
632
638
|
|
|
633
639
|
// src/node/value.ts
|
|
634
|
-
function
|
|
635
|
-
|
|
640
|
+
function removeFragments(fragments) {
|
|
641
|
+
if (fragments != null) {
|
|
642
|
+
const { length } = fragments;
|
|
643
|
+
for (let index = 0;index < length; index += 1) {
|
|
644
|
+
fragments[index].remove();
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
function setArray(fragments, nodes, comment, text, value12) {
|
|
649
|
+
if (value12.length === 0) {
|
|
650
|
+
return {
|
|
651
|
+
nodes: setText(fragments, nodes, comment, text, value12)
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
let templates2 = value12.filter((item) => isFragment(item) && item.identifier != null);
|
|
655
|
+
const identifiers = templates2.map((fragment) => fragment.identifier);
|
|
656
|
+
const oldIdentifiers = fragments?.map((fragment) => fragment.identifier) ?? [];
|
|
657
|
+
if (new Set(identifiers).size !== templates2.length) {
|
|
658
|
+
templates2 = [];
|
|
659
|
+
}
|
|
660
|
+
const noTemplates = templates2.length === 0;
|
|
661
|
+
if (noTemplates || nodes == null || oldIdentifiers.some((identifier) => identifier == null)) {
|
|
662
|
+
return {
|
|
663
|
+
fragments: noTemplates ? undefined : templates2,
|
|
664
|
+
nodes: setNodes(fragments, nodes, comment, text, noTemplates ? value12.flatMap((item) => createNodes(item)) : templates2.flatMap((template4) => template4.get()))
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
const next = templates2.map((template4) => fragments?.find((fragment) => fragment.identifier === template4.identifier) ?? template4);
|
|
668
|
+
const comparison = compareArrays(fragments ?? [], templates2);
|
|
669
|
+
if (comparison !== "removed") {
|
|
670
|
+
let position = nodes[0];
|
|
671
|
+
const before = comparison === "added" && !oldIdentifiers.includes(templates2[0].identifier);
|
|
672
|
+
const items = next.flatMap((fragment) => fragment.get().flatMap((node) => ({
|
|
673
|
+
identifier: fragment.identifier,
|
|
674
|
+
value: node
|
|
675
|
+
})));
|
|
676
|
+
const { length: length2 } = items;
|
|
677
|
+
for (let index = 0;index < length2; index += 1) {
|
|
678
|
+
const item = items[index];
|
|
679
|
+
if (comparison === "dissimilar" || !oldIdentifiers.includes(item.identifier)) {
|
|
680
|
+
if (index === 0 && before) {
|
|
681
|
+
position.before(item.value);
|
|
682
|
+
} else {
|
|
683
|
+
position.after(item.value);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
position = item.value;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
const toRemove = fragments?.filter((fragment) => !identifiers.includes(fragment.identifier)) ?? [];
|
|
690
|
+
const { length } = toRemove;
|
|
691
|
+
for (let index = 0;index < length; index += 1) {
|
|
692
|
+
toRemove[index].remove();
|
|
693
|
+
}
|
|
694
|
+
return {
|
|
695
|
+
fragments: next,
|
|
696
|
+
nodes: next.flatMap((fragment) => fragment.get())
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
function setNodes(fragments, nodes, comment, text, next) {
|
|
636
700
|
if (nodes == null) {
|
|
637
701
|
if (comment.parentNode != null) {
|
|
638
702
|
replaceNodes([comment], next);
|
|
@@ -642,42 +706,50 @@ function setNodes(nodes, comment, text, value12) {
|
|
|
642
706
|
} else {
|
|
643
707
|
replaceNodes(nodes, next);
|
|
644
708
|
}
|
|
709
|
+
removeFragments(fragments);
|
|
645
710
|
return next;
|
|
646
711
|
}
|
|
647
712
|
function setReactiveNode(data, comment, reactive3) {
|
|
648
713
|
const item = data.items.find((item2) => item2.nodes.includes(comment));
|
|
649
714
|
const text = new Text;
|
|
715
|
+
let fragments;
|
|
650
716
|
let nodes;
|
|
651
717
|
effect(() => {
|
|
652
718
|
const value12 = reactive3.get();
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
719
|
+
if (Array.isArray(value12)) {
|
|
720
|
+
const result = setArray(fragments, nodes, comment, text, value12);
|
|
721
|
+
fragments = typeof result === "boolean" ? undefined : result?.fragments;
|
|
722
|
+
nodes = typeof result === "boolean" ? result ? [text] : undefined : result?.nodes;
|
|
656
723
|
} else {
|
|
657
|
-
|
|
724
|
+
const valueIsFragment = isFragment(value12);
|
|
725
|
+
fragments = valueIsFragment ? [value12] : undefined;
|
|
726
|
+
if (valueIsFragment || isProperNode(value12)) {
|
|
727
|
+
nodes = setNodes(fragments, nodes, comment, text, createNodes(value12));
|
|
728
|
+
} else {
|
|
729
|
+
nodes = setText(fragments, nodes, comment, text, value12);
|
|
730
|
+
}
|
|
658
731
|
}
|
|
659
732
|
if (item != null) {
|
|
660
|
-
item.
|
|
733
|
+
item.fragments = fragments;
|
|
661
734
|
item.nodes = [...nodes ?? [comment]];
|
|
662
735
|
}
|
|
663
736
|
});
|
|
664
737
|
}
|
|
665
|
-
function setText(nodes, comment, text, value12) {
|
|
738
|
+
function setText(fragments, nodes, comment, text, value12) {
|
|
666
739
|
const isNullable = isNullableOrWhitespace(value12);
|
|
667
740
|
text.textContent = isNullable ? "" : getString(value12);
|
|
741
|
+
let result = false;
|
|
668
742
|
if (nodes != null) {
|
|
669
743
|
replaceNodes(nodes, [isNullable ? comment : text]);
|
|
670
|
-
|
|
671
|
-
}
|
|
672
|
-
if (isNullable && comment.parentNode == null) {
|
|
744
|
+
result = !isNullable;
|
|
745
|
+
} else if (isNullable && comment.parentNode == null) {
|
|
673
746
|
text.replaceWith(comment);
|
|
674
|
-
|
|
675
|
-
}
|
|
676
|
-
if (!isNullable && text.parentNode == null) {
|
|
747
|
+
} else if (!isNullable && text.parentNode == null) {
|
|
677
748
|
comment.replaceWith(text);
|
|
678
|
-
|
|
749
|
+
result = true;
|
|
679
750
|
}
|
|
680
|
-
|
|
751
|
+
removeFragments(fragments);
|
|
752
|
+
return result ? [text] : undefined;
|
|
681
753
|
}
|
|
682
754
|
|
|
683
755
|
// src/node/index.ts
|
|
@@ -721,7 +793,7 @@ function replaceComment(data, comment, value13) {
|
|
|
721
793
|
const item = data.items.find((item2) => item2.nodes.includes(comment));
|
|
722
794
|
const nodes = createNodes(value13);
|
|
723
795
|
if (item != null) {
|
|
724
|
-
item.
|
|
796
|
+
item.fragments = isFragment(value13) ? [value13] : undefined;
|
|
725
797
|
item.nodes = nodes;
|
|
726
798
|
}
|
|
727
799
|
comment.replaceWith(...nodes);
|
|
@@ -732,6 +804,9 @@ var commentExpression2 = /^abydon\.(\d+)$/;
|
|
|
732
804
|
class Fragment {
|
|
733
805
|
$fragment = true;
|
|
734
806
|
data;
|
|
807
|
+
get identifier() {
|
|
808
|
+
return this.data.identifier;
|
|
809
|
+
}
|
|
735
810
|
constructor(strings, expressions) {
|
|
736
811
|
this.data = {
|
|
737
812
|
expressions,
|
|
@@ -752,17 +827,24 @@ class Fragment {
|
|
|
752
827
|
this.data.items.splice(0, this.data.items.length, ...templated.map((node2) => ({
|
|
753
828
|
nodes: [node2]
|
|
754
829
|
})));
|
|
755
|
-
mapNodes(this.data, this.data.items.flatMap((item) => item.fragment
|
|
830
|
+
mapNodes(this.data, this.data.items.flatMap((item) => item.fragments?.flatMap((fragment) => fragment.get()) ?? item.nodes));
|
|
756
831
|
}
|
|
757
832
|
return [
|
|
758
|
-
...this.data.items.flatMap((item) => item.fragment
|
|
833
|
+
...this.data.items.flatMap((item) => item.fragments?.flatMap((fragment) => fragment.get()) ?? item.nodes)
|
|
759
834
|
];
|
|
760
835
|
}
|
|
836
|
+
identify(identifier) {
|
|
837
|
+
this.data.identifier = identifier;
|
|
838
|
+
return this;
|
|
839
|
+
}
|
|
761
840
|
remove() {
|
|
762
841
|
const { length } = this.data.items;
|
|
763
842
|
for (let index = 0;index < length; index += 1) {
|
|
764
|
-
const {
|
|
765
|
-
|
|
843
|
+
const { fragments, nodes } = this.data.items[index];
|
|
844
|
+
const { length: length2 } = fragments ?? [];
|
|
845
|
+
for (let index2 = 0;index2 < length2; index2 += 1) {
|
|
846
|
+
fragments?.[index2]?.remove();
|
|
847
|
+
}
|
|
766
848
|
removeNodes(nodes);
|
|
767
849
|
}
|
|
768
850
|
this.data.items.splice(0, length);
|
package/package.json
CHANGED
package/src/fragment.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type {Key} from '@oscarpalmer/atoms/models';
|
|
1
2
|
import {html} from '@oscarpalmer/toretto/html';
|
|
2
3
|
import {parse} from './html';
|
|
3
4
|
import type {FragmentData, ProperNode} from './models';
|
|
@@ -8,6 +9,10 @@ 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,
|
|
@@ -45,15 +50,27 @@ export class Fragment {
|
|
|
45
50
|
|
|
46
51
|
mapNodes(
|
|
47
52
|
this.data,
|
|
48
|
-
this.data.items.flatMap(
|
|
53
|
+
this.data.items.flatMap(
|
|
54
|
+
item =>
|
|
55
|
+
item.fragments?.flatMap(fragment => fragment.get()) ?? item.nodes,
|
|
56
|
+
),
|
|
49
57
|
);
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
return [
|
|
53
|
-
...this.data.items.flatMap(
|
|
61
|
+
...this.data.items.flatMap(
|
|
62
|
+
item =>
|
|
63
|
+
item.fragments?.flatMap(fragment => fragment.get()) ?? item.nodes,
|
|
64
|
+
),
|
|
54
65
|
];
|
|
55
66
|
}
|
|
56
67
|
|
|
68
|
+
identify(identifier: Key): Fragment {
|
|
69
|
+
this.data.identifier = identifier;
|
|
70
|
+
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
|
|
57
74
|
/**
|
|
58
75
|
* Removes the fragment from the DOM
|
|
59
76
|
*/
|
|
@@ -61,9 +78,12 @@ export class Fragment {
|
|
|
61
78
|
const {length} = this.data.items;
|
|
62
79
|
|
|
63
80
|
for (let index = 0; index < length; index += 1) {
|
|
64
|
-
const {
|
|
81
|
+
const {fragments, nodes} = this.data.items[index];
|
|
82
|
+
const {length} = fragments ?? [];
|
|
65
83
|
|
|
66
|
-
|
|
84
|
+
for (let index = 0; index < length; index += 1) {
|
|
85
|
+
fragments?.[index]?.remove();
|
|
86
|
+
}
|
|
67
87
|
|
|
68
88
|
removeNodes(nodes);
|
|
69
89
|
}
|
package/src/helpers/dom.ts
CHANGED
|
@@ -26,14 +26,12 @@ export function removeNodes(nodes: ProperNode[]): void {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export function replaceNodes(from: ProperNode[], to: ProperNode[]): void {
|
|
29
|
+
from[0]?.replaceWith(...to);
|
|
30
|
+
|
|
29
31
|
const {length} = from;
|
|
30
32
|
|
|
31
|
-
for (let index =
|
|
32
|
-
|
|
33
|
-
from[index].replaceWith(...to);
|
|
34
|
-
} else {
|
|
35
|
-
from[index].remove();
|
|
36
|
-
}
|
|
33
|
+
for (let index = 1; index < length; index += 1) {
|
|
34
|
+
from[index].remove();
|
|
37
35
|
}
|
|
38
36
|
}
|
|
39
37
|
|
package/src/helpers/index.ts
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
import type {Fragment} from '../fragment';
|
|
2
2
|
import type {ProperElement, ProperNode} from '../models';
|
|
3
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
|
+
|
|
4
23
|
export function isFragment(value: unknown): value is Fragment {
|
|
5
24
|
return (
|
|
6
25
|
typeof value === 'object' &&
|
package/src/models.ts
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
+
import type {Key} from '@oscarpalmer/atoms/models';
|
|
1
2
|
import type {Fragment} from './fragment';
|
|
2
3
|
|
|
3
4
|
export type FragmentData = {
|
|
4
5
|
expressions: unknown[];
|
|
6
|
+
identifier?: Key;
|
|
5
7
|
items: FragmentItem[];
|
|
6
8
|
strings: TemplateStringsArray;
|
|
7
9
|
values: unknown[];
|
|
8
10
|
};
|
|
9
11
|
|
|
10
12
|
export type FragmentItem = {
|
|
11
|
-
|
|
13
|
+
fragments?: Fragment[];
|
|
12
14
|
nodes: ProperNode[];
|
|
13
15
|
};
|
|
14
16
|
|
package/src/node/index.ts
CHANGED
package/src/node/value.ts
CHANGED
|
@@ -1,19 +1,134 @@
|
|
|
1
1
|
import {isNullableOrWhitespace} from '@oscarpalmer/atoms/is';
|
|
2
|
+
import type {Key} from '@oscarpalmer/atoms/models';
|
|
2
3
|
import {getString} from '@oscarpalmer/atoms/string';
|
|
3
4
|
import {type Reactive, effect} from '@oscarpalmer/sentinel';
|
|
4
5
|
import type {Fragment} from '../fragment';
|
|
5
|
-
import {isFragment, isProperNode} from '../helpers';
|
|
6
|
+
import {compareArrays, isFragment, isProperNode} from '../helpers';
|
|
6
7
|
import {createNodes, replaceNodes} from '../helpers/dom';
|
|
7
|
-
import type {FragmentData, ProperNode} from '../models';
|
|
8
|
+
import type {FragmentData, FragmentItem, ProperNode} from '../models';
|
|
9
|
+
|
|
10
|
+
function removeFragments(fragments: Fragment[] | undefined): void {
|
|
11
|
+
if (fragments != null) {
|
|
12
|
+
const {length} = fragments;
|
|
13
|
+
|
|
14
|
+
for (let index = 0; index < length; index += 1) {
|
|
15
|
+
fragments[index].remove();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function setArray(
|
|
21
|
+
fragments: Fragment[] | undefined,
|
|
22
|
+
nodes: ProperNode[] | undefined,
|
|
23
|
+
comment: Comment,
|
|
24
|
+
text: Text,
|
|
25
|
+
value: unknown[],
|
|
26
|
+
): Partial<FragmentItem> | boolean {
|
|
27
|
+
if (value.length === 0) {
|
|
28
|
+
return {
|
|
29
|
+
nodes: setText(fragments, nodes, comment, text, value),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let templates = value.filter(
|
|
34
|
+
item => isFragment(item) && item.identifier != null,
|
|
35
|
+
) as Fragment[];
|
|
36
|
+
|
|
37
|
+
const identifiers = templates.map(fragment => fragment.identifier) as Key[];
|
|
38
|
+
const oldIdentifiers = fragments?.map(fragment => fragment.identifier) ?? [];
|
|
39
|
+
|
|
40
|
+
if (new Set(identifiers).size !== templates.length) {
|
|
41
|
+
templates = [];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const noTemplates = templates.length === 0;
|
|
45
|
+
|
|
46
|
+
if (
|
|
47
|
+
noTemplates ||
|
|
48
|
+
nodes == null ||
|
|
49
|
+
oldIdentifiers.some(identifier => identifier == null)
|
|
50
|
+
) {
|
|
51
|
+
return {
|
|
52
|
+
fragments: noTemplates ? undefined : templates,
|
|
53
|
+
nodes: setNodes(
|
|
54
|
+
fragments,
|
|
55
|
+
nodes,
|
|
56
|
+
comment,
|
|
57
|
+
text,
|
|
58
|
+
noTemplates
|
|
59
|
+
? value.flatMap(item => createNodes(item))
|
|
60
|
+
: templates.flatMap(template => template.get()),
|
|
61
|
+
),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const next = templates.map(
|
|
66
|
+
template =>
|
|
67
|
+
fragments?.find(
|
|
68
|
+
fragment => fragment.identifier === template.identifier,
|
|
69
|
+
) ?? template,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const comparison = compareArrays(fragments ?? [], templates);
|
|
73
|
+
|
|
74
|
+
if (comparison !== 'removed') {
|
|
75
|
+
let position = nodes[0];
|
|
76
|
+
|
|
77
|
+
const before =
|
|
78
|
+
comparison === 'added' &&
|
|
79
|
+
!oldIdentifiers.includes(templates[0].identifier);
|
|
80
|
+
|
|
81
|
+
const items = next.flatMap(fragment =>
|
|
82
|
+
fragment.get().flatMap(node => ({
|
|
83
|
+
identifier: fragment.identifier,
|
|
84
|
+
value: node,
|
|
85
|
+
})),
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const {length} = items;
|
|
89
|
+
|
|
90
|
+
for (let index = 0; index < length; index += 1) {
|
|
91
|
+
const item = items[index];
|
|
92
|
+
|
|
93
|
+
if (
|
|
94
|
+
comparison === 'dissimilar' ||
|
|
95
|
+
!oldIdentifiers.includes(item.identifier)
|
|
96
|
+
) {
|
|
97
|
+
if (index === 0 && before) {
|
|
98
|
+
position.before(item.value);
|
|
99
|
+
} else {
|
|
100
|
+
position.after(item.value);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
position = item.value;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const toRemove =
|
|
109
|
+
fragments?.filter(
|
|
110
|
+
fragment => !identifiers.includes(fragment.identifier as Key),
|
|
111
|
+
) ?? [];
|
|
112
|
+
|
|
113
|
+
const {length} = toRemove;
|
|
114
|
+
|
|
115
|
+
for (let index = 0; index < length; index += 1) {
|
|
116
|
+
toRemove[index].remove();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
fragments: next,
|
|
121
|
+
nodes: next.flatMap(fragment => fragment.get()),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
8
124
|
|
|
9
125
|
function setNodes(
|
|
126
|
+
fragments: Fragment[] | undefined,
|
|
10
127
|
nodes: ProperNode[] | undefined,
|
|
11
128
|
comment: Comment,
|
|
12
129
|
text: Text,
|
|
13
|
-
|
|
130
|
+
next: ProperNode[],
|
|
14
131
|
): ProperNode[] {
|
|
15
|
-
const next = createNodes(value);
|
|
16
|
-
|
|
17
132
|
if (nodes == null) {
|
|
18
133
|
if (comment.parentNode != null) {
|
|
19
134
|
replaceNodes([comment], next);
|
|
@@ -24,6 +139,8 @@ function setNodes(
|
|
|
24
139
|
replaceNodes(nodes, next);
|
|
25
140
|
}
|
|
26
141
|
|
|
142
|
+
removeFragments(fragments);
|
|
143
|
+
|
|
27
144
|
return next;
|
|
28
145
|
}
|
|
29
146
|
|
|
@@ -35,53 +152,68 @@ export function setReactiveNode(
|
|
|
35
152
|
const item = data.items.find(item => item.nodes.includes(comment));
|
|
36
153
|
const text = new Text();
|
|
37
154
|
|
|
155
|
+
let fragments: Fragment[] | undefined;
|
|
38
156
|
let nodes: ProperNode[] | undefined;
|
|
39
157
|
|
|
40
158
|
effect(() => {
|
|
41
159
|
const value = reactive.get();
|
|
42
160
|
|
|
43
|
-
|
|
161
|
+
if (Array.isArray(value)) {
|
|
162
|
+
const result = setArray(fragments, nodes, comment, text, value);
|
|
163
|
+
|
|
164
|
+
fragments = typeof result === 'boolean' ? undefined : result?.fragments;
|
|
44
165
|
|
|
45
|
-
|
|
46
|
-
|
|
166
|
+
nodes =
|
|
167
|
+
typeof result === 'boolean'
|
|
168
|
+
? result
|
|
169
|
+
? [text]
|
|
170
|
+
: undefined
|
|
171
|
+
: result?.nodes;
|
|
47
172
|
} else {
|
|
48
|
-
|
|
173
|
+
const valueIsFragment = isFragment(value);
|
|
174
|
+
|
|
175
|
+
fragments = valueIsFragment ? [value] : undefined;
|
|
176
|
+
|
|
177
|
+
if (valueIsFragment || isProperNode(value)) {
|
|
178
|
+
nodes = setNodes(fragments, nodes, comment, text, createNodes(value));
|
|
179
|
+
} else {
|
|
180
|
+
nodes = setText(fragments, nodes, comment, text, value);
|
|
181
|
+
}
|
|
49
182
|
}
|
|
50
183
|
|
|
51
184
|
if (item != null) {
|
|
52
|
-
item.
|
|
185
|
+
item.fragments = fragments;
|
|
53
186
|
item.nodes = [...(nodes ?? [comment])];
|
|
54
187
|
}
|
|
55
188
|
});
|
|
56
189
|
}
|
|
57
190
|
|
|
58
191
|
function setText(
|
|
192
|
+
fragments: Fragment[] | undefined,
|
|
59
193
|
nodes: ProperNode[] | undefined,
|
|
60
194
|
comment: Comment,
|
|
61
195
|
text: Text,
|
|
62
196
|
value: unknown,
|
|
63
|
-
):
|
|
197
|
+
): ProperNode[] | undefined {
|
|
64
198
|
const isNullable = isNullableOrWhitespace(value);
|
|
65
199
|
|
|
66
200
|
text.textContent = isNullable ? '' : getString(value);
|
|
67
201
|
|
|
202
|
+
let result = false;
|
|
203
|
+
|
|
68
204
|
if (nodes != null) {
|
|
69
205
|
replaceNodes(nodes, [isNullable ? comment : text]);
|
|
70
206
|
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (isNullable && comment.parentNode == null) {
|
|
207
|
+
result = !isNullable;
|
|
208
|
+
} else if (isNullable && comment.parentNode == null) {
|
|
75
209
|
text.replaceWith(comment);
|
|
76
|
-
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (!isNullable && text.parentNode == null) {
|
|
210
|
+
} else if (!isNullable && text.parentNode == null) {
|
|
81
211
|
comment.replaceWith(text);
|
|
82
212
|
|
|
83
|
-
|
|
213
|
+
result = true;
|
|
84
214
|
}
|
|
85
215
|
|
|
86
|
-
|
|
216
|
+
removeFragments(fragments);
|
|
217
|
+
|
|
218
|
+
return result ? [text] : undefined;
|
|
87
219
|
}
|
package/types/fragment.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import type { Key } from '@oscarpalmer/atoms/models';
|
|
1
2
|
import type { ProperNode } from './models';
|
|
2
3
|
export declare class Fragment {
|
|
3
4
|
private readonly $fragment;
|
|
4
5
|
private readonly data;
|
|
6
|
+
get identifier(): Key | undefined;
|
|
5
7
|
constructor(strings: TemplateStringsArray, expressions: unknown[]);
|
|
6
8
|
/**
|
|
7
9
|
* Appends the fragment to the given element
|
|
@@ -11,6 +13,7 @@ export declare class Fragment {
|
|
|
11
13
|
* Gets a list of the fragment's nodes
|
|
12
14
|
*/
|
|
13
15
|
get(): ProperNode[];
|
|
16
|
+
identify(identifier: Key): Fragment;
|
|
14
17
|
/**
|
|
15
18
|
* Removes the fragment from the DOM
|
|
16
19
|
*/
|
package/types/helpers/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Fragment } from '../fragment';
|
|
2
2
|
import type { ProperElement, ProperNode } from '../models';
|
|
3
|
+
export declare function compareArrays(first: unknown[], second: unknown[]): 'added' | 'dissimilar' | 'removed';
|
|
3
4
|
export declare function isFragment(value: unknown): value is Fragment;
|
|
4
5
|
export declare function isProperElement(value: unknown): value is ProperElement;
|
|
5
6
|
export declare function isProperNode(value: unknown): value is ProperNode;
|
package/types/index.d.cts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
// Generated by dts-bundle-generator v9.5.1
|
|
2
2
|
|
|
3
|
+
import { Key } from '@oscarpalmer/atoms/models';
|
|
4
|
+
|
|
3
5
|
export type ProperNode = CharacterData | Element;
|
|
4
6
|
export declare class Fragment {
|
|
5
7
|
private readonly $fragment;
|
|
6
8
|
private readonly data;
|
|
9
|
+
get identifier(): Key | undefined;
|
|
7
10
|
constructor(strings: TemplateStringsArray, expressions: unknown[]);
|
|
8
11
|
/**
|
|
9
12
|
* Appends the fragment to the given element
|
|
@@ -13,6 +16,7 @@ export declare class Fragment {
|
|
|
13
16
|
* Gets a list of the fragment's nodes
|
|
14
17
|
*/
|
|
15
18
|
get(): ProperNode[];
|
|
19
|
+
identify(identifier: Key): Fragment;
|
|
16
20
|
/**
|
|
17
21
|
* Removes the fragment from the DOM
|
|
18
22
|
*/
|
package/types/models.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import type { Key } from '@oscarpalmer/atoms/models';
|
|
1
2
|
import type { Fragment } from './fragment';
|
|
2
3
|
export type FragmentData = {
|
|
3
4
|
expressions: unknown[];
|
|
5
|
+
identifier?: Key;
|
|
4
6
|
items: FragmentItem[];
|
|
5
7
|
strings: TemplateStringsArray;
|
|
6
8
|
values: unknown[];
|
|
7
9
|
};
|
|
8
10
|
export type FragmentItem = {
|
|
9
|
-
|
|
11
|
+
fragments?: Fragment[];
|
|
10
12
|
nodes: ProperNode[];
|
|
11
13
|
};
|
|
12
14
|
export type ProperElement = HTMLElement | SVGElement;
|