@esportsplus/template 0.19.5 → 0.19.7
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 +117 -116
- package/build/render.d.ts +1 -1
- package/build/svg.d.ts +1 -1
- package/build/svg.js +4 -4
- package/package.json +1 -1
- package/src/attributes.ts +172 -152
- package/src/html/index.ts +1 -32
- package/src/html/parser.ts +0 -14
- package/src/render.ts +1 -1
- package/src/svg.ts +5 -5
- package/src/types.ts +0 -6
package/build/attributes.js
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import { effect } from '@esportsplus/reactivity';
|
|
2
|
-
import { isArray, isObject
|
|
2
|
+
import { isArray, isObject } from '@esportsplus/utilities';
|
|
3
3
|
import { STATE_HYDRATING, STATE_NONE, STATE_WAITING } from './constants.js';
|
|
4
4
|
import { className, removeAttribute, setAttribute } from './utilities/element.js';
|
|
5
5
|
import { raf } from './utilities/queue.js';
|
|
6
6
|
import q from '@esportsplus/queue';
|
|
7
7
|
import event from './event.js';
|
|
8
|
-
const EFFECT = Symbol();
|
|
9
8
|
const STORE = Symbol();
|
|
10
|
-
const UPDATES = Symbol();
|
|
11
9
|
let delimiters = {
|
|
12
10
|
class: ' ',
|
|
13
11
|
style: ';'
|
|
14
12
|
}, queue = q(64), scheduled = false;
|
|
15
|
-
function
|
|
16
|
-
if (value
|
|
13
|
+
function apply(element, name, value) {
|
|
14
|
+
if (value == null || value === false || value === '') {
|
|
17
15
|
removeAttribute.call(element, name);
|
|
18
16
|
}
|
|
19
17
|
else if (name === 'class') {
|
|
@@ -26,61 +24,135 @@ function attribute(element, name, value) {
|
|
|
26
24
|
element[name] = value;
|
|
27
25
|
}
|
|
28
26
|
}
|
|
29
|
-
function
|
|
27
|
+
function context(element) {
|
|
28
|
+
return (element[STORE] ??= { element });
|
|
29
|
+
}
|
|
30
|
+
function list(ctx, element, id, name, value, state) {
|
|
31
|
+
if (value == null || value === false || value === '') {
|
|
32
|
+
value = '';
|
|
33
|
+
}
|
|
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 = {};
|
|
39
|
+
}
|
|
40
|
+
if (id === null) {
|
|
41
|
+
if (value && type === 'string') {
|
|
42
|
+
store[base] += (store[base] ? delimiter : '') + value;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
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[part] = null;
|
|
55
|
+
hot[part] = null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
let cold = store[id];
|
|
59
|
+
if (cold !== undefined) {
|
|
60
|
+
for (let part in cold) {
|
|
61
|
+
if (part in hot) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
delete dynamic[part];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
store[id] = hot;
|
|
68
|
+
}
|
|
69
|
+
value = store[base];
|
|
70
|
+
for (let key in dynamic) {
|
|
71
|
+
value += (value ? delimiter : '') + key;
|
|
72
|
+
}
|
|
73
|
+
schedule(ctx, element, name, state, value);
|
|
74
|
+
}
|
|
75
|
+
function property(ctx, element, id, name, value, state) {
|
|
76
|
+
if (value == null || value === false || value === '') {
|
|
77
|
+
value = '';
|
|
78
|
+
}
|
|
79
|
+
if (id !== null) {
|
|
80
|
+
ctx ??= context(element);
|
|
81
|
+
if (ctx[name] === value) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
ctx[name] = value;
|
|
85
|
+
}
|
|
86
|
+
schedule(ctx, element, name, state, value);
|
|
87
|
+
}
|
|
88
|
+
function schedule(ctx, element, name, state, value) {
|
|
89
|
+
if (state === STATE_HYDRATING) {
|
|
90
|
+
apply(element, name, value);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
ctx ??= context(element);
|
|
94
|
+
(ctx.updates ??= {})[name] = value;
|
|
95
|
+
if (state === STATE_NONE && !ctx.updating) {
|
|
96
|
+
ctx.updating = true;
|
|
97
|
+
queue.add(ctx);
|
|
98
|
+
}
|
|
30
99
|
if (scheduled) {
|
|
31
100
|
return;
|
|
32
101
|
}
|
|
33
102
|
scheduled = true;
|
|
34
103
|
raf.add(task);
|
|
35
104
|
}
|
|
36
|
-
function set(
|
|
37
|
-
|
|
38
|
-
value = '';
|
|
39
|
-
}
|
|
40
|
-
let type = typeof value;
|
|
105
|
+
function set(element, name, value, state) {
|
|
106
|
+
let fn = name === 'class' || name === 'style' ? list : property, type = typeof value;
|
|
41
107
|
if (type === 'function') {
|
|
42
108
|
if (name.startsWith('on')) {
|
|
43
|
-
event(
|
|
109
|
+
event(element, name, value);
|
|
110
|
+
return;
|
|
44
111
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
update(context, id, name, v, state);
|
|
112
|
+
let ctx = context(element);
|
|
113
|
+
ctx.effect ??= 0;
|
|
114
|
+
let id = ctx.effect++;
|
|
115
|
+
effect(() => {
|
|
116
|
+
let v = value(element);
|
|
117
|
+
if (v == null || typeof v !== 'object') {
|
|
118
|
+
fn(ctx, element, id, name, v, state);
|
|
119
|
+
}
|
|
120
|
+
else if (isArray(v)) {
|
|
121
|
+
let last = v.length - 1;
|
|
122
|
+
for (let i = 0, n = v.length; i < n; i++) {
|
|
123
|
+
fn(ctx, element, id, name, v[i], state === STATE_HYDRATING
|
|
124
|
+
? state
|
|
125
|
+
: i !== last ? STATE_WAITING : state);
|
|
60
126
|
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
state = STATE_NONE;
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (type !== 'object') {
|
|
133
|
+
fn(null, element, null, name, value, state);
|
|
134
|
+
return;
|
|
64
135
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
136
|
+
if (isArray(value)) {
|
|
137
|
+
for (let i = 0, n = value.length; i < n; i++) {
|
|
138
|
+
let v = value[i];
|
|
139
|
+
if (v == null || v === false || v === '') {
|
|
140
|
+
continue;
|
|
69
141
|
}
|
|
142
|
+
set(element, name, v, state);
|
|
70
143
|
}
|
|
144
|
+
return;
|
|
71
145
|
}
|
|
72
|
-
|
|
73
|
-
update(context, null, name, value, state);
|
|
74
|
-
}
|
|
146
|
+
fn(null, element, null, name, value, state);
|
|
75
147
|
}
|
|
76
148
|
function task() {
|
|
77
149
|
let context, n = queue.length;
|
|
78
150
|
while ((context = queue.next()) && n--) {
|
|
79
151
|
let { element, updates } = context;
|
|
80
152
|
for (let name in updates) {
|
|
81
|
-
|
|
82
|
-
delete updates[name];
|
|
153
|
+
apply(element, name, updates[name]);
|
|
83
154
|
}
|
|
155
|
+
context.updates = {};
|
|
84
156
|
context.updating = false;
|
|
85
157
|
}
|
|
86
158
|
if (queue.length) {
|
|
@@ -90,90 +162,19 @@ function task() {
|
|
|
90
162
|
scheduled = false;
|
|
91
163
|
}
|
|
92
164
|
}
|
|
93
|
-
function update(context, id, name, value, state) {
|
|
94
|
-
if (value === false || value == null) {
|
|
95
|
-
value = '';
|
|
96
|
-
}
|
|
97
|
-
let store = context.store;
|
|
98
|
-
if (name in delimiters) {
|
|
99
|
-
let cache = name + '.static', delimiter = delimiters[name], dynamic = store[name];
|
|
100
|
-
if (dynamic === undefined) {
|
|
101
|
-
let value = (context.element.getAttribute(name) || '').trim();
|
|
102
|
-
store[cache] = value;
|
|
103
|
-
store[name] = dynamic = {};
|
|
104
|
-
}
|
|
105
|
-
if (id === null) {
|
|
106
|
-
if (value && isString(value)) {
|
|
107
|
-
store[cache] += (store[cache] ? delimiter : '') + value;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
let hot = {};
|
|
112
|
-
if (isString(value)) {
|
|
113
|
-
let part, parts = value.split(delimiter);
|
|
114
|
-
for (let i = 0, n = parts.length; i < n; i++) {
|
|
115
|
-
part = parts[i].trim();
|
|
116
|
-
if (part === '') {
|
|
117
|
-
continue;
|
|
118
|
-
}
|
|
119
|
-
dynamic[part] = null;
|
|
120
|
-
hot[part] = null;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
let cold = store[id];
|
|
124
|
-
if (cold !== undefined) {
|
|
125
|
-
for (let part in cold) {
|
|
126
|
-
if (part in hot) {
|
|
127
|
-
continue;
|
|
128
|
-
}
|
|
129
|
-
delete dynamic[part];
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
store[id] = hot;
|
|
133
|
-
}
|
|
134
|
-
value = store[cache];
|
|
135
|
-
for (let key in dynamic) {
|
|
136
|
-
value += (value ? delimiter : '') + key;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
else if (id !== null) {
|
|
140
|
-
if (store[name] === value) {
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
store[name] = value;
|
|
144
|
-
}
|
|
145
|
-
if (state === STATE_HYDRATING) {
|
|
146
|
-
attribute(context.element, name, value);
|
|
147
|
-
}
|
|
148
|
-
else {
|
|
149
|
-
context.updates[name] = value;
|
|
150
|
-
if (state === STATE_NONE && !context.updating) {
|
|
151
|
-
context.updating = true;
|
|
152
|
-
queue.add(context);
|
|
153
|
-
}
|
|
154
|
-
if (!scheduled) {
|
|
155
|
-
schedule();
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
165
|
const spread = function (element, value) {
|
|
160
|
-
let cache = (element[STORE] ??= { [UPDATES]: {} }), context = {
|
|
161
|
-
element,
|
|
162
|
-
store: cache,
|
|
163
|
-
updates: cache[UPDATES],
|
|
164
|
-
updating: false
|
|
165
|
-
};
|
|
166
166
|
if (isObject(value)) {
|
|
167
167
|
for (let name in value) {
|
|
168
|
-
|
|
168
|
+
let v = value[name];
|
|
169
|
+
if (v == null || v === false || v === '') {
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
set(element, name, v, STATE_HYDRATING);
|
|
169
173
|
}
|
|
170
174
|
}
|
|
171
175
|
else if (isArray(value)) {
|
|
172
176
|
for (let i = 0, n = value.length; i < n; i++) {
|
|
173
|
-
|
|
174
|
-
for (let name in v) {
|
|
175
|
-
set(context, name, v[name], STATE_HYDRATING);
|
|
176
|
-
}
|
|
177
|
+
spread(element, value[i]);
|
|
177
178
|
}
|
|
178
179
|
}
|
|
179
180
|
};
|
package/build/render.d.ts
CHANGED
package/build/svg.d.ts
CHANGED
package/build/svg.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import html from './html/index.js';
|
|
2
2
|
const svg = html.bind(null);
|
|
3
|
-
svg.sprite = (
|
|
4
|
-
if (
|
|
5
|
-
|
|
3
|
+
svg.sprite = (href) => {
|
|
4
|
+
if (href[0] !== '#') {
|
|
5
|
+
href = '#' + href;
|
|
6
6
|
}
|
|
7
|
-
return html `<svg><use
|
|
7
|
+
return html `<svg><use ${{ ['href']: href }} /></svg>`;
|
|
8
8
|
};
|
|
9
9
|
export default svg;
|
package/package.json
CHANGED
package/src/attributes.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { effect } from '@esportsplus/reactivity';
|
|
2
|
-
import { isArray, isObject
|
|
2
|
+
import { isArray, isObject } from '@esportsplus/utilities';
|
|
3
3
|
import { STATE_HYDRATING, STATE_NONE, STATE_WAITING } from './constants';
|
|
4
4
|
import { Attributes, Element } from './types';
|
|
5
5
|
import { className, removeAttribute, setAttribute } from './utilities/element';
|
|
@@ -8,22 +8,16 @@ import q from '@esportsplus/queue';
|
|
|
8
8
|
import event from './event';
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
// TODO: Refactor
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const EFFECT = Symbol();
|
|
15
|
-
|
|
16
11
|
const STORE = Symbol();
|
|
17
12
|
|
|
18
|
-
const UPDATES = Symbol();
|
|
19
|
-
|
|
20
13
|
|
|
21
14
|
type Context = {
|
|
15
|
+
effect?: 0,
|
|
22
16
|
element: Element;
|
|
23
|
-
store
|
|
24
|
-
updates
|
|
25
|
-
updating
|
|
26
|
-
}
|
|
17
|
+
store?: Record<string, unknown>;
|
|
18
|
+
updates?: Record<PropertyKey, unknown>;
|
|
19
|
+
updating?: boolean;
|
|
20
|
+
} & Record<PropertyKey, unknown>;
|
|
27
21
|
|
|
28
22
|
type State = typeof STATE_HYDRATING | typeof STATE_NONE | typeof STATE_WAITING;
|
|
29
23
|
|
|
@@ -36,8 +30,8 @@ let delimiters: Record<string, string> = {
|
|
|
36
30
|
scheduled = false;
|
|
37
31
|
|
|
38
32
|
|
|
39
|
-
function
|
|
40
|
-
if (value
|
|
33
|
+
function apply(element: Element, name: string, value: unknown) {
|
|
34
|
+
if (value == null || value === false || value === '') {
|
|
41
35
|
removeAttribute.call(element, name);
|
|
42
36
|
}
|
|
43
37
|
else if (name === 'class') {
|
|
@@ -51,209 +45,235 @@ function attribute(element: Element, name: string, value: unknown) {
|
|
|
51
45
|
}
|
|
52
46
|
}
|
|
53
47
|
|
|
54
|
-
function
|
|
55
|
-
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
scheduled = true;
|
|
60
|
-
raf.add(task);
|
|
48
|
+
function context(element: Element) {
|
|
49
|
+
return (element[STORE] ??= { element }) as Context;
|
|
61
50
|
}
|
|
62
51
|
|
|
63
|
-
function
|
|
64
|
-
|
|
52
|
+
function list(
|
|
53
|
+
ctx: Context | null,
|
|
54
|
+
element: Element,
|
|
55
|
+
id: null | number,
|
|
56
|
+
name: string,
|
|
57
|
+
value: unknown,
|
|
58
|
+
state: State
|
|
59
|
+
) {
|
|
60
|
+
if (value == null || value === false || value === '') {
|
|
65
61
|
value = '';
|
|
66
62
|
}
|
|
67
63
|
|
|
68
|
-
let
|
|
64
|
+
let base = name + '.static',
|
|
65
|
+
delimiter = delimiters[name],
|
|
66
|
+
store = (ctx ??= context(element)).store ??= {},
|
|
67
|
+
dynamic = store[name] as Attributes | undefined,
|
|
68
|
+
type = typeof value;
|
|
69
69
|
|
|
70
|
-
if (
|
|
71
|
-
|
|
72
|
-
event(context.element, name as `on${string}`, value as Function);
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
context.store[EFFECT] ??= 0;
|
|
76
|
-
|
|
77
|
-
let id = (context.store[EFFECT] as number)++;
|
|
78
|
-
|
|
79
|
-
effect(() => {
|
|
80
|
-
let v = (value as Function)(context.element);
|
|
81
|
-
|
|
82
|
-
if (isArray(v)) {
|
|
83
|
-
let last = v.length - 1;
|
|
84
|
-
|
|
85
|
-
for (let i = 0, n = v.length; i < n; i++) {
|
|
86
|
-
update(
|
|
87
|
-
context,
|
|
88
|
-
id,
|
|
89
|
-
name,
|
|
90
|
-
v[i],
|
|
91
|
-
state === STATE_HYDRATING
|
|
92
|
-
? state
|
|
93
|
-
: i !== last ? STATE_WAITING : state
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
update(context, id, name, v, state);
|
|
99
|
-
}
|
|
100
|
-
});
|
|
70
|
+
if (dynamic === undefined) {
|
|
71
|
+
let value = (element.getAttribute(name) || '').trim();
|
|
101
72
|
|
|
102
|
-
|
|
103
|
-
}
|
|
73
|
+
store[base] = value;
|
|
74
|
+
store[name] = dynamic = {};
|
|
104
75
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
76
|
+
|
|
77
|
+
if (id === null) {
|
|
78
|
+
if (value && type === 'string') {
|
|
79
|
+
store[base] += (store[base] ? delimiter : '') + value;
|
|
110
80
|
}
|
|
111
81
|
}
|
|
112
82
|
else {
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
}
|
|
83
|
+
let hot: Attributes = {};
|
|
116
84
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
85
|
+
if (value && type === 'string') {
|
|
86
|
+
let part: string,
|
|
87
|
+
parts = (value as string).split(delimiter);
|
|
120
88
|
|
|
121
|
-
|
|
122
|
-
|
|
89
|
+
for (let i = 0, n = parts.length; i < n; i++) {
|
|
90
|
+
part = parts[i].trim();
|
|
123
91
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
92
|
+
if (part === '') {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
dynamic[part] = null;
|
|
97
|
+
hot[part] = null;
|
|
98
|
+
}
|
|
127
99
|
}
|
|
128
100
|
|
|
129
|
-
|
|
130
|
-
}
|
|
101
|
+
let cold = store[id] as Attributes | undefined;
|
|
131
102
|
|
|
132
|
-
|
|
133
|
-
|
|
103
|
+
if (cold !== undefined) {
|
|
104
|
+
for (let part in cold) {
|
|
105
|
+
if (part in hot) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
delete dynamic[part];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
store[id] = hot;
|
|
134
114
|
}
|
|
135
|
-
|
|
136
|
-
|
|
115
|
+
|
|
116
|
+
value = store[base];
|
|
117
|
+
|
|
118
|
+
for (let key in dynamic) {
|
|
119
|
+
value += (value ? delimiter : '') + key;
|
|
137
120
|
}
|
|
121
|
+
|
|
122
|
+
schedule(ctx, element, name, state, value);
|
|
138
123
|
}
|
|
139
124
|
|
|
140
|
-
function
|
|
141
|
-
|
|
125
|
+
function property(
|
|
126
|
+
ctx: Context | null,
|
|
127
|
+
element: Element,
|
|
142
128
|
id: null | number,
|
|
143
129
|
name: string,
|
|
144
130
|
value: unknown,
|
|
145
131
|
state: State
|
|
146
132
|
) {
|
|
147
|
-
if (value === false || value
|
|
133
|
+
if (value == null || value === false || value === '') {
|
|
148
134
|
value = '';
|
|
149
135
|
}
|
|
150
136
|
|
|
151
|
-
|
|
137
|
+
if (id !== null) {
|
|
138
|
+
ctx ??= context(element);
|
|
152
139
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
dynamic = store[name] as Attributes | undefined;
|
|
140
|
+
if (ctx[name] === value) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
157
143
|
|
|
158
|
-
|
|
159
|
-
|
|
144
|
+
ctx[name] = value as string;
|
|
145
|
+
}
|
|
160
146
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
147
|
+
schedule(ctx, element, name, state, value);
|
|
148
|
+
}
|
|
164
149
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
150
|
+
function schedule(ctx: Context | null, element: Element, name: string, state: State, value: unknown) {
|
|
151
|
+
if (state === STATE_HYDRATING) {
|
|
152
|
+
apply(element, name, value);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
ctx ??= context(element);
|
|
157
|
+
(ctx.updates ??= {})[name] = value;
|
|
158
|
+
|
|
159
|
+
if (state === STATE_NONE && !ctx.updating) {
|
|
160
|
+
ctx.updating = true;
|
|
161
|
+
queue.add(ctx);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (scheduled) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
scheduled = true;
|
|
169
|
+
raf.add(task);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function set(element: Element, name: string, value: unknown, state: State) {
|
|
173
|
+
let fn = name === 'class' || name === 'style' ? list : property,
|
|
174
|
+
type = typeof value;
|
|
175
|
+
|
|
176
|
+
if (type === 'function') {
|
|
177
|
+
if (name.startsWith('on')) {
|
|
178
|
+
event(element, name as `on${string}`, value as Function);
|
|
179
|
+
return;
|
|
169
180
|
}
|
|
170
|
-
else {
|
|
171
|
-
let hot: Attributes = {};
|
|
172
181
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
182
|
+
let ctx = context(element);
|
|
183
|
+
|
|
184
|
+
ctx.effect ??= 0;
|
|
176
185
|
|
|
177
|
-
|
|
178
|
-
part = parts[i].trim();
|
|
186
|
+
let id = (ctx.effect as number)++;
|
|
179
187
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
188
|
+
effect(() => {
|
|
189
|
+
let v = (value as Function)(element);
|
|
183
190
|
|
|
184
|
-
|
|
185
|
-
|
|
191
|
+
if (v == null || typeof v !== 'object') {
|
|
192
|
+
fn(ctx, element, id, name, v, state);
|
|
193
|
+
}
|
|
194
|
+
else if (isArray(v)) {
|
|
195
|
+
let last = v.length - 1;
|
|
196
|
+
|
|
197
|
+
for (let i = 0, n = v.length; i < n; i++) {
|
|
198
|
+
fn(
|
|
199
|
+
ctx,
|
|
200
|
+
element,
|
|
201
|
+
id,
|
|
202
|
+
name,
|
|
203
|
+
v[i],
|
|
204
|
+
state === STATE_HYDRATING
|
|
205
|
+
? state
|
|
206
|
+
: i !== last ? STATE_WAITING : state
|
|
207
|
+
);
|
|
186
208
|
}
|
|
187
209
|
}
|
|
210
|
+
});
|
|
188
211
|
|
|
189
|
-
|
|
212
|
+
state = STATE_NONE;
|
|
190
213
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
if (part in hot) {
|
|
194
|
-
continue;
|
|
195
|
-
}
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
196
216
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
217
|
+
if (type !== 'object') {
|
|
218
|
+
fn(null, element, null, name, value, state);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
200
221
|
|
|
201
|
-
|
|
202
|
-
|
|
222
|
+
if (isArray(value)) {
|
|
223
|
+
for (let i = 0, n = value.length; i < n; i++) {
|
|
224
|
+
let v = value[i];
|
|
203
225
|
|
|
204
|
-
|
|
226
|
+
if (v == null || v === false || v === '') {
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
205
229
|
|
|
206
|
-
|
|
207
|
-
value += (value ? delimiter : '') + key;
|
|
230
|
+
set(element, name, v, state);
|
|
208
231
|
}
|
|
232
|
+
return;
|
|
209
233
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
234
|
+
|
|
235
|
+
fn(null, element, null, name, value, state);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function task() {
|
|
239
|
+
let context,
|
|
240
|
+
n = queue.length;
|
|
241
|
+
|
|
242
|
+
while ((context = queue.next()) && n--) {
|
|
243
|
+
let { element, updates } = context;
|
|
244
|
+
|
|
245
|
+
for (let name in updates) {
|
|
246
|
+
apply(element, name, updates[name]);
|
|
213
247
|
}
|
|
214
248
|
|
|
215
|
-
|
|
249
|
+
context.updates = {};
|
|
250
|
+
context.updating = false;
|
|
216
251
|
}
|
|
217
252
|
|
|
218
|
-
if (
|
|
219
|
-
|
|
253
|
+
if (queue.length) {
|
|
254
|
+
raf.add(task);
|
|
220
255
|
}
|
|
221
256
|
else {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
if (state === STATE_NONE && !context.updating) {
|
|
225
|
-
context.updating = true;
|
|
226
|
-
queue.add(context);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
if (!scheduled) {
|
|
230
|
-
schedule();
|
|
231
|
-
}
|
|
257
|
+
scheduled = false;
|
|
232
258
|
}
|
|
233
259
|
}
|
|
234
260
|
|
|
235
261
|
|
|
236
262
|
const spread = function (element: Element, value: Attributes | Attributes[]) {
|
|
237
|
-
let cache = (element[STORE] ??= { [UPDATES]: {} }) as Record<PropertyKey, unknown>,
|
|
238
|
-
context = {
|
|
239
|
-
element,
|
|
240
|
-
store: cache,
|
|
241
|
-
updates: cache[UPDATES] as Record<PropertyKey, unknown>,
|
|
242
|
-
updating: false
|
|
243
|
-
};
|
|
244
|
-
|
|
245
263
|
if (isObject(value)) {
|
|
246
264
|
for (let name in value) {
|
|
247
|
-
|
|
265
|
+
let v = value[name];
|
|
266
|
+
|
|
267
|
+
if (v == null || v === false || v === '') {
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
set(element, name, v, STATE_HYDRATING);
|
|
248
272
|
}
|
|
249
273
|
}
|
|
250
274
|
else if (isArray(value)) {
|
|
251
275
|
for (let i = 0, n = value.length; i < n; i++) {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
for (let name in v) {
|
|
255
|
-
set(context, name, v[name], STATE_HYDRATING);
|
|
256
|
-
}
|
|
276
|
+
spread(element, value[i]);
|
|
257
277
|
}
|
|
258
278
|
}
|
|
259
279
|
};
|
package/src/html/index.ts
CHANGED
|
@@ -13,42 +13,11 @@ const html = <T>(literals: TemplateStringsArray, ...values: (Values<T> | Values<
|
|
|
13
13
|
clone = cloneNode.call(fragment, true);
|
|
14
14
|
|
|
15
15
|
if (slots !== null) {
|
|
16
|
-
let node, nodePath;
|
|
16
|
+
let node, nodePath;
|
|
17
17
|
|
|
18
|
-
// TODO: when a new slot is added it breaks pathfinding for the next slot
|
|
19
|
-
// for (let i = 0, n = slots.length; i < n; i++) {
|
|
20
18
|
for (let i = slots.length - 1; i >= 0; i--) {
|
|
21
19
|
let { fn, path, slot } = slots[i];
|
|
22
20
|
|
|
23
|
-
// pp = path.parent,
|
|
24
|
-
// pr = path.relative;
|
|
25
|
-
|
|
26
|
-
// if (pp !== parentPath) {
|
|
27
|
-
// if (pp === nodePath) {
|
|
28
|
-
// parent = node;
|
|
29
|
-
// parentPath = nodePath;
|
|
30
|
-
|
|
31
|
-
// nodePath = undefined;
|
|
32
|
-
// }
|
|
33
|
-
// else {
|
|
34
|
-
// parent = clone;
|
|
35
|
-
// parentPath = pp;
|
|
36
|
-
|
|
37
|
-
// for (let i = 0, n = pp.length; i < n; i++) {
|
|
38
|
-
// parent = pp[i].call(parent);
|
|
39
|
-
// }
|
|
40
|
-
// }
|
|
41
|
-
// }
|
|
42
|
-
|
|
43
|
-
// if (pr !== nodePath) {
|
|
44
|
-
// node = parent;
|
|
45
|
-
// nodePath = path.absolute;
|
|
46
|
-
|
|
47
|
-
// for (let i = 0, n = pr.length; i < n; i++) {
|
|
48
|
-
// node = pr[i].call(node);
|
|
49
|
-
// }
|
|
50
|
-
// }
|
|
51
|
-
|
|
52
21
|
if (nodePath !== path) {
|
|
53
22
|
node = clone;
|
|
54
23
|
|
package/src/html/parser.ts
CHANGED
|
@@ -52,12 +52,6 @@ function build(literals: TemplateStringsArray) {
|
|
|
52
52
|
|
|
53
53
|
if (attr) {
|
|
54
54
|
let i = attr.indexOf(SLOT_MARKER);
|
|
55
|
-
// @see ./index.ts comments
|
|
56
|
-
// p = {
|
|
57
|
-
// absolute: path,
|
|
58
|
-
// parent: parent.path,
|
|
59
|
-
// relative: path.slice(parent.path.length)
|
|
60
|
-
// };
|
|
61
55
|
|
|
62
56
|
while (i !== -1) {
|
|
63
57
|
slots.push({
|
|
@@ -82,18 +76,10 @@ function build(literals: TemplateStringsArray) {
|
|
|
82
76
|
parent.elements++;
|
|
83
77
|
}
|
|
84
78
|
else if (type === NODE_SLOT) {
|
|
85
|
-
// @see ./index.ts comments
|
|
86
|
-
// let relative = methods(parent.children, [], firstChild, nextSibling);
|
|
87
|
-
|
|
88
79
|
buffer += parsed[slot] + SLOT_HTML;
|
|
89
80
|
slots.push({
|
|
90
81
|
fn: s,
|
|
91
82
|
path: methods(parent.children, parent.path, firstChild, nextSibling),
|
|
92
|
-
// path: {
|
|
93
|
-
// absolute: [...parent.path, ...relative],
|
|
94
|
-
// parent: parent.path,
|
|
95
|
-
// relative
|
|
96
|
-
// },
|
|
97
83
|
slot: slot++
|
|
98
84
|
});
|
|
99
85
|
}
|
package/src/render.ts
CHANGED
|
@@ -9,7 +9,7 @@ let anchor,
|
|
|
9
9
|
marker = firstChild.call( fragment(SLOT_HTML) );
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
export default (parent: HTMLElement, renderable: Renderable) => {
|
|
12
|
+
export default <T>(parent: HTMLElement, renderable: Renderable<T>) => {
|
|
13
13
|
nodeValue.call(parent, '');
|
|
14
14
|
parent.append(anchor = marker.cloneNode());
|
|
15
15
|
|
package/src/svg.ts
CHANGED
|
@@ -2,15 +2,15 @@ import html from './html';
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
const svg = html.bind(null) as typeof html & {
|
|
5
|
-
sprite: (
|
|
5
|
+
sprite: (href: string) => ReturnType<typeof html>
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
svg.sprite = (
|
|
9
|
-
if (
|
|
10
|
-
|
|
8
|
+
svg.sprite = (href: string) => {
|
|
9
|
+
if (href[0] !== '#') {
|
|
10
|
+
href = '#' + href;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
return html`<svg><use
|
|
13
|
+
return html`<svg><use ${{ ['href']: href }} /></svg>`;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
|
package/src/types.ts
CHANGED
|
@@ -52,13 +52,7 @@ type Template = {
|
|
|
52
52
|
literals: TemplateStringsArray;
|
|
53
53
|
slots: {
|
|
54
54
|
fn: typeof attributes.spread | typeof slot;
|
|
55
|
-
// @see ./html/index.ts comments
|
|
56
55
|
path: typeof firstChild[];
|
|
57
|
-
// path: {
|
|
58
|
-
// absolute: typeof firstChild[],
|
|
59
|
-
// parent: typeof firstChild[],
|
|
60
|
-
// relative: typeof firstChild[]
|
|
61
|
-
// };
|
|
62
56
|
slot: number;
|
|
63
57
|
}[] | null;
|
|
64
58
|
};
|