@esportsplus/template 0.15.16 → 0.15.18
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.
Potentially problematic release.
This version of @esportsplus/template might be problematic. Click here for more details.
- package/build/attributes.d.ts +2 -2
- package/build/attributes.js +90 -45
- package/build/constants.d.ts +1 -2
- package/build/constants.js +1 -2
- package/build/event.js +6 -5
- package/build/html/hydrate.d.ts +3 -3
- package/build/html/hydrate.js +26 -25
- package/build/slot.d.ts +4 -4
- package/build/slot.js +70 -65
- package/build/types.d.ts +8 -7
- package/build/types.js +1 -1
- package/build/utilities.d.ts +2 -1
- package/build/utilities.js +2 -1
- package/package.json +3 -3
- package/src/attributes.ts +138 -50
- package/src/constants.ts +4 -16
- package/src/event.ts +8 -6
- package/src/html/hydrate.ts +31 -37
- package/src/slot.ts +95 -81
- package/src/types.ts +6 -4
- package/src/utilities.ts +3 -1
package/src/slot.ts
CHANGED
|
@@ -1,27 +1,45 @@
|
|
|
1
1
|
import { effect, root } from '@esportsplus/reactivity';
|
|
2
2
|
import { isArray, isFunction, isInstanceOf, isObject } from '@esportsplus/utilities';
|
|
3
|
-
import { RENDERABLE, RENDERABLE_REACTIVE
|
|
3
|
+
import { RENDERABLE, RENDERABLE_REACTIVE } from './constants';
|
|
4
4
|
import { hydrate } from './html';
|
|
5
|
-
import { Element, Elements, RenderableReactive, RenderableTemplate } from './types';
|
|
6
|
-
import { firstChild, microtask, nextSibling, nodeValue, raf, text } from './utilities'
|
|
5
|
+
import { Element, Elements, HydrateResult, RenderableReactive, RenderableTemplate } from './types';
|
|
6
|
+
import { append, cloneNode, firstChild, fragment, microtask, nextSibling, nodeValue, raf, text } from './utilities'
|
|
7
7
|
import queue from '@esportsplus/queue';
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
scheduled = false;
|
|
10
|
+
const CLEANUP_KEY = Symbol();
|
|
12
11
|
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
let cleanup = queue<VoidFunction[]>(64),
|
|
14
|
+
scheduled = false,
|
|
15
|
+
template = fragment('');
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
function after(anchor: Element, groups: HydrateResult[]) {
|
|
19
|
+
let n = groups.length;
|
|
20
|
+
|
|
21
|
+
if (n === 0) {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let elements: Elements[] = [],
|
|
26
|
+
fragment = groups[0].fragment || cloneNode.call(template);
|
|
27
|
+
|
|
28
|
+
if (n === 1) {
|
|
29
|
+
elements.push( groups[0].elements );
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
for (let i = 1; i < n; i++) {
|
|
33
|
+
let { elements: e, fragment: f } = groups[i];
|
|
17
34
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
anchor = group.at(-1)!;
|
|
35
|
+
append.call(fragment, f);
|
|
36
|
+
elements.push(e);
|
|
21
37
|
}
|
|
22
38
|
}
|
|
23
39
|
|
|
24
|
-
|
|
40
|
+
anchor.after(fragment);
|
|
41
|
+
|
|
42
|
+
return elements;
|
|
25
43
|
}
|
|
26
44
|
|
|
27
45
|
function remove(...groups: Elements[]) {
|
|
@@ -31,8 +49,8 @@ function remove(...groups: Elements[]) {
|
|
|
31
49
|
for (let j = 0, o = group.length; j < o; j++) {
|
|
32
50
|
let item = group[j];
|
|
33
51
|
|
|
34
|
-
if (item
|
|
35
|
-
cleanup.add(
|
|
52
|
+
if (CLEANUP_KEY in item) {
|
|
53
|
+
cleanup.add(item[CLEANUP_KEY] as VoidFunction[]);
|
|
36
54
|
}
|
|
37
55
|
|
|
38
56
|
item.remove();
|
|
@@ -46,62 +64,58 @@ function remove(...groups: Elements[]) {
|
|
|
46
64
|
return groups;
|
|
47
65
|
}
|
|
48
66
|
|
|
49
|
-
function render(
|
|
50
|
-
if (input === false || input == null) {
|
|
51
|
-
|
|
67
|
+
function render(elements: Elements[], fragment: DocumentFragment | Node, input: unknown, slot?: Slot) {
|
|
68
|
+
if (input === false || input == null || input === '') {
|
|
69
|
+
return;
|
|
52
70
|
}
|
|
53
|
-
else if (isObject(input)) {
|
|
54
|
-
if (isArray(input)) {
|
|
55
|
-
let groups: Elements[] = [];
|
|
56
|
-
|
|
57
|
-
for (let i = 0, n = input.length; i < n; i++) {
|
|
58
|
-
groups.push( render(null, input[i]) as Elements );
|
|
59
|
-
}
|
|
60
71
|
|
|
61
|
-
|
|
72
|
+
if (isArray(input)) {
|
|
73
|
+
for (let i = 0, n = input.length; i < n; i++) {
|
|
74
|
+
render(elements, fragment, input[i]);
|
|
62
75
|
}
|
|
76
|
+
}
|
|
77
|
+
else if (isObject(input) && RENDERABLE in input) {
|
|
78
|
+
if (input[RENDERABLE] === RENDERABLE_REACTIVE) {
|
|
79
|
+
let response = hydrate.reactive(input as RenderableReactive, slot!);
|
|
63
80
|
|
|
64
|
-
|
|
81
|
+
for (let i = 0, n = response.length; i < n; i++) {
|
|
82
|
+
let { elements: e, fragment: f } = response[i];
|
|
65
83
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return after(anchor!, hydrate.reactive(input as RenderableReactive, slot!));
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
nodes = hydrate.static(input as RenderableTemplate<unknown>);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
else if (isInstanceOf(input, NodeList)) {
|
|
75
|
-
for (let node = firstChild.call(input); node; node = nextSibling.call(node)) {
|
|
76
|
-
nodes.push(node);
|
|
84
|
+
append.call(fragment, f);
|
|
85
|
+
elements.push(e);
|
|
77
86
|
}
|
|
78
87
|
}
|
|
79
|
-
else
|
|
80
|
-
|
|
88
|
+
else {
|
|
89
|
+
let { elements: e, fragment: f } = hydrate.static(input as RenderableTemplate<unknown>);
|
|
90
|
+
|
|
91
|
+
append.call(fragment, f);
|
|
92
|
+
elements.push(e);
|
|
81
93
|
}
|
|
94
|
+
}
|
|
95
|
+
else if (isInstanceOf(input, NodeList)) {
|
|
96
|
+
let e: Elements = [];
|
|
82
97
|
|
|
83
|
-
|
|
84
|
-
|
|
98
|
+
for (let node = firstChild.call(input); node; node = nextSibling.call(node)) {
|
|
99
|
+
e.push(node);
|
|
85
100
|
}
|
|
86
101
|
|
|
87
|
-
|
|
102
|
+
append.call(fragment, ...e);
|
|
103
|
+
elements.push(e);
|
|
88
104
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
105
|
+
else if (isInstanceOf(input, Node)) {
|
|
106
|
+
append.call(fragment, input);
|
|
107
|
+
elements.push([ input as Element ]);
|
|
92
108
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if (anchor) {
|
|
97
|
-
anchor.after(node);
|
|
109
|
+
else {
|
|
110
|
+
let element = text( typeof input === 'string' ? input : String(input) );
|
|
98
111
|
|
|
99
112
|
if (slot) {
|
|
100
|
-
slot.text =
|
|
113
|
+
slot.text = element;
|
|
101
114
|
}
|
|
102
|
-
}
|
|
103
115
|
|
|
104
|
-
|
|
116
|
+
append.call(fragment, element);
|
|
117
|
+
elements.push([ element ]);
|
|
118
|
+
}
|
|
105
119
|
}
|
|
106
120
|
|
|
107
121
|
function schedule() {
|
|
@@ -110,20 +124,19 @@ function schedule() {
|
|
|
110
124
|
}
|
|
111
125
|
|
|
112
126
|
scheduled = true;
|
|
113
|
-
|
|
114
127
|
microtask.add(task);
|
|
115
128
|
}
|
|
116
129
|
|
|
117
130
|
function task() {
|
|
118
|
-
let fns;
|
|
131
|
+
let fn, fns;
|
|
119
132
|
|
|
120
133
|
while (fns = cleanup.next()) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
134
|
+
try {
|
|
135
|
+
while (fn = fns.pop()) {
|
|
136
|
+
fn();
|
|
124
137
|
}
|
|
125
|
-
catch { }
|
|
126
138
|
}
|
|
139
|
+
catch { }
|
|
127
140
|
}
|
|
128
141
|
|
|
129
142
|
scheduled = false;
|
|
@@ -162,7 +175,7 @@ class Slot {
|
|
|
162
175
|
nodes = this.nodes[index];
|
|
163
176
|
|
|
164
177
|
if (nodes) {
|
|
165
|
-
node = nodes.
|
|
178
|
+
node = nodes[nodes.length - 1];
|
|
166
179
|
}
|
|
167
180
|
|
|
168
181
|
return node || this.marker;
|
|
@@ -170,6 +183,7 @@ class Slot {
|
|
|
170
183
|
|
|
171
184
|
clear() {
|
|
172
185
|
remove(...this.nodes);
|
|
186
|
+
this.nodes.length = 0;
|
|
173
187
|
this.text = null;
|
|
174
188
|
}
|
|
175
189
|
|
|
@@ -183,14 +197,8 @@ class Slot {
|
|
|
183
197
|
return remove(group);
|
|
184
198
|
}
|
|
185
199
|
|
|
186
|
-
push(...groups:
|
|
187
|
-
after(this.anchor(), groups);
|
|
188
|
-
|
|
189
|
-
for (let i = 0, n = groups.length; i < n; i++) {
|
|
190
|
-
this.nodes.push(groups[i]);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return this.nodes.length;
|
|
200
|
+
push(...groups: HydrateResult[]) {
|
|
201
|
+
return this.nodes.push( ...after(this.anchor(), groups) );
|
|
194
202
|
}
|
|
195
203
|
|
|
196
204
|
render(input: unknown) {
|
|
@@ -198,7 +206,7 @@ class Slot {
|
|
|
198
206
|
ondisconnect(
|
|
199
207
|
this.marker,
|
|
200
208
|
effect(() => {
|
|
201
|
-
let v =
|
|
209
|
+
let v = input();
|
|
202
210
|
|
|
203
211
|
if (isFunction(v)) {
|
|
204
212
|
root(() => this.render(v()));
|
|
@@ -217,7 +225,8 @@ class Slot {
|
|
|
217
225
|
if (this.text) {
|
|
218
226
|
let type = typeof input;
|
|
219
227
|
|
|
220
|
-
if (type === 'object' && input !== null) {
|
|
228
|
+
if (type === 'object' && input !== null) {
|
|
229
|
+
}
|
|
221
230
|
else if (this.text.isConnected) {
|
|
222
231
|
nodeValue.call(
|
|
223
232
|
this.text,
|
|
@@ -229,12 +238,13 @@ class Slot {
|
|
|
229
238
|
|
|
230
239
|
this.clear();
|
|
231
240
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
241
|
+
let fragment = cloneNode.call(template),
|
|
242
|
+
nodes: Elements[] = [];
|
|
243
|
+
|
|
244
|
+
render(nodes, fragment, input, this);
|
|
245
|
+
|
|
246
|
+
this.marker.after(fragment);
|
|
247
|
+
this.nodes = nodes;
|
|
238
248
|
|
|
239
249
|
return this;
|
|
240
250
|
}
|
|
@@ -249,20 +259,24 @@ class Slot {
|
|
|
249
259
|
return remove(group);
|
|
250
260
|
}
|
|
251
261
|
|
|
252
|
-
splice(start: number, stop: number = this.nodes.length, ...groups:
|
|
262
|
+
splice(start: number, stop: number = this.nodes.length, ...groups: HydrateResult[]) {
|
|
253
263
|
return remove(
|
|
254
|
-
...this.nodes.splice(
|
|
264
|
+
...this.nodes.splice(
|
|
265
|
+
start,
|
|
266
|
+
stop,
|
|
267
|
+
...after(this.anchor(start), groups)
|
|
268
|
+
)
|
|
255
269
|
);
|
|
256
270
|
}
|
|
257
271
|
|
|
258
|
-
unshift(...groups:
|
|
259
|
-
return this.nodes.unshift(...after(this.marker, groups));
|
|
272
|
+
unshift(...groups: HydrateResult[]) {
|
|
273
|
+
return this.nodes.unshift( ...after(this.marker, groups) );
|
|
260
274
|
}
|
|
261
275
|
}
|
|
262
276
|
|
|
263
277
|
|
|
264
278
|
const ondisconnect = (element: Element, fn: VoidFunction) => {
|
|
265
|
-
(
|
|
279
|
+
((element[CLEANUP_KEY] ??= []) as VoidFunction[]).push(fn);
|
|
266
280
|
};
|
|
267
281
|
|
|
268
282
|
|
package/src/types.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { ReactiveArray } from '@esportsplus/reactivity';
|
|
2
|
-
import { RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE
|
|
2
|
+
import { RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE } from './constants';
|
|
3
3
|
import { firstChild } from './utilities';
|
|
4
4
|
import attributes from './attributes';
|
|
5
|
-
import event from './event';
|
|
6
5
|
import slot from './slot';
|
|
7
6
|
|
|
8
7
|
|
|
@@ -27,10 +26,12 @@ type Effect<T> = () => EffectResponse<T>;
|
|
|
27
26
|
|
|
28
27
|
type EffectResponse<T> = T extends [] ? EffectResponse<T[number]>[] : Primitive | Renderable<T>;
|
|
29
28
|
|
|
30
|
-
type Element = HTMLElement & Attributes &
|
|
29
|
+
type Element = HTMLElement & Attributes & Record<PropertyKey, unknown>;
|
|
31
30
|
|
|
32
31
|
type Elements = Element[];
|
|
33
32
|
|
|
33
|
+
type HydrateResult = { elements: Elements, fragment: DocumentFragment | Node };
|
|
34
|
+
|
|
34
35
|
// Copied from '@esportsplus/utilities'
|
|
35
36
|
// - Importing from ^ causes 'cannot be named without a reference to...' error
|
|
36
37
|
type Primitive = bigint | boolean | null | number | string | undefined;
|
|
@@ -61,7 +62,7 @@ type Template = {
|
|
|
61
62
|
html: string;
|
|
62
63
|
literals: TemplateStringsArray;
|
|
63
64
|
slots: {
|
|
64
|
-
fn: typeof attributes.spread | typeof
|
|
65
|
+
fn: typeof attributes.spread | typeof slot;
|
|
65
66
|
path: typeof firstChild[];
|
|
66
67
|
slot: number;
|
|
67
68
|
}[] | null;
|
|
@@ -71,6 +72,7 @@ type Template = {
|
|
|
71
72
|
export type {
|
|
72
73
|
Attributes,
|
|
73
74
|
Effect, Element, Elements,
|
|
75
|
+
HydrateResult,
|
|
74
76
|
Renderable, RenderableReactive, RenderableTemplate, RenderableValue,
|
|
75
77
|
Template
|
|
76
78
|
};
|
package/src/utilities.ts
CHANGED
|
@@ -12,6 +12,8 @@ prototype = Element.prototype;
|
|
|
12
12
|
|
|
13
13
|
const addEventListener = prototype.addEventListener;
|
|
14
14
|
|
|
15
|
+
const append = prototype.append;
|
|
16
|
+
|
|
15
17
|
const removeEventListener = prototype.removeEventListener;
|
|
16
18
|
|
|
17
19
|
const className = Object.getOwnPropertyDescriptor(prototype, 'className')!.set!;
|
|
@@ -70,7 +72,7 @@ const text = (value: string) => {
|
|
|
70
72
|
|
|
71
73
|
|
|
72
74
|
export {
|
|
73
|
-
addEventListener,
|
|
75
|
+
addEventListener, append,
|
|
74
76
|
className, cloneNode,
|
|
75
77
|
firstChild, firstElementChild, fragment,
|
|
76
78
|
innerHTML,
|