@esportsplus/template 0.12.12 → 0.13.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.
Potentially problematic release.
This version of @esportsplus/template might be problematic. Click here for more details.
- package/build/attributes.d.ts +3 -1
- package/build/attributes.js +37 -40
- package/build/constants.d.ts +2 -5
- package/build/constants.js +2 -5
- package/build/html/cache.js +14 -70
- package/build/html/hydrate.js +6 -4
- package/build/types.d.ts +3 -2
- package/package.json +2 -2
- package/src/attributes.ts +43 -43
- package/src/constants.ts +4 -14
- package/src/html/cache.ts +16 -88
- package/src/html/hydrate.ts +6 -4
- package/src/slot.ts +1 -1
- package/src/types.ts +7 -2
package/build/attributes.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Attributes, Element } from './types.js';
|
|
2
|
+
declare const apply: (element: Element) => void;
|
|
3
|
+
declare const spread: (element: Element, attributes: Attributes | Attributes[]) => void;
|
|
2
4
|
declare const _default: {
|
|
3
5
|
apply: (element: Element) => void;
|
|
4
|
-
set: (element: Element, value: unknown, name: string) => void;
|
|
5
6
|
spread: (element: Element, attributes: Attributes | Attributes[]) => void;
|
|
6
7
|
};
|
|
7
8
|
export default _default;
|
|
9
|
+
export { apply, spread };
|
package/build/attributes.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { effect, root } from '@esportsplus/reactivity';
|
|
2
|
-
import { ATTRIBUTES } from './constants.js';
|
|
3
2
|
import { className, isArray, isObject, raf, removeAttribute, setAttribute } from './utilities.js';
|
|
4
3
|
import event from './event.js';
|
|
5
4
|
let attributes = {}, delimiters = {
|
|
6
5
|
class: ' ',
|
|
7
6
|
style: ';'
|
|
8
|
-
};
|
|
7
|
+
}, key = Symbol();
|
|
9
8
|
function attribute(element, name, value) {
|
|
10
9
|
if (value === false || value == null) {
|
|
11
10
|
value = '';
|
|
@@ -45,12 +44,22 @@ function reactive(element, id, name, value, wait = false) {
|
|
|
45
44
|
}
|
|
46
45
|
}
|
|
47
46
|
function set(element, value, name) {
|
|
48
|
-
if (
|
|
47
|
+
if (name === 'style' && isObject(value)) {
|
|
48
|
+
for (let key in value) {
|
|
49
|
+
set(element, value[key], name);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else if (isArray(value)) {
|
|
53
|
+
for (let i = 0, n = value.length; i < n; i++) {
|
|
54
|
+
set(element, value[i], name);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else if (typeof value === 'function') {
|
|
49
58
|
if (name.startsWith('on')) {
|
|
50
59
|
event(element, name, value);
|
|
51
60
|
}
|
|
52
61
|
else {
|
|
53
|
-
reactive(element, ('e' + store(element)[
|
|
62
|
+
reactive(element, ('e' + store(element)[key]++), name, value, true);
|
|
54
63
|
}
|
|
55
64
|
}
|
|
56
65
|
else {
|
|
@@ -58,7 +67,7 @@ function set(element, value, name) {
|
|
|
58
67
|
}
|
|
59
68
|
}
|
|
60
69
|
function store(element) {
|
|
61
|
-
return (element[
|
|
70
|
+
return (element[key] || (element[key] = { [key]: 0 }));
|
|
62
71
|
}
|
|
63
72
|
function update(element, id, name, value, wait = false) {
|
|
64
73
|
if (value === false || value == null) {
|
|
@@ -119,44 +128,32 @@ function update(element, id, name, value, wait = false) {
|
|
|
119
128
|
attribute(element, name, value);
|
|
120
129
|
}
|
|
121
130
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
set(element, value[key], name);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
else if (isArray(value)) {
|
|
136
|
-
for (let i = 0, n = value.length; i < n; i++) {
|
|
137
|
-
set(element, value[i], name);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
else {
|
|
141
|
-
set(element, value, name);
|
|
131
|
+
const apply = (element) => {
|
|
132
|
+
for (let key in attributes) {
|
|
133
|
+
attribute(element, key, attributes[key]);
|
|
134
|
+
}
|
|
135
|
+
attributes = {};
|
|
136
|
+
};
|
|
137
|
+
const spread = function (element, attributes) {
|
|
138
|
+
if (isObject(attributes)) {
|
|
139
|
+
for (let name in attributes) {
|
|
140
|
+
set(element, attributes[name], name);
|
|
142
141
|
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
142
|
+
}
|
|
143
|
+
else if (isArray(attributes)) {
|
|
144
|
+
for (let i = 0, n = attributes.length; i < n; i++) {
|
|
145
|
+
let attrs = attributes[i];
|
|
146
|
+
if (!isObject(attrs)) {
|
|
147
|
+
continue;
|
|
148
148
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
for (let i = 0, n = attributes.length; i < n; i++) {
|
|
152
|
-
let attrs = attributes[i];
|
|
153
|
-
if (!isObject(attrs)) {
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
156
|
-
for (let name in attrs) {
|
|
157
|
-
this.set(element, attrs[name], name);
|
|
158
|
-
}
|
|
149
|
+
for (let name in attrs) {
|
|
150
|
+
set(element, attrs[name], name);
|
|
159
151
|
}
|
|
160
152
|
}
|
|
161
153
|
}
|
|
154
|
+
else {
|
|
155
|
+
throw new Error('@esportsplus/template: attributes must be of type `Attributes` or `Attributes[]`; Received ' + JSON.stringify(attributes));
|
|
156
|
+
}
|
|
162
157
|
};
|
|
158
|
+
export default { apply, spread };
|
|
159
|
+
export { apply, spread };
|
package/build/constants.d.ts
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
declare const ATTRIBUTES: unique symbol;
|
|
2
1
|
declare const NODE_CLOSING = 1;
|
|
3
2
|
declare const NODE_ELEMENT = 3;
|
|
4
3
|
declare const NODE_SLOT = 4;
|
|
5
4
|
declare const NODE_VOID = 5;
|
|
6
5
|
declare const NODE_WHITELIST: Record<string, number>;
|
|
7
6
|
declare const REGEX_EMPTY_TEXT_NODES: RegExp;
|
|
8
|
-
declare const REGEX_EVENTS: RegExp;
|
|
9
|
-
declare const REGEX_EXTRA_WHITESPACE: RegExp;
|
|
10
|
-
declare const REGEX_SLOT_ATTRIBUTES: RegExp;
|
|
11
7
|
declare const REGEX_SLOT_NODES: RegExp;
|
|
12
8
|
declare const RENDERABLE: unique symbol;
|
|
13
9
|
declare const RENDERABLE_REACTIVE: unique symbol;
|
|
@@ -15,4 +11,5 @@ declare const RENDERABLE_TEMPLATE: unique symbol;
|
|
|
15
11
|
declare const SLOT: unique symbol;
|
|
16
12
|
declare const SLOT_HTML = "<!--$-->";
|
|
17
13
|
declare const SLOT_MARKER = "{{$}}";
|
|
18
|
-
|
|
14
|
+
declare const SLOT_MARKER_LENGTH: number;
|
|
15
|
+
export { NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE, SLOT, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH };
|
package/build/constants.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const ATTRIBUTES = Symbol();
|
|
2
1
|
const NODE_CLOSING = 1;
|
|
3
2
|
const NODE_COMMENT = 2;
|
|
4
3
|
const NODE_ELEMENT = 3;
|
|
@@ -25,9 +24,6 @@ const NODE_WHITELIST = {
|
|
|
25
24
|
'wbr': NODE_VOID
|
|
26
25
|
};
|
|
27
26
|
const REGEX_EMPTY_TEXT_NODES = /(>|})\s+(<|{)/g;
|
|
28
|
-
const REGEX_EVENTS = /(?:\s*on[\w-:]+\s*=\s*["'][^"']*["'])/g;
|
|
29
|
-
const REGEX_EXTRA_WHITESPACE = /\s\s+/g;
|
|
30
|
-
const REGEX_SLOT_ATTRIBUTES = /<[\w-]+([^><]*{{\$}}[^><]*)>/g;
|
|
31
27
|
const REGEX_SLOT_NODES = /<([\w-]+|[\/!])(?:([^><]*{{\$}}[^><]*)|(?:[^><]*))?>|{{\$}}/g;
|
|
32
28
|
const RENDERABLE = Symbol();
|
|
33
29
|
const RENDERABLE_REACTIVE = Symbol();
|
|
@@ -35,4 +31,5 @@ const RENDERABLE_TEMPLATE = Symbol();
|
|
|
35
31
|
const SLOT = Symbol();
|
|
36
32
|
const SLOT_HTML = '<!--$-->';
|
|
37
33
|
const SLOT_MARKER = '{{$}}';
|
|
38
|
-
|
|
34
|
+
const SLOT_MARKER_LENGTH = SLOT_MARKER.length;
|
|
35
|
+
export { NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE, SLOT, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH };
|
package/build/html/cache.js
CHANGED
|
@@ -1,67 +1,19 @@
|
|
|
1
|
-
import { NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES,
|
|
1
|
+
import { NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH } from '../constants.js';
|
|
2
2
|
import { firstChild, firstElementChild, fragment, nextElementSibling, nextSibling } from '../utilities.js';
|
|
3
|
-
import
|
|
3
|
+
import { spread } from '../attributes.js';
|
|
4
4
|
import s from '../slot.js';
|
|
5
5
|
let cache = new WeakMap();
|
|
6
6
|
function build(literals, values) {
|
|
7
7
|
if (values.length === 0) {
|
|
8
8
|
return set(literals, literals[0]);
|
|
9
9
|
}
|
|
10
|
-
let
|
|
10
|
+
let buffer = '', html = literals.join(SLOT_MARKER)
|
|
11
|
+
.replace(REGEX_EMPTY_TEXT_NODES, '$1$2')
|
|
12
|
+
.trim(), index = 0, level = 0, levels = [{
|
|
11
13
|
children: 0,
|
|
12
14
|
elements: 0,
|
|
13
15
|
path: []
|
|
14
|
-
}], slot = 0, slots = [], total = values.length;
|
|
15
|
-
{
|
|
16
|
-
let attribute = '', buffer = '', char = '', quote = '';
|
|
17
|
-
for (let match of html.matchAll(REGEX_SLOT_ATTRIBUTES)) {
|
|
18
|
-
let found = match[1], metadata = attributes[found];
|
|
19
|
-
if (metadata) {
|
|
20
|
-
continue;
|
|
21
|
-
}
|
|
22
|
-
metadata = attributes[found] = [];
|
|
23
|
-
for (let i = 0, n = found.length; i < n; i++) {
|
|
24
|
-
char = found[i];
|
|
25
|
-
if (char === ' ') {
|
|
26
|
-
buffer = '';
|
|
27
|
-
}
|
|
28
|
-
else if (char === '=') {
|
|
29
|
-
attribute = buffer;
|
|
30
|
-
buffer = '';
|
|
31
|
-
}
|
|
32
|
-
else if (char === '"' || char === "'") {
|
|
33
|
-
if (!attribute) {
|
|
34
|
-
}
|
|
35
|
-
else if (!quote) {
|
|
36
|
-
quote = char;
|
|
37
|
-
}
|
|
38
|
-
else if (quote === char) {
|
|
39
|
-
attribute = '';
|
|
40
|
-
buffer = '';
|
|
41
|
-
quote = '';
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
else if (char === '{' && char !== buffer) {
|
|
45
|
-
buffer = char;
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
buffer += char;
|
|
49
|
-
if (buffer === SLOT_MARKER) {
|
|
50
|
-
buffer = '';
|
|
51
|
-
if (attribute) {
|
|
52
|
-
metadata.push(attribute);
|
|
53
|
-
if (!quote) {
|
|
54
|
-
attribute = '';
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
metadata.push(null);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
16
|
+
}], parsed = html.split(SLOT_MARKER), slot = 0, slots = [], total = values.length;
|
|
65
17
|
for (let match of html.matchAll(REGEX_SLOT_NODES)) {
|
|
66
18
|
let parent = levels[level], type = match[1] === undefined ? NODE_SLOT : (NODE_WHITELIST[match[1].toLowerCase()] || NODE_ELEMENT);
|
|
67
19
|
if ((match.index || 1) - 1 > index) {
|
|
@@ -70,19 +22,15 @@ function build(literals, values) {
|
|
|
70
22
|
if (type === NODE_ELEMENT || type === NODE_VOID) {
|
|
71
23
|
let attr = match[2];
|
|
72
24
|
if (attr) {
|
|
73
|
-
let
|
|
74
|
-
|
|
75
|
-
throw new Error(`Template: attribute metadata could not be found for '${attr}'`);
|
|
76
|
-
}
|
|
77
|
-
for (let i = 0, n = metadata.length; i < n; i++) {
|
|
78
|
-
let name = metadata[i];
|
|
25
|
+
let i = attr.indexOf(SLOT_MARKER), path = methods(parent.children, parent.path, firstChild, nextSibling);
|
|
26
|
+
while (i !== -1) {
|
|
79
27
|
slots.push({
|
|
80
|
-
fn:
|
|
81
|
-
name,
|
|
28
|
+
fn: spread,
|
|
82
29
|
path,
|
|
83
30
|
slot
|
|
84
31
|
});
|
|
85
|
-
buffer +=
|
|
32
|
+
buffer += parsed[slot++];
|
|
33
|
+
i = attr.indexOf(SLOT_MARKER, i + SLOT_MARKER_LENGTH);
|
|
86
34
|
}
|
|
87
35
|
}
|
|
88
36
|
if (type === NODE_ELEMENT) {
|
|
@@ -97,16 +45,15 @@ function build(literals, values) {
|
|
|
97
45
|
parent.elements++;
|
|
98
46
|
}
|
|
99
47
|
else if (type === NODE_SLOT) {
|
|
100
|
-
buffer +=
|
|
48
|
+
buffer += parsed[slot] + SLOT_HTML;
|
|
101
49
|
slots.push({
|
|
102
50
|
fn: s,
|
|
103
|
-
name: null,
|
|
104
51
|
path: methods(parent.children, parent.path, firstChild, nextSibling),
|
|
105
52
|
slot: slot++
|
|
106
53
|
});
|
|
107
54
|
}
|
|
108
55
|
if (slot === total) {
|
|
109
|
-
buffer +=
|
|
56
|
+
buffer += parsed[slot];
|
|
110
57
|
break;
|
|
111
58
|
}
|
|
112
59
|
if (type === NODE_CLOSING) {
|
|
@@ -117,7 +64,7 @@ function build(literals, values) {
|
|
|
117
64
|
}
|
|
118
65
|
index = (match.index || 0) + match[0].length;
|
|
119
66
|
}
|
|
120
|
-
return set(literals,
|
|
67
|
+
return set(literals, buffer, slots);
|
|
121
68
|
}
|
|
122
69
|
function methods(children, copy, first, next) {
|
|
123
70
|
let methods = copy.slice();
|
|
@@ -127,9 +74,6 @@ function methods(children, copy, first, next) {
|
|
|
127
74
|
}
|
|
128
75
|
return methods;
|
|
129
76
|
}
|
|
130
|
-
function minify(html) {
|
|
131
|
-
return html.replace(REGEX_EMPTY_TEXT_NODES, '$1$2').replace(REGEX_EXTRA_WHITESPACE, ' ').trim();
|
|
132
|
-
}
|
|
133
77
|
function set(literals, html, slots = null) {
|
|
134
78
|
let template = {
|
|
135
79
|
fragment: fragment(html),
|
package/build/html/hydrate.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { root } from '@esportsplus/reactivity';
|
|
2
2
|
import { cloneNode, firstChild, nextSibling } from '../utilities.js';
|
|
3
|
-
import
|
|
3
|
+
import { apply } from '../attributes.js';
|
|
4
4
|
import cache from './cache.js';
|
|
5
5
|
function reactive(renderable, slot) {
|
|
6
6
|
let array = renderable.values, factory = renderable.template, refresh = () => {
|
|
@@ -23,10 +23,10 @@ function render(renderable, template) {
|
|
|
23
23
|
if (slots !== null) {
|
|
24
24
|
let node, previous, values = renderable.values;
|
|
25
25
|
for (let i = slots.length - 1; i >= 0; i--) {
|
|
26
|
-
let { fn,
|
|
26
|
+
let { fn, path, slot } = slots[i];
|
|
27
27
|
if (path === previous) { }
|
|
28
28
|
else {
|
|
29
|
-
|
|
29
|
+
apply(node);
|
|
30
30
|
node = fragment;
|
|
31
31
|
previous = path;
|
|
32
32
|
for (let o = 0, j = path.length; o < j; o++) {
|
|
@@ -35,7 +35,9 @@ function render(renderable, template) {
|
|
|
35
35
|
}
|
|
36
36
|
fn(node, values[slot], name);
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
if (node) {
|
|
39
|
+
apply(node);
|
|
40
|
+
}
|
|
39
41
|
}
|
|
40
42
|
for (let element = firstChild.call(fragment); element; element = nextSibling.call(element)) {
|
|
41
43
|
elements.push(element);
|
package/build/types.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ type Attributes = {
|
|
|
12
12
|
} & {
|
|
13
13
|
[key: `aria-${string}`]: string | number | boolean | undefined;
|
|
14
14
|
[key: `data-${string}`]: string | undefined;
|
|
15
|
+
onmount?: (element: Element) => void;
|
|
16
|
+
onrender?: (element: Element) => void;
|
|
15
17
|
} & Record<PropertyKey, unknown>;
|
|
16
18
|
type Effect<T> = () => EffectResponse<T>;
|
|
17
19
|
type EffectResponse<T> = T extends [] ? EffectResponse<T[number]>[] : Primitive | Renderable<T>;
|
|
@@ -37,8 +39,7 @@ type Template = {
|
|
|
37
39
|
html: string;
|
|
38
40
|
literals: TemplateStringsArray;
|
|
39
41
|
slots: {
|
|
40
|
-
fn: typeof attributes.
|
|
41
|
-
name: PropertyKey | null;
|
|
42
|
+
fn: typeof attributes.spread | typeof event | typeof slot;
|
|
42
43
|
path: typeof firstChild[];
|
|
43
44
|
slot: number;
|
|
44
45
|
}[] | null;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"dependencies": {
|
|
4
4
|
"@esportsplus/reactivity": "^0.4.6",
|
|
5
5
|
"@esportsplus/tasks": "^0.1.9",
|
|
6
|
-
"@esportsplus/utilities": "^0.
|
|
6
|
+
"@esportsplus/utilities": "^0.19.0"
|
|
7
7
|
},
|
|
8
8
|
"devDependencies": {
|
|
9
9
|
"@esportsplus/typescript": "^0.9.1"
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"private": false,
|
|
14
14
|
"type": "module",
|
|
15
15
|
"types": "./build/index.d.ts",
|
|
16
|
-
"version": "0.
|
|
16
|
+
"version": "0.13.0",
|
|
17
17
|
"scripts": {
|
|
18
18
|
"build": "tsc && tsc-alias",
|
|
19
19
|
"-": "-"
|
package/src/attributes.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { effect, root } from '@esportsplus/reactivity';
|
|
2
|
-
import { ATTRIBUTES } from './constants';
|
|
3
2
|
import { Attributes, Element } from './types';
|
|
4
3
|
import { className, isArray, isObject, raf, removeAttribute, setAttribute } from './utilities';
|
|
5
4
|
import event from './event';
|
|
@@ -9,7 +8,8 @@ let attributes: Record<string, unknown> = {},
|
|
|
9
8
|
delimiters: Record<string, string> = {
|
|
10
9
|
class: ' ',
|
|
11
10
|
style: ';'
|
|
12
|
-
}
|
|
11
|
+
},
|
|
12
|
+
key = Symbol();
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
function attribute(element: Element, name: string, value: unknown) {
|
|
@@ -55,12 +55,22 @@ function reactive(element: Element, id: string, name: string, value: unknown, wa
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
function set(element: Element, value: unknown, name: string) {
|
|
58
|
-
if (
|
|
58
|
+
if (name === 'style' && isObject(value)) {
|
|
59
|
+
for (let key in value) {
|
|
60
|
+
set(element, value[key], name);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else if (isArray(value)) {
|
|
64
|
+
for (let i = 0, n = value.length; i < n; i++) {
|
|
65
|
+
set(element, value[i], name);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else if (typeof value === 'function') {
|
|
59
69
|
if (name.startsWith('on')) {
|
|
60
70
|
event(element, name, value);
|
|
61
71
|
}
|
|
62
72
|
else {
|
|
63
|
-
reactive(element, ('e' + store(element)[
|
|
73
|
+
reactive(element, ('e' + store(element)[key]++), name, value, true);
|
|
64
74
|
}
|
|
65
75
|
}
|
|
66
76
|
else {
|
|
@@ -70,8 +80,8 @@ function set(element: Element, value: unknown, name: string) {
|
|
|
70
80
|
|
|
71
81
|
function store(element: Element) {
|
|
72
82
|
return (
|
|
73
|
-
element[
|
|
74
|
-
) as Attributes & { [
|
|
83
|
+
element[key] || (element[key] = { [key]: 0 })
|
|
84
|
+
) as Attributes & { [key]: number };
|
|
75
85
|
}
|
|
76
86
|
|
|
77
87
|
function update(element: Element, id: null | string, name: string, value: unknown, wait = false) {
|
|
@@ -155,47 +165,37 @@ function update(element: Element, id: null | string, name: string, value: unknow
|
|
|
155
165
|
}
|
|
156
166
|
|
|
157
167
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
168
|
+
const apply = (element: Element) => {
|
|
169
|
+
for (let key in attributes) {
|
|
170
|
+
attribute(element, key, attributes[key]);
|
|
171
|
+
}
|
|
163
172
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
else if (isArray(value)) {
|
|
173
|
-
for (let i = 0, n = value.length; i < n; i++) {
|
|
174
|
-
set(element, value[i], name);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
set(element, value, name);
|
|
179
|
-
}
|
|
180
|
-
},
|
|
181
|
-
spread: function (element: Element, attributes: Attributes | Attributes[]) {
|
|
182
|
-
if (isObject(attributes)) {
|
|
183
|
-
for (let name in attributes) {
|
|
184
|
-
this.set(element, attributes[name], name);
|
|
185
|
-
}
|
|
173
|
+
attributes = {};
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const spread = function (element: Element, attributes: Attributes | Attributes[]) {
|
|
177
|
+
if (isObject(attributes)) {
|
|
178
|
+
for (let name in attributes) {
|
|
179
|
+
set(element, attributes[name], name);
|
|
186
180
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
181
|
+
}
|
|
182
|
+
else if (isArray(attributes)) {
|
|
183
|
+
for (let i = 0, n = attributes.length; i < n; i++) {
|
|
184
|
+
let attrs = attributes[i];
|
|
190
185
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
186
|
+
if (!isObject(attrs)) {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
194
189
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
190
|
+
for (let name in attrs) {
|
|
191
|
+
set(element, attrs[name], name);
|
|
198
192
|
}
|
|
199
193
|
}
|
|
200
194
|
}
|
|
201
|
-
|
|
195
|
+
else {
|
|
196
|
+
throw new Error('@esportsplus/template: attributes must be of type `Attributes` or `Attributes[]`; Received ' + JSON.stringify(attributes));
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
export default { apply, spread };
|
|
201
|
+
export { apply, spread }
|
package/src/constants.ts
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
const ATTRIBUTES = Symbol();
|
|
2
|
-
|
|
3
|
-
|
|
4
1
|
const NODE_CLOSING = 1;
|
|
5
2
|
|
|
6
3
|
const NODE_COMMENT = 2;
|
|
@@ -36,12 +33,6 @@ const NODE_WHITELIST: Record<string, number> = {
|
|
|
36
33
|
|
|
37
34
|
const REGEX_EMPTY_TEXT_NODES = /(>|})\s+(<|{)/g;
|
|
38
35
|
|
|
39
|
-
const REGEX_EVENTS = /(?:\s*on[\w-:]+\s*=\s*["'][^"']*["'])/g;
|
|
40
|
-
|
|
41
|
-
const REGEX_EXTRA_WHITESPACE = /\s\s+/g;
|
|
42
|
-
|
|
43
|
-
const REGEX_SLOT_ATTRIBUTES = /<[\w-]+([^><]*{{\$}}[^><]*)>/g;
|
|
44
|
-
|
|
45
36
|
const REGEX_SLOT_NODES = /<([\w-]+|[\/!])(?:([^><]*{{\$}}[^><]*)|(?:[^><]*))?>|{{\$}}/g;
|
|
46
37
|
|
|
47
38
|
|
|
@@ -58,23 +49,22 @@ const SLOT_HTML = '<!--$-->';
|
|
|
58
49
|
|
|
59
50
|
const SLOT_MARKER = '{{$}}';
|
|
60
51
|
|
|
52
|
+
const SLOT_MARKER_LENGTH = SLOT_MARKER.length;
|
|
53
|
+
|
|
61
54
|
|
|
62
55
|
export {
|
|
63
|
-
ATTRIBUTES,
|
|
64
56
|
NODE_CLOSING,
|
|
65
57
|
NODE_ELEMENT,
|
|
66
58
|
NODE_SLOT,
|
|
67
59
|
NODE_VOID,
|
|
68
60
|
NODE_WHITELIST,
|
|
69
61
|
REGEX_EMPTY_TEXT_NODES,
|
|
70
|
-
REGEX_EVENTS,
|
|
71
|
-
REGEX_EXTRA_WHITESPACE,
|
|
72
|
-
REGEX_SLOT_ATTRIBUTES,
|
|
73
62
|
REGEX_SLOT_NODES,
|
|
74
63
|
RENDERABLE,
|
|
75
64
|
RENDERABLE_REACTIVE,
|
|
76
65
|
RENDERABLE_TEMPLATE,
|
|
77
66
|
SLOT,
|
|
78
67
|
SLOT_HTML,
|
|
79
|
-
SLOT_MARKER
|
|
68
|
+
SLOT_MARKER,
|
|
69
|
+
SLOT_MARKER_LENGTH
|
|
80
70
|
};
|
package/src/html/cache.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
-
NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES,
|
|
3
|
-
|
|
2
|
+
NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES,
|
|
3
|
+
REGEX_SLOT_NODES, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH
|
|
4
4
|
} from '~/constants';
|
|
5
5
|
import { RenderableTemplate, Template } from '~/types';
|
|
6
6
|
import { firstChild, firstElementChild, fragment, nextElementSibling, nextSibling } from '~/utilities';
|
|
7
|
-
import
|
|
7
|
+
import { spread } from '~/attributes';
|
|
8
8
|
import s from '~/slot';
|
|
9
9
|
|
|
10
10
|
|
|
@@ -16,9 +16,10 @@ function build(literals: TemplateStringsArray, values: unknown[]) {
|
|
|
16
16
|
return set(literals, literals[0]);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
let
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
let buffer = '',
|
|
20
|
+
html = literals.join(SLOT_MARKER)
|
|
21
|
+
.replace(REGEX_EMPTY_TEXT_NODES, '$1$2')
|
|
22
|
+
.trim(),
|
|
22
23
|
index = 0,
|
|
23
24
|
level = 0,
|
|
24
25
|
levels = [{
|
|
@@ -26,73 +27,11 @@ function build(literals: TemplateStringsArray, values: unknown[]) {
|
|
|
26
27
|
elements: 0,
|
|
27
28
|
path: [] as NonNullable<Template['slots']>[0]['path']
|
|
28
29
|
}],
|
|
30
|
+
parsed = html.split(SLOT_MARKER),
|
|
29
31
|
slot = 0,
|
|
30
32
|
slots: Template['slots'] = [],
|
|
31
33
|
total = values.length;
|
|
32
34
|
|
|
33
|
-
{
|
|
34
|
-
let attribute = '',
|
|
35
|
-
buffer = '',
|
|
36
|
-
char = '',
|
|
37
|
-
quote = '';
|
|
38
|
-
|
|
39
|
-
for (let match of html.matchAll(REGEX_SLOT_ATTRIBUTES)) {
|
|
40
|
-
let found = match[1],
|
|
41
|
-
metadata = attributes[found];
|
|
42
|
-
|
|
43
|
-
if (metadata) {
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
metadata = attributes[found] = [];
|
|
48
|
-
|
|
49
|
-
for (let i = 0, n = found.length; i < n; i++) {
|
|
50
|
-
char = found[i];
|
|
51
|
-
|
|
52
|
-
if (char === ' ') {
|
|
53
|
-
buffer = '';
|
|
54
|
-
}
|
|
55
|
-
else if (char === '=') {
|
|
56
|
-
attribute = buffer;
|
|
57
|
-
buffer = '';
|
|
58
|
-
}
|
|
59
|
-
else if (char === '"' || char === "'") {
|
|
60
|
-
if (!attribute) {
|
|
61
|
-
}
|
|
62
|
-
else if (!quote) {
|
|
63
|
-
quote = char;
|
|
64
|
-
}
|
|
65
|
-
else if (quote === char) {
|
|
66
|
-
attribute = '';
|
|
67
|
-
buffer = '';
|
|
68
|
-
quote = '';
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
else if (char === '{' && char !== buffer) {
|
|
72
|
-
buffer = char;
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
buffer += char;
|
|
76
|
-
|
|
77
|
-
if (buffer === SLOT_MARKER) {
|
|
78
|
-
buffer = '';
|
|
79
|
-
|
|
80
|
-
if (attribute) {
|
|
81
|
-
metadata.push(attribute);
|
|
82
|
-
|
|
83
|
-
if (!quote) {
|
|
84
|
-
attribute = '';
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
metadata.push(null);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
35
|
for (let match of html.matchAll(REGEX_SLOT_NODES)) {
|
|
97
36
|
let parent = levels[level],
|
|
98
37
|
type = match[1] === undefined ? NODE_SLOT : (NODE_WHITELIST[match[1].toLowerCase()] || NODE_ELEMENT);
|
|
@@ -106,24 +45,18 @@ function build(literals: TemplateStringsArray, values: unknown[]) {
|
|
|
106
45
|
let attr = match[2];
|
|
107
46
|
|
|
108
47
|
if (attr) {
|
|
109
|
-
let
|
|
48
|
+
let i = attr.indexOf(SLOT_MARKER),
|
|
110
49
|
path = methods(parent.children, parent.path, firstChild, nextSibling);
|
|
111
50
|
|
|
112
|
-
|
|
113
|
-
throw new Error(`Template: attribute metadata could not be found for '${attr}'`);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
for (let i = 0, n = metadata.length; i < n; i++) {
|
|
117
|
-
let name = metadata[i];
|
|
118
|
-
|
|
51
|
+
while (i !== -1) {
|
|
119
52
|
slots.push({
|
|
120
|
-
fn:
|
|
121
|
-
name,
|
|
53
|
+
fn: spread,
|
|
122
54
|
path,
|
|
123
55
|
slot
|
|
124
56
|
});
|
|
125
57
|
|
|
126
|
-
buffer +=
|
|
58
|
+
buffer += parsed[slot++];
|
|
59
|
+
i = attr.indexOf(SLOT_MARKER, i + SLOT_MARKER_LENGTH);
|
|
127
60
|
}
|
|
128
61
|
}
|
|
129
62
|
|
|
@@ -140,17 +73,16 @@ function build(literals: TemplateStringsArray, values: unknown[]) {
|
|
|
140
73
|
parent.elements++;
|
|
141
74
|
}
|
|
142
75
|
else if (type === NODE_SLOT) {
|
|
143
|
-
buffer +=
|
|
76
|
+
buffer += parsed[slot] + SLOT_HTML;
|
|
144
77
|
slots.push({
|
|
145
78
|
fn: s,
|
|
146
|
-
name: null,
|
|
147
79
|
path: methods(parent.children, parent.path, firstChild, nextSibling),
|
|
148
80
|
slot: slot++
|
|
149
81
|
});
|
|
150
82
|
}
|
|
151
83
|
|
|
152
84
|
if (slot === total) {
|
|
153
|
-
buffer +=
|
|
85
|
+
buffer += parsed[slot];
|
|
154
86
|
break;
|
|
155
87
|
}
|
|
156
88
|
|
|
@@ -164,7 +96,7 @@ function build(literals: TemplateStringsArray, values: unknown[]) {
|
|
|
164
96
|
index = (match.index || 0) + match[0].length;
|
|
165
97
|
}
|
|
166
98
|
|
|
167
|
-
return set(literals,
|
|
99
|
+
return set(literals, buffer, slots);
|
|
168
100
|
}
|
|
169
101
|
|
|
170
102
|
function methods(children: number, copy: (typeof firstChild)[], first: (typeof firstChild), next: (typeof firstChild)) {
|
|
@@ -179,10 +111,6 @@ function methods(children: number, copy: (typeof firstChild)[], first: (typeof f
|
|
|
179
111
|
return methods;
|
|
180
112
|
}
|
|
181
113
|
|
|
182
|
-
function minify(html: string) {
|
|
183
|
-
return html.replace(REGEX_EMPTY_TEXT_NODES, '$1$2').replace(REGEX_EXTRA_WHITESPACE, ' ').trim();
|
|
184
|
-
}
|
|
185
|
-
|
|
186
114
|
function set(literals: TemplateStringsArray, html: string, slots: Template['slots'] = null) {
|
|
187
115
|
let template = {
|
|
188
116
|
fragment: fragment(html),
|
package/src/html/hydrate.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { root, ReactiveArray } from '@esportsplus/reactivity';
|
|
|
2
2
|
import { Element, Elements, Renderable, RenderableReactive, RenderableTemplate, Template } from '~/types';
|
|
3
3
|
import { Slot } from '~/slot';
|
|
4
4
|
import { cloneNode, firstChild, nextSibling } from '~/utilities';
|
|
5
|
-
import
|
|
5
|
+
import { apply } from '~/attributes';
|
|
6
6
|
import cache from './cache';
|
|
7
7
|
|
|
8
8
|
|
|
@@ -41,11 +41,11 @@ function render<T>(renderable: Renderable<T>, template: Template) {
|
|
|
41
41
|
values = renderable.values;
|
|
42
42
|
|
|
43
43
|
for (let i = slots.length - 1; i >= 0; i--) {
|
|
44
|
-
let { fn,
|
|
44
|
+
let { fn, path, slot } = slots[i];
|
|
45
45
|
|
|
46
46
|
if (path === previous) {}
|
|
47
47
|
else {
|
|
48
|
-
|
|
48
|
+
apply(node);
|
|
49
49
|
|
|
50
50
|
node = fragment;
|
|
51
51
|
previous = path;
|
|
@@ -59,7 +59,9 @@ function render<T>(renderable: Renderable<T>, template: Template) {
|
|
|
59
59
|
fn(node, values[slot], name);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
if (node) {
|
|
63
|
+
apply(node);
|
|
64
|
+
}
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
for (let element = firstChild.call(fragment as Element); element; element = nextSibling.call(element)) {
|
package/src/slot.ts
CHANGED
|
@@ -5,8 +5,8 @@ import { Element, Elements, RenderableReactive, RenderableTemplate } from './typ
|
|
|
5
5
|
import { firstChild, isArray, isObject, nextSibling, nodeValue, raf, text } from './utilities'
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
// Using a private symbol since 'SLOT' is used as a different flag in 'render.ts'
|
|
9
8
|
let cleanup: Slot[] = [],
|
|
9
|
+
// Using a private symbol since 'SLOT' is used as a different flag in 'render.ts'
|
|
10
10
|
key = Symbol(),
|
|
11
11
|
scheduled = false;
|
|
12
12
|
|
package/src/types.ts
CHANGED
|
@@ -14,6 +14,12 @@ type Attributes = {
|
|
|
14
14
|
} & {
|
|
15
15
|
[key: `aria-${string}`]: string | number | boolean | undefined;
|
|
16
16
|
[key: `data-${string}`]: string | undefined;
|
|
17
|
+
// Element is mounted to DOM
|
|
18
|
+
// - Trigger animations, etc.
|
|
19
|
+
onmount?: (element: Element) => void;
|
|
20
|
+
// Element is rendered in fragment
|
|
21
|
+
// - Used to retrieve reference to the element
|
|
22
|
+
onrender?: (element: Element) => void;
|
|
17
23
|
} & Record<PropertyKey, unknown>;
|
|
18
24
|
|
|
19
25
|
type Effect<T> = () => EffectResponse<T>;
|
|
@@ -51,8 +57,7 @@ type Template = {
|
|
|
51
57
|
html: string;
|
|
52
58
|
literals: TemplateStringsArray;
|
|
53
59
|
slots: {
|
|
54
|
-
fn: typeof attributes.
|
|
55
|
-
name: PropertyKey | null;
|
|
60
|
+
fn: typeof attributes.spread | typeof event | typeof slot;
|
|
56
61
|
path: typeof firstChild[];
|
|
57
62
|
slot: number;
|
|
58
63
|
}[] | null;
|