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