@esportsplus/template 0.23.1 → 0.23.3
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 -4
- package/build/attributes.js +51 -27
- package/build/event/index.js +3 -3
- package/build/slot/{reactive.js → array.js} +14 -26
- package/build/slot/cleanup.d.ts +1 -1
- package/build/slot/cleanup.js +7 -35
- package/build/slot/effect.js +59 -51
- package/build/slot/render.js +4 -4
- package/build/types.d.ts +3 -3
- package/build/utilities/fragment.js +4 -5
- package/build/utilities/queue.d.ts +1 -2
- package/build/utilities/queue.js +2 -3
- package/package.json +2 -2
- package/src/attributes.ts +66 -30
- package/src/event/index.ts +4 -4
- package/src/slot/{reactive.ts → array.ts} +15 -41
- package/src/slot/cleanup.ts +10 -47
- package/src/slot/effect.ts +69 -57
- package/src/slot/render.ts +5 -5
- package/src/types.ts +3 -7
- package/src/utilities/fragment.ts +4 -6
- package/src/utilities/queue.ts +2 -4
- /package/build/slot/{reactive.d.ts → array.d.ts} +0 -0
package/build/attributes.d.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { STATE_HYDRATING, STATE_NONE, STATE_WAITING } from './constants.js';
|
|
2
1
|
import { Attributes, Element } from './types.js';
|
|
3
|
-
|
|
4
|
-
declare const set: (element: Element, name: string, value: unknown, state?: State) => void;
|
|
2
|
+
declare const set: (element: Element, name: string, value: unknown) => void;
|
|
5
3
|
declare const spread: (element: Element, value: Attributes | Attributes[]) => void;
|
|
6
4
|
declare const _default: {
|
|
7
|
-
set: (element: Element, name: string, value: unknown
|
|
5
|
+
set: (element: Element, name: string, value: unknown) => void;
|
|
8
6
|
spread: (element: Element, value: Attributes | Attributes[]) => void;
|
|
9
7
|
};
|
|
10
8
|
export default _default;
|
package/build/attributes.js
CHANGED
|
@@ -31,27 +31,51 @@ function list(ctx, element, id, name, state, value) {
|
|
|
31
31
|
if (value == null || value === false || value === '') {
|
|
32
32
|
value = '';
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
v = store[name] = (element.getAttribute(name) || '').trim();
|
|
34
|
+
let base = name + '.static', delimiter = delimiters[name], store = (ctx ??= context(element)).store ??= {}, dynamic = store[name], type = typeof value;
|
|
35
|
+
if (dynamic === undefined) {
|
|
36
|
+
let value = (element.getAttribute(name) || '').trim();
|
|
37
|
+
store[base] = value;
|
|
38
|
+
store[name] = dynamic = new Set();
|
|
40
39
|
}
|
|
41
40
|
if (id === null) {
|
|
42
|
-
|
|
41
|
+
if (value && type === 'string') {
|
|
42
|
+
store[base] += (store[base] ? delimiter : '') + value;
|
|
43
|
+
}
|
|
43
44
|
}
|
|
44
45
|
else {
|
|
45
|
-
let
|
|
46
|
-
if (
|
|
47
|
-
|
|
46
|
+
let hot = {};
|
|
47
|
+
if (value && type === 'string') {
|
|
48
|
+
let part, parts = value.split(delimiter);
|
|
49
|
+
for (let i = 0, n = parts.length; i < n; i++) {
|
|
50
|
+
part = parts[i].trim();
|
|
51
|
+
if (part === '') {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
dynamic.add(part);
|
|
55
|
+
hot[part] = null;
|
|
56
|
+
}
|
|
48
57
|
}
|
|
49
|
-
|
|
50
|
-
|
|
58
|
+
let cold = store[id];
|
|
59
|
+
if (cold !== undefined) {
|
|
60
|
+
for (let part in cold) {
|
|
61
|
+
if (part in hot) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
dynamic.delete(part);
|
|
65
|
+
}
|
|
51
66
|
}
|
|
52
|
-
store[id] =
|
|
67
|
+
store[id] = hot;
|
|
68
|
+
}
|
|
69
|
+
value = store[base];
|
|
70
|
+
for (let key of dynamic) {
|
|
71
|
+
value += (value ? delimiter : '') + key;
|
|
72
|
+
}
|
|
73
|
+
if (state === STATE_HYDRATING) {
|
|
74
|
+
apply(element, name, value);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
schedule(ctx, element, name, state, value);
|
|
53
78
|
}
|
|
54
|
-
schedule(ctx, element, name, state, v);
|
|
55
79
|
}
|
|
56
80
|
function property(ctx, element, id, name, state, value) {
|
|
57
81
|
if (value == null || value === false || value === '') {
|
|
@@ -64,13 +88,14 @@ function property(ctx, element, id, name, state, value) {
|
|
|
64
88
|
}
|
|
65
89
|
ctx[name] = value;
|
|
66
90
|
}
|
|
67
|
-
schedule(ctx, element, name, state, value);
|
|
68
|
-
}
|
|
69
|
-
function schedule(ctx, element, name, state, value) {
|
|
70
91
|
if (state === STATE_HYDRATING) {
|
|
71
92
|
apply(element, name, value);
|
|
72
|
-
return;
|
|
73
93
|
}
|
|
94
|
+
else {
|
|
95
|
+
schedule(ctx, element, name, state, value);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function schedule(ctx, element, name, state, value) {
|
|
74
99
|
ctx ??= context(element);
|
|
75
100
|
(ctx.updates ??= {})[name] = value;
|
|
76
101
|
if (state === STATE_NONE && !ctx.updating) {
|
|
@@ -100,12 +125,11 @@ function task() {
|
|
|
100
125
|
scheduled = false;
|
|
101
126
|
}
|
|
102
127
|
}
|
|
103
|
-
const set = (element, name, value
|
|
104
|
-
let fn = name === 'class' || name === 'style' ? list : property, type = typeof value;
|
|
128
|
+
const set = (element, name, value) => {
|
|
129
|
+
let fn = name === 'class' || name === 'style' ? list : property, state = STATE_HYDRATING, type = typeof value;
|
|
105
130
|
if (type === 'function') {
|
|
106
131
|
if (name.startsWith('on')) {
|
|
107
|
-
event(element, name, value);
|
|
108
|
-
return;
|
|
132
|
+
return event(element, name, value);
|
|
109
133
|
}
|
|
110
134
|
let ctx = context(element);
|
|
111
135
|
ctx.effect ??= 0;
|
|
@@ -113,7 +137,7 @@ const set = (element, name, value, state = STATE_HYDRATING) => {
|
|
|
113
137
|
effect(() => {
|
|
114
138
|
let v = value(element);
|
|
115
139
|
if (v == null || typeof v !== 'object') {
|
|
116
|
-
fn(ctx, element, id, name,
|
|
140
|
+
fn(ctx, element, id, name, state, v);
|
|
117
141
|
}
|
|
118
142
|
else if (isArray(v)) {
|
|
119
143
|
let last = v.length - 1;
|
|
@@ -128,8 +152,7 @@ const set = (element, name, value, state = STATE_HYDRATING) => {
|
|
|
128
152
|
return;
|
|
129
153
|
}
|
|
130
154
|
if (type !== 'object') {
|
|
131
|
-
fn(null, element, null, name, state, value);
|
|
132
|
-
return;
|
|
155
|
+
return fn(null, element, null, name, state, value);
|
|
133
156
|
}
|
|
134
157
|
if (isArray(value)) {
|
|
135
158
|
for (let i = 0, n = value.length; i < n; i++) {
|
|
@@ -137,7 +160,7 @@ const set = (element, name, value, state = STATE_HYDRATING) => {
|
|
|
137
160
|
if (v == null || v === false || v === '') {
|
|
138
161
|
continue;
|
|
139
162
|
}
|
|
140
|
-
set(element, name, v
|
|
163
|
+
set(element, name, v);
|
|
141
164
|
}
|
|
142
165
|
return;
|
|
143
166
|
}
|
|
@@ -145,7 +168,8 @@ const set = (element, name, value, state = STATE_HYDRATING) => {
|
|
|
145
168
|
};
|
|
146
169
|
const spread = function (element, value) {
|
|
147
170
|
if (isObject(value)) {
|
|
148
|
-
|
|
171
|
+
let names = Object.keys(value), name;
|
|
172
|
+
while (name = names.pop()) {
|
|
149
173
|
let v = value[name];
|
|
150
174
|
if (v == null || v === false || v === '') {
|
|
151
175
|
continue;
|
package/build/event/index.js
CHANGED
|
@@ -66,15 +66,15 @@ export default (element, event, listener) => {
|
|
|
66
66
|
case 'ondisconnect':
|
|
67
67
|
ondisconnect(element, () => listener(element));
|
|
68
68
|
return;
|
|
69
|
+
case 'onrender':
|
|
70
|
+
root(() => listener(element));
|
|
71
|
+
return;
|
|
69
72
|
case 'onresize':
|
|
70
73
|
onresize(element, listener);
|
|
71
74
|
return;
|
|
72
75
|
case 'ontick':
|
|
73
76
|
ontick(element, listener);
|
|
74
77
|
return;
|
|
75
|
-
case 'onrender':
|
|
76
|
-
root(() => listener(element));
|
|
77
|
-
return;
|
|
78
78
|
default:
|
|
79
79
|
element[keys[event] || register(element, event)] = listener;
|
|
80
80
|
return;
|
|
@@ -3,7 +3,7 @@ import { EMPTY_FRAGMENT } from '../constants.js';
|
|
|
3
3
|
import { append } from '../utilities/fragment.js';
|
|
4
4
|
import { cloneNode, firstChild, lastChild } from '../utilities/node.js';
|
|
5
5
|
import { ondisconnect, remove } from './cleanup.js';
|
|
6
|
-
class
|
|
6
|
+
class ArraySlot {
|
|
7
7
|
array;
|
|
8
8
|
fragment;
|
|
9
9
|
marker;
|
|
@@ -16,7 +16,7 @@ class ReactiveArraySlot {
|
|
|
16
16
|
this.template = function (data, i) {
|
|
17
17
|
let dispose, frag = root((d) => {
|
|
18
18
|
dispose = d;
|
|
19
|
-
return template
|
|
19
|
+
return template(data, i);
|
|
20
20
|
}), group = {
|
|
21
21
|
head: firstChild.call(frag),
|
|
22
22
|
tail: lastChild.call(frag)
|
|
@@ -66,58 +66,46 @@ class ReactiveArraySlot {
|
|
|
66
66
|
return this.marker;
|
|
67
67
|
}
|
|
68
68
|
clear() {
|
|
69
|
-
remove(this.nodes);
|
|
69
|
+
remove(...this.nodes.splice(0));
|
|
70
70
|
}
|
|
71
71
|
pop() {
|
|
72
72
|
let group = this.nodes.pop();
|
|
73
73
|
if (group) {
|
|
74
|
-
remove(
|
|
74
|
+
remove(group);
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
push(items) {
|
|
78
|
-
let anchor = this.anchor()
|
|
79
|
-
this.nodes.
|
|
80
|
-
for (let i = 0, n = items.length; i < n; i++) {
|
|
81
|
-
this.nodes[i + length] = this.template.call(array, items[i], i);
|
|
82
|
-
}
|
|
78
|
+
let anchor = this.anchor();
|
|
79
|
+
this.nodes.push(...items.map(this.template));
|
|
83
80
|
anchor.after(this.fragment);
|
|
84
81
|
}
|
|
85
82
|
render() {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
remove(nodes);
|
|
83
|
+
if (this.nodes.length) {
|
|
84
|
+
remove(...this.nodes.splice(0));
|
|
89
85
|
}
|
|
90
|
-
nodes = this.array.map(this.template);
|
|
86
|
+
this.nodes = this.array.map(this.template);
|
|
91
87
|
this.marker.after(this.fragment);
|
|
92
88
|
}
|
|
93
89
|
shift() {
|
|
94
90
|
let group = this.nodes.shift();
|
|
95
91
|
if (group) {
|
|
96
|
-
remove(
|
|
92
|
+
remove(group);
|
|
97
93
|
}
|
|
98
94
|
}
|
|
99
95
|
splice(start, stop = this.nodes.length, ...items) {
|
|
100
96
|
if (!items.length) {
|
|
101
|
-
return remove(this.nodes.splice(start, stop));
|
|
102
|
-
}
|
|
103
|
-
let array = this.array, n = items.length, nodes = new Array(n);
|
|
104
|
-
for (let i = 0; i < n; i++) {
|
|
105
|
-
nodes[i] = this.template.call(array, items[i], i);
|
|
97
|
+
return remove(...this.nodes.splice(start, stop));
|
|
106
98
|
}
|
|
107
|
-
remove(this.nodes.splice(start, stop, ...
|
|
99
|
+
remove(...this.nodes.splice(start, stop, ...items.map(this.template)));
|
|
108
100
|
this.anchor(start - 1).after(this.fragment);
|
|
109
101
|
}
|
|
110
102
|
unshift(items) {
|
|
111
|
-
|
|
112
|
-
for (let i = 0; i < n; i++) {
|
|
113
|
-
nodes[i] = this.template.call(array, items[i], i);
|
|
114
|
-
}
|
|
115
|
-
this.nodes.unshift(...nodes);
|
|
103
|
+
this.nodes.unshift(...items.map(this.template));
|
|
116
104
|
this.marker.after(this.fragment);
|
|
117
105
|
}
|
|
118
106
|
}
|
|
119
107
|
export default (anchor, renderable) => {
|
|
120
|
-
let { array, template } = renderable, slot = new
|
|
108
|
+
let { array, template } = renderable, slot = new ArraySlot(anchor, array, template);
|
|
121
109
|
if (array.length) {
|
|
122
110
|
root(() => {
|
|
123
111
|
slot.nodes = array.map(slot.template);
|
package/build/slot/cleanup.d.ts
CHANGED
package/build/slot/cleanup.js
CHANGED
|
@@ -1,42 +1,17 @@
|
|
|
1
|
-
import queue from '@esportsplus/queue';
|
|
2
1
|
import { CLEANUP } from '../constants.js';
|
|
3
|
-
import { microtask } from '../utilities/queue.js';
|
|
4
2
|
import { previousSibling } from '../utilities/node.js';
|
|
5
|
-
let cleanup = queue(64), scheduled = false;
|
|
6
|
-
function schedule() {
|
|
7
|
-
if (!cleanup.length || scheduled) {
|
|
8
|
-
return;
|
|
9
|
-
}
|
|
10
|
-
scheduled = true;
|
|
11
|
-
microtask.add(task);
|
|
12
|
-
}
|
|
13
|
-
function task() {
|
|
14
|
-
try {
|
|
15
|
-
let fns, fn, n = cleanup.length;
|
|
16
|
-
while ((fns = cleanup.next()) && n--) {
|
|
17
|
-
while (fn = fns.pop()) {
|
|
18
|
-
fn();
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
catch { }
|
|
23
|
-
if (cleanup.length) {
|
|
24
|
-
microtask.add(task);
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
scheduled = false;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
3
|
const ondisconnect = (element, fn) => {
|
|
31
4
|
(element[CLEANUP] ??= []).push(fn);
|
|
32
5
|
};
|
|
33
|
-
const remove = (groups) => {
|
|
34
|
-
let
|
|
35
|
-
|
|
36
|
-
let head = group.head, next, tail = group.tail || head;
|
|
6
|
+
const remove = (...groups) => {
|
|
7
|
+
for (let i = 0, n = groups.length; i < n; i++) {
|
|
8
|
+
let fns, fn, group = groups[i], head = group.head, next, tail = group.tail || head;
|
|
37
9
|
while (tail) {
|
|
38
10
|
if (CLEANUP in tail) {
|
|
39
|
-
|
|
11
|
+
fns = tail[CLEANUP];
|
|
12
|
+
while (fn = fns.pop()) {
|
|
13
|
+
fn();
|
|
14
|
+
}
|
|
40
15
|
}
|
|
41
16
|
next = previousSibling.call(tail);
|
|
42
17
|
tail.remove();
|
|
@@ -46,8 +21,5 @@ const remove = (groups) => {
|
|
|
46
21
|
tail = next;
|
|
47
22
|
}
|
|
48
23
|
}
|
|
49
|
-
if (!scheduled && cleanup.length) {
|
|
50
|
-
schedule();
|
|
51
|
-
}
|
|
52
24
|
};
|
|
53
25
|
export { ondisconnect, remove };
|
package/build/slot/effect.js
CHANGED
|
@@ -5,67 +5,75 @@ import { raf } from '../utilities/queue.js';
|
|
|
5
5
|
import { remove } from './cleanup.js';
|
|
6
6
|
import text from '../utilities/text.js';
|
|
7
7
|
import render from './render.js';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
anchor.after(textnode);
|
|
8
|
+
class EffectSlot {
|
|
9
|
+
anchor;
|
|
10
|
+
disposer;
|
|
11
|
+
group = null;
|
|
12
|
+
textnode = null;
|
|
13
|
+
constructor(anchor, fn) {
|
|
14
|
+
let dispose = fn.length ? () => this.dispose() : undefined, state = STATE_HYDRATING;
|
|
15
|
+
this.anchor = anchor;
|
|
16
|
+
this.disposer = effect(() => {
|
|
17
|
+
let value = fn(dispose);
|
|
18
|
+
if (state === STATE_HYDRATING) {
|
|
19
|
+
state = STATE_NONE;
|
|
20
|
+
this.update(value);
|
|
22
21
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
let fragment = render(anchor, value), head = firstChild.call(fragment);
|
|
30
|
-
if (textnode && textnode.isConnected) {
|
|
31
|
-
remove([{ head: textnode, tail: textnode }]);
|
|
32
|
-
}
|
|
33
|
-
if (head) {
|
|
34
|
-
this.group = {
|
|
35
|
-
head,
|
|
36
|
-
tail: lastChild.call(fragment)
|
|
37
|
-
};
|
|
38
|
-
anchor.after(fragment);
|
|
39
|
-
}
|
|
22
|
+
else {
|
|
23
|
+
raf.add(() => {
|
|
24
|
+
this.update(value);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
});
|
|
40
28
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
let context = {
|
|
44
|
-
group: undefined,
|
|
45
|
-
textnode: undefined
|
|
46
|
-
}, dispose = fn.length ? () => {
|
|
47
|
-
let { group, textnode } = context;
|
|
29
|
+
dispose() {
|
|
30
|
+
let { anchor, group, textnode } = this;
|
|
48
31
|
if (textnode) {
|
|
49
32
|
group = { head: anchor, tail: textnode };
|
|
50
33
|
}
|
|
51
34
|
else if (group) {
|
|
52
35
|
group.head = anchor;
|
|
53
36
|
}
|
|
54
|
-
|
|
37
|
+
this.disposer();
|
|
55
38
|
if (group) {
|
|
56
|
-
remove(
|
|
39
|
+
remove(group);
|
|
57
40
|
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
41
|
+
}
|
|
42
|
+
update(value) {
|
|
43
|
+
if (this.group) {
|
|
44
|
+
remove(this.group);
|
|
45
|
+
this.group = null;
|
|
46
|
+
}
|
|
47
|
+
if (value == null || value === false) {
|
|
48
|
+
value = '';
|
|
64
49
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
50
|
+
let { anchor, textnode } = this;
|
|
51
|
+
if (typeof value !== 'object') {
|
|
52
|
+
if (textnode) {
|
|
53
|
+
nodeValue.call(textnode, String(value));
|
|
54
|
+
if (!textnode.isConnected) {
|
|
55
|
+
anchor.after(textnode);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
anchor.after(this.textnode = text(String(value)));
|
|
60
|
+
}
|
|
69
61
|
}
|
|
70
|
-
|
|
62
|
+
else {
|
|
63
|
+
let fragment = render(anchor, value), head = firstChild.call(fragment);
|
|
64
|
+
if (textnode?.isConnected) {
|
|
65
|
+
remove({ head: textnode, tail: textnode });
|
|
66
|
+
}
|
|
67
|
+
if (head) {
|
|
68
|
+
this.group = {
|
|
69
|
+
head,
|
|
70
|
+
tail: lastChild.call(fragment)
|
|
71
|
+
};
|
|
72
|
+
anchor.after(fragment);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export default (anchor, fn) => {
|
|
78
|
+
new EffectSlot(anchor, fn);
|
|
71
79
|
};
|
package/build/slot/render.js
CHANGED
|
@@ -3,7 +3,7 @@ import { EMPTY_FRAGMENT, RENDERABLE } from '../constants.js';
|
|
|
3
3
|
import { cloneNode, lastChild } from '../utilities/node.js';
|
|
4
4
|
import { append } from '../utilities/fragment.js';
|
|
5
5
|
import text from '../utilities/text.js';
|
|
6
|
-
import
|
|
6
|
+
import array from './array.js';
|
|
7
7
|
export default function render(anchor, input) {
|
|
8
8
|
if (input == null || input === false || input === '') {
|
|
9
9
|
return EMPTY_FRAGMENT;
|
|
@@ -11,12 +11,12 @@ export default function render(anchor, input) {
|
|
|
11
11
|
if (typeof input !== 'object') {
|
|
12
12
|
return text(input);
|
|
13
13
|
}
|
|
14
|
+
if (RENDERABLE in input) {
|
|
15
|
+
return array(anchor, input);
|
|
16
|
+
}
|
|
14
17
|
if ('nodeType' in input) {
|
|
15
18
|
return input;
|
|
16
19
|
}
|
|
17
|
-
if (RENDERABLE in input) {
|
|
18
|
-
return reactive(anchor, input);
|
|
19
|
-
}
|
|
20
20
|
if (isArray(input)) {
|
|
21
21
|
let fragment = cloneNode.call(EMPTY_FRAGMENT);
|
|
22
22
|
for (let i = 0, n = input.length; i < n; i++) {
|
package/build/types.d.ts
CHANGED
|
@@ -6,14 +6,14 @@ import slot from './slot/index.js';
|
|
|
6
6
|
import html from './html/index.js';
|
|
7
7
|
type Attribute = Effect<Primitive | Primitive[]> | ((...args: any[]) => void) | Primitive;
|
|
8
8
|
type Attributes<T extends HTMLElement = Element> = {
|
|
9
|
-
[key: `aria-${string}`]: string | number | boolean | undefined;
|
|
10
|
-
[key: `data-${string}`]: string | undefined;
|
|
11
9
|
class?: Attribute | Attribute[];
|
|
12
10
|
onconnect?: (element: T) => void;
|
|
13
11
|
ondisconnect?: (element: T) => void;
|
|
14
12
|
onrender?: (element: T) => void;
|
|
15
13
|
ontick?: (dispose: VoidFunction, element: T) => void;
|
|
16
14
|
style?: Attribute | Attribute[];
|
|
15
|
+
[key: `aria-${string}`]: string | number | boolean | undefined;
|
|
16
|
+
[key: `data-${string}`]: string | undefined;
|
|
17
17
|
} & {
|
|
18
18
|
[K in keyof GlobalEventHandlersEventMap as `on${string & K}`]?: (this: T, event: GlobalEventHandlersEventMap[K]) => void;
|
|
19
19
|
} & Record<PropertyKey, unknown>;
|
|
@@ -24,7 +24,7 @@ type Renderable<T> = DocumentFragment | Effect<T> | Node | NodeList | Primitive
|
|
|
24
24
|
type RenderableReactive<T> = Readonly<{
|
|
25
25
|
[RENDERABLE]: typeof RENDERABLE_HTML_REACTIVE_ARRAY;
|
|
26
26
|
array: ReactiveArray<T>;
|
|
27
|
-
template: (
|
|
27
|
+
template: (value: T, i: number) => ReturnType<typeof html>;
|
|
28
28
|
}>;
|
|
29
29
|
type SlotGroup = {
|
|
30
30
|
head: Element;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { innerHTML } from './element.js';
|
|
2
2
|
import { cloneNode } from './node.js';
|
|
3
|
-
let
|
|
3
|
+
let template = document.createElement('template');
|
|
4
4
|
const append = DocumentFragment.prototype.append;
|
|
5
5
|
const fragment = (html) => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
return content;
|
|
6
|
+
let element = cloneNode.call(template);
|
|
7
|
+
innerHTML.call(element, html);
|
|
8
|
+
return element.content;
|
|
10
9
|
};
|
|
11
10
|
export { append, fragment };
|
package/build/utilities/queue.js
CHANGED
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"author": "ICJR",
|
|
3
3
|
"dependencies": {
|
|
4
4
|
"@esportsplus/queue": "^0.1.0",
|
|
5
|
-
"@esportsplus/reactivity": "^0.
|
|
5
|
+
"@esportsplus/reactivity": "^0.17.1",
|
|
6
6
|
"@esportsplus/tasks": "^0.2.1",
|
|
7
7
|
"@esportsplus/utilities": "^0.22.1"
|
|
8
8
|
},
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"private": false,
|
|
15
15
|
"type": "module",
|
|
16
16
|
"types": "./build/index.d.ts",
|
|
17
|
-
"version": "0.23.
|
|
17
|
+
"version": "0.23.3",
|
|
18
18
|
"scripts": {
|
|
19
19
|
"build": "tsc && tsc-alias",
|
|
20
20
|
"-": "-"
|
package/src/attributes.ts
CHANGED
|
@@ -61,36 +61,70 @@ function list(
|
|
|
61
61
|
value = '';
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
let delimiter = delimiters[name],
|
|
64
|
+
let base = name + '.static',
|
|
65
|
+
delimiter = delimiters[name],
|
|
69
66
|
store = (ctx ??= context(element)).store ??= {},
|
|
70
|
-
|
|
67
|
+
dynamic = store[name] as Set<string> | undefined,
|
|
68
|
+
type = typeof value;
|
|
69
|
+
|
|
70
|
+
if (dynamic === undefined) {
|
|
71
|
+
let value = (element.getAttribute(name) || '').trim();
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
store[base] = value;
|
|
74
|
+
store[name] = dynamic = new Set();
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
if (id === null) {
|
|
77
|
-
|
|
78
|
+
if (value && type === 'string') {
|
|
79
|
+
store[base] += (store[base] ? delimiter : '') + value;
|
|
80
|
+
}
|
|
78
81
|
}
|
|
79
82
|
else {
|
|
80
|
-
let
|
|
81
|
-
|
|
83
|
+
let hot: Attributes = {};
|
|
84
|
+
|
|
85
|
+
if (value && type === 'string') {
|
|
86
|
+
let part: string,
|
|
87
|
+
parts = (value as string).split(delimiter);
|
|
88
|
+
|
|
89
|
+
for (let i = 0, n = parts.length; i < n; i++) {
|
|
90
|
+
part = parts[i].trim();
|
|
91
|
+
|
|
92
|
+
if (part === '') {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
82
95
|
|
|
83
|
-
|
|
84
|
-
|
|
96
|
+
dynamic.add(part);
|
|
97
|
+
hot[part] = null;
|
|
98
|
+
}
|
|
85
99
|
}
|
|
86
|
-
|
|
87
|
-
|
|
100
|
+
|
|
101
|
+
let cold = store[id] as Attributes | undefined;
|
|
102
|
+
|
|
103
|
+
if (cold !== undefined) {
|
|
104
|
+
for (let part in cold) {
|
|
105
|
+
if (part in hot) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
dynamic.delete(part);
|
|
110
|
+
}
|
|
88
111
|
}
|
|
89
112
|
|
|
90
|
-
store[id] =
|
|
113
|
+
store[id] = hot;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
value = store[base];
|
|
117
|
+
|
|
118
|
+
for (let key of dynamic) {
|
|
119
|
+
value += (value ? delimiter : '') + key;
|
|
91
120
|
}
|
|
92
121
|
|
|
93
|
-
|
|
122
|
+
if (state === STATE_HYDRATING) {
|
|
123
|
+
apply(element, name, value);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
schedule(ctx, element, name, state, value);
|
|
127
|
+
}
|
|
94
128
|
}
|
|
95
129
|
|
|
96
130
|
function property(
|
|
@@ -115,15 +149,15 @@ function property(
|
|
|
115
149
|
ctx[name] = value as string;
|
|
116
150
|
}
|
|
117
151
|
|
|
118
|
-
schedule(ctx, element, name, state, value);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function schedule(ctx: Context | null, element: Element, name: string, state: State, value: unknown) {
|
|
122
152
|
if (state === STATE_HYDRATING) {
|
|
123
153
|
apply(element, name, value);
|
|
124
|
-
return;
|
|
125
154
|
}
|
|
155
|
+
else {
|
|
156
|
+
schedule(ctx, element, name, state, value);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
126
159
|
|
|
160
|
+
function schedule(ctx: Context | null, element: Element, name: string, state: State, value: unknown) {
|
|
127
161
|
ctx ??= context(element);
|
|
128
162
|
(ctx.updates ??= {})[name] = value;
|
|
129
163
|
|
|
@@ -164,14 +198,14 @@ function task() {
|
|
|
164
198
|
}
|
|
165
199
|
|
|
166
200
|
|
|
167
|
-
const set = (element: Element, name: string, value: unknown
|
|
201
|
+
const set = (element: Element, name: string, value: unknown) => {
|
|
168
202
|
let fn = name === 'class' || name === 'style' ? list : property,
|
|
203
|
+
state: State = STATE_HYDRATING,
|
|
169
204
|
type = typeof value;
|
|
170
205
|
|
|
171
206
|
if (type === 'function') {
|
|
172
207
|
if (name.startsWith('on')) {
|
|
173
|
-
event(element, name as `on${string}`, value as Function);
|
|
174
|
-
return;
|
|
208
|
+
return event(element, name as `on${string}`, value as Function);
|
|
175
209
|
}
|
|
176
210
|
|
|
177
211
|
let ctx = context(element);
|
|
@@ -184,7 +218,7 @@ const set = (element: Element, name: string, value: unknown, state: State = STAT
|
|
|
184
218
|
let v = (value as Function)(element);
|
|
185
219
|
|
|
186
220
|
if (v == null || typeof v !== 'object') {
|
|
187
|
-
fn(ctx, element, id, name,
|
|
221
|
+
fn(ctx, element, id, name, state, v);
|
|
188
222
|
}
|
|
189
223
|
else if (isArray(v)) {
|
|
190
224
|
let last = v.length - 1;
|
|
@@ -210,8 +244,7 @@ const set = (element: Element, name: string, value: unknown, state: State = STAT
|
|
|
210
244
|
}
|
|
211
245
|
|
|
212
246
|
if (type !== 'object') {
|
|
213
|
-
fn(null, element, null, name, state, value);
|
|
214
|
-
return;
|
|
247
|
+
return fn(null, element, null, name, state, value);
|
|
215
248
|
}
|
|
216
249
|
|
|
217
250
|
if (isArray(value)) {
|
|
@@ -222,7 +255,7 @@ const set = (element: Element, name: string, value: unknown, state: State = STAT
|
|
|
222
255
|
continue;
|
|
223
256
|
}
|
|
224
257
|
|
|
225
|
-
set(element, name, v
|
|
258
|
+
set(element, name, v);
|
|
226
259
|
}
|
|
227
260
|
return;
|
|
228
261
|
}
|
|
@@ -232,7 +265,10 @@ const set = (element: Element, name: string, value: unknown, state: State = STAT
|
|
|
232
265
|
|
|
233
266
|
const spread = function (element: Element, value: Attributes | Attributes[]) {
|
|
234
267
|
if (isObject(value)) {
|
|
235
|
-
|
|
268
|
+
let names = Object.keys(value),
|
|
269
|
+
name;
|
|
270
|
+
|
|
271
|
+
while (name = names.pop()) {
|
|
236
272
|
let v = value[name];
|
|
237
273
|
|
|
238
274
|
if (v == null || v === false || v === '') {
|
package/src/event/index.ts
CHANGED
|
@@ -98,6 +98,10 @@ export default (element: Element, event: `on${string}`, listener: Function): voi
|
|
|
98
98
|
ondisconnect(element, () => listener(element));
|
|
99
99
|
return;
|
|
100
100
|
|
|
101
|
+
case 'onrender':
|
|
102
|
+
root(() => listener(element));
|
|
103
|
+
return;
|
|
104
|
+
|
|
101
105
|
case 'onresize':
|
|
102
106
|
onresize(element, listener);
|
|
103
107
|
return;
|
|
@@ -106,10 +110,6 @@ export default (element: Element, event: `on${string}`, listener: Function): voi
|
|
|
106
110
|
ontick(element, listener);
|
|
107
111
|
return;
|
|
108
112
|
|
|
109
|
-
case 'onrender':
|
|
110
|
-
root(() => listener(element));
|
|
111
|
-
return;
|
|
112
|
-
|
|
113
113
|
default:
|
|
114
114
|
element[ keys[event] || register(element, event) ] = listener;
|
|
115
115
|
return;
|
|
@@ -6,15 +6,12 @@ import { cloneNode, firstChild, lastChild } from '~/utilities/node';
|
|
|
6
6
|
import { ondisconnect, remove } from './cleanup';
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class
|
|
9
|
+
class ArraySlot<T> {
|
|
10
10
|
array: ReactiveArray<T>;
|
|
11
11
|
fragment: Node;
|
|
12
12
|
marker: Element;
|
|
13
13
|
nodes: SlotGroup[] = [];
|
|
14
|
-
template: (
|
|
15
|
-
this: ReactiveArray<T>,
|
|
16
|
-
...args: Parameters< Parameters<ReactiveArray<T>['map']>[0] >
|
|
17
|
-
) => SlotGroup;
|
|
14
|
+
template: (...args: Parameters< RenderableReactive<T>['template'] >) => SlotGroup;
|
|
18
15
|
|
|
19
16
|
|
|
20
17
|
constructor(anchor: Element, array: ReactiveArray<T>, template: RenderableReactive<T>['template']) {
|
|
@@ -26,7 +23,7 @@ class ReactiveArraySlot<T> {
|
|
|
26
23
|
let dispose: VoidFunction,
|
|
27
24
|
frag = root((d) => {
|
|
28
25
|
dispose = d;
|
|
29
|
-
return template
|
|
26
|
+
return template(data, i);
|
|
30
27
|
}),
|
|
31
28
|
group = {
|
|
32
29
|
head: firstChild.call(frag),
|
|
@@ -88,38 +85,31 @@ class ReactiveArraySlot<T> {
|
|
|
88
85
|
}
|
|
89
86
|
|
|
90
87
|
clear() {
|
|
91
|
-
remove(this.nodes);
|
|
88
|
+
remove(...this.nodes.splice(0));
|
|
92
89
|
}
|
|
93
90
|
|
|
94
91
|
pop() {
|
|
95
92
|
let group = this.nodes.pop();
|
|
96
93
|
|
|
97
94
|
if (group) {
|
|
98
|
-
remove(
|
|
95
|
+
remove(group);
|
|
99
96
|
}
|
|
100
97
|
}
|
|
101
98
|
|
|
102
99
|
push(items: T[]) {
|
|
103
|
-
let anchor = this.anchor()
|
|
104
|
-
array = this.array,
|
|
105
|
-
length = this.nodes.length;
|
|
100
|
+
let anchor = this.anchor();
|
|
106
101
|
|
|
107
|
-
this.nodes.
|
|
102
|
+
this.nodes.push( ...items.map(this.template) );
|
|
108
103
|
|
|
109
|
-
for (let i = 0, n = items.length; i < n; i++) {
|
|
110
|
-
this.nodes[i + length] = this.template.call(array, items[i], i);
|
|
111
|
-
}
|
|
112
104
|
anchor.after(this.fragment);
|
|
113
105
|
}
|
|
114
106
|
|
|
115
107
|
render() {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (nodes.length) {
|
|
119
|
-
remove(nodes);
|
|
108
|
+
if (this.nodes.length) {
|
|
109
|
+
remove(...this.nodes.splice(0));
|
|
120
110
|
}
|
|
121
111
|
|
|
122
|
-
nodes = this.array.map(this.template);
|
|
112
|
+
this.nodes = this.array.map(this.template);
|
|
123
113
|
this.marker.after(this.fragment);
|
|
124
114
|
}
|
|
125
115
|
|
|
@@ -127,37 +117,21 @@ class ReactiveArraySlot<T> {
|
|
|
127
117
|
let group = this.nodes.shift();
|
|
128
118
|
|
|
129
119
|
if (group) {
|
|
130
|
-
remove(
|
|
120
|
+
remove(group);
|
|
131
121
|
}
|
|
132
122
|
}
|
|
133
123
|
|
|
134
124
|
splice(start: number, stop: number = this.nodes.length, ...items: T[]) {
|
|
135
125
|
if (!items.length) {
|
|
136
|
-
return remove(this.nodes.splice(start, stop));
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
let array = this.array,
|
|
140
|
-
n = items.length,
|
|
141
|
-
nodes = new Array(n);
|
|
142
|
-
|
|
143
|
-
for (let i = 0; i < n; i++) {
|
|
144
|
-
nodes[i] = this.template.call(array, items[i], i);
|
|
126
|
+
return remove(...this.nodes.splice(start, stop));
|
|
145
127
|
}
|
|
146
128
|
|
|
147
|
-
remove(this.nodes.splice(start, stop, ...
|
|
129
|
+
remove( ...this.nodes.splice(start, stop, ...items.map(this.template)) );
|
|
148
130
|
this.anchor(start - 1).after(this.fragment);
|
|
149
131
|
}
|
|
150
132
|
|
|
151
133
|
unshift(items: T[]) {
|
|
152
|
-
|
|
153
|
-
n = items.length,
|
|
154
|
-
nodes = new Array(n);
|
|
155
|
-
|
|
156
|
-
for (let i = 0; i < n; i++) {
|
|
157
|
-
nodes[i] = this.template.call(array, items[i], i);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
this.nodes.unshift(...nodes);
|
|
134
|
+
this.nodes.unshift(...items.map(this.template));
|
|
161
135
|
this.marker.after(this.fragment);
|
|
162
136
|
}
|
|
163
137
|
}
|
|
@@ -165,7 +139,7 @@ class ReactiveArraySlot<T> {
|
|
|
165
139
|
|
|
166
140
|
export default <T>(anchor: Element, renderable: RenderableReactive<T>) => {
|
|
167
141
|
let { array, template } = renderable,
|
|
168
|
-
slot = new
|
|
142
|
+
slot = new ArraySlot(anchor, array, template);
|
|
169
143
|
|
|
170
144
|
if (array.length) {
|
|
171
145
|
root(() => {
|
package/src/slot/cleanup.ts
CHANGED
|
@@ -1,60 +1,27 @@
|
|
|
1
|
-
import queue from '@esportsplus/queue';
|
|
2
1
|
import { CLEANUP } from '~/constants';
|
|
3
|
-
import { microtask } from '~/utilities/queue';
|
|
4
2
|
import { previousSibling } from '~/utilities/node';
|
|
5
3
|
import { SlotGroup } from '~/types';
|
|
6
4
|
|
|
7
5
|
|
|
8
|
-
let cleanup = queue<VoidFunction[]>(64),
|
|
9
|
-
scheduled = false;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
function schedule() {
|
|
13
|
-
if (!cleanup.length || scheduled) {
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
scheduled = true;
|
|
18
|
-
microtask.add(task);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function task() {
|
|
22
|
-
try {
|
|
23
|
-
let fns, fn,
|
|
24
|
-
n = cleanup.length;
|
|
25
|
-
|
|
26
|
-
while ((fns = cleanup.next()) && n--) {
|
|
27
|
-
while (fn = fns.pop()) {
|
|
28
|
-
fn();
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
catch { }
|
|
33
|
-
|
|
34
|
-
if (cleanup.length) {
|
|
35
|
-
microtask.add(task);
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
scheduled = false;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
6
|
const ondisconnect = (element: Element, fn: VoidFunction) => {
|
|
44
7
|
((element as any)[CLEANUP] ??= []).push(fn);
|
|
45
8
|
};
|
|
46
9
|
|
|
47
|
-
const remove = (groups: SlotGroup[]) => {
|
|
48
|
-
let
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
10
|
+
const remove = (...groups: SlotGroup[]) => {
|
|
11
|
+
for (let i = 0, n = groups.length; i < n; i++) {
|
|
12
|
+
let fns, fn,
|
|
13
|
+
group = groups[i],
|
|
14
|
+
head = group.head,
|
|
52
15
|
next,
|
|
53
16
|
tail = group.tail || head;
|
|
54
17
|
|
|
55
18
|
while (tail) {
|
|
56
19
|
if (CLEANUP in tail) {
|
|
57
|
-
|
|
20
|
+
fns = tail[CLEANUP] as VoidFunction[];
|
|
21
|
+
|
|
22
|
+
while (fn = fns.pop()) {
|
|
23
|
+
fn();
|
|
24
|
+
}
|
|
58
25
|
}
|
|
59
26
|
|
|
60
27
|
next = previousSibling.call(tail);
|
|
@@ -67,10 +34,6 @@ const remove = (groups: SlotGroup[]) => {
|
|
|
67
34
|
tail = next;
|
|
68
35
|
}
|
|
69
36
|
}
|
|
70
|
-
|
|
71
|
-
if (!scheduled && cleanup.length) {
|
|
72
|
-
schedule();
|
|
73
|
-
}
|
|
74
37
|
};
|
|
75
38
|
|
|
76
39
|
|
package/src/slot/effect.ts
CHANGED
|
@@ -8,84 +8,96 @@ import text from '~/utilities/text';
|
|
|
8
8
|
import render from './render';
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
class EffectSlot {
|
|
12
|
+
anchor: Element;
|
|
13
|
+
disposer: VoidFunction;
|
|
14
|
+
group: SlotGroup | null = null;
|
|
15
|
+
textnode: Node | null = null;
|
|
16
16
|
|
|
17
|
-
if (value == null || value === false) {
|
|
18
|
-
value = '';
|
|
19
|
-
}
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
constructor(anchor: Element, fn: (dispose?: VoidFunction) => Renderable<any>) {
|
|
19
|
+
let dispose = fn.length ? () => this.dispose() : undefined,
|
|
20
|
+
state = STATE_HYDRATING;
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
this.anchor = anchor;
|
|
23
|
+
this.disposer = effect(() => {
|
|
24
|
+
let value = fn(dispose);
|
|
26
25
|
|
|
27
|
-
if (
|
|
28
|
-
|
|
26
|
+
if (state === STATE_HYDRATING) {
|
|
27
|
+
state = STATE_NONE;
|
|
28
|
+
this.update(value);
|
|
29
29
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
else {
|
|
31
|
+
raf.add(() => {
|
|
32
|
+
this.update(value);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
});
|
|
34
36
|
}
|
|
35
|
-
else {
|
|
36
|
-
let fragment = render(anchor, value),
|
|
37
|
-
head = firstChild.call(fragment);
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
|
|
39
|
+
dispose() {
|
|
40
|
+
let { anchor, group, textnode } = this;
|
|
41
|
+
|
|
42
|
+
if (textnode) {
|
|
43
|
+
group = { head: anchor, tail: textnode as Element };
|
|
44
|
+
}
|
|
45
|
+
else if (group) {
|
|
46
|
+
group.head = anchor;
|
|
41
47
|
}
|
|
42
48
|
|
|
43
|
-
|
|
44
|
-
this.group = {
|
|
45
|
-
head,
|
|
46
|
-
tail: lastChild.call(fragment)
|
|
47
|
-
};
|
|
49
|
+
this.disposer();
|
|
48
50
|
|
|
49
|
-
|
|
51
|
+
if (group) {
|
|
52
|
+
remove(group);
|
|
50
53
|
}
|
|
51
54
|
}
|
|
52
|
-
}
|
|
53
55
|
|
|
56
|
+
update(value: unknown) {
|
|
57
|
+
if (this.group) {
|
|
58
|
+
remove(this.group);
|
|
59
|
+
this.group = null;
|
|
60
|
+
}
|
|
54
61
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
dispose = fn.length ? () => {
|
|
61
|
-
let { group, textnode } = context;
|
|
62
|
+
if (value == null || value === false) {
|
|
63
|
+
value = '';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let { anchor, textnode } = this;
|
|
62
67
|
|
|
68
|
+
if (typeof value !== 'object') {
|
|
63
69
|
if (textnode) {
|
|
64
|
-
|
|
70
|
+
nodeValue.call(textnode, String(value));
|
|
71
|
+
|
|
72
|
+
if (!textnode.isConnected) {
|
|
73
|
+
anchor.after(textnode);
|
|
74
|
+
}
|
|
65
75
|
}
|
|
66
|
-
else
|
|
67
|
-
|
|
76
|
+
else {
|
|
77
|
+
anchor.after( this.textnode = text( String(value) ) );
|
|
68
78
|
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
let fragment = render(anchor, value),
|
|
82
|
+
head = firstChild.call(fragment);
|
|
69
83
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (group) {
|
|
73
|
-
remove([group]);
|
|
84
|
+
if (textnode?.isConnected) {
|
|
85
|
+
remove({ head: textnode as Element, tail: textnode as Element });
|
|
74
86
|
}
|
|
75
|
-
} : undefined,
|
|
76
|
-
state = STATE_HYDRATING;
|
|
77
87
|
|
|
78
|
-
|
|
79
|
-
|
|
88
|
+
if (head) {
|
|
89
|
+
this.group = {
|
|
90
|
+
head,
|
|
91
|
+
tail: lastChild.call(fragment)
|
|
92
|
+
};
|
|
80
93
|
|
|
81
|
-
|
|
82
|
-
update.call(context, anchor, value);
|
|
83
|
-
state = STATE_NONE;
|
|
94
|
+
anchor.after(fragment);
|
|
84
95
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
export default (anchor: Element, fn: (dispose?: VoidFunction) => Renderable<any>) => {
|
|
102
|
+
new EffectSlot(anchor, fn);
|
|
91
103
|
};
|
package/src/slot/render.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { Element, RenderableReactive } from '~/types';
|
|
|
4
4
|
import { cloneNode, lastChild } from '~/utilities/node';
|
|
5
5
|
import { append } from '~/utilities/fragment';
|
|
6
6
|
import text from '~/utilities/text';
|
|
7
|
-
import
|
|
7
|
+
import array from './array';
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
export default function render(anchor: Element, input: unknown): Node {
|
|
@@ -16,12 +16,12 @@ export default function render(anchor: Element, input: unknown): Node {
|
|
|
16
16
|
return text(input as any);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
if (
|
|
20
|
-
return input as
|
|
19
|
+
if (RENDERABLE in input) {
|
|
20
|
+
return array(anchor, input as RenderableReactive<unknown>);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
if (
|
|
24
|
-
return
|
|
23
|
+
if ('nodeType' in input) {
|
|
24
|
+
return input as Node;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
if (isArray(input)) {
|
package/src/types.ts
CHANGED
|
@@ -9,14 +9,14 @@ import html from './html';
|
|
|
9
9
|
type Attribute = Effect<Primitive | Primitive[]> | ((...args: any[]) => void) | Primitive;
|
|
10
10
|
|
|
11
11
|
type Attributes<T extends HTMLElement = Element> = {
|
|
12
|
-
[key: `aria-${string}`]: string | number | boolean | undefined;
|
|
13
|
-
[key: `data-${string}`]: string | undefined;
|
|
14
12
|
class?: Attribute | Attribute[];
|
|
15
13
|
onconnect?: (element: T) => void;
|
|
16
14
|
ondisconnect?: (element: T) => void;
|
|
17
15
|
onrender?: (element: T) => void;
|
|
18
16
|
ontick?: (dispose: VoidFunction, element: T) => void;
|
|
19
17
|
style?: Attribute | Attribute[];
|
|
18
|
+
[key: `aria-${string}`]: string | number | boolean | undefined;
|
|
19
|
+
[key: `data-${string}`]: string | undefined;
|
|
20
20
|
} & {
|
|
21
21
|
[K in keyof GlobalEventHandlersEventMap as `on${string & K}`]?: (this: T, event: GlobalEventHandlersEventMap[K]) => void;
|
|
22
22
|
} & Record<PropertyKey, unknown>;
|
|
@@ -34,11 +34,7 @@ type Renderable<T> = DocumentFragment | Effect<T> | Node | NodeList | Primitive
|
|
|
34
34
|
type RenderableReactive<T> = Readonly<{
|
|
35
35
|
[RENDERABLE]: typeof RENDERABLE_HTML_REACTIVE_ARRAY;
|
|
36
36
|
array: ReactiveArray<T>;
|
|
37
|
-
template: (
|
|
38
|
-
this: ReactiveArray<T>,
|
|
39
|
-
value: T,
|
|
40
|
-
i: number
|
|
41
|
-
) => ReturnType<typeof html>;
|
|
37
|
+
template: (value: T, i: number) => ReturnType<typeof html>;
|
|
42
38
|
}>;
|
|
43
39
|
|
|
44
40
|
type SlotGroup = {
|
|
@@ -2,19 +2,17 @@ import { innerHTML } from './element';
|
|
|
2
2
|
import { cloneNode } from './node';
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
let
|
|
5
|
+
let template = document.createElement('template');
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
const append = DocumentFragment.prototype.append;
|
|
9
9
|
|
|
10
10
|
const fragment = (html: string): DocumentFragment => {
|
|
11
|
-
|
|
11
|
+
let element = cloneNode.call(template) as HTMLTemplateElement;
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
innerHTML.call(element, html);
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return content;
|
|
15
|
+
return element.content;
|
|
18
16
|
};
|
|
19
17
|
|
|
20
18
|
|
package/src/utilities/queue.ts
CHANGED
|
File without changes
|