@esportsplus/template 0.17.0 → 0.19.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/build/attributes.js +4 -4
- package/build/constants.d.ts +2 -9
- package/build/constants.js +3 -10
- package/build/event.js +47 -45
- package/build/html/index.d.ts +3 -2106
- package/build/html/index.js +34 -8
- package/build/html/{cache.d.ts → parser.d.ts} +1 -1
- package/build/html/{cache.js → parser.js} +13 -7
- package/build/index.d.ts +1 -1
- package/build/render.js +3 -2
- package/build/slot/cleanup.js +2 -1
- package/build/slot/effect.js +22 -17
- package/build/slot/index.js +4 -9
- package/build/slot/reactive.d.ts +1 -1
- package/build/slot/reactive.js +26 -16
- package/build/slot/render.d.ts +2 -2
- package/build/slot/render.js +24 -45
- package/build/types.d.ts +5 -13
- package/build/utilities/element.d.ts +11 -0
- package/build/utilities/element.js +9 -0
- package/build/utilities/fragment.d.ts +3 -0
- package/build/utilities/fragment.js +11 -0
- package/build/utilities/node.d.ts +9 -0
- package/build/utilities/node.js +10 -0
- package/build/utilities/queue.d.ts +3 -0
- package/build/utilities/queue.js +4 -0
- package/build/utilities/text.d.ts +2 -0
- package/build/utilities/text.js +9 -0
- package/package.json +2 -2
- package/src/attributes.ts +23 -26
- package/src/constants.ts +3 -20
- package/src/event.ts +55 -52
- package/src/html/index.ts +50 -11
- package/src/html/{cache.ts → parser.ts} +15 -7
- package/src/index.ts +1 -1
- package/src/render.ts +3 -3
- package/src/slot/cleanup.ts +3 -4
- package/src/slot/effect.ts +33 -35
- package/src/slot/index.ts +6 -16
- package/src/slot/reactive.ts +33 -23
- package/src/slot/render.ts +28 -59
- package/src/types.ts +6 -19
- package/src/utilities/element.ts +28 -0
- package/src/utilities/fragment.ts +21 -0
- package/src/utilities/node.ts +29 -0
- package/src/utilities/queue.ts +9 -0
- package/src/utilities/text.ts +15 -0
- package/build/html/hydrate.d.ts +0 -3
- package/build/html/hydrate.js +0 -34
- package/build/utilities.d.ts +0 -28
- package/build/utilities.js +0 -37
- package/src/html/hydrate.ts +0 -53
- package/src/utilities.ts +0 -89
package/src/event.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { root } from '@esportsplus/reactivity';
|
|
2
2
|
import { defineProperty } from '@esportsplus/utilities';
|
|
3
3
|
import { Element } from './types';
|
|
4
|
-
import { addEventListener
|
|
4
|
+
import { addEventListener } from './utilities/element';
|
|
5
|
+
import { parentElement } from './utilities/node';
|
|
6
|
+
import { raf } from './utilities/queue';
|
|
5
7
|
import { ondisconnect } from './slot/cleanup';
|
|
6
8
|
|
|
7
9
|
|
|
@@ -24,35 +26,7 @@ let capture = new Set<`on${string}`>(['onblur', 'onfocus', 'onscroll']),
|
|
|
24
26
|
});
|
|
25
27
|
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
if (event === 'onconnect') {
|
|
29
|
-
let retry = 60,
|
|
30
|
-
task = () => {
|
|
31
|
-
retry--;
|
|
32
|
-
|
|
33
|
-
if (element.isConnected) {
|
|
34
|
-
retry = 0;
|
|
35
|
-
root(() => listener(element));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (retry) {
|
|
39
|
-
raf.add(task);
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
raf.add(task);
|
|
44
|
-
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
else if (event === 'ondisconnect') {
|
|
48
|
-
ondisconnect(element, () => listener(element));
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
else if (event === 'onrender') {
|
|
52
|
-
root(() => listener(element));
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
|
|
29
|
+
function register(element: Element, event: `on${string}`) {
|
|
56
30
|
let controller = controllers.get(event),
|
|
57
31
|
signal: AbortController['signal'] | undefined;
|
|
58
32
|
|
|
@@ -83,34 +57,63 @@ export default (element: Element, event: `on${string}`, listener: Function): voi
|
|
|
83
57
|
signal = controller.signal;
|
|
84
58
|
}
|
|
85
59
|
|
|
86
|
-
let key = keys[event];
|
|
60
|
+
let key = keys[event] = Symbol();
|
|
61
|
+
|
|
62
|
+
addEventListener.call(window.document, event.slice(2), (e) => {
|
|
63
|
+
let node = e.target as Element | null;
|
|
87
64
|
|
|
88
|
-
|
|
89
|
-
|
|
65
|
+
while (node) {
|
|
66
|
+
if (key in node) {
|
|
67
|
+
defineProperty(e, 'currentTarget', {
|
|
68
|
+
configurable: true,
|
|
69
|
+
get() {
|
|
70
|
+
return node || window.document;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
90
73
|
|
|
91
|
-
|
|
92
|
-
|
|
74
|
+
return (node[key] as Function).call(node, e);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
node = parentElement.call(node);
|
|
78
|
+
}
|
|
79
|
+
}, {
|
|
80
|
+
capture: capture.has(event),
|
|
81
|
+
passive: passive.has(event),
|
|
82
|
+
signal
|
|
83
|
+
});
|
|
93
84
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
defineProperty(e, 'currentTarget', {
|
|
97
|
-
configurable: true,
|
|
98
|
-
get() {
|
|
99
|
-
return node || window.document;
|
|
100
|
-
}
|
|
101
|
-
});
|
|
85
|
+
return key;
|
|
86
|
+
}
|
|
102
87
|
|
|
103
|
-
|
|
88
|
+
|
|
89
|
+
export default (element: Element, event: `on${string}`, listener: Function): void => {
|
|
90
|
+
if (event === 'onconnect') {
|
|
91
|
+
let retry = 60,
|
|
92
|
+
task = () => {
|
|
93
|
+
retry--;
|
|
94
|
+
|
|
95
|
+
if (element.isConnected) {
|
|
96
|
+
retry = 0;
|
|
97
|
+
root(() => listener(element));
|
|
104
98
|
}
|
|
105
99
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
100
|
+
if (retry) {
|
|
101
|
+
raf.add(task);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
raf.add(task);
|
|
106
|
+
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
else if (event === 'ondisconnect') {
|
|
110
|
+
ondisconnect(element, () => listener(element));
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
else if (event === 'onrender') {
|
|
114
|
+
root(() => listener(element));
|
|
115
|
+
return;
|
|
113
116
|
}
|
|
114
117
|
|
|
115
|
-
element[
|
|
118
|
+
element[ keys[event] || register(element, event) ] = listener;
|
|
116
119
|
};
|
package/src/html/index.ts
CHANGED
|
@@ -1,19 +1,58 @@
|
|
|
1
1
|
import { ReactiveArray } from '@esportsplus/reactivity';
|
|
2
|
-
import { RENDERABLE,
|
|
3
|
-
import { RenderableReactive,
|
|
4
|
-
import
|
|
5
|
-
import
|
|
2
|
+
import { RENDERABLE, RENDERABLE_HTML_REACTIVE_ARRAY } from '~/constants';
|
|
3
|
+
import { RenderableReactive, RenderableValue } from '~/types';
|
|
4
|
+
import { cloneNode } from '~/utilities/node';
|
|
5
|
+
import parser from './parser';
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
const html = (literals: TemplateStringsArray, ...values:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
const html = (literals: TemplateStringsArray, ...values: (RenderableValue | RenderableValue[])[]): DocumentFragment => {
|
|
9
|
+
let { fragment, slots } = parser.parse(literals);
|
|
10
|
+
|
|
11
|
+
fragment = cloneNode.call(fragment, true) as DocumentFragment;
|
|
12
|
+
|
|
13
|
+
if (slots !== null) {
|
|
14
|
+
let node, nodePath, parent, parentPath;
|
|
15
|
+
|
|
16
|
+
for (let i = 0, n = slots.length; i < n; i++) {
|
|
17
|
+
let { fn, path, slot } = slots[i],
|
|
18
|
+
pp = path.parent,
|
|
19
|
+
pr = path.relative;
|
|
20
|
+
|
|
21
|
+
if (pp !== parentPath) {
|
|
22
|
+
if (pp === nodePath) {
|
|
23
|
+
parent = node;
|
|
24
|
+
parentPath = nodePath;
|
|
25
|
+
|
|
26
|
+
nodePath = undefined;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
parent = fragment;
|
|
30
|
+
parentPath = pp;
|
|
31
|
+
|
|
32
|
+
for (let i = 0, n = pp.length; i < n; i++) {
|
|
33
|
+
parent = pp[i].call(parent);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (pr !== nodePath) {
|
|
39
|
+
node = parent;
|
|
40
|
+
nodePath = path.absolute;
|
|
41
|
+
|
|
42
|
+
for (let i = 0, n = pr.length; i < n; i++) {
|
|
43
|
+
node = pr[i].call(node);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// @ts-ignore
|
|
48
|
+
fn(node, values[slot]);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return fragment;
|
|
14
53
|
};
|
|
15
54
|
|
|
16
|
-
html.reactive = <T>(array: ReactiveArray<T[]>, template: RenderableReactive['template']) => {
|
|
55
|
+
html.reactive = <T>(array: ReactiveArray<T[]>, template: RenderableReactive['template']): RenderableReactive => {
|
|
17
56
|
return {
|
|
18
57
|
[RENDERABLE]: RENDERABLE_HTML_REACTIVE_ARRAY,
|
|
19
58
|
array,
|
|
@@ -3,8 +3,10 @@ import {
|
|
|
3
3
|
REGEX_SLOT_NODES, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH
|
|
4
4
|
} from '~/constants';
|
|
5
5
|
import { Template } from '~/types';
|
|
6
|
-
import {
|
|
6
|
+
import { firstElementChild, nextElementSibling } from '~/utilities/element';
|
|
7
|
+
import { firstChild, nextSibling } from '~/utilities/node';
|
|
7
8
|
import { spread } from '~/attributes';
|
|
9
|
+
import { fragment } from '~/utilities/fragment';
|
|
8
10
|
import s from '~/slot';
|
|
9
11
|
|
|
10
12
|
|
|
@@ -124,22 +126,28 @@ function methods(children: number, copy: (typeof firstChild)[], first: (typeof f
|
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
function set(literals: TemplateStringsArray, html: string, slots: Template['slots'] = null) {
|
|
127
|
-
let
|
|
129
|
+
let value = {
|
|
128
130
|
fragment: fragment(html),
|
|
129
131
|
html,
|
|
130
132
|
literals,
|
|
131
133
|
slots
|
|
132
134
|
};
|
|
133
135
|
|
|
134
|
-
cache.set(literals,
|
|
136
|
+
cache.set(literals, value);
|
|
135
137
|
|
|
136
|
-
return
|
|
138
|
+
return value;
|
|
137
139
|
}
|
|
138
140
|
|
|
139
141
|
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
+
const parse = (literals: TemplateStringsArray) => {
|
|
143
|
+
let result = cache.get(literals);
|
|
144
|
+
|
|
145
|
+
if (result === undefined) {
|
|
146
|
+
result = build(literals);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return result;
|
|
142
150
|
};
|
|
143
151
|
|
|
144
152
|
|
|
145
|
-
export default {
|
|
153
|
+
export default { parse };
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { default as html } from './html';
|
|
2
2
|
export { default as render } from './render';
|
|
3
3
|
export { default as svg } from './svg';
|
|
4
|
-
export type { Attributes, Element,
|
|
4
|
+
export type { Attributes, Element, Renderable, RenderableValue } from './types';
|
package/src/render.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SLOT_HTML } from './constants';
|
|
2
2
|
import { Renderable } from './types';
|
|
3
|
-
import {
|
|
3
|
+
import { fragment } from './utilities/fragment';
|
|
4
|
+
import { firstChild, nodeValue } from './utilities/node';
|
|
4
5
|
import slot from './slot';
|
|
5
6
|
|
|
6
7
|
|
|
@@ -9,9 +10,8 @@ let anchor,
|
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
export default (parent: HTMLElement, renderable: Renderable) => {
|
|
12
|
-
// parent.nodeValue = '';
|
|
13
13
|
nodeValue.call(parent, '');
|
|
14
14
|
parent.append(anchor = marker.cloneNode());
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
slot(anchor, renderable);
|
|
17
17
|
};
|
package/src/slot/cleanup.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import queue from '@esportsplus/queue';
|
|
2
2
|
import { CLEANUP } from '~/constants';
|
|
3
|
-
import { microtask
|
|
3
|
+
import { microtask } from '~/utilities/queue';
|
|
4
|
+
import { previousSibling } from '~/utilities/node';
|
|
4
5
|
import { SlotGroup } from '~/types';
|
|
5
6
|
|
|
6
7
|
|
|
@@ -19,8 +20,7 @@ function schedule() {
|
|
|
19
20
|
|
|
20
21
|
function task() {
|
|
21
22
|
try {
|
|
22
|
-
let fns,
|
|
23
|
-
fn,
|
|
23
|
+
let fns, fn,
|
|
24
24
|
n = cleanup.length;
|
|
25
25
|
|
|
26
26
|
while ((fns = cleanup.next()) && n--) {
|
|
@@ -51,7 +51,6 @@ const remove = (groups: SlotGroup[]) => {
|
|
|
51
51
|
head = group.head;
|
|
52
52
|
tail = group.tail || head;
|
|
53
53
|
|
|
54
|
-
// for (let node: Element | null = tail; node; node = node.previousSibling as Element | null) {
|
|
55
54
|
for (let node = tail; node; node = previousSibling.call(node)) {
|
|
56
55
|
if (CLEANUP in node) {
|
|
57
56
|
cleanup.add( node[CLEANUP] as VoidFunction[] );
|
package/src/slot/effect.ts
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
import { effect } from '@esportsplus/reactivity';
|
|
2
|
-
import {
|
|
3
|
-
import { Element,
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { STATE_HYDRATING, STATE_NONE } from '~/constants';
|
|
3
|
+
import { Element, SlotGroup } from '~/types';
|
|
4
|
+
import { firstChild, lastChild, nodeValue } from '~/utilities/node'
|
|
5
|
+
import { raf } from '~/utilities/queue'
|
|
6
6
|
import { remove } from './cleanup';
|
|
7
|
+
import text from '~/utilities/text';
|
|
7
8
|
import render from './render';
|
|
8
9
|
|
|
9
10
|
|
|
10
|
-
function update(this: { group?: SlotGroup, textnode?:
|
|
11
|
-
let type = typeof value;
|
|
12
|
-
|
|
11
|
+
function update(this: { group?: SlotGroup, textnode?: Node }, anchor: Element, value: unknown) {
|
|
13
12
|
if (this.group) {
|
|
14
13
|
remove([this.group]);
|
|
15
14
|
this.group = undefined;
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
if (value == null ||
|
|
17
|
+
if (value == null || value === false) {
|
|
18
|
+
value = '';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (typeof value !== 'object') {
|
|
19
22
|
let textnode = this.textnode;
|
|
20
23
|
|
|
21
24
|
if (textnode) {
|
|
22
|
-
// textnode.nodeValue = String(value);
|
|
23
25
|
nodeValue.call(textnode, String(value));
|
|
24
26
|
}
|
|
25
27
|
else {
|
|
@@ -31,16 +33,17 @@ function update(this: { group?: SlotGroup, textnode?: Element }, anchor: Element
|
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
else {
|
|
34
|
-
render(anchor,
|
|
36
|
+
let fragment = render(anchor, value),
|
|
37
|
+
head = firstChild.call(fragment);
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
};
|
|
39
|
+
if (head) {
|
|
40
|
+
this.group = {
|
|
41
|
+
head,
|
|
42
|
+
tail: lastChild.call(fragment)
|
|
43
|
+
};
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
anchor.after(fragment);
|
|
46
|
+
}
|
|
44
47
|
}
|
|
45
48
|
}
|
|
46
49
|
|
|
@@ -48,26 +51,21 @@ function update(this: { group?: SlotGroup, textnode?: Element }, anchor: Element
|
|
|
48
51
|
export default (anchor: Element, fn: Function) => {
|
|
49
52
|
let context = {
|
|
50
53
|
group: undefined as SlotGroup | undefined,
|
|
51
|
-
textnode: undefined as
|
|
54
|
+
textnode: undefined as Node | undefined
|
|
52
55
|
},
|
|
53
|
-
// fragment = EMPTY_FRAGMENT.cloneNode() as Fragment,
|
|
54
|
-
fragment = cloneNode.call(EMPTY_FRAGMENT) as Fragment,
|
|
55
56
|
state = STATE_HYDRATING;
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
effect(() => {
|
|
60
|
-
let value = fn();
|
|
58
|
+
effect(() => {
|
|
59
|
+
let value = fn();
|
|
61
60
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
);
|
|
61
|
+
if (state === STATE_HYDRATING) {
|
|
62
|
+
update.call(context, anchor, value);
|
|
63
|
+
state = STATE_NONE;
|
|
64
|
+
}
|
|
65
|
+
else if (state === STATE_NONE) {
|
|
66
|
+
raf.add(() => {
|
|
67
|
+
update.call(context, anchor, value);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
});
|
|
73
71
|
};
|
package/src/slot/index.ts
CHANGED
|
@@ -1,23 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Element, Fragment } from '~/types';
|
|
3
|
-
import { cloneNode } from '~/utilities';
|
|
1
|
+
import { Element } from '~/types';
|
|
4
2
|
import effect from './effect';
|
|
5
3
|
import render from './render';
|
|
6
4
|
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
let fragment = cloneNode.call(EMPTY_FRAGMENT) as Fragment;
|
|
10
|
-
|
|
11
|
-
render(anchor, fragment, input);
|
|
12
|
-
|
|
13
|
-
anchor.after(fragment);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
export default (anchor: Element, value: unknown) => {
|
|
6
|
+
export default (anchor: Element, value: unknown): void => {
|
|
18
7
|
if (typeof value === 'function') {
|
|
19
|
-
|
|
8
|
+
effect(anchor, value as Function);
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
anchor.after( render(anchor, value) );
|
|
20
12
|
}
|
|
21
|
-
|
|
22
|
-
return slot(anchor, value);
|
|
23
13
|
};
|
package/src/slot/reactive.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { root, ReactiveArray } from '@esportsplus/reactivity';
|
|
2
2
|
import { EMPTY_FRAGMENT } from '~/constants';
|
|
3
|
-
import {
|
|
4
|
-
import { append
|
|
5
|
-
import {
|
|
3
|
+
import { RenderableReactive, SlotGroup } from '~/types';
|
|
4
|
+
import { append } from '~/utilities/fragment';
|
|
5
|
+
import { cloneNode, firstChild, lastChild } from '~/utilities/node';
|
|
6
|
+
import { ondisconnect, remove } from './cleanup';
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class ReactiveArraySlot<T> {
|
|
9
10
|
array: ReactiveArray<T[]>;
|
|
10
|
-
fragment
|
|
11
|
+
fragment: Node;
|
|
11
12
|
marker: Element;
|
|
12
13
|
nodes: SlotGroup[] = [];
|
|
13
14
|
template: (
|
|
@@ -17,45 +18,45 @@ class ReactiveArraySlot<T> {
|
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
constructor(anchor: Element, array: ReactiveArray<T[]>, template: RenderableReactive['template']) {
|
|
20
|
-
let fragment = this.fragment;
|
|
21
|
+
let fragment = this.fragment = cloneNode.call(EMPTY_FRAGMENT);
|
|
21
22
|
|
|
22
23
|
this.array = array;
|
|
23
24
|
this.marker = anchor;
|
|
24
25
|
this.template = function (data, i) {
|
|
25
|
-
let
|
|
26
|
+
let dispose: VoidFunction,
|
|
27
|
+
frag = root((d) => {
|
|
28
|
+
dispose = d;
|
|
29
|
+
return template.call(this, data, i);
|
|
30
|
+
}),
|
|
26
31
|
group = {
|
|
27
32
|
head: firstChild.call(frag),
|
|
28
33
|
tail: lastChild.call(frag)
|
|
29
34
|
};
|
|
30
35
|
|
|
31
36
|
append.call(fragment, frag);
|
|
37
|
+
ondisconnect(group.head, dispose!);
|
|
32
38
|
|
|
33
39
|
return group;
|
|
34
40
|
};
|
|
35
41
|
|
|
36
|
-
|
|
37
|
-
let render = () => {
|
|
38
|
-
root(() => this.render());
|
|
39
|
-
};
|
|
40
|
-
|
|
41
42
|
array.on('clear', () => this.clear());
|
|
42
|
-
array.on('reverse',
|
|
43
|
+
array.on('reverse', () => {
|
|
44
|
+
root(() => this.render());
|
|
45
|
+
});
|
|
43
46
|
array.on('pop', () => this.pop());
|
|
44
47
|
array.on('push', ({ items }) => {
|
|
45
48
|
root(() => this.push(items));
|
|
46
49
|
});
|
|
47
50
|
array.on('shift', () => this.shift());
|
|
48
|
-
array.on('sort',
|
|
51
|
+
array.on('sort', () => {
|
|
52
|
+
root(() => this.render());
|
|
53
|
+
});
|
|
49
54
|
array.on('splice', ({ deleteCount, items, start }) => {
|
|
50
55
|
root(() => this.splice(start, deleteCount, ...items));
|
|
51
56
|
});
|
|
52
57
|
array.on('unshift', ({ items }) => {
|
|
53
58
|
root(() => this.unshift(items));
|
|
54
59
|
});
|
|
55
|
-
|
|
56
|
-
if (array.length) {
|
|
57
|
-
render();
|
|
58
|
-
}
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
|
|
@@ -100,14 +101,14 @@ class ReactiveArraySlot<T> {
|
|
|
100
101
|
|
|
101
102
|
push(items: T[]) {
|
|
102
103
|
let anchor = this.anchor(),
|
|
103
|
-
array = this.array
|
|
104
|
+
array = this.array,
|
|
105
|
+
length = this.nodes.length;
|
|
106
|
+
|
|
107
|
+
this.nodes.length = length + items.length;
|
|
104
108
|
|
|
105
109
|
for (let i = 0, n = items.length; i < n; i++) {
|
|
106
|
-
this.nodes.
|
|
107
|
-
this.template.call(array, items[i], i)
|
|
108
|
-
);
|
|
110
|
+
this.nodes[i + length] = this.template.call(array, items[i], i);
|
|
109
111
|
}
|
|
110
|
-
|
|
111
112
|
anchor.after(this.fragment);
|
|
112
113
|
}
|
|
113
114
|
|
|
@@ -163,5 +164,14 @@ class ReactiveArraySlot<T> {
|
|
|
163
164
|
|
|
164
165
|
|
|
165
166
|
export default (anchor: Element, renderable: RenderableReactive) => {
|
|
166
|
-
|
|
167
|
+
let { array, template } = renderable,
|
|
168
|
+
slot = new ReactiveArraySlot(anchor, array, template);
|
|
169
|
+
|
|
170
|
+
if (array.length) {
|
|
171
|
+
root(() => {
|
|
172
|
+
slot.nodes = array.map(slot.template);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return slot.fragment;
|
|
167
177
|
};
|
package/src/slot/render.ts
CHANGED
|
@@ -1,81 +1,50 @@
|
|
|
1
1
|
import { isArray } from '@esportsplus/utilities';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import { Element, Fragment, RenderableReactive, RenderableTemplate } from '~/types';
|
|
8
|
-
import { append, text } from '~/utilities';
|
|
2
|
+
import { EMPTY_FRAGMENT, RENDERABLE } from '~/constants';
|
|
3
|
+
import { Element, RenderableReactive } from '~/types';
|
|
4
|
+
import { cloneNode, lastChild } from '~/utilities/node';
|
|
5
|
+
import { append } from '~/utilities/fragment';
|
|
6
|
+
import text from '~/utilities/text';
|
|
9
7
|
import reactive from './reactive';
|
|
10
8
|
|
|
11
9
|
|
|
12
|
-
function
|
|
13
|
-
if (input
|
|
14
|
-
return
|
|
10
|
+
export default function render(anchor: Element, input: unknown): Node {
|
|
11
|
+
if (input == null || input === false || input === '') {
|
|
12
|
+
return EMPTY_FRAGMENT;
|
|
15
13
|
}
|
|
16
14
|
|
|
17
15
|
if (typeof input !== 'object') {
|
|
18
|
-
return
|
|
16
|
+
return text(input as any);
|
|
19
17
|
}
|
|
20
18
|
|
|
21
|
-
if (
|
|
22
|
-
return input
|
|
19
|
+
if ('nodeType' in input) {
|
|
20
|
+
return input as Node;
|
|
23
21
|
}
|
|
24
22
|
|
|
25
|
-
if (
|
|
26
|
-
return
|
|
23
|
+
if (RENDERABLE in input) {
|
|
24
|
+
return reactive(anchor, input as RenderableReactive);
|
|
27
25
|
}
|
|
28
26
|
|
|
29
|
-
|
|
27
|
+
if (isArray(input)) {
|
|
28
|
+
let fragment = cloneNode.call(EMPTY_FRAGMENT);
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
for (let i = 0, n = (input as unknown[]).length; i < n; i++) {
|
|
31
|
+
append.call(fragment, render(anchor, (input as unknown[])[i]));
|
|
32
|
+
anchor = lastChild.call(fragment);
|
|
33
|
+
}
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
return RENDERABLE_NODE;
|
|
35
|
+
return fragment;
|
|
37
36
|
}
|
|
38
37
|
|
|
39
38
|
if (input instanceof NodeList) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
export default function render(anchor: Element, fragment: Fragment, input: unknown) {
|
|
46
|
-
let t = type(input);
|
|
39
|
+
let fragment = cloneNode.call(EMPTY_FRAGMENT),
|
|
40
|
+
nodes = Array.from(input as NodeList);
|
|
47
41
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
42
|
+
for (let i = 0, n = nodes.length; i < n; i++) {
|
|
43
|
+
append.call(fragment, nodes[i]);
|
|
44
|
+
}
|
|
51
45
|
|
|
52
|
-
|
|
53
|
-
append.call(fragment, text(String(input)));
|
|
54
|
-
return;
|
|
55
|
-
|
|
56
|
-
case RENDERABLE_HTML_FRAGMENT:
|
|
57
|
-
append.call(fragment, (input as RenderableTemplate).fragment);
|
|
58
|
-
return;
|
|
59
|
-
|
|
60
|
-
case RENDERABLE_HTML_REACTIVE_ARRAY:
|
|
61
|
-
return reactive(anchor, input as RenderableReactive);
|
|
62
|
-
|
|
63
|
-
case RENDERABLE_ARRAY:
|
|
64
|
-
for (let i = 0, n = (input as unknown[]).length; i < n; i++) {
|
|
65
|
-
render(anchor, fragment, (input as unknown[])[i]);
|
|
66
|
-
}
|
|
67
|
-
return;
|
|
68
|
-
|
|
69
|
-
case RENDERABLE_FRAGMENT:
|
|
70
|
-
append.call(fragment, input as Fragment);
|
|
71
|
-
return;
|
|
72
|
-
|
|
73
|
-
case RENDERABLE_NODE:
|
|
74
|
-
append.call(fragment, input as Node);
|
|
75
|
-
return;
|
|
76
|
-
|
|
77
|
-
case RENDERABLE_NODE_LIST:
|
|
78
|
-
append.call(fragment, ...(input as NodeList));
|
|
79
|
-
return;
|
|
46
|
+
return fragment;
|
|
80
47
|
}
|
|
48
|
+
|
|
49
|
+
return text(input as any);
|
|
81
50
|
};
|