@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/build/attributes.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Attributes, Element } from './types.js';
|
|
2
2
|
declare const apply: (element: Element) => void;
|
|
3
|
-
declare const spread: (element: Element,
|
|
3
|
+
declare const spread: (element: Element, value: Attributes | Attributes[]) => void;
|
|
4
4
|
declare const _default: {
|
|
5
5
|
apply: (element: Element) => void;
|
|
6
|
-
spread: (element: Element,
|
|
6
|
+
spread: (element: Element, value: Attributes | Attributes[]) => void;
|
|
7
7
|
};
|
|
8
8
|
export default _default;
|
|
9
9
|
export { apply, spread };
|
package/build/attributes.js
CHANGED
|
@@ -2,11 +2,19 @@ import { effect } from '@esportsplus/reactivity';
|
|
|
2
2
|
import { isArray, isFunction, isObject, isString } from '@esportsplus/utilities';
|
|
3
3
|
import { ondisconnect } from './slot.js';
|
|
4
4
|
import { className, raf, removeAttribute, setAttribute } from './utilities.js';
|
|
5
|
+
import q from '@esportsplus/queue';
|
|
5
6
|
import event from './event.js';
|
|
6
|
-
|
|
7
|
+
const EFFECT_KEY = Symbol();
|
|
8
|
+
const HYDRATE_KEY = Symbol();
|
|
9
|
+
const STORE_KEY = Symbol();
|
|
10
|
+
const UPDATES_KEY = Symbol();
|
|
11
|
+
const STATE_HYDRATING = 0;
|
|
12
|
+
const STATE_NONE = 1;
|
|
13
|
+
const STATE_WAITING = 2;
|
|
14
|
+
let delimiters = {
|
|
7
15
|
class: ' ',
|
|
8
16
|
style: ';'
|
|
9
|
-
},
|
|
17
|
+
}, queue = q(64), scheduled = false;
|
|
10
18
|
function attribute(element, name, value) {
|
|
11
19
|
if (value === '' || value === false || value == null) {
|
|
12
20
|
removeAttribute.call(element, name);
|
|
@@ -21,55 +29,79 @@ function attribute(element, name, value) {
|
|
|
21
29
|
element[name] = value;
|
|
22
30
|
}
|
|
23
31
|
}
|
|
24
|
-
function
|
|
32
|
+
function schedule() {
|
|
33
|
+
if (scheduled) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
scheduled = true;
|
|
37
|
+
raf.add(task);
|
|
38
|
+
}
|
|
39
|
+
function set(context, name, value, state) {
|
|
25
40
|
if (isArray(value)) {
|
|
26
41
|
for (let i = 0, n = value.length; i < n; i++) {
|
|
27
|
-
set(
|
|
42
|
+
set(context, name, value[i], state);
|
|
28
43
|
}
|
|
29
44
|
}
|
|
30
45
|
else if (isFunction(value)) {
|
|
31
46
|
if (name.startsWith('on')) {
|
|
32
|
-
event(element, name, value);
|
|
47
|
+
event(context.element, name, value);
|
|
33
48
|
}
|
|
34
49
|
else {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
50
|
+
context.store[EFFECT_KEY] ??= 0;
|
|
51
|
+
let id = context.store[EFFECT_KEY]++;
|
|
52
|
+
ondisconnect(context.element, effect(() => {
|
|
53
|
+
let v = value(context.element);
|
|
38
54
|
if (isArray(v)) {
|
|
39
55
|
let last = v.length - 1;
|
|
40
56
|
for (let i = 0, n = v.length; i < n; i++) {
|
|
41
|
-
update(
|
|
57
|
+
update(context, id, name, v[i], state === STATE_HYDRATING
|
|
58
|
+
? state
|
|
59
|
+
: i !== last ? STATE_WAITING : state);
|
|
42
60
|
}
|
|
43
61
|
}
|
|
44
62
|
else {
|
|
45
|
-
update(
|
|
63
|
+
update(context, id, name, v, state);
|
|
46
64
|
}
|
|
47
65
|
}));
|
|
48
|
-
|
|
66
|
+
state = STATE_NONE;
|
|
49
67
|
}
|
|
50
68
|
}
|
|
51
69
|
else {
|
|
52
|
-
update(
|
|
70
|
+
update(context, null, name, value, state);
|
|
53
71
|
}
|
|
54
72
|
}
|
|
55
|
-
function
|
|
56
|
-
|
|
73
|
+
function task() {
|
|
74
|
+
let context, n = queue.length;
|
|
75
|
+
while ((context = queue.next()) && n--) {
|
|
76
|
+
let { element, updates } = context;
|
|
77
|
+
for (let name in updates) {
|
|
78
|
+
attribute(element, name, updates[name]);
|
|
79
|
+
delete updates[name];
|
|
80
|
+
}
|
|
81
|
+
context.updating = false;
|
|
82
|
+
}
|
|
83
|
+
if (queue.length) {
|
|
84
|
+
raf.add(task);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
scheduled = false;
|
|
88
|
+
}
|
|
57
89
|
}
|
|
58
|
-
function update(
|
|
90
|
+
function update(context, id, name, value, state) {
|
|
59
91
|
if (value === false || value == null) {
|
|
60
92
|
value = '';
|
|
61
93
|
}
|
|
62
|
-
let
|
|
94
|
+
let store = context.store;
|
|
63
95
|
if (name in delimiters) {
|
|
64
|
-
let cache = name + '.static', delimiter = delimiters[name], dynamic =
|
|
96
|
+
let cache = name + '.static', delimiter = delimiters[name], dynamic = store[name];
|
|
65
97
|
if (dynamic === undefined) {
|
|
66
|
-
let value = (element.getAttribute(name) || '').trim();
|
|
67
|
-
|
|
68
|
-
|
|
98
|
+
let value = (context.element.getAttribute(name) || '').trim();
|
|
99
|
+
store[cache] = value;
|
|
100
|
+
store[name] = dynamic = {};
|
|
69
101
|
}
|
|
70
102
|
if (id === null) {
|
|
71
103
|
if (value && isString(value)) {
|
|
72
|
-
|
|
104
|
+
store[cache] += (store[cache] ? delimiter : '') + value;
|
|
73
105
|
}
|
|
74
106
|
}
|
|
75
107
|
else {
|
|
@@ -85,7 +117,7 @@ function update(element, id, name, value, wait = false) {
|
|
|
85
117
|
hot[part] = null;
|
|
86
118
|
}
|
|
87
119
|
}
|
|
88
|
-
let cold =
|
|
120
|
+
let cold = store[id];
|
|
89
121
|
if (cold !== undefined) {
|
|
90
122
|
for (let part in cold) {
|
|
91
123
|
if (part in hot) {
|
|
@@ -94,48 +126,61 @@ function update(element, id, name, value, wait = false) {
|
|
|
94
126
|
delete dynamic[part];
|
|
95
127
|
}
|
|
96
128
|
}
|
|
97
|
-
|
|
129
|
+
store[id] = hot;
|
|
98
130
|
}
|
|
99
|
-
value =
|
|
131
|
+
value = store[cache];
|
|
100
132
|
for (let key in dynamic) {
|
|
101
133
|
value += (value ? delimiter : '') + key;
|
|
102
134
|
}
|
|
103
135
|
}
|
|
104
|
-
else if (
|
|
105
|
-
if (
|
|
136
|
+
else if (id !== null) {
|
|
137
|
+
if (store[name] === value) {
|
|
106
138
|
return;
|
|
107
139
|
}
|
|
108
|
-
|
|
140
|
+
store[name] = value;
|
|
109
141
|
}
|
|
110
|
-
if (
|
|
111
|
-
|
|
112
|
-
attributes[name] = value;
|
|
113
|
-
}
|
|
142
|
+
if (state === STATE_HYDRATING) {
|
|
143
|
+
(context.element[HYDRATE_KEY] ??= {})[name] = value;
|
|
114
144
|
}
|
|
115
145
|
else {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
146
|
+
context.updates[name] = value;
|
|
147
|
+
if (state === STATE_NONE && !context.updating) {
|
|
148
|
+
context.updating = true;
|
|
149
|
+
queue.add(context);
|
|
150
|
+
}
|
|
151
|
+
if (!scheduled) {
|
|
152
|
+
schedule();
|
|
153
|
+
}
|
|
119
154
|
}
|
|
120
155
|
}
|
|
121
156
|
const apply = (element) => {
|
|
157
|
+
let attributes = element[HYDRATE_KEY];
|
|
158
|
+
if (!attributes) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
122
161
|
for (let key in attributes) {
|
|
123
162
|
attribute(element, key, attributes[key]);
|
|
124
163
|
}
|
|
125
|
-
|
|
164
|
+
delete element[HYDRATE_KEY];
|
|
126
165
|
};
|
|
127
|
-
const spread = function (element,
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
166
|
+
const spread = function (element, value) {
|
|
167
|
+
let cache = (element[STORE_KEY] ??= { [UPDATES_KEY]: {} }), context = {
|
|
168
|
+
element,
|
|
169
|
+
store: cache,
|
|
170
|
+
updates: cache[UPDATES_KEY],
|
|
171
|
+
updating: false
|
|
172
|
+
};
|
|
173
|
+
if (isArray(value)) {
|
|
174
|
+
for (let i = 0, n = value.length; i < n; i++) {
|
|
175
|
+
let v = value[i];
|
|
176
|
+
for (let name in v) {
|
|
177
|
+
set(context, name, v[name], STATE_HYDRATING);
|
|
178
|
+
}
|
|
131
179
|
}
|
|
132
180
|
}
|
|
133
|
-
else if (
|
|
134
|
-
for (let
|
|
135
|
-
|
|
136
|
-
for (let name in attrs) {
|
|
137
|
-
set(element, attrs[name], name, true);
|
|
138
|
-
}
|
|
181
|
+
else if (isObject(value)) {
|
|
182
|
+
for (let name in value) {
|
|
183
|
+
set(context, name, value[name], STATE_HYDRATING);
|
|
139
184
|
}
|
|
140
185
|
}
|
|
141
186
|
};
|
package/build/constants.d.ts
CHANGED
|
@@ -8,8 +8,7 @@ declare const REGEX_SLOT_NODES: RegExp;
|
|
|
8
8
|
declare const RENDERABLE: unique symbol;
|
|
9
9
|
declare const RENDERABLE_REACTIVE: unique symbol;
|
|
10
10
|
declare const RENDERABLE_TEMPLATE: unique symbol;
|
|
11
|
-
declare const SLOT_CLEANUP: unique symbol;
|
|
12
11
|
declare const SLOT_HTML = "<!--$-->";
|
|
13
12
|
declare const SLOT_MARKER = "{{$}}";
|
|
14
13
|
declare const SLOT_MARKER_LENGTH: number;
|
|
15
|
-
export { NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE,
|
|
14
|
+
export { NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH };
|
package/build/constants.js
CHANGED
|
@@ -28,8 +28,7 @@ const REGEX_SLOT_NODES = /<([\w-]+|[\/!])(?:([^><]*{{\$}}[^><]*)|(?:[^><]*))?>|{
|
|
|
28
28
|
const RENDERABLE = Symbol();
|
|
29
29
|
const RENDERABLE_REACTIVE = Symbol();
|
|
30
30
|
const RENDERABLE_TEMPLATE = Symbol();
|
|
31
|
-
const SLOT_CLEANUP = Symbol();
|
|
32
31
|
const SLOT_HTML = '<!--$-->';
|
|
33
32
|
const SLOT_MARKER = '{{$}}';
|
|
34
33
|
const SLOT_MARKER_LENGTH = SLOT_MARKER.length;
|
|
35
|
-
export { NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE,
|
|
34
|
+
export { NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH };
|
package/build/event.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { root } from '@esportsplus/reactivity';
|
|
2
2
|
import { defineProperty } from '@esportsplus/utilities';
|
|
3
3
|
import { ondisconnect } from './slot.js';
|
|
4
|
-
import { addEventListener, parentElement } from './utilities.js';
|
|
4
|
+
import { addEventListener, parentElement, raf } from './utilities.js';
|
|
5
5
|
let capture = new Set(['onblur', 'onfocus', 'onscroll']), controllers = new Map(), keys = {}, passive = new Set([
|
|
6
6
|
'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel',
|
|
7
7
|
'onscroll',
|
|
@@ -13,16 +13,17 @@ let capture = new Set(['onblur', 'onfocus', 'onscroll']), controllers = new Map(
|
|
|
13
13
|
});
|
|
14
14
|
export default (element, event, listener) => {
|
|
15
15
|
if (event === 'onconnect') {
|
|
16
|
-
let
|
|
16
|
+
let retry = 60, task = () => {
|
|
17
17
|
retry--;
|
|
18
18
|
if (element.isConnected) {
|
|
19
19
|
retry = 0;
|
|
20
20
|
root(() => listener(element));
|
|
21
21
|
}
|
|
22
|
-
if (
|
|
23
|
-
|
|
22
|
+
if (retry) {
|
|
23
|
+
raf.add(task);
|
|
24
24
|
}
|
|
25
|
-
}
|
|
25
|
+
};
|
|
26
|
+
raf.add(task);
|
|
26
27
|
return;
|
|
27
28
|
}
|
|
28
29
|
else if (event === 'ondisconnect') {
|
package/build/html/hydrate.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HydrateResult, RenderableReactive, RenderableTemplate } from '../types.js';
|
|
2
2
|
import { Slot } from '../slot.js';
|
|
3
3
|
declare const _default: {
|
|
4
|
-
reactive: <T>(renderable: RenderableReactive<T>, slot: Slot) =>
|
|
5
|
-
static: <T>(renderable: RenderableTemplate<T>) =>
|
|
4
|
+
reactive: <T>(renderable: RenderableReactive<T>, slot: Slot) => HydrateResult[];
|
|
5
|
+
static: <T>(renderable: RenderableTemplate<T>) => HydrateResult;
|
|
6
6
|
};
|
|
7
7
|
export default _default;
|
package/build/html/hydrate.js
CHANGED
|
@@ -4,28 +4,37 @@ import { apply } from '../attributes.js';
|
|
|
4
4
|
import cache from './cache.js';
|
|
5
5
|
function reactive(renderable, slot) {
|
|
6
6
|
let array = renderable.values, factory = renderable.template, refresh = () => {
|
|
7
|
-
slot.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return
|
|
11
|
-
}
|
|
12
|
-
array.on('pop', () =>
|
|
13
|
-
|
|
7
|
+
slot.render(root(() => array.map(template)));
|
|
8
|
+
}, template = function (data, i) {
|
|
9
|
+
let renderable = factory.call(this, data, i);
|
|
10
|
+
return hydrate(renderable, cache.get(renderable));
|
|
11
|
+
};
|
|
12
|
+
array.on('pop', () => {
|
|
13
|
+
slot.pop();
|
|
14
|
+
});
|
|
15
|
+
array.on('push', ({ items }) => {
|
|
16
|
+
slot.push(...root(() => array.map(template, array.length - items.length)));
|
|
17
|
+
});
|
|
14
18
|
array.on('reverse', refresh);
|
|
15
|
-
array.on('shift', () =>
|
|
19
|
+
array.on('shift', () => {
|
|
20
|
+
slot.shift();
|
|
21
|
+
});
|
|
16
22
|
array.on('sort', refresh);
|
|
17
|
-
array.on('splice', ({ deleteCount: d, items: i, start: s }) =>
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
array.on('splice', ({ deleteCount: d, items: i, start: s }) => {
|
|
24
|
+
slot.splice(s, d, ...root(() => array.map(template, s, i.length)));
|
|
25
|
+
});
|
|
26
|
+
array.on('unshift', ({ items }) => {
|
|
27
|
+
slot.unshift(...root(() => array.map(template, 0, items.length)));
|
|
28
|
+
});
|
|
29
|
+
return array.map(template);
|
|
20
30
|
}
|
|
21
|
-
function
|
|
31
|
+
function hydrate(renderable, template) {
|
|
22
32
|
let elements = [], fragment = cloneNode.call(template.fragment, true), slots = template.slots;
|
|
23
33
|
if (slots !== null) {
|
|
24
34
|
let node, previous, values = renderable.values;
|
|
25
35
|
for (let i = slots.length - 1; i >= 0; i--) {
|
|
26
36
|
let { fn, path, slot } = slots[i];
|
|
27
|
-
if (path
|
|
28
|
-
else {
|
|
37
|
+
if (path !== previous) {
|
|
29
38
|
apply(node);
|
|
30
39
|
node = fragment;
|
|
31
40
|
previous = path;
|
|
@@ -33,28 +42,20 @@ function render(renderable, template) {
|
|
|
33
42
|
node = path[o].call(node);
|
|
34
43
|
}
|
|
35
44
|
}
|
|
36
|
-
fn(node, values[slot]
|
|
45
|
+
fn(node, values[slot]);
|
|
37
46
|
}
|
|
38
47
|
apply(node);
|
|
39
48
|
}
|
|
40
49
|
for (let element = firstChild.call(fragment); element; element = nextSibling.call(element)) {
|
|
41
50
|
elements.push(element);
|
|
42
51
|
}
|
|
43
|
-
return elements;
|
|
44
|
-
}
|
|
45
|
-
function template(array, template, i, n) {
|
|
46
|
-
let groups = [], renderables = array.map(template, i, n);
|
|
47
|
-
for (let i = 0, n = renderables.length; i < n; i++) {
|
|
48
|
-
let renderable = renderables[i];
|
|
49
|
-
groups.push(render(renderable, cache.get(renderable)));
|
|
50
|
-
}
|
|
51
|
-
return groups;
|
|
52
|
+
return { elements, fragment };
|
|
52
53
|
}
|
|
53
54
|
export default {
|
|
54
55
|
reactive: (renderable, slot) => {
|
|
55
56
|
return reactive(renderable, slot);
|
|
56
57
|
},
|
|
57
58
|
static: (renderable) => {
|
|
58
|
-
return
|
|
59
|
+
return hydrate(renderable, renderable.template || (renderable.template = cache.get(renderable)));
|
|
59
60
|
}
|
|
60
61
|
};
|
package/build/slot.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Element, Elements } from './types.js';
|
|
1
|
+
import { Element, Elements, HydrateResult } from './types.js';
|
|
2
2
|
declare class Slot {
|
|
3
3
|
marker: Element;
|
|
4
4
|
nodes: Elements[];
|
|
@@ -9,11 +9,11 @@ declare class Slot {
|
|
|
9
9
|
anchor(index?: number): Element;
|
|
10
10
|
clear(): void;
|
|
11
11
|
pop(): Elements[] | undefined;
|
|
12
|
-
push(...groups:
|
|
12
|
+
push(...groups: HydrateResult[]): number;
|
|
13
13
|
render(input: unknown): this;
|
|
14
14
|
shift(): Elements[] | undefined;
|
|
15
|
-
splice(start: number, stop?: number, ...groups:
|
|
16
|
-
unshift(...groups:
|
|
15
|
+
splice(start: number, stop?: number, ...groups: HydrateResult[]): Elements[];
|
|
16
|
+
unshift(...groups: HydrateResult[]): number;
|
|
17
17
|
}
|
|
18
18
|
declare const ondisconnect: (element: Element, fn: VoidFunction) => void;
|
|
19
19
|
declare const _default: (marker: Element, value: unknown) => Slot;
|
package/build/slot.js
CHANGED
|
@@ -1,27 +1,37 @@
|
|
|
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.js';
|
|
4
4
|
import { hydrate } from './html/index.js';
|
|
5
|
-
import { firstChild, microtask, nextSibling, nodeValue, raf, text } from './utilities.js';
|
|
5
|
+
import { append, cloneNode, firstChild, fragment, microtask, nextSibling, nodeValue, raf, text } from './utilities.js';
|
|
6
6
|
import queue from '@esportsplus/queue';
|
|
7
|
-
|
|
7
|
+
const CLEANUP_KEY = Symbol();
|
|
8
|
+
let cleanup = queue(64), scheduled = false, template = fragment('');
|
|
8
9
|
function after(anchor, groups) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
let n = groups.length;
|
|
11
|
+
if (n === 0) {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
let elements = [], fragment = groups[0].fragment || cloneNode.call(template);
|
|
15
|
+
if (n === 1) {
|
|
16
|
+
elements.push(groups[0].elements);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
for (let i = 1; i < n; i++) {
|
|
20
|
+
let { elements: e, fragment: f } = groups[i];
|
|
21
|
+
append.call(fragment, f);
|
|
22
|
+
elements.push(e);
|
|
14
23
|
}
|
|
15
24
|
}
|
|
16
|
-
|
|
25
|
+
anchor.after(fragment);
|
|
26
|
+
return elements;
|
|
17
27
|
}
|
|
18
28
|
function remove(...groups) {
|
|
19
29
|
for (let i = 0, n = groups.length; i < n; i++) {
|
|
20
30
|
let group = groups[i];
|
|
21
31
|
for (let j = 0, o = group.length; j < o; j++) {
|
|
22
32
|
let item = group[j];
|
|
23
|
-
if (item
|
|
24
|
-
cleanup.add(item[
|
|
33
|
+
if (CLEANUP_KEY in item) {
|
|
34
|
+
cleanup.add(item[CLEANUP_KEY]);
|
|
25
35
|
}
|
|
26
36
|
item.remove();
|
|
27
37
|
}
|
|
@@ -31,51 +41,50 @@ function remove(...groups) {
|
|
|
31
41
|
}
|
|
32
42
|
return groups;
|
|
33
43
|
}
|
|
34
|
-
function render(
|
|
35
|
-
if (input === false || input == null) {
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
for (let i = 0, n = input.length; i < n; i++) {
|
|
42
|
-
groups.push(render(null, input[i]));
|
|
43
|
-
}
|
|
44
|
-
return anchor ? after(anchor, groups) : groups;
|
|
45
|
-
}
|
|
46
|
-
let nodes = [];
|
|
47
|
-
if (RENDERABLE in input) {
|
|
48
|
-
if (input[RENDERABLE] === RENDERABLE_REACTIVE) {
|
|
49
|
-
return after(anchor, hydrate.reactive(input, slot));
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
nodes = hydrate.static(input);
|
|
53
|
-
}
|
|
44
|
+
function render(elements, fragment, input, slot) {
|
|
45
|
+
if (input === false || input == null || input === '') {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (isArray(input)) {
|
|
49
|
+
for (let i = 0, n = input.length; i < n; i++) {
|
|
50
|
+
render(elements, fragment, input[i]);
|
|
54
51
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
}
|
|
53
|
+
else if (isObject(input) && RENDERABLE in input) {
|
|
54
|
+
if (input[RENDERABLE] === RENDERABLE_REACTIVE) {
|
|
55
|
+
let response = hydrate.reactive(input, slot);
|
|
56
|
+
for (let i = 0, n = response.length; i < n; i++) {
|
|
57
|
+
let { elements: e, fragment: f } = response[i];
|
|
58
|
+
append.call(fragment, f);
|
|
59
|
+
elements.push(e);
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
|
-
else
|
|
61
|
-
|
|
62
|
+
else {
|
|
63
|
+
let { elements: e, fragment: f } = hydrate.static(input);
|
|
64
|
+
append.call(fragment, f);
|
|
65
|
+
elements.push(e);
|
|
62
66
|
}
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
}
|
|
68
|
+
else if (isInstanceOf(input, NodeList)) {
|
|
69
|
+
let e = [];
|
|
70
|
+
for (let node = firstChild.call(input); node; node = nextSibling.call(node)) {
|
|
71
|
+
e.push(node);
|
|
65
72
|
}
|
|
66
|
-
|
|
73
|
+
append.call(fragment, ...e);
|
|
74
|
+
elements.push(e);
|
|
67
75
|
}
|
|
68
|
-
if (input
|
|
69
|
-
|
|
76
|
+
else if (isInstanceOf(input, Node)) {
|
|
77
|
+
append.call(fragment, input);
|
|
78
|
+
elements.push([input]);
|
|
70
79
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
anchor.after(node);
|
|
80
|
+
else {
|
|
81
|
+
let element = text(typeof input === 'string' ? input : String(input));
|
|
74
82
|
if (slot) {
|
|
75
|
-
slot.text =
|
|
83
|
+
slot.text = element;
|
|
76
84
|
}
|
|
85
|
+
append.call(fragment, element);
|
|
86
|
+
elements.push([element]);
|
|
77
87
|
}
|
|
78
|
-
return [node];
|
|
79
88
|
}
|
|
80
89
|
function schedule() {
|
|
81
90
|
if (scheduled) {
|
|
@@ -85,14 +94,14 @@ function schedule() {
|
|
|
85
94
|
microtask.add(task);
|
|
86
95
|
}
|
|
87
96
|
function task() {
|
|
88
|
-
let fns;
|
|
97
|
+
let fn, fns;
|
|
89
98
|
while (fns = cleanup.next()) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
99
|
+
try {
|
|
100
|
+
while (fn = fns.pop()) {
|
|
101
|
+
fn();
|
|
93
102
|
}
|
|
94
|
-
catch { }
|
|
95
103
|
}
|
|
104
|
+
catch { }
|
|
96
105
|
}
|
|
97
106
|
scheduled = false;
|
|
98
107
|
if (cleanup.length) {
|
|
@@ -117,12 +126,13 @@ class Slot {
|
|
|
117
126
|
anchor(index = this.nodes.length - 1) {
|
|
118
127
|
let node, nodes = this.nodes[index];
|
|
119
128
|
if (nodes) {
|
|
120
|
-
node = nodes.
|
|
129
|
+
node = nodes[nodes.length - 1];
|
|
121
130
|
}
|
|
122
131
|
return node || this.marker;
|
|
123
132
|
}
|
|
124
133
|
clear() {
|
|
125
134
|
remove(...this.nodes);
|
|
135
|
+
this.nodes.length = 0;
|
|
126
136
|
this.text = null;
|
|
127
137
|
}
|
|
128
138
|
pop() {
|
|
@@ -133,11 +143,7 @@ class Slot {
|
|
|
133
143
|
return remove(group);
|
|
134
144
|
}
|
|
135
145
|
push(...groups) {
|
|
136
|
-
after(this.anchor(), groups);
|
|
137
|
-
for (let i = 0, n = groups.length; i < n; i++) {
|
|
138
|
-
this.nodes.push(groups[i]);
|
|
139
|
-
}
|
|
140
|
-
return this.nodes.length;
|
|
146
|
+
return this.nodes.push(...after(this.anchor(), groups));
|
|
141
147
|
}
|
|
142
148
|
render(input) {
|
|
143
149
|
if (isFunction(input)) {
|
|
@@ -156,19 +162,18 @@ class Slot {
|
|
|
156
162
|
}
|
|
157
163
|
if (this.text) {
|
|
158
164
|
let type = typeof input;
|
|
159
|
-
if (type === 'object' && input !== null) {
|
|
165
|
+
if (type === 'object' && input !== null) {
|
|
166
|
+
}
|
|
160
167
|
else if (this.text.isConnected) {
|
|
161
168
|
nodeValue.call(this.text, (type === 'string' || type === 'number') ? input : '');
|
|
162
169
|
return this;
|
|
163
170
|
}
|
|
164
171
|
}
|
|
165
172
|
this.clear();
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
this.nodes = [render(this.marker, input, this)];
|
|
171
|
-
}
|
|
173
|
+
let fragment = cloneNode.call(template), nodes = [];
|
|
174
|
+
render(nodes, fragment, input, this);
|
|
175
|
+
this.marker.after(fragment);
|
|
176
|
+
this.nodes = nodes;
|
|
172
177
|
return this;
|
|
173
178
|
}
|
|
174
179
|
shift() {
|
|
@@ -186,7 +191,7 @@ class Slot {
|
|
|
186
191
|
}
|
|
187
192
|
}
|
|
188
193
|
const ondisconnect = (element, fn) => {
|
|
189
|
-
(element[
|
|
194
|
+
(element[CLEANUP_KEY] ??= []).push(fn);
|
|
190
195
|
};
|
|
191
196
|
export default (marker, value) => {
|
|
192
197
|
return new Slot(marker).render(value);
|
package/build/types.d.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.js';
|
|
3
3
|
import { firstChild } from './utilities.js';
|
|
4
4
|
import attributes from './attributes.js';
|
|
5
|
-
import event from './event.js';
|
|
6
5
|
import slot from './slot.js';
|
|
7
6
|
type Attribute = Primitive | Effect<Primitive | Primitive[]>;
|
|
8
7
|
type Attributes = {
|
|
@@ -19,10 +18,12 @@ type Attributes = {
|
|
|
19
18
|
} & Record<PropertyKey, unknown>;
|
|
20
19
|
type Effect<T> = () => EffectResponse<T>;
|
|
21
20
|
type EffectResponse<T> = T extends [] ? EffectResponse<T[number]>[] : Primitive | Renderable<T>;
|
|
22
|
-
type Element = HTMLElement & Attributes &
|
|
23
|
-
[SLOT_CLEANUP]?: VoidFunction[];
|
|
24
|
-
} & Record<PropertyKey, unknown>;
|
|
21
|
+
type Element = HTMLElement & Attributes & Record<PropertyKey, unknown>;
|
|
25
22
|
type Elements = Element[];
|
|
23
|
+
type HydrateResult = {
|
|
24
|
+
elements: Elements;
|
|
25
|
+
fragment: DocumentFragment | Node;
|
|
26
|
+
};
|
|
26
27
|
type Primitive = bigint | boolean | null | number | string | undefined;
|
|
27
28
|
type Renderable<T = unknown> = RenderableReactive<T> | RenderableTemplate<T>;
|
|
28
29
|
type RenderableReactive<T = unknown> = Readonly<{
|
|
@@ -43,9 +44,9 @@ type Template = {
|
|
|
43
44
|
html: string;
|
|
44
45
|
literals: TemplateStringsArray;
|
|
45
46
|
slots: {
|
|
46
|
-
fn: typeof attributes.spread | typeof
|
|
47
|
+
fn: typeof attributes.spread | typeof slot;
|
|
47
48
|
path: typeof firstChild[];
|
|
48
49
|
slot: number;
|
|
49
50
|
}[] | null;
|
|
50
51
|
};
|
|
51
|
-
export type { Attributes, Effect, Element, Elements, Renderable, RenderableReactive, RenderableTemplate, RenderableValue, Template };
|
|
52
|
+
export type { Attributes, Effect, Element, Elements, HydrateResult, Renderable, RenderableReactive, RenderableTemplate, RenderableValue, Template };
|
package/build/types.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import { RENDERABLE
|
|
1
|
+
import { RENDERABLE } from './constants.js';
|