@esportsplus/template 0.15.4 → 0.15.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @esportsplus/template might be problematic. Click here for more details.
- package/build/attributes.js +34 -46
- package/build/constants.d.ts +1 -2
- package/build/constants.js +1 -2
- package/build/event.d.ts +1 -1
- package/build/event.js +9 -7
- package/build/html/hydrate.js +1 -3
- package/build/render.js +4 -3
- package/build/slot.d.ts +2 -4
- package/build/slot.js +12 -14
- package/build/types.d.ts +3 -3
- package/build/utilities.d.ts +1 -2
- package/build/utilities.js +1 -2
- package/package.json +2 -2
- package/src/attributes.ts +41 -50
- package/src/constants.ts +0 -3
- package/src/event.ts +10 -8
- package/src/html/cache.ts +2 -0
- package/src/html/hydrate.ts +1 -3
- package/src/render.ts +4 -3
- package/src/slot.ts +16 -17
- package/src/types.ts +3 -3
- package/src/utilities.ts +5 -18
package/build/attributes.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { effect } from '@esportsplus/reactivity';
|
|
2
|
+
import { isArray, isFunction, isObject, isString } from '@esportsplus/utilities';
|
|
3
|
+
import { onRemove } from './slot.js';
|
|
4
|
+
import { className, raf, removeAttribute, setAttribute } from './utilities.js';
|
|
4
5
|
import event from './event.js';
|
|
5
6
|
let attributes = {}, delimiters = {
|
|
6
7
|
class: ' ',
|
|
@@ -23,52 +24,35 @@ function attribute(element, name, value) {
|
|
|
23
24
|
element[name] = value;
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
|
-
function
|
|
27
|
-
if (
|
|
28
|
-
let instance = computed(() => {
|
|
29
|
-
let v = value(element);
|
|
30
|
-
if (typeof v === 'function') {
|
|
31
|
-
root(() => {
|
|
32
|
-
reactive(element, id, name, v(element), wait);
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
else if (isArray(v) || isObject(v)) {
|
|
36
|
-
spread(element, v);
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
raf.add(() => {
|
|
40
|
-
update(element, id, name, v, wait);
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
oncleanup(element, () => dispose(instance));
|
|
45
|
-
wait = false;
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
update(element, id, name, value, wait);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
function set(element, value, name) {
|
|
52
|
-
if (name === 'style' && isObject(value)) {
|
|
53
|
-
for (let key in value) {
|
|
54
|
-
set(element, value[key], name);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
else if (isArray(value)) {
|
|
27
|
+
function set(element, value, name, wait = false) {
|
|
28
|
+
if (isArray(value)) {
|
|
58
29
|
for (let i = 0, n = value.length; i < n; i++) {
|
|
59
|
-
set(element, value[i], name);
|
|
30
|
+
set(element, value[i], name, wait);
|
|
60
31
|
}
|
|
61
32
|
}
|
|
62
|
-
else if (
|
|
33
|
+
else if (isFunction(value)) {
|
|
63
34
|
if (name.startsWith('on')) {
|
|
64
35
|
event(element, name, value);
|
|
65
36
|
}
|
|
66
37
|
else {
|
|
67
|
-
|
|
38
|
+
let id = ('e' + store(element)[key]++);
|
|
39
|
+
onRemove(element, effect(() => {
|
|
40
|
+
let v = value(element);
|
|
41
|
+
if (isArray(v)) {
|
|
42
|
+
let last = v.length - 1;
|
|
43
|
+
for (let i = 0, n = v.length; i < n; i++) {
|
|
44
|
+
update(element, id, name, v[i], wait || i !== last);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
update(element, id, name, v, wait);
|
|
49
|
+
}
|
|
50
|
+
}));
|
|
51
|
+
wait = false;
|
|
68
52
|
}
|
|
69
53
|
}
|
|
70
54
|
else {
|
|
71
|
-
update(element, null, name, value,
|
|
55
|
+
update(element, null, name, value, wait);
|
|
72
56
|
}
|
|
73
57
|
}
|
|
74
58
|
function store(element) {
|
|
@@ -87,13 +71,13 @@ function update(element, id, name, value, wait = false) {
|
|
|
87
71
|
data[name] = dynamic = {};
|
|
88
72
|
}
|
|
89
73
|
if (id === null) {
|
|
90
|
-
if (value &&
|
|
74
|
+
if (value && isString(value)) {
|
|
91
75
|
data[cache] += (data[cache] ? delimiter : '') + value;
|
|
92
76
|
}
|
|
93
77
|
}
|
|
94
78
|
else {
|
|
95
79
|
let hot = {};
|
|
96
|
-
if (
|
|
80
|
+
if (isString(value)) {
|
|
97
81
|
let part, parts = value.split(delimiter);
|
|
98
82
|
for (let i = 0, n = parts.length; i < n; i++) {
|
|
99
83
|
part = parts[i].trim();
|
|
@@ -120,17 +104,21 @@ function update(element, id, name, value, wait = false) {
|
|
|
120
104
|
value += (value ? delimiter : '') + key;
|
|
121
105
|
}
|
|
122
106
|
}
|
|
123
|
-
else if (
|
|
107
|
+
else if (isString(id)) {
|
|
124
108
|
if (data[name] === value) {
|
|
125
109
|
return;
|
|
126
110
|
}
|
|
127
111
|
data[name] = value;
|
|
128
112
|
}
|
|
129
113
|
if (wait) {
|
|
130
|
-
|
|
114
|
+
if (id === null) {
|
|
115
|
+
attributes[name] = value;
|
|
116
|
+
}
|
|
131
117
|
}
|
|
132
118
|
else {
|
|
133
|
-
|
|
119
|
+
raf.add(() => {
|
|
120
|
+
attribute(element, name, value);
|
|
121
|
+
});
|
|
134
122
|
}
|
|
135
123
|
}
|
|
136
124
|
const apply = (element) => {
|
|
@@ -142,7 +130,7 @@ const apply = (element) => {
|
|
|
142
130
|
const spread = function (element, attributes) {
|
|
143
131
|
if (isObject(attributes)) {
|
|
144
132
|
for (let name in attributes) {
|
|
145
|
-
set(element, attributes[name], name);
|
|
133
|
+
set(element, attributes[name], name, true);
|
|
146
134
|
}
|
|
147
135
|
}
|
|
148
136
|
else if (isArray(attributes)) {
|
|
@@ -152,7 +140,7 @@ const spread = function (element, attributes) {
|
|
|
152
140
|
throw new Error('@esportsplus/template: attributes must be of type `Attributes` or `Attributes[]`; Received ' + JSON.stringify(attributes));
|
|
153
141
|
}
|
|
154
142
|
for (let name in attrs) {
|
|
155
|
-
set(element, attrs[name], name);
|
|
143
|
+
set(element, attrs[name], name, true);
|
|
156
144
|
}
|
|
157
145
|
}
|
|
158
146
|
}
|
package/build/constants.d.ts
CHANGED
|
@@ -8,9 +8,8 @@ declare const REGEX_SLOT_NODES: RegExp;
|
|
|
8
8
|
declare const RENDERABLE: unique symbol;
|
|
9
9
|
declare const RENDERABLE_REACTIVE: unique symbol;
|
|
10
10
|
declare const RENDERABLE_TEMPLATE: unique symbol;
|
|
11
|
-
declare const SLOT: unique symbol;
|
|
12
11
|
declare const SLOT_CLEANUP: unique symbol;
|
|
13
12
|
declare const SLOT_HTML = "<!--$-->";
|
|
14
13
|
declare const SLOT_MARKER = "{{$}}";
|
|
15
14
|
declare const SLOT_MARKER_LENGTH: number;
|
|
16
|
-
export { NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE,
|
|
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 };
|
package/build/constants.js
CHANGED
|
@@ -28,9 +28,8 @@ const REGEX_SLOT_NODES = /<([\w-]+|[\/!])(?:([^><]*{{\$}}[^><]*)|(?:[^><]*))?>|{
|
|
|
28
28
|
const RENDERABLE = Symbol();
|
|
29
29
|
const RENDERABLE_REACTIVE = Symbol();
|
|
30
30
|
const RENDERABLE_TEMPLATE = Symbol();
|
|
31
|
-
const SLOT = Symbol();
|
|
32
31
|
const SLOT_CLEANUP = Symbol();
|
|
33
32
|
const SLOT_HTML = '<!--$-->';
|
|
34
33
|
const SLOT_MARKER = '{{$}}';
|
|
35
34
|
const SLOT_MARKER_LENGTH = SLOT_MARKER.length;
|
|
36
|
-
export { NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE,
|
|
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 };
|
package/build/event.d.ts
CHANGED
package/build/event.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { root } from '@esportsplus/reactivity';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { defineProperty } from '@esportsplus/utilities';
|
|
3
|
+
import { onRemove } from './slot.js';
|
|
4
|
+
import { addEventListener, parentElement } from './utilities.js';
|
|
4
5
|
let capture = new Set(['onblur', 'onfocus', 'onscroll']), controllers = new Map(), keys = {}, passive = new Set([
|
|
5
6
|
'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel',
|
|
6
7
|
'onscroll',
|
|
@@ -18,18 +19,19 @@ export default (element, event, listener) => {
|
|
|
18
19
|
retry = 0;
|
|
19
20
|
root(() => listener(element));
|
|
20
21
|
}
|
|
21
|
-
if (retry
|
|
22
|
+
if (!retry) {
|
|
22
23
|
clearInterval(interval);
|
|
23
24
|
}
|
|
24
25
|
}, 1000 / 60), retry = 60;
|
|
25
26
|
return;
|
|
26
27
|
}
|
|
27
|
-
else if (event === '
|
|
28
|
-
|
|
28
|
+
else if (event === 'onremove') {
|
|
29
|
+
onRemove(element, () => listener(element));
|
|
29
30
|
return;
|
|
30
31
|
}
|
|
31
32
|
else if (event === 'onrender') {
|
|
32
|
-
|
|
33
|
+
root(() => listener(element));
|
|
34
|
+
return;
|
|
33
35
|
}
|
|
34
36
|
let controller = controllers.get(event), signal;
|
|
35
37
|
if (controller === null) {
|
|
@@ -42,7 +44,7 @@ export default (element, event, listener) => {
|
|
|
42
44
|
}
|
|
43
45
|
if (controller) {
|
|
44
46
|
controller.listeners++;
|
|
45
|
-
|
|
47
|
+
onRemove(element, () => {
|
|
46
48
|
if (--controller.listeners) {
|
|
47
49
|
return;
|
|
48
50
|
}
|
package/build/html/hydrate.js
CHANGED
|
@@ -35,9 +35,7 @@ function render(renderable, template) {
|
|
|
35
35
|
}
|
|
36
36
|
fn(node, values[slot], name);
|
|
37
37
|
}
|
|
38
|
-
|
|
39
|
-
apply(node);
|
|
40
|
-
}
|
|
38
|
+
apply(node);
|
|
41
39
|
}
|
|
42
40
|
for (let element = firstChild.call(fragment); element; element = nextSibling.call(element)) {
|
|
43
41
|
elements.push(element);
|
package/build/render.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { isInstanceOf } from '@esportsplus/utilities';
|
|
2
|
+
import { SLOT_HTML } from './constants.js';
|
|
3
|
+
import slot, { Slot } from './slot.js';
|
|
3
4
|
import { firstChild, fragment, nodeValue, prepend } from './utilities.js';
|
|
4
5
|
let marker = firstChild.call(fragment(SLOT_HTML)), node;
|
|
5
6
|
export default (renderable, parent) => {
|
|
6
|
-
if (
|
|
7
|
+
if (isInstanceOf(parent, Slot)) {
|
|
7
8
|
return parent.render(renderable);
|
|
8
9
|
}
|
|
9
10
|
nodeValue.call(parent, '');
|
package/build/slot.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { SLOT } from './constants.js';
|
|
2
1
|
import { Element, Elements } from './types.js';
|
|
3
2
|
declare class Slot {
|
|
4
|
-
[SLOT]: null;
|
|
5
3
|
marker: Element;
|
|
6
4
|
nodes: Elements[];
|
|
7
5
|
text: Element | null;
|
|
@@ -17,7 +15,7 @@ declare class Slot {
|
|
|
17
15
|
splice(start: number, stop?: number, ...groups: Elements[]): Elements[];
|
|
18
16
|
unshift(...groups: Elements[]): number;
|
|
19
17
|
}
|
|
20
|
-
declare const
|
|
18
|
+
declare const onRemove: (element: Element, fn: VoidFunction) => void;
|
|
21
19
|
declare const _default: (marker: Element, value: unknown) => Slot;
|
|
22
20
|
export default _default;
|
|
23
|
-
export {
|
|
21
|
+
export { onRemove, Slot };
|
package/build/slot.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { effect, root } from '@esportsplus/reactivity';
|
|
2
|
+
import { isArray, isFunction, isInstanceOf, isObject } from '@esportsplus/utilities';
|
|
3
|
+
import { RENDERABLE, RENDERABLE_REACTIVE, SLOT_CLEANUP } from './constants.js';
|
|
3
4
|
import { hydrate } from './html/index.js';
|
|
4
|
-
import { firstChild,
|
|
5
|
-
import { isFunction } from '@esportsplus/utilities';
|
|
5
|
+
import { firstChild, nextSibling, nodeValue, raf, text } from './utilities.js';
|
|
6
6
|
let cleanup = [], scheduled = false;
|
|
7
7
|
function after(anchor, groups) {
|
|
8
8
|
for (let i = 0, n = groups.length; i < n; i++) {
|
|
@@ -34,7 +34,7 @@ function render(anchor, input, slot) {
|
|
|
34
34
|
if (input === false || input == null) {
|
|
35
35
|
input = '';
|
|
36
36
|
}
|
|
37
|
-
else if (
|
|
37
|
+
else if (isObject(input)) {
|
|
38
38
|
if (isArray(input)) {
|
|
39
39
|
let groups = [];
|
|
40
40
|
for (let i = 0, n = input.length; i < n; i++) {
|
|
@@ -51,12 +51,12 @@ function render(anchor, input, slot) {
|
|
|
51
51
|
nodes = hydrate.static(input);
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
-
else if (input
|
|
54
|
+
else if (isInstanceOf(input, NodeList)) {
|
|
55
55
|
for (let node = firstChild.call(input); node; node = nextSibling.call(node)) {
|
|
56
56
|
nodes.push(node);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
-
else if (input
|
|
59
|
+
else if (isInstanceOf(input, Node)) {
|
|
60
60
|
nodes = [input];
|
|
61
61
|
}
|
|
62
62
|
if (anchor) {
|
|
@@ -96,12 +96,11 @@ function schedule() {
|
|
|
96
96
|
});
|
|
97
97
|
}
|
|
98
98
|
class Slot {
|
|
99
|
-
[SLOT] = null;
|
|
100
99
|
marker;
|
|
101
100
|
nodes;
|
|
102
101
|
text = null;
|
|
103
102
|
constructor(marker) {
|
|
104
|
-
|
|
103
|
+
onRemove(marker, () => this.clear());
|
|
105
104
|
this.marker = marker;
|
|
106
105
|
this.nodes = [];
|
|
107
106
|
}
|
|
@@ -138,7 +137,7 @@ class Slot {
|
|
|
138
137
|
}
|
|
139
138
|
render(input) {
|
|
140
139
|
if (isFunction(input)) {
|
|
141
|
-
|
|
140
|
+
onRemove(this.marker, effect(() => {
|
|
142
141
|
let v = input();
|
|
143
142
|
if (isFunction(v)) {
|
|
144
143
|
root(() => this.render(v()));
|
|
@@ -148,8 +147,7 @@ class Slot {
|
|
|
148
147
|
this.render(v);
|
|
149
148
|
});
|
|
150
149
|
}
|
|
151
|
-
});
|
|
152
|
-
oncleanup(this.marker, () => dispose(instance));
|
|
150
|
+
}));
|
|
153
151
|
return this;
|
|
154
152
|
}
|
|
155
153
|
if (this.text) {
|
|
@@ -183,10 +181,10 @@ class Slot {
|
|
|
183
181
|
return this.nodes.unshift(...after(this.marker, groups));
|
|
184
182
|
}
|
|
185
183
|
}
|
|
186
|
-
const
|
|
184
|
+
const onRemove = (element, fn) => {
|
|
187
185
|
(element[SLOT_CLEANUP] ??= []).push(fn);
|
|
188
186
|
};
|
|
189
187
|
export default (marker, value) => {
|
|
190
188
|
return new Slot(marker).render(value);
|
|
191
189
|
};
|
|
192
|
-
export {
|
|
190
|
+
export { onRemove, Slot };
|
package/build/types.d.ts
CHANGED
|
@@ -5,15 +5,15 @@ import attributes from './attributes.js';
|
|
|
5
5
|
import event from './event.js';
|
|
6
6
|
import slot from './slot.js';
|
|
7
7
|
type Attributes = {
|
|
8
|
-
class?: string | Effect<Primitive> | (string | Effect<Primitive>)[];
|
|
9
|
-
style?: string | Effect<Primitive> | (string | Effect<Primitive>)[];
|
|
8
|
+
class?: string | Effect<Primitive | Primitive[]> | (string | Effect<Primitive | Primitive[]>)[];
|
|
9
|
+
style?: string | Effect<Primitive | Primitive[]> | (string | Effect<Primitive | Primitive[]>)[];
|
|
10
10
|
} & {
|
|
11
11
|
[K in keyof GlobalEventHandlersEventMap as `on${string & K}`]?: (this: Element, event: GlobalEventHandlersEventMap[K]) => void;
|
|
12
12
|
} & {
|
|
13
13
|
[key: `aria-${string}`]: string | number | boolean | undefined;
|
|
14
14
|
[key: `data-${string}`]: string | undefined;
|
|
15
15
|
onconnected?: (element: Element) => void;
|
|
16
|
-
|
|
16
|
+
onremove?: (element: Element) => void;
|
|
17
17
|
onrender?: (element: Element) => void;
|
|
18
18
|
} & Record<PropertyKey, unknown>;
|
|
19
19
|
type Effect<T> = () => EffectResponse<T>;
|
package/build/utilities.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { defineProperty, isArray, isObject } from '@esportsplus/utilities';
|
|
2
1
|
import { Element as E } from './types.js';
|
|
3
2
|
declare const addEventListener: {
|
|
4
3
|
<K extends keyof ElementEventMap>(type: K, listener: (this: Element, ev: ElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
|
@@ -24,4 +23,4 @@ declare const parentNode: () => any;
|
|
|
24
23
|
declare const fragment: (html: string) => DocumentFragment;
|
|
25
24
|
declare const raf: import("@esportsplus/tasks/build/factory").Scheduler;
|
|
26
25
|
declare const text: (value: string) => E;
|
|
27
|
-
export { addEventListener, className, cloneNode,
|
|
26
|
+
export { addEventListener, className, cloneNode, firstChild, firstElementChild, fragment, innerHTML, nextElementSibling, nextSibling, nodeValue, parentElement, parentNode, prepend, raf, removeAttribute, removeEventListener, setAttribute, text };
|
package/build/utilities.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { raf as tasks } from '@esportsplus/tasks';
|
|
2
|
-
import { defineProperty, isArray, isObject } from '@esportsplus/utilities';
|
|
3
2
|
let prototype, template = document.createElement('template'), t = document.createTextNode('');
|
|
4
3
|
prototype = Element.prototype;
|
|
5
4
|
const addEventListener = prototype.addEventListener;
|
|
@@ -32,4 +31,4 @@ const text = (value) => {
|
|
|
32
31
|
}
|
|
33
32
|
return element;
|
|
34
33
|
};
|
|
35
|
-
export { addEventListener, className, cloneNode,
|
|
34
|
+
export { addEventListener, className, cloneNode, firstChild, firstElementChild, fragment, innerHTML, nextElementSibling, nextSibling, nodeValue, parentElement, parentNode, prepend, raf, removeAttribute, removeEventListener, setAttribute, text };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": "ICJR",
|
|
3
3
|
"dependencies": {
|
|
4
|
-
"@esportsplus/reactivity": "^0.
|
|
4
|
+
"@esportsplus/reactivity": "^0.10.1",
|
|
5
5
|
"@esportsplus/tasks": "^0.1.11",
|
|
6
6
|
"@esportsplus/utilities": "^0.21.0"
|
|
7
7
|
},
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"private": false,
|
|
14
14
|
"type": "module",
|
|
15
15
|
"types": "./build/index.d.ts",
|
|
16
|
-
"version": "0.15.
|
|
16
|
+
"version": "0.15.6",
|
|
17
17
|
"scripts": {
|
|
18
18
|
"build": "tsc && tsc-alias",
|
|
19
19
|
"-": "-"
|
package/src/attributes.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { effect } from '@esportsplus/reactivity';
|
|
2
|
+
import { isArray, isFunction, isObject, isString } from '@esportsplus/utilities';
|
|
3
|
+
import { onRemove } from './slot';
|
|
3
4
|
import { Attributes, Element } from './types';
|
|
4
|
-
import { className,
|
|
5
|
+
import { className, raf, removeAttribute, setAttribute } from './utilities';
|
|
5
6
|
import event from './event';
|
|
6
7
|
|
|
7
8
|
|
|
@@ -32,56 +33,42 @@ function attribute(element: Element, name: string, value: unknown) {
|
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
function
|
|
36
|
-
if (
|
|
37
|
-
let instance = computed(() => {
|
|
38
|
-
let v = (value as Function)(element);
|
|
39
|
-
|
|
40
|
-
if (typeof v === 'function') {
|
|
41
|
-
root(() => {
|
|
42
|
-
reactive(element, id, name, v(element), wait);
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
else if (isArray(v) || isObject(v)) {
|
|
46
|
-
spread(element, v as Attributes | Attributes[]);
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
raf.add(() => {
|
|
50
|
-
update(element, id, name, v, wait);
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
oncleanup(element, () => dispose(instance));
|
|
56
|
-
|
|
57
|
-
wait = false;
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
update(element, id, name, value, wait);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function set(element: Element, value: unknown, name: string) {
|
|
65
|
-
if (name === 'style' && isObject(value)) {
|
|
66
|
-
for (let key in value) {
|
|
67
|
-
set(element, value[key], name);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
else if (isArray(value)) {
|
|
36
|
+
function set(element: Element, value: unknown, name: string, wait = false) {
|
|
37
|
+
if (isArray(value)) {
|
|
71
38
|
for (let i = 0, n = value.length; i < n; i++) {
|
|
72
|
-
set(element, value[i], name);
|
|
39
|
+
set(element, value[i], name, wait);
|
|
73
40
|
}
|
|
74
41
|
}
|
|
75
|
-
else if (
|
|
42
|
+
else if (isFunction(value)) {
|
|
76
43
|
if (name.startsWith('on')) {
|
|
77
44
|
event(element, name as `on${string}`, value);
|
|
78
45
|
}
|
|
79
46
|
else {
|
|
80
|
-
|
|
47
|
+
let id = ('e' + store(element)[key]++);
|
|
48
|
+
|
|
49
|
+
onRemove(
|
|
50
|
+
element,
|
|
51
|
+
effect(() => {
|
|
52
|
+
let v = (value as Function)(element);
|
|
53
|
+
|
|
54
|
+
if (isArray(v)) {
|
|
55
|
+
let last = v.length - 1;
|
|
56
|
+
|
|
57
|
+
for (let i = 0, n = v.length; i < n; i++) {
|
|
58
|
+
update(element, id, name, v[i], wait || i !== last);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
update(element, id, name, v, wait);
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
wait = false;
|
|
81
68
|
}
|
|
82
69
|
}
|
|
83
70
|
else {
|
|
84
|
-
update(element, null, name, value,
|
|
71
|
+
update(element, null, name, value, wait);
|
|
85
72
|
}
|
|
86
73
|
}
|
|
87
74
|
|
|
@@ -111,14 +98,14 @@ function update(element: Element, id: null | string, name: string, value: unknow
|
|
|
111
98
|
}
|
|
112
99
|
|
|
113
100
|
if (id === null) {
|
|
114
|
-
if (value &&
|
|
101
|
+
if (value && isString(value)) {
|
|
115
102
|
data[cache] += (data[cache] ? delimiter : '') + value;
|
|
116
103
|
}
|
|
117
104
|
}
|
|
118
105
|
else {
|
|
119
106
|
let hot: Attributes = {};
|
|
120
107
|
|
|
121
|
-
if (
|
|
108
|
+
if (isString(value)) {
|
|
122
109
|
let part: string,
|
|
123
110
|
parts = value.split(delimiter);
|
|
124
111
|
|
|
@@ -155,7 +142,7 @@ function update(element: Element, id: null | string, name: string, value: unknow
|
|
|
155
142
|
value += (value ? delimiter : '') + key;
|
|
156
143
|
}
|
|
157
144
|
}
|
|
158
|
-
else if (
|
|
145
|
+
else if (isString(id)) {
|
|
159
146
|
if (data[name] === value) {
|
|
160
147
|
return;
|
|
161
148
|
}
|
|
@@ -164,10 +151,14 @@ function update(element: Element, id: null | string, name: string, value: unknow
|
|
|
164
151
|
}
|
|
165
152
|
|
|
166
153
|
if (wait) {
|
|
167
|
-
|
|
154
|
+
if (id === null) {
|
|
155
|
+
attributes[name] = value;
|
|
156
|
+
}
|
|
168
157
|
}
|
|
169
158
|
else {
|
|
170
|
-
|
|
159
|
+
raf.add(() => {
|
|
160
|
+
attribute(element, name, value);
|
|
161
|
+
});
|
|
171
162
|
}
|
|
172
163
|
}
|
|
173
164
|
|
|
@@ -183,7 +174,7 @@ const apply = (element: Element) => {
|
|
|
183
174
|
const spread = function (element: Element, attributes: Attributes | Attributes[]) {
|
|
184
175
|
if (isObject(attributes)) {
|
|
185
176
|
for (let name in attributes) {
|
|
186
|
-
set(element, attributes[name], name);
|
|
177
|
+
set(element, attributes[name], name, true);
|
|
187
178
|
}
|
|
188
179
|
}
|
|
189
180
|
else if (isArray(attributes)) {
|
|
@@ -195,7 +186,7 @@ const spread = function (element: Element, attributes: Attributes | Attributes[]
|
|
|
195
186
|
}
|
|
196
187
|
|
|
197
188
|
for (let name in attrs) {
|
|
198
|
-
set(element, attrs[name], name);
|
|
189
|
+
set(element, attrs[name], name, true);
|
|
199
190
|
}
|
|
200
191
|
}
|
|
201
192
|
}
|
package/src/constants.ts
CHANGED
|
@@ -43,8 +43,6 @@ const RENDERABLE_REACTIVE = Symbol();
|
|
|
43
43
|
const RENDERABLE_TEMPLATE = Symbol();
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
const SLOT = Symbol();
|
|
47
|
-
|
|
48
46
|
const SLOT_CLEANUP = Symbol();
|
|
49
47
|
|
|
50
48
|
const SLOT_HTML = '<!--$-->';
|
|
@@ -65,7 +63,6 @@ export {
|
|
|
65
63
|
RENDERABLE,
|
|
66
64
|
RENDERABLE_REACTIVE,
|
|
67
65
|
RENDERABLE_TEMPLATE,
|
|
68
|
-
SLOT,
|
|
69
66
|
SLOT_CLEANUP,
|
|
70
67
|
SLOT_HTML,
|
|
71
68
|
SLOT_MARKER,
|
package/src/event.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { root } from '@esportsplus/reactivity';
|
|
2
|
-
import {
|
|
2
|
+
import { defineProperty } from '@esportsplus/utilities';
|
|
3
|
+
import { onRemove } from './slot';
|
|
3
4
|
import { Element } from './types';
|
|
4
|
-
import { addEventListener,
|
|
5
|
+
import { addEventListener, parentElement } from './utilities';
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
let capture = new Set<`on${string}`>(['onblur', 'onfocus', 'onscroll']),
|
|
@@ -23,7 +24,7 @@ let capture = new Set<`on${string}`>(['onblur', 'onfocus', 'onscroll']),
|
|
|
23
24
|
});
|
|
24
25
|
|
|
25
26
|
|
|
26
|
-
export default (element: Element, event: `on${string}`, listener: Function) => {
|
|
27
|
+
export default (element: Element, event: `on${string}`, listener: Function): void => {
|
|
27
28
|
if (event === 'onconnected') {
|
|
28
29
|
let interval = setInterval(() => {
|
|
29
30
|
retry--;
|
|
@@ -33,7 +34,7 @@ export default (element: Element, event: `on${string}`, listener: Function) => {
|
|
|
33
34
|
root(() => listener(element));
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
if (retry
|
|
37
|
+
if (!retry) {
|
|
37
38
|
clearInterval(interval);
|
|
38
39
|
}
|
|
39
40
|
}, 1000 / 60),
|
|
@@ -41,12 +42,13 @@ export default (element: Element, event: `on${string}`, listener: Function) => {
|
|
|
41
42
|
|
|
42
43
|
return;
|
|
43
44
|
}
|
|
44
|
-
else if (event === '
|
|
45
|
-
|
|
45
|
+
else if (event === 'onremove') {
|
|
46
|
+
onRemove(element, () => listener(element));
|
|
46
47
|
return;
|
|
47
48
|
}
|
|
48
49
|
else if (event === 'onrender') {
|
|
49
|
-
|
|
50
|
+
root(() => listener(element));
|
|
51
|
+
return;
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
let controller = controllers.get(event),
|
|
@@ -68,7 +70,7 @@ export default (element: Element, event: `on${string}`, listener: Function) => {
|
|
|
68
70
|
if (controller) {
|
|
69
71
|
controller.listeners++;
|
|
70
72
|
|
|
71
|
-
|
|
73
|
+
onRemove(element, () => {
|
|
72
74
|
if (--controller.listeners) {
|
|
73
75
|
return;
|
|
74
76
|
}
|
package/src/html/cache.ts
CHANGED
package/src/html/hydrate.ts
CHANGED
|
@@ -58,9 +58,7 @@ function render<T>(renderable: Renderable<T>, template: Template) {
|
|
|
58
58
|
fn(node, values[slot], name);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
apply(node);
|
|
63
|
-
}
|
|
61
|
+
apply(node);
|
|
64
62
|
}
|
|
65
63
|
|
|
66
64
|
for (let element = firstChild.call(fragment as Element); element; element = nextSibling.call(element)) {
|
package/src/render.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isInstanceOf } from '@esportsplus/utilities';
|
|
2
|
+
import { SLOT_HTML } from './constants';
|
|
2
3
|
import slot, { Slot } from './slot';
|
|
3
4
|
import { Renderable } from './types';
|
|
4
5
|
import { firstChild, fragment, nodeValue, prepend } from './utilities';
|
|
5
6
|
|
|
6
7
|
|
|
7
|
-
let marker = firstChild.call(fragment(SLOT_HTML)),
|
|
8
|
+
let marker = firstChild.call( fragment(SLOT_HTML) ),
|
|
8
9
|
node;
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
export default (renderable: Renderable, parent: HTMLElement | Slot) => {
|
|
12
|
-
if (
|
|
13
|
+
if (isInstanceOf(parent, Slot)) {
|
|
13
14
|
return parent.render(renderable);
|
|
14
15
|
}
|
|
15
16
|
|
package/src/slot.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { effect, root } from '@esportsplus/reactivity';
|
|
2
|
+
import { isArray, isFunction, isInstanceOf, isObject } from '@esportsplus/utilities';
|
|
3
|
+
import { RENDERABLE, RENDERABLE_REACTIVE, SLOT_CLEANUP } from './constants';
|
|
3
4
|
import { hydrate } from './html';
|
|
4
5
|
import { Element, Elements, RenderableReactive, RenderableTemplate } from './types';
|
|
5
|
-
import { firstChild,
|
|
6
|
-
import { isFunction } from '@esportsplus/utilities';
|
|
6
|
+
import { firstChild, nextSibling, nodeValue, raf, text } from './utilities'
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
let cleanup: VoidFunction[] = [],
|
|
@@ -49,7 +49,7 @@ function render(anchor: Element | null, input: unknown, slot?: Slot): Elements |
|
|
|
49
49
|
if (input === false || input == null) {
|
|
50
50
|
input = '';
|
|
51
51
|
}
|
|
52
|
-
else if (
|
|
52
|
+
else if (isObject(input)) {
|
|
53
53
|
if (isArray(input)) {
|
|
54
54
|
let groups: Elements[] = [];
|
|
55
55
|
|
|
@@ -70,12 +70,12 @@ function render(anchor: Element | null, input: unknown, slot?: Slot): Elements |
|
|
|
70
70
|
nodes = hydrate.static(input as RenderableTemplate<unknown>);
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
-
else if (input
|
|
74
|
-
for (let node = firstChild.call(input
|
|
73
|
+
else if (isInstanceOf(input, NodeList)) {
|
|
74
|
+
for (let node = firstChild.call(input); node; node = nextSibling.call(node)) {
|
|
75
75
|
nodes.push(node);
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
-
else if (input
|
|
78
|
+
else if (isInstanceOf(input, Node)) {
|
|
79
79
|
nodes = [input] as Elements;
|
|
80
80
|
}
|
|
81
81
|
|
|
@@ -130,15 +130,13 @@ function schedule() {
|
|
|
130
130
|
|
|
131
131
|
|
|
132
132
|
class Slot {
|
|
133
|
-
[SLOT] = null;
|
|
134
|
-
|
|
135
133
|
marker: Element;
|
|
136
134
|
nodes: Elements[];
|
|
137
135
|
text: Element | null = null;
|
|
138
136
|
|
|
139
137
|
|
|
140
138
|
constructor(marker: Element) {
|
|
141
|
-
|
|
139
|
+
onRemove(marker, () => this.clear());
|
|
142
140
|
|
|
143
141
|
this.marker = marker;
|
|
144
142
|
this.nodes = [];
|
|
@@ -192,7 +190,9 @@ class Slot {
|
|
|
192
190
|
|
|
193
191
|
render(input: unknown) {
|
|
194
192
|
if (isFunction(input)) {
|
|
195
|
-
|
|
193
|
+
onRemove(
|
|
194
|
+
this.marker,
|
|
195
|
+
effect(() => {
|
|
196
196
|
let v = (input as Function)();
|
|
197
197
|
|
|
198
198
|
if (isFunction(v)) {
|
|
@@ -203,9 +203,8 @@ class Slot {
|
|
|
203
203
|
this.render(v);
|
|
204
204
|
});
|
|
205
205
|
}
|
|
206
|
-
})
|
|
207
|
-
|
|
208
|
-
oncleanup(this.marker, () => dispose(instance));
|
|
206
|
+
})
|
|
207
|
+
);
|
|
209
208
|
|
|
210
209
|
return this;
|
|
211
210
|
}
|
|
@@ -257,7 +256,7 @@ class Slot {
|
|
|
257
256
|
}
|
|
258
257
|
|
|
259
258
|
|
|
260
|
-
const
|
|
259
|
+
const onRemove = (element: Element, fn: VoidFunction) => {
|
|
261
260
|
( element[SLOT_CLEANUP] ??= [] ).push(fn);
|
|
262
261
|
};
|
|
263
262
|
|
|
@@ -265,4 +264,4 @@ const oncleanup = (element: Element, fn: VoidFunction) => {
|
|
|
265
264
|
export default (marker: Element, value: unknown) => {
|
|
266
265
|
return new Slot(marker).render(value);
|
|
267
266
|
};
|
|
268
|
-
export {
|
|
267
|
+
export { onRemove, Slot };
|
package/src/types.ts
CHANGED
|
@@ -7,15 +7,15 @@ import slot from './slot';
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
type Attributes = {
|
|
10
|
-
class?: string | Effect<Primitive> | (string | Effect<Primitive>)[];
|
|
11
|
-
style?: string | Effect<Primitive> | (string | Effect<Primitive>)[];
|
|
10
|
+
class?: string | Effect<Primitive | Primitive[]> | (string | Effect<Primitive | Primitive[]>)[];
|
|
11
|
+
style?: string | Effect<Primitive | Primitive[]> | (string | Effect<Primitive | Primitive[]>)[];
|
|
12
12
|
} & {
|
|
13
13
|
[K in keyof GlobalEventHandlersEventMap as `on${string & K}`]?: (this: Element, event: GlobalEventHandlersEventMap[K]) => void;
|
|
14
14
|
} & {
|
|
15
15
|
[key: `aria-${string}`]: string | number | boolean | undefined;
|
|
16
16
|
[key: `data-${string}`]: string | undefined;
|
|
17
17
|
onconnected?: (element: Element) => void;
|
|
18
|
-
|
|
18
|
+
onremove?: (element: Element) => void;
|
|
19
19
|
// Rendered in fragment
|
|
20
20
|
// - Used to retrieve reference to the element
|
|
21
21
|
onrender?: (element: Element) => void;
|
package/src/utilities.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { raf as tasks } from '@esportsplus/tasks';
|
|
2
|
-
import { defineProperty, isArray, isObject } from '@esportsplus/utilities';
|
|
3
2
|
import { Element as E } from './types';
|
|
4
3
|
|
|
5
4
|
|
|
@@ -70,24 +69,12 @@ const text = (value: string) => {
|
|
|
70
69
|
|
|
71
70
|
export {
|
|
72
71
|
addEventListener,
|
|
73
|
-
className,
|
|
74
|
-
|
|
75
|
-
defineProperty,
|
|
76
|
-
firstChild,
|
|
77
|
-
firstElementChild,
|
|
78
|
-
fragment,
|
|
72
|
+
className, cloneNode,
|
|
73
|
+
firstChild, firstElementChild, fragment,
|
|
79
74
|
innerHTML,
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
nextSibling,
|
|
84
|
-
nodeValue,
|
|
85
|
-
parentElement,
|
|
86
|
-
parentNode,
|
|
87
|
-
prepend,
|
|
88
|
-
raf,
|
|
89
|
-
removeAttribute,
|
|
90
|
-
removeEventListener,
|
|
75
|
+
nextElementSibling, nextSibling, nodeValue,
|
|
76
|
+
parentElement, parentNode, prepend,
|
|
77
|
+
raf, removeAttribute, removeEventListener,
|
|
91
78
|
setAttribute,
|
|
92
79
|
text
|
|
93
80
|
};
|