@esportsplus/template 0.16.1 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/attributes.js +27 -23
- package/build/constants.d.ts +13 -3
- package/build/constants.js +13 -3
- package/build/event.js +7 -7
- package/build/html/cache.js +1 -1
- package/build/html/hydrate.d.ts +2 -8
- package/build/html/hydrate.js +27 -78
- package/build/html/index.d.ts +2106 -5
- package/build/html/index.js +12 -4
- package/build/render.d.ts +1 -2
- package/build/render.js +6 -10
- package/build/slot/cleanup.d.ts +4 -0
- package/build/slot/cleanup.js +51 -0
- package/build/slot/effect.d.ts +3 -0
- package/build/slot/effect.js +51 -0
- package/build/slot/index.d.ts +3 -0
- package/build/slot/index.js +15 -0
- package/build/slot/reactive.d.ts +3 -0
- package/build/slot/reactive.js +117 -0
- package/build/slot/render.d.ts +2 -0
- package/build/slot/render.js +58 -0
- package/build/svg.d.ts +1 -2
- package/build/types.d.ts +20 -16
- package/build/utilities.d.ts +3 -3
- package/build/utilities.js +12 -12
- package/package.json +2 -2
- package/src/attributes.ts +30 -28
- package/src/constants.ts +31 -4
- package/src/event.ts +8 -8
- package/src/html/hydrate.ts +35 -107
- package/src/html/index.ts +16 -8
- package/src/render.ts +8 -12
- package/src/slot/cleanup.ts +74 -0
- package/src/slot/effect.ts +73 -0
- package/src/slot/index.ts +23 -0
- package/src/slot/reactive.ts +167 -0
- package/src/slot/render.ts +81 -0
- package/src/svg.ts +1 -2
- package/src/types.ts +24 -17
- package/src/utilities.ts +15 -13
- package/build/slot.d.ts +0 -21
- package/build/slot.js +0 -204
- package/src/slot.ts +0 -277
package/build/html/index.js
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
import { RENDERABLE,
|
|
1
|
+
import { RENDERABLE, RENDERABLE_HTML_FRAGMENT, RENDERABLE_HTML_REACTIVE_ARRAY } from '../constants.js';
|
|
2
2
|
import hydrate from './hydrate.js';
|
|
3
|
+
import cache from './cache.js';
|
|
3
4
|
const html = (literals, ...values) => {
|
|
4
|
-
return {
|
|
5
|
+
return {
|
|
6
|
+
[RENDERABLE]: RENDERABLE_HTML_FRAGMENT,
|
|
7
|
+
fragment: hydrate(cache.get(literals), values),
|
|
8
|
+
literals
|
|
9
|
+
};
|
|
5
10
|
};
|
|
6
11
|
html.reactive = (array, template) => {
|
|
7
|
-
return {
|
|
12
|
+
return {
|
|
13
|
+
[RENDERABLE]: RENDERABLE_HTML_REACTIVE_ARRAY,
|
|
14
|
+
array,
|
|
15
|
+
template
|
|
16
|
+
};
|
|
8
17
|
};
|
|
9
18
|
export default html;
|
|
10
|
-
export { hydrate };
|
package/build/render.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Slot } from './slot.js';
|
|
2
1
|
import { Renderable } from './types.js';
|
|
3
|
-
declare const _default: (
|
|
2
|
+
declare const _default: (parent: HTMLElement, renderable: Renderable) => void;
|
|
4
3
|
export default _default;
|
package/build/render.js
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import { isInstanceOf } from '@esportsplus/utilities';
|
|
2
1
|
import { SLOT_HTML } from './constants.js';
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
let marker = firstChild.call(fragment(SLOT_HTML))
|
|
6
|
-
export default (
|
|
7
|
-
if (isInstanceOf(parent, Slot)) {
|
|
8
|
-
return parent.render(renderable);
|
|
9
|
-
}
|
|
2
|
+
import { firstChild, fragment, nodeValue } from './utilities.js';
|
|
3
|
+
import slot from './slot/index.js';
|
|
4
|
+
let anchor, marker = firstChild.call(fragment(SLOT_HTML));
|
|
5
|
+
export default (parent, renderable) => {
|
|
10
6
|
nodeValue.call(parent, '');
|
|
11
|
-
|
|
12
|
-
return slot(
|
|
7
|
+
parent.append(anchor = marker.cloneNode());
|
|
8
|
+
return slot(anchor, renderable);
|
|
13
9
|
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import queue from '@esportsplus/queue';
|
|
2
|
+
import { CLEANUP } from '../constants.js';
|
|
3
|
+
import { microtask, previousSibling } from '../utilities.js';
|
|
4
|
+
let cleanup = queue(64), scheduled = false;
|
|
5
|
+
function schedule() {
|
|
6
|
+
if (!cleanup.length || scheduled) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
scheduled = true;
|
|
10
|
+
microtask.add(task);
|
|
11
|
+
}
|
|
12
|
+
function task() {
|
|
13
|
+
try {
|
|
14
|
+
let fns, fn, n = cleanup.length;
|
|
15
|
+
while ((fns = cleanup.next()) && n--) {
|
|
16
|
+
while (fn = fns.pop()) {
|
|
17
|
+
fn();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
catch { }
|
|
22
|
+
if (cleanup.length) {
|
|
23
|
+
microtask.add(task);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
scheduled = false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const ondisconnect = (element, fn) => {
|
|
30
|
+
(element[CLEANUP] ??= []).push(fn);
|
|
31
|
+
};
|
|
32
|
+
const remove = (groups) => {
|
|
33
|
+
let group, head, tail;
|
|
34
|
+
while (group = groups.pop()) {
|
|
35
|
+
head = group.head;
|
|
36
|
+
tail = group.tail || head;
|
|
37
|
+
for (let node = tail; node; node = previousSibling.call(node)) {
|
|
38
|
+
if (CLEANUP in node) {
|
|
39
|
+
cleanup.add(node[CLEANUP]);
|
|
40
|
+
}
|
|
41
|
+
node.remove();
|
|
42
|
+
if (head === node) {
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (!scheduled && cleanup.length) {
|
|
48
|
+
schedule();
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
export { ondisconnect, remove };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { effect } from '@esportsplus/reactivity';
|
|
2
|
+
import { EMPTY_FRAGMENT, STATE_HYDRATING, STATE_NONE } from '../constants.js';
|
|
3
|
+
import { cloneNode, firstChild, lastChild, nodeValue, raf, text } from '../utilities.js';
|
|
4
|
+
import { ondisconnect } from '../slot/cleanup.js';
|
|
5
|
+
import { remove } from './cleanup.js';
|
|
6
|
+
import render from './render.js';
|
|
7
|
+
function update(anchor, fragment, value) {
|
|
8
|
+
let type = typeof value;
|
|
9
|
+
if (this.group) {
|
|
10
|
+
remove([this.group]);
|
|
11
|
+
this.group = undefined;
|
|
12
|
+
}
|
|
13
|
+
if (value == null || type !== 'object') {
|
|
14
|
+
let textnode = this.textnode;
|
|
15
|
+
if (textnode) {
|
|
16
|
+
nodeValue.call(textnode, String(value));
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
textnode = this.textnode = text(String(value));
|
|
20
|
+
}
|
|
21
|
+
if (!textnode.isConnected) {
|
|
22
|
+
anchor.after(textnode);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
render(anchor, fragment, value);
|
|
27
|
+
this.group = {
|
|
28
|
+
head: firstChild.call(fragment),
|
|
29
|
+
tail: lastChild.call(fragment)
|
|
30
|
+
};
|
|
31
|
+
anchor.after(fragment);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export default (anchor, fn) => {
|
|
35
|
+
let context = {
|
|
36
|
+
group: undefined,
|
|
37
|
+
textnode: undefined
|
|
38
|
+
}, fragment = cloneNode.call(EMPTY_FRAGMENT), state = STATE_HYDRATING;
|
|
39
|
+
ondisconnect(anchor, effect(() => {
|
|
40
|
+
let value = fn();
|
|
41
|
+
if (state === STATE_HYDRATING) {
|
|
42
|
+
update.call(context, anchor, fragment, value);
|
|
43
|
+
state = STATE_NONE;
|
|
44
|
+
}
|
|
45
|
+
else if (state === STATE_NONE) {
|
|
46
|
+
raf.add(() => {
|
|
47
|
+
update.call(context, anchor, fragment, value);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}));
|
|
51
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { EMPTY_FRAGMENT } from '../constants.js';
|
|
2
|
+
import { cloneNode } from '../utilities.js';
|
|
3
|
+
import effect from './effect.js';
|
|
4
|
+
import render from './render.js';
|
|
5
|
+
function slot(anchor, input) {
|
|
6
|
+
let fragment = cloneNode.call(EMPTY_FRAGMENT);
|
|
7
|
+
render(anchor, fragment, input);
|
|
8
|
+
anchor.after(fragment);
|
|
9
|
+
}
|
|
10
|
+
export default (anchor, value) => {
|
|
11
|
+
if (typeof value === 'function') {
|
|
12
|
+
return effect(anchor, value);
|
|
13
|
+
}
|
|
14
|
+
return slot(anchor, value);
|
|
15
|
+
};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { root } from '@esportsplus/reactivity';
|
|
2
|
+
import { EMPTY_FRAGMENT } from '../constants.js';
|
|
3
|
+
import { append, cloneNode, firstChild, lastChild } from '../utilities.js';
|
|
4
|
+
import { remove } from './cleanup.js';
|
|
5
|
+
class ReactiveArraySlot {
|
|
6
|
+
array;
|
|
7
|
+
fragment = cloneNode.call(EMPTY_FRAGMENT);
|
|
8
|
+
marker;
|
|
9
|
+
nodes = [];
|
|
10
|
+
template;
|
|
11
|
+
constructor(anchor, array, template) {
|
|
12
|
+
let fragment = this.fragment;
|
|
13
|
+
this.array = array;
|
|
14
|
+
this.marker = anchor;
|
|
15
|
+
this.template = function (data, i) {
|
|
16
|
+
let frag = template.call(this, data, i).fragment, group = {
|
|
17
|
+
head: firstChild.call(frag),
|
|
18
|
+
tail: lastChild.call(frag)
|
|
19
|
+
};
|
|
20
|
+
append.call(fragment, frag);
|
|
21
|
+
return group;
|
|
22
|
+
};
|
|
23
|
+
let render = () => {
|
|
24
|
+
root(() => this.render());
|
|
25
|
+
};
|
|
26
|
+
array.on('clear', () => this.clear());
|
|
27
|
+
array.on('reverse', render);
|
|
28
|
+
array.on('pop', () => this.pop());
|
|
29
|
+
array.on('push', ({ items }) => {
|
|
30
|
+
root(() => this.push(items));
|
|
31
|
+
});
|
|
32
|
+
array.on('shift', () => this.shift());
|
|
33
|
+
array.on('sort', render);
|
|
34
|
+
array.on('splice', ({ deleteCount, items, start }) => {
|
|
35
|
+
root(() => this.splice(start, deleteCount, ...items));
|
|
36
|
+
});
|
|
37
|
+
array.on('unshift', ({ items }) => {
|
|
38
|
+
root(() => this.unshift(items));
|
|
39
|
+
});
|
|
40
|
+
if (array.length) {
|
|
41
|
+
render();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
get length() {
|
|
45
|
+
return this.nodes.length;
|
|
46
|
+
}
|
|
47
|
+
set length(n) {
|
|
48
|
+
if (n >= this.nodes.length) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
else if (n === 0) {
|
|
52
|
+
this.clear();
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
this.splice(n);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
anchor(index = this.nodes.length - 1) {
|
|
59
|
+
let node = this.nodes[index];
|
|
60
|
+
if (node) {
|
|
61
|
+
return node.tail || node.head;
|
|
62
|
+
}
|
|
63
|
+
return this.marker;
|
|
64
|
+
}
|
|
65
|
+
clear() {
|
|
66
|
+
remove(this.nodes);
|
|
67
|
+
}
|
|
68
|
+
pop() {
|
|
69
|
+
let group = this.nodes.pop();
|
|
70
|
+
if (group) {
|
|
71
|
+
remove([group]);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
push(items) {
|
|
75
|
+
let anchor = this.anchor(), array = this.array;
|
|
76
|
+
for (let i = 0, n = items.length; i < n; i++) {
|
|
77
|
+
this.nodes.push(this.template.call(array, items[i], i));
|
|
78
|
+
}
|
|
79
|
+
anchor.after(this.fragment);
|
|
80
|
+
}
|
|
81
|
+
render() {
|
|
82
|
+
let nodes = this.nodes;
|
|
83
|
+
if (nodes.length) {
|
|
84
|
+
remove(nodes);
|
|
85
|
+
}
|
|
86
|
+
nodes = this.array.map(this.template);
|
|
87
|
+
this.marker.after(this.fragment);
|
|
88
|
+
}
|
|
89
|
+
shift() {
|
|
90
|
+
let group = this.nodes.shift();
|
|
91
|
+
if (group) {
|
|
92
|
+
remove([group]);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
splice(start, stop = this.nodes.length, ...items) {
|
|
96
|
+
if (!items.length) {
|
|
97
|
+
return remove(this.nodes.splice(start, stop));
|
|
98
|
+
}
|
|
99
|
+
let array = this.array, n = items.length, nodes = new Array(n);
|
|
100
|
+
for (let i = 0; i < n; i++) {
|
|
101
|
+
nodes[i] = this.template.call(array, items[i], i);
|
|
102
|
+
}
|
|
103
|
+
remove(this.nodes.splice(start, stop, ...nodes));
|
|
104
|
+
this.anchor(start - 1).after(this.fragment);
|
|
105
|
+
}
|
|
106
|
+
unshift(items) {
|
|
107
|
+
let array = this.array, n = items.length, nodes = new Array(n);
|
|
108
|
+
for (let i = 0; i < n; i++) {
|
|
109
|
+
nodes[i] = this.template.call(array, items[i], i);
|
|
110
|
+
}
|
|
111
|
+
this.nodes.unshift(...nodes);
|
|
112
|
+
this.marker.after(this.fragment);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export default (anchor, renderable) => {
|
|
116
|
+
new ReactiveArraySlot(anchor, renderable.array, renderable.template);
|
|
117
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { isArray } from '@esportsplus/utilities';
|
|
2
|
+
import { RENDERABLE, RENDERABLE_ARRAY, RENDERABLE_FRAGMENT, RENDERABLE_HTML_FRAGMENT, RENDERABLE_HTML_REACTIVE_ARRAY, RENDERABLE_NODE, RENDERABLE_NODE_LIST, RENDERABLE_TEXT, RENDERABLE_VOID } from '../constants.js';
|
|
3
|
+
import { append, text } from '../utilities.js';
|
|
4
|
+
import reactive from './reactive.js';
|
|
5
|
+
function type(input) {
|
|
6
|
+
if (input === false || input == null || input === '') {
|
|
7
|
+
return RENDERABLE_VOID;
|
|
8
|
+
}
|
|
9
|
+
if (typeof input !== 'object') {
|
|
10
|
+
return RENDERABLE_TEXT;
|
|
11
|
+
}
|
|
12
|
+
if (RENDERABLE in input) {
|
|
13
|
+
return input[RENDERABLE];
|
|
14
|
+
}
|
|
15
|
+
if (isArray(input)) {
|
|
16
|
+
return RENDERABLE_ARRAY;
|
|
17
|
+
}
|
|
18
|
+
let nodeType = input.nodeType;
|
|
19
|
+
if (nodeType === 11) {
|
|
20
|
+
return RENDERABLE_FRAGMENT;
|
|
21
|
+
}
|
|
22
|
+
if (nodeType !== undefined) {
|
|
23
|
+
return RENDERABLE_NODE;
|
|
24
|
+
}
|
|
25
|
+
if (input instanceof NodeList) {
|
|
26
|
+
return RENDERABLE_NODE_LIST;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export default function render(anchor, fragment, input) {
|
|
30
|
+
let t = type(input);
|
|
31
|
+
switch (t) {
|
|
32
|
+
case RENDERABLE_VOID:
|
|
33
|
+
return;
|
|
34
|
+
case RENDERABLE_TEXT:
|
|
35
|
+
append.call(fragment, text(String(input)));
|
|
36
|
+
return;
|
|
37
|
+
case RENDERABLE_HTML_FRAGMENT:
|
|
38
|
+
append.call(fragment, input.fragment);
|
|
39
|
+
return;
|
|
40
|
+
case RENDERABLE_HTML_REACTIVE_ARRAY:
|
|
41
|
+
return reactive(anchor, input);
|
|
42
|
+
case RENDERABLE_ARRAY:
|
|
43
|
+
for (let i = 0, n = input.length; i < n; i++) {
|
|
44
|
+
render(anchor, fragment, input[i]);
|
|
45
|
+
}
|
|
46
|
+
return;
|
|
47
|
+
case RENDERABLE_FRAGMENT:
|
|
48
|
+
append.call(fragment, input);
|
|
49
|
+
return;
|
|
50
|
+
case RENDERABLE_NODE:
|
|
51
|
+
append.call(fragment, input);
|
|
52
|
+
return;
|
|
53
|
+
case RENDERABLE_NODE_LIST:
|
|
54
|
+
append.call(fragment, ...input);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
;
|
package/build/svg.d.ts
CHANGED
package/build/types.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { ReactiveArray } from '@esportsplus/reactivity';
|
|
2
|
-
import { RENDERABLE,
|
|
2
|
+
import { RENDERABLE, RENDERABLE_HTML_FRAGMENT, RENDERABLE_HTML_REACTIVE_ARRAY } from './constants.js';
|
|
3
3
|
import { firstChild } from './utilities.js';
|
|
4
4
|
import attributes from './attributes.js';
|
|
5
|
-
import slot from './slot.js';
|
|
5
|
+
import slot from './slot/index.js';
|
|
6
|
+
import html from './html/index.js';
|
|
6
7
|
type Attribute = Primitive | Effect<Primitive | Primitive[]>;
|
|
7
8
|
type Attributes = {
|
|
8
9
|
class?: Attribute | Attribute[];
|
|
@@ -17,25 +18,28 @@ type Attributes = {
|
|
|
17
18
|
onrender?: (element: Element) => void;
|
|
18
19
|
} & Record<PropertyKey, unknown>;
|
|
19
20
|
type Effect<T> = () => EffectResponse<T>;
|
|
20
|
-
type EffectResponse<T> = T extends [] ?
|
|
21
|
+
type EffectResponse<T> = T extends [] ? (Primitive | Renderable)[] : Primitive | Renderable;
|
|
21
22
|
type Element = HTMLElement & Attributes & Record<PropertyKey, unknown>;
|
|
22
23
|
type Elements = Element[];
|
|
23
|
-
type Fragment = DocumentFragment | Node
|
|
24
|
+
type Fragment = (DocumentFragment | Node) & Record<PropertyKey, unknown>;
|
|
24
25
|
type Primitive = bigint | boolean | null | number | string | undefined;
|
|
25
|
-
type Renderable
|
|
26
|
-
type RenderableReactive
|
|
27
|
-
[RENDERABLE]: typeof
|
|
28
|
-
|
|
29
|
-
template: (this:
|
|
30
|
-
values: ReactiveArray<T>;
|
|
26
|
+
type Renderable = Fragment | RenderableReactive;
|
|
27
|
+
type RenderableReactive = Readonly<{
|
|
28
|
+
[RENDERABLE]: typeof RENDERABLE_HTML_REACTIVE_ARRAY;
|
|
29
|
+
array: ReactiveArray<unknown[]>;
|
|
30
|
+
template: (this: ReactiveArray<unknown[]>, ...args: Parameters<Parameters<ReactiveArray<unknown[]>['map']>[0]>) => ReturnType<typeof html>;
|
|
31
31
|
}>;
|
|
32
|
-
type RenderableTemplate
|
|
33
|
-
[RENDERABLE]: typeof
|
|
32
|
+
type RenderableTemplate = {
|
|
33
|
+
[RENDERABLE]: typeof RENDERABLE_HTML_FRAGMENT;
|
|
34
|
+
fragment: Fragment;
|
|
34
35
|
literals: TemplateStringsArray;
|
|
35
|
-
template: Template | null;
|
|
36
|
-
values: (RenderableValue<T> | RenderableValue<T>[])[];
|
|
37
36
|
};
|
|
38
|
-
type RenderableValue<T = unknown> = Attributes | Readonly<Attributes> | Readonly<Attributes[]> | Effect<T> | Primitive |
|
|
37
|
+
type RenderableValue<T = unknown> = Attributes | Readonly<Attributes> | Readonly<Attributes[]> | Effect<T> | Fragment | Primitive | RenderableReactive;
|
|
38
|
+
type RenderableValues = RenderableValue | RenderableValue[];
|
|
39
|
+
type SlotGroup = {
|
|
40
|
+
head: Element;
|
|
41
|
+
tail: Element;
|
|
42
|
+
};
|
|
39
43
|
type Template = {
|
|
40
44
|
fragment: DocumentFragment;
|
|
41
45
|
html: string;
|
|
@@ -50,4 +54,4 @@ type Template = {
|
|
|
50
54
|
slot: number;
|
|
51
55
|
}[] | null;
|
|
52
56
|
};
|
|
53
|
-
export type { Attributes, Effect, Element, Elements, Fragment, Renderable, RenderableReactive, RenderableTemplate, RenderableValue, Template };
|
|
57
|
+
export type { Attributes, Effect, Element, Elements, Fragment, Renderable, RenderableReactive, RenderableTemplate, RenderableValue, RenderableValues, SlotGroup, Template };
|
package/build/utilities.d.ts
CHANGED
|
@@ -12,17 +12,17 @@ declare const className: (v: any) => void;
|
|
|
12
12
|
declare const innerHTML: (v: any) => void;
|
|
13
13
|
declare const firstElementChild: () => any;
|
|
14
14
|
declare const nextElementSibling: () => any;
|
|
15
|
-
declare const prepend: (...nodes: (Node | string)[]) => void;
|
|
16
15
|
declare const removeAttribute: (qualifiedName: string) => void;
|
|
17
16
|
declare const setAttribute: (qualifiedName: string, value: string) => void;
|
|
18
17
|
declare const cloneNode: (subtree?: boolean) => Node;
|
|
19
18
|
declare const firstChild: () => any;
|
|
19
|
+
declare const lastChild: () => any;
|
|
20
20
|
declare const nextSibling: () => any;
|
|
21
21
|
declare const nodeValue: (v: any) => void;
|
|
22
22
|
declare const parentElement: () => any;
|
|
23
|
-
declare const
|
|
23
|
+
declare const previousSibling: () => any;
|
|
24
24
|
declare const fragment: (html: string) => DocumentFragment;
|
|
25
25
|
declare const microtask: import("@esportsplus/tasks/build/factory").Scheduler;
|
|
26
26
|
declare const raf: import("@esportsplus/tasks/build/factory").Scheduler;
|
|
27
27
|
declare const text: (value: string) => E;
|
|
28
|
-
export { addEventListener, append, className, cloneNode, firstChild, firstElementChild, fragment, innerHTML, microtask, nextElementSibling, nextSibling, nodeValue, parentElement,
|
|
28
|
+
export { addEventListener, append, className, cloneNode, firstChild, firstElementChild, fragment, innerHTML, lastChild, microtask, nextElementSibling, nextSibling, nodeValue, parentElement, previousSibling, raf, removeAttribute, removeEventListener, setAttribute, text };
|
package/build/utilities.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import { micro as m, raf as r } from '@esportsplus/tasks';
|
|
2
|
-
let prototype, template = document.createElement('template'), t = document.createTextNode('');
|
|
2
|
+
let getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor, prototype, template = document.createElement('template'), t = document.createTextNode('');
|
|
3
3
|
prototype = DocumentFragment.prototype;
|
|
4
4
|
const append = prototype.append;
|
|
5
5
|
prototype = Element.prototype;
|
|
6
6
|
const addEventListener = prototype.addEventListener;
|
|
7
7
|
const removeEventListener = prototype.removeEventListener;
|
|
8
|
-
const className =
|
|
9
|
-
const innerHTML =
|
|
10
|
-
const firstElementChild =
|
|
11
|
-
const nextElementSibling =
|
|
12
|
-
const prepend = prototype.prepend;
|
|
8
|
+
const className = getOwnPropertyDescriptor(prototype, 'className').set;
|
|
9
|
+
const innerHTML = getOwnPropertyDescriptor(prototype, 'innerHTML').set;
|
|
10
|
+
const firstElementChild = getOwnPropertyDescriptor(prototype, 'firstElementChild').get;
|
|
11
|
+
const nextElementSibling = getOwnPropertyDescriptor(prototype, 'nextElementSibling').get;
|
|
13
12
|
const removeAttribute = prototype.removeAttribute;
|
|
14
13
|
const setAttribute = prototype.setAttribute;
|
|
15
14
|
prototype = Node.prototype;
|
|
16
15
|
const cloneNode = prototype.cloneNode;
|
|
17
|
-
const firstChild =
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
16
|
+
const firstChild = getOwnPropertyDescriptor(prototype, 'firstChild').get;
|
|
17
|
+
const lastChild = getOwnPropertyDescriptor(prototype, 'lastChild').get;
|
|
18
|
+
const nextSibling = getOwnPropertyDescriptor(prototype, 'nextSibling').get;
|
|
19
|
+
const nodeValue = getOwnPropertyDescriptor(prototype, 'nodeValue').set;
|
|
20
|
+
const parentElement = getOwnPropertyDescriptor(prototype, 'parentElement').get;
|
|
21
|
+
const previousSibling = getOwnPropertyDescriptor(prototype, 'previousSibling').get;
|
|
22
22
|
const fragment = (html) => {
|
|
23
23
|
innerHTML.call(template, html);
|
|
24
24
|
let { content } = template;
|
|
@@ -34,4 +34,4 @@ const text = (value) => {
|
|
|
34
34
|
}
|
|
35
35
|
return element;
|
|
36
36
|
};
|
|
37
|
-
export { addEventListener, append, className, cloneNode, firstChild, firstElementChild, fragment, innerHTML, microtask, nextElementSibling, nextSibling, nodeValue, parentElement,
|
|
37
|
+
export { addEventListener, append, className, cloneNode, firstChild, firstElementChild, fragment, innerHTML, lastChild, microtask, nextElementSibling, nextSibling, nodeValue, parentElement, previousSibling, raf, removeAttribute, removeEventListener, setAttribute, text };
|
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.15.0",
|
|
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.
|
|
17
|
+
"version": "0.17.0",
|
|
18
18
|
"scripts": {
|
|
19
19
|
"build": "tsc && tsc-alias",
|
|
20
20
|
"-": "-"
|
package/src/attributes.ts
CHANGED
|
@@ -1,24 +1,18 @@
|
|
|
1
1
|
import { effect } from '@esportsplus/reactivity';
|
|
2
|
-
import { isArray,
|
|
3
|
-
import { ondisconnect } from './slot';
|
|
2
|
+
import { isArray, isObject, isString } from '@esportsplus/utilities';
|
|
3
|
+
import { ondisconnect } from './slot/cleanup';
|
|
4
|
+
import { STATE_HYDRATING, STATE_NONE, STATE_WAITING } from './constants';
|
|
4
5
|
import { Attributes, Element } from './types';
|
|
5
6
|
import { className, raf, removeAttribute, setAttribute } from './utilities';
|
|
6
7
|
import q from '@esportsplus/queue';
|
|
7
8
|
import event from './event';
|
|
8
9
|
|
|
9
10
|
|
|
10
|
-
const
|
|
11
|
+
const EFFECT = Symbol();
|
|
11
12
|
|
|
12
|
-
const
|
|
13
|
+
const STORE = Symbol();
|
|
13
14
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const STATE_HYDRATING = 0;
|
|
18
|
-
|
|
19
|
-
const STATE_NONE = 1;
|
|
20
|
-
|
|
21
|
-
const STATE_WAITING = 2;
|
|
15
|
+
const UPDATES = Symbol();
|
|
22
16
|
|
|
23
17
|
|
|
24
18
|
type Context = {
|
|
@@ -64,19 +58,20 @@ function schedule() {
|
|
|
64
58
|
}
|
|
65
59
|
|
|
66
60
|
function set(context: Context, name: string, value: unknown, state: State) {
|
|
67
|
-
if (
|
|
68
|
-
|
|
69
|
-
set(context, name, value[i], state);
|
|
70
|
-
}
|
|
61
|
+
if (value === false || value == null) {
|
|
62
|
+
value = '';
|
|
71
63
|
}
|
|
72
|
-
|
|
64
|
+
|
|
65
|
+
let type = typeof value;
|
|
66
|
+
|
|
67
|
+
if (type === 'function') {
|
|
73
68
|
if (name.startsWith('on')) {
|
|
74
|
-
event(context.element, name as `on${string}`, value);
|
|
69
|
+
event(context.element, name as `on${string}`, value as Function);
|
|
75
70
|
}
|
|
76
71
|
else {
|
|
77
|
-
context.store[
|
|
72
|
+
context.store[EFFECT] ??= 0;
|
|
78
73
|
|
|
79
|
-
let id = (context.store[
|
|
74
|
+
let id = (context.store[EFFECT] as number)++;
|
|
80
75
|
|
|
81
76
|
ondisconnect(
|
|
82
77
|
context.element,
|
|
@@ -107,6 +102,13 @@ function set(context: Context, name: string, value: unknown, state: State) {
|
|
|
107
102
|
state = STATE_NONE;
|
|
108
103
|
}
|
|
109
104
|
}
|
|
105
|
+
else if (type === 'object') {
|
|
106
|
+
if (isArray(value)) {
|
|
107
|
+
for (let i = 0, n = value.length; i < n; i++) {
|
|
108
|
+
set(context, name, value[i], state);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
110
112
|
else {
|
|
111
113
|
update(context, null, name, value, state);
|
|
112
114
|
}
|
|
@@ -232,15 +234,20 @@ function update(
|
|
|
232
234
|
|
|
233
235
|
|
|
234
236
|
const spread = function (element: Element, value: Attributes | Attributes[]) {
|
|
235
|
-
let cache = (element[
|
|
237
|
+
let cache = (element[STORE] ??= { [UPDATES]: {} }) as Record<PropertyKey, unknown>,
|
|
236
238
|
context = {
|
|
237
239
|
element,
|
|
238
240
|
store: cache,
|
|
239
|
-
updates: cache[
|
|
241
|
+
updates: cache[UPDATES] as Record<PropertyKey, unknown>,
|
|
240
242
|
updating: false
|
|
241
243
|
};
|
|
242
244
|
|
|
243
|
-
if (
|
|
245
|
+
if (isObject(value)) {
|
|
246
|
+
for (let name in value) {
|
|
247
|
+
set(context, name, value[name], STATE_HYDRATING);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
else if (isArray(value)) {
|
|
244
251
|
for (let i = 0, n = value.length; i < n; i++) {
|
|
245
252
|
let v = value[i];
|
|
246
253
|
|
|
@@ -249,11 +256,6 @@ const spread = function (element: Element, value: Attributes | Attributes[]) {
|
|
|
249
256
|
}
|
|
250
257
|
}
|
|
251
258
|
}
|
|
252
|
-
else if (isObject(value)) {
|
|
253
|
-
for (let name in value) {
|
|
254
|
-
set(context, name, value[name], STATE_HYDRATING);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
259
|
};
|
|
258
260
|
|
|
259
261
|
|