@neeloong/form 0.1.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/index.d.mts +312 -0
- package/index.js +3658 -0
- package/index.min.js +60 -0
- package/index.min.mjs +60 -0
- package/index.mjs +3076 -0
- package/package.json +36 -0
package/index.js
ADDED
|
@@ -0,0 +1,3658 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* @neeloong/form v0.1.0
|
|
3
|
+
* (c) 2024-2025 Fierflame
|
|
4
|
+
* @license Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
(function (global, factory) {
|
|
8
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
9
|
+
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
10
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.neeloongForm = {}));
|
|
11
|
+
})(this, (function (exports) { 'use strict';
|
|
12
|
+
|
|
13
|
+
var __defProp = Object.defineProperty;
|
|
14
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
15
|
+
var __publicField = (obj, key, value) => {
|
|
16
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
17
|
+
return value;
|
|
18
|
+
};
|
|
19
|
+
var __accessCheck = (obj, member, msg) => {
|
|
20
|
+
if (!member.has(obj))
|
|
21
|
+
throw TypeError("Cannot " + msg);
|
|
22
|
+
};
|
|
23
|
+
var __privateIn = (member, obj) => {
|
|
24
|
+
if (Object(obj) !== obj)
|
|
25
|
+
throw TypeError('Cannot use the "in" operator on this value');
|
|
26
|
+
return member.has(obj);
|
|
27
|
+
};
|
|
28
|
+
var __privateAdd = (obj, member, value) => {
|
|
29
|
+
if (member.has(obj))
|
|
30
|
+
throw TypeError("Cannot add the same private member more than once");
|
|
31
|
+
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
32
|
+
};
|
|
33
|
+
var __privateMethod = (obj, member, method) => {
|
|
34
|
+
__accessCheck(obj, member, "access private method");
|
|
35
|
+
return method;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* @license
|
|
39
|
+
* Copyright Google LLC All Rights Reserved.
|
|
40
|
+
*
|
|
41
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
42
|
+
* found in the LICENSE file at https://angular.io/license
|
|
43
|
+
*/
|
|
44
|
+
function defaultEquals(a, b) {
|
|
45
|
+
return Object.is(a, b);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* @license
|
|
49
|
+
* Copyright Google LLC All Rights Reserved.
|
|
50
|
+
*
|
|
51
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
52
|
+
* found in the LICENSE file at https://angular.io/license
|
|
53
|
+
*/
|
|
54
|
+
let activeConsumer = null;
|
|
55
|
+
let inNotificationPhase = false;
|
|
56
|
+
let epoch = 1;
|
|
57
|
+
const SIGNAL = /* @__PURE__ */ Symbol("SIGNAL");
|
|
58
|
+
function setActiveConsumer(consumer) {
|
|
59
|
+
const prev = activeConsumer;
|
|
60
|
+
activeConsumer = consumer;
|
|
61
|
+
return prev;
|
|
62
|
+
}
|
|
63
|
+
function getActiveConsumer() {
|
|
64
|
+
return activeConsumer;
|
|
65
|
+
}
|
|
66
|
+
function isInNotificationPhase() {
|
|
67
|
+
return inNotificationPhase;
|
|
68
|
+
}
|
|
69
|
+
const REACTIVE_NODE = {
|
|
70
|
+
version: 0,
|
|
71
|
+
lastCleanEpoch: 0,
|
|
72
|
+
dirty: false,
|
|
73
|
+
producerNode: void 0,
|
|
74
|
+
producerLastReadVersion: void 0,
|
|
75
|
+
producerIndexOfThis: void 0,
|
|
76
|
+
nextProducerIndex: 0,
|
|
77
|
+
liveConsumerNode: void 0,
|
|
78
|
+
liveConsumerIndexOfThis: void 0,
|
|
79
|
+
consumerAllowSignalWrites: false,
|
|
80
|
+
consumerIsAlwaysLive: false,
|
|
81
|
+
producerMustRecompute: () => false,
|
|
82
|
+
producerRecomputeValue: () => {
|
|
83
|
+
},
|
|
84
|
+
consumerMarkedDirty: () => {
|
|
85
|
+
},
|
|
86
|
+
consumerOnSignalRead: () => {
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
function producerAccessed(node) {
|
|
90
|
+
if (inNotificationPhase) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
typeof ngDevMode !== "undefined" && ngDevMode ? `Assertion error: signal read during notification phase` : ""
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
if (activeConsumer === null) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
activeConsumer.consumerOnSignalRead(node);
|
|
99
|
+
const idx = activeConsumer.nextProducerIndex++;
|
|
100
|
+
assertConsumerNode(activeConsumer);
|
|
101
|
+
if (idx < activeConsumer.producerNode.length && activeConsumer.producerNode[idx] !== node) {
|
|
102
|
+
if (consumerIsLive(activeConsumer)) {
|
|
103
|
+
const staleProducer = activeConsumer.producerNode[idx];
|
|
104
|
+
producerRemoveLiveConsumerAtIndex(staleProducer, activeConsumer.producerIndexOfThis[idx]);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (activeConsumer.producerNode[idx] !== node) {
|
|
108
|
+
activeConsumer.producerNode[idx] = node;
|
|
109
|
+
activeConsumer.producerIndexOfThis[idx] = consumerIsLive(activeConsumer) ? producerAddLiveConsumer(node, activeConsumer, idx) : 0;
|
|
110
|
+
}
|
|
111
|
+
activeConsumer.producerLastReadVersion[idx] = node.version;
|
|
112
|
+
}
|
|
113
|
+
function producerIncrementEpoch() {
|
|
114
|
+
epoch++;
|
|
115
|
+
}
|
|
116
|
+
function producerUpdateValueVersion(node) {
|
|
117
|
+
if (!node.dirty && node.lastCleanEpoch === epoch) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (!node.producerMustRecompute(node) && !consumerPollProducersForChange(node)) {
|
|
121
|
+
node.dirty = false;
|
|
122
|
+
node.lastCleanEpoch = epoch;
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
node.producerRecomputeValue(node);
|
|
126
|
+
node.dirty = false;
|
|
127
|
+
node.lastCleanEpoch = epoch;
|
|
128
|
+
}
|
|
129
|
+
function producerNotifyConsumers(node) {
|
|
130
|
+
if (node.liveConsumerNode === void 0) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const prev = inNotificationPhase;
|
|
134
|
+
inNotificationPhase = true;
|
|
135
|
+
try {
|
|
136
|
+
for (const consumer of node.liveConsumerNode) {
|
|
137
|
+
if (!consumer.dirty) {
|
|
138
|
+
consumerMarkDirty(consumer);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
} finally {
|
|
142
|
+
inNotificationPhase = prev;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function producerUpdatesAllowed() {
|
|
146
|
+
return (activeConsumer == null ? void 0 : activeConsumer.consumerAllowSignalWrites) !== false;
|
|
147
|
+
}
|
|
148
|
+
function consumerMarkDirty(node) {
|
|
149
|
+
var _a;
|
|
150
|
+
node.dirty = true;
|
|
151
|
+
producerNotifyConsumers(node);
|
|
152
|
+
(_a = node.consumerMarkedDirty) == null ? void 0 : _a.call(node.wrapper ?? node);
|
|
153
|
+
}
|
|
154
|
+
function consumerBeforeComputation(node) {
|
|
155
|
+
node && (node.nextProducerIndex = 0);
|
|
156
|
+
return setActiveConsumer(node);
|
|
157
|
+
}
|
|
158
|
+
function consumerAfterComputation(node, prevConsumer) {
|
|
159
|
+
setActiveConsumer(prevConsumer);
|
|
160
|
+
if (!node || node.producerNode === void 0 || node.producerIndexOfThis === void 0 || node.producerLastReadVersion === void 0) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (consumerIsLive(node)) {
|
|
164
|
+
for (let i = node.nextProducerIndex; i < node.producerNode.length; i++) {
|
|
165
|
+
producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
while (node.producerNode.length > node.nextProducerIndex) {
|
|
169
|
+
node.producerNode.pop();
|
|
170
|
+
node.producerLastReadVersion.pop();
|
|
171
|
+
node.producerIndexOfThis.pop();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function consumerPollProducersForChange(node) {
|
|
175
|
+
assertConsumerNode(node);
|
|
176
|
+
for (let i = 0; i < node.producerNode.length; i++) {
|
|
177
|
+
const producer = node.producerNode[i];
|
|
178
|
+
const seenVersion = node.producerLastReadVersion[i];
|
|
179
|
+
if (seenVersion !== producer.version) {
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
producerUpdateValueVersion(producer);
|
|
183
|
+
if (seenVersion !== producer.version) {
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
function producerAddLiveConsumer(node, consumer, indexOfThis) {
|
|
190
|
+
var _a;
|
|
191
|
+
assertProducerNode(node);
|
|
192
|
+
assertConsumerNode(node);
|
|
193
|
+
if (node.liveConsumerNode.length === 0) {
|
|
194
|
+
(_a = node.watched) == null ? void 0 : _a.call(node.wrapper);
|
|
195
|
+
for (let i = 0; i < node.producerNode.length; i++) {
|
|
196
|
+
node.producerIndexOfThis[i] = producerAddLiveConsumer(node.producerNode[i], node, i);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
node.liveConsumerIndexOfThis.push(indexOfThis);
|
|
200
|
+
return node.liveConsumerNode.push(consumer) - 1;
|
|
201
|
+
}
|
|
202
|
+
function producerRemoveLiveConsumerAtIndex(node, idx) {
|
|
203
|
+
var _a;
|
|
204
|
+
assertProducerNode(node);
|
|
205
|
+
assertConsumerNode(node);
|
|
206
|
+
if (typeof ngDevMode !== "undefined" && ngDevMode && idx >= node.liveConsumerNode.length) {
|
|
207
|
+
throw new Error(
|
|
208
|
+
`Assertion error: active consumer index ${idx} is out of bounds of ${node.liveConsumerNode.length} consumers)`
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
if (node.liveConsumerNode.length === 1) {
|
|
212
|
+
(_a = node.unwatched) == null ? void 0 : _a.call(node.wrapper);
|
|
213
|
+
for (let i = 0; i < node.producerNode.length; i++) {
|
|
214
|
+
producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const lastIdx = node.liveConsumerNode.length - 1;
|
|
218
|
+
node.liveConsumerNode[idx] = node.liveConsumerNode[lastIdx];
|
|
219
|
+
node.liveConsumerIndexOfThis[idx] = node.liveConsumerIndexOfThis[lastIdx];
|
|
220
|
+
node.liveConsumerNode.length--;
|
|
221
|
+
node.liveConsumerIndexOfThis.length--;
|
|
222
|
+
if (idx < node.liveConsumerNode.length) {
|
|
223
|
+
const idxProducer = node.liveConsumerIndexOfThis[idx];
|
|
224
|
+
const consumer = node.liveConsumerNode[idx];
|
|
225
|
+
assertConsumerNode(consumer);
|
|
226
|
+
consumer.producerIndexOfThis[idxProducer] = idx;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function consumerIsLive(node) {
|
|
230
|
+
var _a;
|
|
231
|
+
return node.consumerIsAlwaysLive || (((_a = node == null ? void 0 : node.liveConsumerNode) == null ? void 0 : _a.length) ?? 0) > 0;
|
|
232
|
+
}
|
|
233
|
+
function assertConsumerNode(node) {
|
|
234
|
+
node.producerNode ?? (node.producerNode = []);
|
|
235
|
+
node.producerIndexOfThis ?? (node.producerIndexOfThis = []);
|
|
236
|
+
node.producerLastReadVersion ?? (node.producerLastReadVersion = []);
|
|
237
|
+
}
|
|
238
|
+
function assertProducerNode(node) {
|
|
239
|
+
node.liveConsumerNode ?? (node.liveConsumerNode = []);
|
|
240
|
+
node.liveConsumerIndexOfThis ?? (node.liveConsumerIndexOfThis = []);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* @license
|
|
244
|
+
* Copyright Google LLC All Rights Reserved.
|
|
245
|
+
*
|
|
246
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
247
|
+
* found in the LICENSE file at https://angular.io/license
|
|
248
|
+
*/
|
|
249
|
+
function computedGet(node) {
|
|
250
|
+
producerUpdateValueVersion(node);
|
|
251
|
+
producerAccessed(node);
|
|
252
|
+
if (node.value === ERRORED) {
|
|
253
|
+
throw node.error;
|
|
254
|
+
}
|
|
255
|
+
return node.value;
|
|
256
|
+
}
|
|
257
|
+
function createComputed(computation) {
|
|
258
|
+
const node = Object.create(COMPUTED_NODE);
|
|
259
|
+
node.computation = computation;
|
|
260
|
+
const computed = () => computedGet(node);
|
|
261
|
+
computed[SIGNAL] = node;
|
|
262
|
+
return computed;
|
|
263
|
+
}
|
|
264
|
+
const UNSET = /* @__PURE__ */ Symbol("UNSET");
|
|
265
|
+
const COMPUTING = /* @__PURE__ */ Symbol("COMPUTING");
|
|
266
|
+
const ERRORED = /* @__PURE__ */ Symbol("ERRORED");
|
|
267
|
+
const COMPUTED_NODE = /* @__PURE__ */ (() => {
|
|
268
|
+
return {
|
|
269
|
+
...REACTIVE_NODE,
|
|
270
|
+
value: UNSET,
|
|
271
|
+
dirty: true,
|
|
272
|
+
error: null,
|
|
273
|
+
equal: defaultEquals,
|
|
274
|
+
producerMustRecompute(node) {
|
|
275
|
+
return node.value === UNSET || node.value === COMPUTING;
|
|
276
|
+
},
|
|
277
|
+
producerRecomputeValue(node) {
|
|
278
|
+
if (node.value === COMPUTING) {
|
|
279
|
+
throw new Error("Detected cycle in computations.");
|
|
280
|
+
}
|
|
281
|
+
const oldValue = node.value;
|
|
282
|
+
node.value = COMPUTING;
|
|
283
|
+
const prevConsumer = consumerBeforeComputation(node);
|
|
284
|
+
let newValue;
|
|
285
|
+
let wasEqual = false;
|
|
286
|
+
try {
|
|
287
|
+
newValue = node.computation.call(node.wrapper);
|
|
288
|
+
const oldOk = oldValue !== UNSET && oldValue !== ERRORED;
|
|
289
|
+
wasEqual = oldOk && node.equal.call(node.wrapper, oldValue, newValue);
|
|
290
|
+
} catch (err) {
|
|
291
|
+
newValue = ERRORED;
|
|
292
|
+
node.error = err;
|
|
293
|
+
} finally {
|
|
294
|
+
consumerAfterComputation(node, prevConsumer);
|
|
295
|
+
}
|
|
296
|
+
if (wasEqual) {
|
|
297
|
+
node.value = oldValue;
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
node.value = newValue;
|
|
301
|
+
node.version++;
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
})();
|
|
305
|
+
/**
|
|
306
|
+
* @license
|
|
307
|
+
* Copyright Google LLC All Rights Reserved.
|
|
308
|
+
*
|
|
309
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
310
|
+
* found in the LICENSE file at https://angular.io/license
|
|
311
|
+
*/
|
|
312
|
+
function defaultThrowError() {
|
|
313
|
+
throw new Error();
|
|
314
|
+
}
|
|
315
|
+
let throwInvalidWriteToSignalErrorFn = defaultThrowError;
|
|
316
|
+
function throwInvalidWriteToSignalError() {
|
|
317
|
+
throwInvalidWriteToSignalErrorFn();
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* @license
|
|
321
|
+
* Copyright Google LLC All Rights Reserved.
|
|
322
|
+
*
|
|
323
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
324
|
+
* found in the LICENSE file at https://angular.io/license
|
|
325
|
+
*/
|
|
326
|
+
function createSignal(initialValue) {
|
|
327
|
+
const node = Object.create(SIGNAL_NODE);
|
|
328
|
+
node.value = initialValue;
|
|
329
|
+
const getter = () => {
|
|
330
|
+
producerAccessed(node);
|
|
331
|
+
return node.value;
|
|
332
|
+
};
|
|
333
|
+
getter[SIGNAL] = node;
|
|
334
|
+
return getter;
|
|
335
|
+
}
|
|
336
|
+
function signalGetFn() {
|
|
337
|
+
producerAccessed(this);
|
|
338
|
+
return this.value;
|
|
339
|
+
}
|
|
340
|
+
function signalSetFn(node, newValue) {
|
|
341
|
+
if (!producerUpdatesAllowed()) {
|
|
342
|
+
throwInvalidWriteToSignalError();
|
|
343
|
+
}
|
|
344
|
+
if (!node.equal.call(node.wrapper, node.value, newValue)) {
|
|
345
|
+
node.value = newValue;
|
|
346
|
+
signalValueChanged(node);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
const SIGNAL_NODE = /* @__PURE__ */ (() => {
|
|
350
|
+
return {
|
|
351
|
+
...REACTIVE_NODE,
|
|
352
|
+
equal: defaultEquals,
|
|
353
|
+
value: void 0
|
|
354
|
+
};
|
|
355
|
+
})();
|
|
356
|
+
function signalValueChanged(node) {
|
|
357
|
+
node.version++;
|
|
358
|
+
producerIncrementEpoch();
|
|
359
|
+
producerNotifyConsumers(node);
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* @license
|
|
363
|
+
* Copyright 2024 Bloomberg Finance L.P.
|
|
364
|
+
*
|
|
365
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
366
|
+
* you may not use this file except in compliance with the License.
|
|
367
|
+
* You may obtain a copy of the License at
|
|
368
|
+
*
|
|
369
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
370
|
+
*
|
|
371
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
372
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
373
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
374
|
+
* See the License for the specific language governing permissions and
|
|
375
|
+
* limitations under the License.
|
|
376
|
+
*/
|
|
377
|
+
const NODE = Symbol("node");
|
|
378
|
+
exports.Signal = void 0;
|
|
379
|
+
((Signal2) => {
|
|
380
|
+
var _a, _brand, _b, _brand2;
|
|
381
|
+
class State {
|
|
382
|
+
constructor(initialValue, options = {}) {
|
|
383
|
+
__privateAdd(this, _brand);
|
|
384
|
+
__publicField(this, _a);
|
|
385
|
+
const ref = createSignal(initialValue);
|
|
386
|
+
const node = ref[SIGNAL];
|
|
387
|
+
this[NODE] = node;
|
|
388
|
+
node.wrapper = this;
|
|
389
|
+
if (options) {
|
|
390
|
+
const equals = options.equals;
|
|
391
|
+
if (equals) {
|
|
392
|
+
node.equal = equals;
|
|
393
|
+
}
|
|
394
|
+
node.watched = options[Signal2.subtle.watched];
|
|
395
|
+
node.unwatched = options[Signal2.subtle.unwatched];
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
get() {
|
|
399
|
+
if (!(0, Signal2.isState)(this))
|
|
400
|
+
throw new TypeError("Wrong receiver type for Signal.State.prototype.get");
|
|
401
|
+
return signalGetFn.call(this[NODE]);
|
|
402
|
+
}
|
|
403
|
+
set(newValue) {
|
|
404
|
+
if (!(0, Signal2.isState)(this))
|
|
405
|
+
throw new TypeError("Wrong receiver type for Signal.State.prototype.set");
|
|
406
|
+
if (isInNotificationPhase()) {
|
|
407
|
+
throw new Error("Writes to signals not permitted during Watcher callback");
|
|
408
|
+
}
|
|
409
|
+
const ref = this[NODE];
|
|
410
|
+
signalSetFn(ref, newValue);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
_a = NODE;
|
|
414
|
+
_brand = new WeakSet();
|
|
415
|
+
Signal2.isState = (s) => __privateIn(_brand, s);
|
|
416
|
+
Signal2.State = State;
|
|
417
|
+
class Computed {
|
|
418
|
+
// Create a Signal which evaluates to the value returned by the callback.
|
|
419
|
+
// Callback is called with this signal as the parameter.
|
|
420
|
+
constructor(computation, options) {
|
|
421
|
+
__privateAdd(this, _brand2);
|
|
422
|
+
__publicField(this, _b);
|
|
423
|
+
const ref = createComputed(computation);
|
|
424
|
+
const node = ref[SIGNAL];
|
|
425
|
+
node.consumerAllowSignalWrites = true;
|
|
426
|
+
this[NODE] = node;
|
|
427
|
+
node.wrapper = this;
|
|
428
|
+
if (options) {
|
|
429
|
+
const equals = options.equals;
|
|
430
|
+
if (equals) {
|
|
431
|
+
node.equal = equals;
|
|
432
|
+
}
|
|
433
|
+
node.watched = options[Signal2.subtle.watched];
|
|
434
|
+
node.unwatched = options[Signal2.subtle.unwatched];
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
get() {
|
|
438
|
+
if (!(0, Signal2.isComputed)(this))
|
|
439
|
+
throw new TypeError("Wrong receiver type for Signal.Computed.prototype.get");
|
|
440
|
+
return computedGet(this[NODE]);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
_b = NODE;
|
|
444
|
+
_brand2 = new WeakSet();
|
|
445
|
+
Signal2.isComputed = (c) => __privateIn(_brand2, c);
|
|
446
|
+
Signal2.Computed = Computed;
|
|
447
|
+
((subtle2) => {
|
|
448
|
+
var _a2, _brand3, _assertSignals, assertSignals_fn;
|
|
449
|
+
function untrack(cb) {
|
|
450
|
+
let output;
|
|
451
|
+
let prevActiveConsumer = null;
|
|
452
|
+
try {
|
|
453
|
+
prevActiveConsumer = setActiveConsumer(null);
|
|
454
|
+
output = cb();
|
|
455
|
+
} finally {
|
|
456
|
+
setActiveConsumer(prevActiveConsumer);
|
|
457
|
+
}
|
|
458
|
+
return output;
|
|
459
|
+
}
|
|
460
|
+
subtle2.untrack = untrack;
|
|
461
|
+
function introspectSources(sink) {
|
|
462
|
+
var _a3;
|
|
463
|
+
if (!(0, Signal2.isComputed)(sink) && !(0, Signal2.isWatcher)(sink)) {
|
|
464
|
+
throw new TypeError("Called introspectSources without a Computed or Watcher argument");
|
|
465
|
+
}
|
|
466
|
+
return ((_a3 = sink[NODE].producerNode) == null ? void 0 : _a3.map((n) => n.wrapper)) ?? [];
|
|
467
|
+
}
|
|
468
|
+
subtle2.introspectSources = introspectSources;
|
|
469
|
+
function introspectSinks(signal) {
|
|
470
|
+
var _a3;
|
|
471
|
+
if (!(0, Signal2.isComputed)(signal) && !(0, Signal2.isState)(signal)) {
|
|
472
|
+
throw new TypeError("Called introspectSinks without a Signal argument");
|
|
473
|
+
}
|
|
474
|
+
return ((_a3 = signal[NODE].liveConsumerNode) == null ? void 0 : _a3.map((n) => n.wrapper)) ?? [];
|
|
475
|
+
}
|
|
476
|
+
subtle2.introspectSinks = introspectSinks;
|
|
477
|
+
function hasSinks(signal) {
|
|
478
|
+
if (!(0, Signal2.isComputed)(signal) && !(0, Signal2.isState)(signal)) {
|
|
479
|
+
throw new TypeError("Called hasSinks without a Signal argument");
|
|
480
|
+
}
|
|
481
|
+
const liveConsumerNode = signal[NODE].liveConsumerNode;
|
|
482
|
+
if (!liveConsumerNode)
|
|
483
|
+
return false;
|
|
484
|
+
return liveConsumerNode.length > 0;
|
|
485
|
+
}
|
|
486
|
+
subtle2.hasSinks = hasSinks;
|
|
487
|
+
function hasSources(signal) {
|
|
488
|
+
if (!(0, Signal2.isComputed)(signal) && !(0, Signal2.isWatcher)(signal)) {
|
|
489
|
+
throw new TypeError("Called hasSources without a Computed or Watcher argument");
|
|
490
|
+
}
|
|
491
|
+
const producerNode = signal[NODE].producerNode;
|
|
492
|
+
if (!producerNode)
|
|
493
|
+
return false;
|
|
494
|
+
return producerNode.length > 0;
|
|
495
|
+
}
|
|
496
|
+
subtle2.hasSources = hasSources;
|
|
497
|
+
class Watcher {
|
|
498
|
+
// When a (recursive) source of Watcher is written to, call this callback,
|
|
499
|
+
// if it hasn't already been called since the last `watch` call.
|
|
500
|
+
// No signals may be read or written during the notify.
|
|
501
|
+
constructor(notify) {
|
|
502
|
+
__privateAdd(this, _brand3);
|
|
503
|
+
__privateAdd(this, _assertSignals);
|
|
504
|
+
__publicField(this, _a2);
|
|
505
|
+
let node = Object.create(REACTIVE_NODE);
|
|
506
|
+
node.wrapper = this;
|
|
507
|
+
node.consumerMarkedDirty = notify;
|
|
508
|
+
node.consumerIsAlwaysLive = true;
|
|
509
|
+
node.consumerAllowSignalWrites = false;
|
|
510
|
+
node.producerNode = [];
|
|
511
|
+
this[NODE] = node;
|
|
512
|
+
}
|
|
513
|
+
// Add these signals to the Watcher's set, and set the watcher to run its
|
|
514
|
+
// notify callback next time any signal in the set (or one of its dependencies) changes.
|
|
515
|
+
// Can be called with no arguments just to reset the "notified" state, so that
|
|
516
|
+
// the notify callback will be invoked again.
|
|
517
|
+
watch(...signals) {
|
|
518
|
+
if (!(0, Signal2.isWatcher)(this)) {
|
|
519
|
+
throw new TypeError("Called unwatch without Watcher receiver");
|
|
520
|
+
}
|
|
521
|
+
__privateMethod(this, _assertSignals, assertSignals_fn).call(this, signals);
|
|
522
|
+
const node = this[NODE];
|
|
523
|
+
node.dirty = false;
|
|
524
|
+
const prev = setActiveConsumer(node);
|
|
525
|
+
for (const signal of signals) {
|
|
526
|
+
producerAccessed(signal[NODE]);
|
|
527
|
+
}
|
|
528
|
+
setActiveConsumer(prev);
|
|
529
|
+
}
|
|
530
|
+
// Remove these signals from the watched set (e.g., for an effect which is disposed)
|
|
531
|
+
unwatch(...signals) {
|
|
532
|
+
if (!(0, Signal2.isWatcher)(this)) {
|
|
533
|
+
throw new TypeError("Called unwatch without Watcher receiver");
|
|
534
|
+
}
|
|
535
|
+
__privateMethod(this, _assertSignals, assertSignals_fn).call(this, signals);
|
|
536
|
+
const node = this[NODE];
|
|
537
|
+
assertConsumerNode(node);
|
|
538
|
+
for (let i = node.producerNode.length - 1; i >= 0; i--) {
|
|
539
|
+
if (signals.includes(node.producerNode[i].wrapper)) {
|
|
540
|
+
producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]);
|
|
541
|
+
const lastIdx = node.producerNode.length - 1;
|
|
542
|
+
node.producerNode[i] = node.producerNode[lastIdx];
|
|
543
|
+
node.producerIndexOfThis[i] = node.producerIndexOfThis[lastIdx];
|
|
544
|
+
node.producerNode.length--;
|
|
545
|
+
node.producerIndexOfThis.length--;
|
|
546
|
+
node.nextProducerIndex--;
|
|
547
|
+
if (i < node.producerNode.length) {
|
|
548
|
+
const idxConsumer = node.producerIndexOfThis[i];
|
|
549
|
+
const producer = node.producerNode[i];
|
|
550
|
+
assertProducerNode(producer);
|
|
551
|
+
producer.liveConsumerIndexOfThis[idxConsumer] = i;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
// Returns the set of computeds in the Watcher's set which are still yet
|
|
557
|
+
// to be re-evaluated
|
|
558
|
+
getPending() {
|
|
559
|
+
if (!(0, Signal2.isWatcher)(this)) {
|
|
560
|
+
throw new TypeError("Called getPending without Watcher receiver");
|
|
561
|
+
}
|
|
562
|
+
const node = this[NODE];
|
|
563
|
+
return node.producerNode.filter((n) => n.dirty).map((n) => n.wrapper);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
_a2 = NODE;
|
|
567
|
+
_brand3 = new WeakSet();
|
|
568
|
+
_assertSignals = new WeakSet();
|
|
569
|
+
assertSignals_fn = function(signals) {
|
|
570
|
+
for (const signal of signals) {
|
|
571
|
+
if (!(0, Signal2.isComputed)(signal) && !(0, Signal2.isState)(signal)) {
|
|
572
|
+
throw new TypeError("Called watch/unwatch without a Computed or State argument");
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
Signal2.isWatcher = (w) => __privateIn(_brand3, w);
|
|
577
|
+
subtle2.Watcher = Watcher;
|
|
578
|
+
function currentComputed() {
|
|
579
|
+
var _a3;
|
|
580
|
+
return (_a3 = getActiveConsumer()) == null ? void 0 : _a3.wrapper;
|
|
581
|
+
}
|
|
582
|
+
subtle2.currentComputed = currentComputed;
|
|
583
|
+
subtle2.watched = Symbol("watched");
|
|
584
|
+
subtle2.unwatched = Symbol("unwatched");
|
|
585
|
+
})(Signal2.subtle || (Signal2.subtle = {}));
|
|
586
|
+
})(exports.Signal || (exports.Signal = {}));
|
|
587
|
+
|
|
588
|
+
/** @import Store from './index.mjs' */
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
*
|
|
592
|
+
* @param {Store} self
|
|
593
|
+
* @param {boolean?} [defState]
|
|
594
|
+
* @param {boolean | ((store: Store) => boolean) | null} [fn]
|
|
595
|
+
* @param {Signal.Computed<boolean>?} [parent]
|
|
596
|
+
* @returns {[Signal.State<boolean?>, Signal.Computed<boolean>]}
|
|
597
|
+
*/
|
|
598
|
+
const createBooleanStates = (self, defState, fn, parent) => {
|
|
599
|
+
|
|
600
|
+
const selfState = new exports.Signal.State(typeof defState === 'boolean' ? defState : null);
|
|
601
|
+
const scriptState = typeof fn === 'function' ? new exports.Signal.Computed(() => fn(self)) : fn ? new exports.Signal.Computed(() => true) : new exports.Signal.Computed(() => false);
|
|
602
|
+
|
|
603
|
+
const getState = () => {
|
|
604
|
+
const s = selfState.get();
|
|
605
|
+
return s === null ? scriptState.get() : s;
|
|
606
|
+
};
|
|
607
|
+
const state = parent
|
|
608
|
+
? new exports.Signal.Computed(() => parent.get() || getState())
|
|
609
|
+
: new exports.Signal.Computed(getState);
|
|
610
|
+
|
|
611
|
+
return [selfState, state];
|
|
612
|
+
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
/** @import { Schema } from '../types.mjs' */
|
|
616
|
+
/**
|
|
617
|
+
* @template [T=any]
|
|
618
|
+
*/
|
|
619
|
+
class Store {
|
|
620
|
+
/**
|
|
621
|
+
* @param {Schema} schema
|
|
622
|
+
* @param {object} [options]
|
|
623
|
+
* @param {boolean} [options.new]
|
|
624
|
+
*/
|
|
625
|
+
static create(schema, options = {}) {
|
|
626
|
+
return new ObjectStore({type: null, props: schema}, { ...options, parent: null });
|
|
627
|
+
}
|
|
628
|
+
#null = false;
|
|
629
|
+
get null() { return this.#null; }
|
|
630
|
+
/**
|
|
631
|
+
* @param {Schema.Field} schema
|
|
632
|
+
* @param {object} options
|
|
633
|
+
* @param {*} [options.parent]
|
|
634
|
+
* @param {*} [options.state]
|
|
635
|
+
* @param {number | string | null} [options.index]
|
|
636
|
+
* @param {number} [options.length]
|
|
637
|
+
* @param {boolean} [options.null]
|
|
638
|
+
* @param {boolean} [options.new]
|
|
639
|
+
* @param {boolean} [options.hidden]
|
|
640
|
+
* @param {boolean} [options.clearable]
|
|
641
|
+
* @param {boolean} [options.required]
|
|
642
|
+
* @param {boolean} [options.readonly]
|
|
643
|
+
* @param {boolean} [options.disabled]
|
|
644
|
+
* @param {((value: any) => any)?} [options.setValue]
|
|
645
|
+
* @param {((value: any) => any)?} [options.setState]
|
|
646
|
+
* @param {((value: any, state: any) => [value: any, state: any])?} [options.convert]
|
|
647
|
+
* @param {((value: T?, index: any) => void)?} [options.onUpdate]
|
|
648
|
+
* @param {((value: T?, index: any) => void)?} [options.onUpdateState]
|
|
649
|
+
*/
|
|
650
|
+
constructor(schema, {
|
|
651
|
+
null: isNull, state,
|
|
652
|
+
setValue, setState, convert, onUpdate, onUpdateState,
|
|
653
|
+
index, length, new: isNew, parent: parentNode,
|
|
654
|
+
hidden, clearable, required, disabled, readonly,
|
|
655
|
+
}) {
|
|
656
|
+
this.schema = schema;
|
|
657
|
+
this.#state.set(typeof state === 'object' && state || {});
|
|
658
|
+
const parent = parentNode instanceof Store ? parentNode : null;
|
|
659
|
+
if (parent) {
|
|
660
|
+
this.#parent = parent;
|
|
661
|
+
this.#root = parent.#root;
|
|
662
|
+
// TODO: 事件向上冒泡
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
const selfNewState = new exports.Signal.State(Boolean(isNew));
|
|
666
|
+
this.#selfNew = selfNewState;
|
|
667
|
+
/** @type {Signal.Computed<boolean>} */
|
|
668
|
+
const newState = parent
|
|
669
|
+
? new exports.Signal.Computed(() => parent.#new.get() || selfNewState.get())
|
|
670
|
+
: new exports.Signal.Computed(() => selfNewState.get());
|
|
671
|
+
|
|
672
|
+
this.#new = newState;
|
|
673
|
+
const immutable = Boolean(schema.immutable);
|
|
674
|
+
const creatable = schema.creatable !== false;
|
|
675
|
+
this.#immutable = immutable;
|
|
676
|
+
this.#creatable = creatable;
|
|
677
|
+
this.#editable = new exports.Signal.Computed(() => newState.get() ? creatable : !immutable);
|
|
678
|
+
|
|
679
|
+
[this.#selfHidden, this.#hidden] = createBooleanStates(this, hidden, schema.hidden, parent ? parent.#hidden : null);
|
|
680
|
+
[this.#selfClearable, this.#clearable] = createBooleanStates(this, clearable, schema.clearable, parent ? parent.#clearable : null);
|
|
681
|
+
[this.#selfRequired, this.#required] = createBooleanStates(this, required, schema.required, parent ? parent.#required : null);
|
|
682
|
+
[this.#selfDisabled, this.#disabled] = createBooleanStates(this, disabled, schema.disabled, parent ? parent.#disabled : null);
|
|
683
|
+
[this.#selfReadonly, this.#readonly] = createBooleanStates(this, readonly, schema.readonly, parent ? parent.#readonly : null);
|
|
684
|
+
|
|
685
|
+
if (isNull) {
|
|
686
|
+
this.#null = true;
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
this.#onUpdate = onUpdate || null;
|
|
690
|
+
this.#onUpdateState = onUpdateState || null;
|
|
691
|
+
this.#setValue = typeof setValue === 'function' ? setValue : null;
|
|
692
|
+
this.#setState = typeof setState === 'function' ? setState : null;
|
|
693
|
+
this.#convert = typeof convert === 'function' ? convert : null;
|
|
694
|
+
this.#length.set(length || 0);
|
|
695
|
+
this.#index.set(index ?? '');
|
|
696
|
+
|
|
697
|
+
}
|
|
698
|
+
#destroyed = false;
|
|
699
|
+
/** @type {((value: any) => any)?} */
|
|
700
|
+
#setValue = null
|
|
701
|
+
/** @type {((value: any) => any)?} */
|
|
702
|
+
#setState = null
|
|
703
|
+
/** @type {((value: any, state: any) => [value: any, state: any])?} */
|
|
704
|
+
#convert = null
|
|
705
|
+
/** @type {((value: any, index: any) => void)?} */
|
|
706
|
+
#onUpdate = null
|
|
707
|
+
/** @type {((value: any, index: any) => void)?} */
|
|
708
|
+
#onUpdateState = null
|
|
709
|
+
/** @readonly @type {Store?} */
|
|
710
|
+
#parent = null;
|
|
711
|
+
/** @readonly @type {Store} */
|
|
712
|
+
#root = this;
|
|
713
|
+
get parent() { return this.#parent; }
|
|
714
|
+
get root() { return this.#root; }
|
|
715
|
+
|
|
716
|
+
#length = new exports.Signal.State(0);
|
|
717
|
+
get length() { return this.#length.get(); }
|
|
718
|
+
set length(v) { this.#length.set(v); }
|
|
719
|
+
#index = new exports.Signal.State(/** @type {string | number} */(''));
|
|
720
|
+
get index() { return this.#index.get(); }
|
|
721
|
+
set index(v) { this.#index.set(v); }
|
|
722
|
+
get no() {
|
|
723
|
+
if (this.#null) { return ''; }
|
|
724
|
+
const index = this.index;
|
|
725
|
+
return typeof index === 'number' ? index + 1 : index;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
#creatable = true;
|
|
729
|
+
get creatable() { return this.#creatable; }
|
|
730
|
+
#immutable = false;
|
|
731
|
+
get immutable() { return this.#immutable; }
|
|
732
|
+
|
|
733
|
+
/** @readonly @type {Signal.Computed<boolean>} */
|
|
734
|
+
#new
|
|
735
|
+
/** @readonly @type {Signal.State<boolean>} */
|
|
736
|
+
#selfNew
|
|
737
|
+
/** @readonly @type {Signal.Computed<boolean>} */
|
|
738
|
+
#editable
|
|
739
|
+
get selfNew() { return this.#selfNew.get(); }
|
|
740
|
+
set selfNew(v) { this.#selfNew.set(Boolean(v)); }
|
|
741
|
+
get new() { return this.#new.get(); }
|
|
742
|
+
set new(v) { this.#selfNew.set(Boolean(v)); }
|
|
743
|
+
get editable() { return this.#editable.get(); }
|
|
744
|
+
|
|
745
|
+
/** @readonly @type {Signal.State<boolean?>} */
|
|
746
|
+
#selfHidden
|
|
747
|
+
/** @readonly @type {Signal.Computed<boolean>} */
|
|
748
|
+
#hidden
|
|
749
|
+
get selfHidden() { return this.#selfHidden.get(); }
|
|
750
|
+
set selfHidden(v) { this.#selfHidden.set(typeof v === 'boolean' ? v : null); }
|
|
751
|
+
get hidden() { return this.#hidden.get(); }
|
|
752
|
+
set hidden(v) { this.#selfHidden.set(typeof v === 'boolean' ? v : null); }
|
|
753
|
+
|
|
754
|
+
/** @readonly @type {Signal.State<boolean?>} */
|
|
755
|
+
#selfClearable
|
|
756
|
+
/** @readonly @type {Signal.Computed<boolean>} */
|
|
757
|
+
#clearable
|
|
758
|
+
get selfClearable() { return this.#selfClearable.get(); }
|
|
759
|
+
set selfClearable(v) { this.#selfClearable.set(typeof v === 'boolean' ? v : null); }
|
|
760
|
+
get clearable() { return this.#clearable.get(); }
|
|
761
|
+
set clearable(v) { this.#selfClearable.set(typeof v === 'boolean' ? v : null); }
|
|
762
|
+
|
|
763
|
+
/** @readonly @type {Signal.State<boolean?>} */
|
|
764
|
+
#selfRequired
|
|
765
|
+
/** @readonly @type {Signal.Computed<boolean>} */
|
|
766
|
+
#required
|
|
767
|
+
get selfRequired() { return this.#selfRequired.get(); }
|
|
768
|
+
set selfRequired(v) { this.#selfRequired.set(typeof v === 'boolean' ? v : null); }
|
|
769
|
+
get required() { return this.#required.get(); }
|
|
770
|
+
set required(v) { this.#selfRequired.set(typeof v === 'boolean' ? v : null); }
|
|
771
|
+
|
|
772
|
+
/** @readonly @type {Signal.State<boolean?>} */
|
|
773
|
+
#selfDisabled
|
|
774
|
+
/** @readonly @type {Signal.Computed<boolean>} */
|
|
775
|
+
#disabled
|
|
776
|
+
get selfDisabled() { return this.#selfDisabled.get(); }
|
|
777
|
+
set selfDisabled(v) { this.#selfDisabled.set(typeof v === 'boolean' ? v : null); }
|
|
778
|
+
get disabled() { return this.#disabled.get(); }
|
|
779
|
+
set disabled(v) { this.#selfDisabled.set(typeof v === 'boolean' ? v : null); }
|
|
780
|
+
|
|
781
|
+
/** @readonly @type {Signal.State<boolean?>} */
|
|
782
|
+
#selfReadonly
|
|
783
|
+
/** @readonly @type {Signal.Computed<boolean>} */
|
|
784
|
+
#readonly
|
|
785
|
+
get selfReadonly() { return this.#selfReadonly.get(); }
|
|
786
|
+
set selfReadonly(v) { this.#selfReadonly.set(typeof v === 'boolean' ? v : null); }
|
|
787
|
+
get readonly() { return this.#readonly.get(); }
|
|
788
|
+
set readonly(v) { this.#selfReadonly.set(typeof v === 'boolean' ? v : null); }
|
|
789
|
+
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
|
|
793
|
+
|
|
794
|
+
/** @returns {IterableIterator<[key: string | number, value: Store]>} */
|
|
795
|
+
*[Symbol.iterator]() {}
|
|
796
|
+
/**
|
|
797
|
+
*
|
|
798
|
+
* @param {string | number} key
|
|
799
|
+
* @returns {Store?}
|
|
800
|
+
*/
|
|
801
|
+
child(key) { return null; }
|
|
802
|
+
|
|
803
|
+
#set = false;
|
|
804
|
+
/** @type {T?} */
|
|
805
|
+
#initValue = null;
|
|
806
|
+
#lastValue = this.#initValue;
|
|
807
|
+
#value = new exports.Signal.State(this.#initValue);
|
|
808
|
+
|
|
809
|
+
|
|
810
|
+
#state = new exports.Signal.State(/** @type {any} */(null));
|
|
811
|
+
#lastState = this.#state.get();
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
get changed() { return this.#value.get() === this.#lastValue; }
|
|
815
|
+
get saved() { return this.#value.get() === this.#initValue; }
|
|
816
|
+
|
|
817
|
+
get value() { return this.#value.get(); }
|
|
818
|
+
set value(v) {
|
|
819
|
+
if (this.#destroyed) { return; }
|
|
820
|
+
const val = this.#setValue?.(v) || v;
|
|
821
|
+
this.#value.set(val);
|
|
822
|
+
if (!this.#set) {
|
|
823
|
+
this.#set = true;
|
|
824
|
+
this.#initValue = v;
|
|
825
|
+
}
|
|
826
|
+
this.#onUpdate?.(this.#value.get(), this.#index.get());
|
|
827
|
+
this.#requestUpdate();
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
get state() { return this.#state.get(); }
|
|
831
|
+
set state(v) {
|
|
832
|
+
if (this.#destroyed) { return; }
|
|
833
|
+
const sta = this.#setState?.(v) || v;
|
|
834
|
+
this.#state.set(sta);
|
|
835
|
+
this.#set = true;
|
|
836
|
+
this.#onUpdateState?.(this.#state.get(), this.#index.get());
|
|
837
|
+
this.#requestUpdate();
|
|
838
|
+
}
|
|
839
|
+
#requestUpdate() {
|
|
840
|
+
if (this.#needUpdate) { return; }
|
|
841
|
+
this.#needUpdate = true;
|
|
842
|
+
queueMicrotask(() => {
|
|
843
|
+
const oldValue = this.#value.get();
|
|
844
|
+
const oldState = this.#state.get();
|
|
845
|
+
return this.#runUpdate(oldValue, oldState);
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
|
|
850
|
+
#needUpdate = false;
|
|
851
|
+
/**
|
|
852
|
+
*
|
|
853
|
+
* @param {T} value
|
|
854
|
+
* @param {*} state
|
|
855
|
+
* @returns
|
|
856
|
+
*/
|
|
857
|
+
#toUpdate(value, state) {
|
|
858
|
+
if (this.#destroyed) { return value; }
|
|
859
|
+
const [val,sta] = this.#convert?.(value, state) || [value, state];
|
|
860
|
+
if(this.#value.get() === val && this.#state.get() === sta) { return [val,sta] }
|
|
861
|
+
this.#value.set(val);
|
|
862
|
+
this.#state.set(sta);
|
|
863
|
+
if (!this.#set) {
|
|
864
|
+
this.#set = true;
|
|
865
|
+
this.#initValue = val;
|
|
866
|
+
}
|
|
867
|
+
return this.#runUpdate(val, sta);
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
*
|
|
871
|
+
* @param {*} val
|
|
872
|
+
* @param {*} sta
|
|
873
|
+
* @returns
|
|
874
|
+
*/
|
|
875
|
+
#runUpdate(val, sta) {
|
|
876
|
+
if (this.#destroyed) { return [val, sta]; }
|
|
877
|
+
this.#needUpdate = false;
|
|
878
|
+
if (val && typeof val === 'object') {
|
|
879
|
+
/** @type {T} */
|
|
880
|
+
// @ts-ignore
|
|
881
|
+
let newValues = Array.isArray(val) ? [...val] : {...val};
|
|
882
|
+
let newStates = Array.isArray(val) ? Array.isArray(sta) ? [...sta] : [] : {...sta};
|
|
883
|
+
let updated = false;
|
|
884
|
+
for (const [key, field] of this) {
|
|
885
|
+
// @ts-ignore
|
|
886
|
+
const data = val[key];
|
|
887
|
+
const state = sta?.[key];
|
|
888
|
+
const [newData, newState] = field.#toUpdate(data, state);
|
|
889
|
+
if (data !== newData) {
|
|
890
|
+
// @ts-ignore
|
|
891
|
+
newValues[key] = newData;
|
|
892
|
+
updated = true;
|
|
893
|
+
}
|
|
894
|
+
if (state !== newState) {
|
|
895
|
+
newStates[key] = newState;
|
|
896
|
+
updated = true;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
if (updated) {
|
|
900
|
+
val = newValues;
|
|
901
|
+
sta = newStates;
|
|
902
|
+
this.#value.set(val);
|
|
903
|
+
this.#state.set(newStates);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
if (this.#lastValue === val && this.#lastState === sta) {
|
|
907
|
+
return [val, sta];
|
|
908
|
+
}
|
|
909
|
+
this.#lastValue = val;
|
|
910
|
+
this.#lastState = sta;
|
|
911
|
+
return [val, sta];
|
|
912
|
+
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
|
|
917
|
+
get destroyed() { return this.#destroyed; }
|
|
918
|
+
destroy() {
|
|
919
|
+
if (this.#destroyed) { return; }
|
|
920
|
+
this.#destroyed = true;
|
|
921
|
+
for (const [, field] of this) {
|
|
922
|
+
field.destroy();
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
|
|
929
|
+
|
|
930
|
+
class ObjectStore extends Store {
|
|
931
|
+
/** @type {Record<string, Store>} */
|
|
932
|
+
#children
|
|
933
|
+
*[Symbol.iterator]() {yield* Object.entries(this.#children);}
|
|
934
|
+
/**
|
|
935
|
+
*
|
|
936
|
+
* @param {string | number} key
|
|
937
|
+
* @returns {Store?}
|
|
938
|
+
*/
|
|
939
|
+
child(key) { return this.#children[key] || null; }
|
|
940
|
+
/**
|
|
941
|
+
* @param {Schema.Field} schema
|
|
942
|
+
* @param {object} [options]
|
|
943
|
+
* @param {Store?} [options.parent]
|
|
944
|
+
* @param {string | number} [options.index]
|
|
945
|
+
* @param {boolean} [options.new]
|
|
946
|
+
* @param {(value: any, index: any) => void} [options.onUpdate]
|
|
947
|
+
* @param {(value: any, index: any) => void} [options.onUpdateState]
|
|
948
|
+
*/
|
|
949
|
+
constructor(schema,{ parent, index, new: isNew, onUpdate, onUpdateState } = {}) {
|
|
950
|
+
super(schema, {
|
|
951
|
+
parent, index, new: isNew, onUpdate, onUpdateState,
|
|
952
|
+
setValue(v) {
|
|
953
|
+
if (typeof v !== 'object') { return {}; }
|
|
954
|
+
return v;
|
|
955
|
+
},
|
|
956
|
+
setState(v) {
|
|
957
|
+
if (typeof v !== 'object') { return {}; }
|
|
958
|
+
return v;
|
|
959
|
+
},
|
|
960
|
+
convert(v, state) {
|
|
961
|
+
return [
|
|
962
|
+
typeof v === 'object' ? v : {},
|
|
963
|
+
typeof state === 'object' ? state : {},
|
|
964
|
+
]
|
|
965
|
+
},
|
|
966
|
+
});
|
|
967
|
+
const children = Object.create(null);
|
|
968
|
+
const childCommonOptions = {
|
|
969
|
+
parent: this,
|
|
970
|
+
/** @param {*} value @param {*} index */
|
|
971
|
+
onUpdate: (value, index) => {
|
|
972
|
+
this.value = {...this.value, [index]: value};
|
|
973
|
+
},
|
|
974
|
+
/** @param {*} state @param {*} index */
|
|
975
|
+
onUpdateState: (state, index) => {
|
|
976
|
+
this.state = {...this.state, [index]: state};
|
|
977
|
+
}
|
|
978
|
+
};
|
|
979
|
+
|
|
980
|
+
for (const [index, field] of Object.entries(schema.props || {})) {
|
|
981
|
+
let child;
|
|
982
|
+
if (typeof field.type === 'string') {
|
|
983
|
+
if (field.array) {
|
|
984
|
+
child = new ArrayStore(field, {...childCommonOptions, index});
|
|
985
|
+
} else {
|
|
986
|
+
child = new Store(field, {...childCommonOptions, index});
|
|
987
|
+
}
|
|
988
|
+
} else if (field.array) {
|
|
989
|
+
child = new ArrayStore(field, {...childCommonOptions, index});
|
|
990
|
+
} else {
|
|
991
|
+
child = new ObjectStore(field, { ...childCommonOptions, index});
|
|
992
|
+
}
|
|
993
|
+
children[index] = child;
|
|
994
|
+
}
|
|
995
|
+
this.#children = children;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
/**
|
|
1000
|
+
* @template [T=any]
|
|
1001
|
+
* @extends {Store<(T | null)[]>}
|
|
1002
|
+
*/
|
|
1003
|
+
class ArrayStore extends Store {
|
|
1004
|
+
/** @type {(index: number, isNew?: boolean) => Store} */
|
|
1005
|
+
#create = () => {throw new Error}
|
|
1006
|
+
#children = new exports.Signal.State(/** @type {Store[]} */([]));
|
|
1007
|
+
get children() { return [...this.#children.get()]; }
|
|
1008
|
+
*[Symbol.iterator]() { return yield*[...this.#children.get().entries()]; }
|
|
1009
|
+
/**
|
|
1010
|
+
*
|
|
1011
|
+
* @param {string | number} key
|
|
1012
|
+
* @returns {Store?}
|
|
1013
|
+
*/
|
|
1014
|
+
child(key) {
|
|
1015
|
+
const children = this.#children.get();
|
|
1016
|
+
if (typeof key === 'number' && key < 0) {
|
|
1017
|
+
return children[children.length + key] || null;
|
|
1018
|
+
}
|
|
1019
|
+
return children[Number(key)] || null;
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* @param {Schema.Field} schema
|
|
1023
|
+
* @param {object} [options]
|
|
1024
|
+
* @param {Store?} [options.parent]
|
|
1025
|
+
* @param {string | number | null} [options.index]
|
|
1026
|
+
* @param {boolean} [options.new]
|
|
1027
|
+
* @param {(value: any, index: any) => void} [options.onUpdate]
|
|
1028
|
+
* @param {(value: any, index: any) => void} [options.onUpdateState]
|
|
1029
|
+
*/
|
|
1030
|
+
constructor(schema, { parent, onUpdate, onUpdateState, index, new: isNew} = {}) {
|
|
1031
|
+
// @ts-ignore
|
|
1032
|
+
const updateChildren = (list) => {
|
|
1033
|
+
if (this.destroyed) { return; }
|
|
1034
|
+
const length = Array.isArray(list) && list.length || 0;
|
|
1035
|
+
const children = [...this.#children.get()];
|
|
1036
|
+
const oldLength = children.length;
|
|
1037
|
+
for (let i = children.length; i < length; i++) {
|
|
1038
|
+
children.push(this.#create(i));
|
|
1039
|
+
}
|
|
1040
|
+
for (const schema of children.splice(length)) {
|
|
1041
|
+
schema.destroy();
|
|
1042
|
+
}
|
|
1043
|
+
if (oldLength !== length) {
|
|
1044
|
+
this.length = children.length;
|
|
1045
|
+
this.#children.set(children);
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
};
|
|
1049
|
+
super(schema, {
|
|
1050
|
+
index, new: isNew, parent,
|
|
1051
|
+
state: [],
|
|
1052
|
+
setValue(v) { return Array.isArray(v) ? v : v == null ? [] : [v] },
|
|
1053
|
+
setState(v) { return Array.isArray(v) ? v : v == null ? [] : [v] },
|
|
1054
|
+
convert(v, state) {
|
|
1055
|
+
const val = Array.isArray(v) ? v : v == null ? [] : [v];
|
|
1056
|
+
updateChildren(val);
|
|
1057
|
+
return [
|
|
1058
|
+
val,
|
|
1059
|
+
(Array.isArray(state) ? state : v == null ? [] : [state]),
|
|
1060
|
+
];
|
|
1061
|
+
},
|
|
1062
|
+
onUpdate:(value, index) => {
|
|
1063
|
+
updateChildren(value);
|
|
1064
|
+
onUpdate?.(value, index);
|
|
1065
|
+
},
|
|
1066
|
+
onUpdateState,
|
|
1067
|
+
});
|
|
1068
|
+
const childCommonOptions = {
|
|
1069
|
+
parent: this,
|
|
1070
|
+
/** @param {*} value @param {*} index */
|
|
1071
|
+
onUpdate: (value, index) => {
|
|
1072
|
+
const val = [...this.value || []];
|
|
1073
|
+
if (val.length < index) {
|
|
1074
|
+
val.length = index;
|
|
1075
|
+
}
|
|
1076
|
+
val[index] = value;
|
|
1077
|
+
this.value = val;
|
|
1078
|
+
},
|
|
1079
|
+
/** @param {*} state @param {*} index */
|
|
1080
|
+
onUpdateState: (state, index) => {
|
|
1081
|
+
const sta = [...this.state || []];
|
|
1082
|
+
if (sta.length < index) {
|
|
1083
|
+
sta.length = index;
|
|
1084
|
+
}
|
|
1085
|
+
sta[index] = state;
|
|
1086
|
+
this.state = sta;
|
|
1087
|
+
},
|
|
1088
|
+
};
|
|
1089
|
+
if (typeof schema.type === 'string') {
|
|
1090
|
+
this.#create = (index, isNew) => {
|
|
1091
|
+
const child = new Store(schema, {...childCommonOptions, index, new: isNew });
|
|
1092
|
+
child.index = index;
|
|
1093
|
+
return child
|
|
1094
|
+
};
|
|
1095
|
+
} else if (!Array.isArray(schema.props)) {
|
|
1096
|
+
this.#create = (index, isNew) => {
|
|
1097
|
+
const child = new ObjectStore(schema, { ...childCommonOptions, index, new: isNew});
|
|
1098
|
+
child.index = index;
|
|
1099
|
+
return child
|
|
1100
|
+
};
|
|
1101
|
+
} else {
|
|
1102
|
+
throw new Error();
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
*
|
|
1108
|
+
* @param {number} index
|
|
1109
|
+
* @param {T} value
|
|
1110
|
+
* @param {boolean} [isNew]
|
|
1111
|
+
* @returns
|
|
1112
|
+
*/
|
|
1113
|
+
insert(index, value, isNew) {
|
|
1114
|
+
if (this.destroyed) { return false; }
|
|
1115
|
+
const data = this.value;
|
|
1116
|
+
if (!Array.isArray(data)) { return false; }
|
|
1117
|
+
const children = [...this.#children.get()];
|
|
1118
|
+
const insertIndex = Math.max(0, Math.min(Math.floor(index), children.length));
|
|
1119
|
+
const item = this.#create(insertIndex, isNew);
|
|
1120
|
+
item.new = true;
|
|
1121
|
+
children.splice(insertIndex, 0, item);
|
|
1122
|
+
for (let i = index + 1; i < children.length; i++) {
|
|
1123
|
+
children[i].index = i;
|
|
1124
|
+
}
|
|
1125
|
+
const val = [...data];
|
|
1126
|
+
val.splice(insertIndex, 0, value);
|
|
1127
|
+
const state = this.state;
|
|
1128
|
+
if (Array.isArray(state)) {
|
|
1129
|
+
const sta = [...state];
|
|
1130
|
+
sta.splice(insertIndex, 0, {});
|
|
1131
|
+
this.state = sta;
|
|
1132
|
+
}
|
|
1133
|
+
this.value = val;
|
|
1134
|
+
this.length = children.length;
|
|
1135
|
+
this.#children.set(children);
|
|
1136
|
+
return true;
|
|
1137
|
+
}
|
|
1138
|
+
/**
|
|
1139
|
+
*
|
|
1140
|
+
* @param {T} value
|
|
1141
|
+
* @returns
|
|
1142
|
+
*/
|
|
1143
|
+
add(value) {
|
|
1144
|
+
return this.insert(this.#children.get().length, value);
|
|
1145
|
+
}
|
|
1146
|
+
/**
|
|
1147
|
+
*
|
|
1148
|
+
* @param {number} index
|
|
1149
|
+
* @returns
|
|
1150
|
+
*/
|
|
1151
|
+
remove(index) {
|
|
1152
|
+
if (this.destroyed) { return; }
|
|
1153
|
+
const data = this.value;
|
|
1154
|
+
if (!Array.isArray(data)) { return; }
|
|
1155
|
+
const children = [...this.#children.get()];
|
|
1156
|
+
const removeIndex = Math.max(0, Math.min(Math.floor(index), children.length));
|
|
1157
|
+
const [item] = children.splice(removeIndex, 1);
|
|
1158
|
+
if (!item) { return; }
|
|
1159
|
+
for (let i = index; i < children.length; i++) {
|
|
1160
|
+
children[i].index = i;
|
|
1161
|
+
}
|
|
1162
|
+
item.destroy();
|
|
1163
|
+
const val = [...data];
|
|
1164
|
+
const [value] = val.splice(removeIndex, 1);
|
|
1165
|
+
const state = this.state;
|
|
1166
|
+
if (Array.isArray(state)) {
|
|
1167
|
+
const sta = [...this.state];
|
|
1168
|
+
sta.splice(removeIndex, 1);
|
|
1169
|
+
this.state = sta;
|
|
1170
|
+
}
|
|
1171
|
+
this.value = val;
|
|
1172
|
+
this.length = children.length;
|
|
1173
|
+
this.#children.set(children);
|
|
1174
|
+
return value;
|
|
1175
|
+
|
|
1176
|
+
}
|
|
1177
|
+
/**
|
|
1178
|
+
*
|
|
1179
|
+
* @param {number} from
|
|
1180
|
+
* @param {number} to
|
|
1181
|
+
* @returns
|
|
1182
|
+
*/
|
|
1183
|
+
move(from, to) {
|
|
1184
|
+
if (this.destroyed) { return false; }
|
|
1185
|
+
const data = this.value;
|
|
1186
|
+
if (!Array.isArray(data)) { return false; }
|
|
1187
|
+
const children = [...this.#children.get()];
|
|
1188
|
+
const [item] = children.splice(from, 1);
|
|
1189
|
+
if (!item) { return false; }
|
|
1190
|
+
children.splice(to, 0, item);
|
|
1191
|
+
let lft = Math.min(from, to);
|
|
1192
|
+
let rgt = Math.max(from, to);
|
|
1193
|
+
for (let i = lft; i <= rgt; i++) {
|
|
1194
|
+
children[i].index = i;
|
|
1195
|
+
}
|
|
1196
|
+
const val = [...data];
|
|
1197
|
+
const [value] = val.splice(from, 1);
|
|
1198
|
+
val.splice(to, 0, value);
|
|
1199
|
+
const state = this.state;
|
|
1200
|
+
if (Array.isArray(state)) {
|
|
1201
|
+
const sta = [...state];
|
|
1202
|
+
const [value = {}] = sta.splice(from, 1);
|
|
1203
|
+
if (to <= sta.length) {
|
|
1204
|
+
sta.splice(to, 0, value);
|
|
1205
|
+
} else {
|
|
1206
|
+
sta[to] = value;
|
|
1207
|
+
}
|
|
1208
|
+
this.state = sta;
|
|
1209
|
+
}
|
|
1210
|
+
this.value = val;
|
|
1211
|
+
this.#children.set(children);
|
|
1212
|
+
return true;
|
|
1213
|
+
|
|
1214
|
+
}
|
|
1215
|
+
/**
|
|
1216
|
+
*
|
|
1217
|
+
* @param {number} a
|
|
1218
|
+
* @param {number} b
|
|
1219
|
+
* @returns
|
|
1220
|
+
*/
|
|
1221
|
+
exchange(a, b) {
|
|
1222
|
+
if (this.destroyed) { return false; }
|
|
1223
|
+
const data = this.value;
|
|
1224
|
+
if (!Array.isArray(data)) { return false; }
|
|
1225
|
+
const children = [...this.#children.get()];
|
|
1226
|
+
const aItem = children[a];
|
|
1227
|
+
const bItem = children[b];
|
|
1228
|
+
if (!aItem || !bItem) { return false; }
|
|
1229
|
+
children[b] = aItem;
|
|
1230
|
+
children[a] = bItem;
|
|
1231
|
+
aItem.index = b;
|
|
1232
|
+
bItem.index = a;
|
|
1233
|
+
const val = [...data];
|
|
1234
|
+
const aValue = val[a];
|
|
1235
|
+
const bValue = val[b];
|
|
1236
|
+
val[b] = aValue;
|
|
1237
|
+
val[a] = bValue;
|
|
1238
|
+
const state = this.state;
|
|
1239
|
+
if (Array.isArray(state)) {
|
|
1240
|
+
const sta = [...state];
|
|
1241
|
+
const aValue = sta[a];
|
|
1242
|
+
const bValue = sta[b];
|
|
1243
|
+
sta[b] = aValue;
|
|
1244
|
+
sta[a] = bValue;
|
|
1245
|
+
this.state = sta;
|
|
1246
|
+
}
|
|
1247
|
+
this.value = val;
|
|
1248
|
+
this.#children.set(children);
|
|
1249
|
+
return true;
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
const errors = {
|
|
1254
|
+
CALC: 'no `creteCalc` option, no expression parsing support',
|
|
1255
|
+
EVENT: 'no `creteEvent`, options, no event parsing support',
|
|
1256
|
+
/** @param {string} endTag @param {string} startTag */
|
|
1257
|
+
CLOSE: (endTag, startTag) => `end tag name: ${endTag} is not match the current start tagName: ${startTag}`,
|
|
1258
|
+
/** @param {string} name */
|
|
1259
|
+
UNCLOSE: (name) => `end tag name: ${name} maybe not complete`,
|
|
1260
|
+
/** @param {string} char */
|
|
1261
|
+
QUOTE: (char) => `attribute value no end \'${char}\' match`,
|
|
1262
|
+
CLOSE_SYMBOL: `elements closed character '/' and '>' must be connected to`,
|
|
1263
|
+
/** @param {string} endTag @param {string} [startTag] */
|
|
1264
|
+
UNCOMPLETED: (endTag, startTag) => startTag
|
|
1265
|
+
? `end tag name: ${endTag} is not complete: ${startTag}`
|
|
1266
|
+
: `end tag name: ${endTag} maybe not complete`,
|
|
1267
|
+
/** @param {string} entity */
|
|
1268
|
+
ENTITY: entity => `entity not found: ${entity}`,
|
|
1269
|
+
/** @param {string} symbol */
|
|
1270
|
+
SYMBOL: symbol => `unexpected symbol: ${symbol}`,
|
|
1271
|
+
/** @param {string} tag */
|
|
1272
|
+
TAG: tag => `invalid tagName: ${tag}`,
|
|
1273
|
+
/** @param {string} attr */
|
|
1274
|
+
ATTR: attr => `invalid attribute: ${attr}`,
|
|
1275
|
+
EQUAL: 'attribute equal must after attrName',
|
|
1276
|
+
ATTR_VALUE: 'attribute value must after "="',
|
|
1277
|
+
EOF: `unexpected end of file`,
|
|
1278
|
+
};
|
|
1279
|
+
class ParseError extends Error {
|
|
1280
|
+
/**
|
|
1281
|
+
* @param {keyof typeof errors} code
|
|
1282
|
+
* @param {...*} p
|
|
1283
|
+
*/
|
|
1284
|
+
constructor(code, ...p) {
|
|
1285
|
+
/** @type {*} */
|
|
1286
|
+
const f = errors[code];
|
|
1287
|
+
if (typeof f === 'function') {
|
|
1288
|
+
super(f(...p));
|
|
1289
|
+
|
|
1290
|
+
} else {
|
|
1291
|
+
super(f);
|
|
1292
|
+
}
|
|
1293
|
+
this.code = code;
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
/** @import * as Layout from './index.mjs' */
|
|
1298
|
+
|
|
1299
|
+
const attrPattern = /^(?<decorator>[:@!+*\.]|style:|样式:)?(?<name>-?[\w\p{Unified_Ideograph}_][-\w\p{Unified_Ideograph}_:\d\.]*)$/u;
|
|
1300
|
+
const nameRegex = /^(?<name>[a-zA-Z$\p{Unified_Ideograph}_][\da-zA-Z$\p{Unified_Ideograph}_]*)?$/u;
|
|
1301
|
+
/**
|
|
1302
|
+
* @param {Layout.Node} node
|
|
1303
|
+
* @param {Exclude<Layout.Options['creteCalc'], undefined>} creteCalc
|
|
1304
|
+
* @param {Exclude<Layout.Options['creteEvent'], undefined>} creteEvent
|
|
1305
|
+
*/
|
|
1306
|
+
function createAttributeAdder(node, creteCalc, creteEvent) {
|
|
1307
|
+
const { attrs, directives, events, classes, styles, vars, aliases } = node;
|
|
1308
|
+
/**
|
|
1309
|
+
* @param {string} qName
|
|
1310
|
+
* @param {string} value
|
|
1311
|
+
*/
|
|
1312
|
+
function addAttribute(qName, value) {
|
|
1313
|
+
const attr = attrPattern.exec(qName
|
|
1314
|
+
.replace(/./g,'.')
|
|
1315
|
+
.replace(/:/g,':')
|
|
1316
|
+
.replace(/@/g,'@')
|
|
1317
|
+
.replace(/+/g,'+')
|
|
1318
|
+
.replace(/-/g,'-')
|
|
1319
|
+
.replace(/[*×]/g,'*')
|
|
1320
|
+
.replace(/!/g, '!'))?.groups;
|
|
1321
|
+
if (!attr) { throw new ParseError('ATTR', qName); }
|
|
1322
|
+
const { name } = attr;
|
|
1323
|
+
const decorator = attr.decorator?.toLowerCase();
|
|
1324
|
+
if (!decorator) {
|
|
1325
|
+
attrs[name] = value;
|
|
1326
|
+
} else if (decorator === ':') {
|
|
1327
|
+
attrs[name] = nameRegex.test(value) ? {name: value} : creteCalc(value);
|
|
1328
|
+
} else if (decorator === '.') {
|
|
1329
|
+
classes[name] = !value ? true : nameRegex.test(value) ? value : creteCalc(value);
|
|
1330
|
+
} else if (decorator === 'style:') {
|
|
1331
|
+
styles[name] = nameRegex.test(value) ? value : creteCalc(value);
|
|
1332
|
+
} else if (decorator === '@') {
|
|
1333
|
+
events[name] = nameRegex.test(value) ? value : creteEvent(value);
|
|
1334
|
+
} else if (decorator === '+') {
|
|
1335
|
+
vars[name] = !value ? '' : nameRegex.test(value) ? value : creteCalc(value);
|
|
1336
|
+
} else if (decorator === '*') {
|
|
1337
|
+
aliases[name] = nameRegex.test(value) ? value : creteEvent(value);
|
|
1338
|
+
} else if (decorator === '!') {
|
|
1339
|
+
const key = name.toString();
|
|
1340
|
+
switch (key) {
|
|
1341
|
+
case 'fragment':
|
|
1342
|
+
case 'else':
|
|
1343
|
+
case 'enum':
|
|
1344
|
+
directives[key] = true;
|
|
1345
|
+
break;
|
|
1346
|
+
case 'if':
|
|
1347
|
+
case 'text':
|
|
1348
|
+
case 'html':
|
|
1349
|
+
directives[key] = nameRegex.test(value) ? value : creteCalc(value);
|
|
1350
|
+
break;
|
|
1351
|
+
case 'bind':
|
|
1352
|
+
case 'value':
|
|
1353
|
+
case 'comment':
|
|
1354
|
+
directives[key] = value;
|
|
1355
|
+
break;
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
return addAttribute;
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
/** @import * as Layout from './index.mjs' */
|
|
1363
|
+
|
|
1364
|
+
/**
|
|
1365
|
+
* @param {string} name
|
|
1366
|
+
* @param {string?} [is]
|
|
1367
|
+
* @returns {Layout.Node}
|
|
1368
|
+
*
|
|
1369
|
+
*/
|
|
1370
|
+
function createElement(name, is) {
|
|
1371
|
+
return {
|
|
1372
|
+
name,
|
|
1373
|
+
is,
|
|
1374
|
+
children: [],
|
|
1375
|
+
attrs: Object.create(null),
|
|
1376
|
+
events: Object.create(null),
|
|
1377
|
+
directives: Object.create(null),
|
|
1378
|
+
classes: Object.create(null),
|
|
1379
|
+
styles: Object.create(null),
|
|
1380
|
+
vars: Object.create(null),
|
|
1381
|
+
aliases: Object.create(null),
|
|
1382
|
+
};
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
/** @type {Record<string, string>} */
|
|
1386
|
+
var entityMap = {
|
|
1387
|
+
lt: '<',
|
|
1388
|
+
gt: '>',
|
|
1389
|
+
amp: '&',
|
|
1390
|
+
quot: '"',
|
|
1391
|
+
apos: "'",
|
|
1392
|
+
|
|
1393
|
+
Agrave: 'À',
|
|
1394
|
+
Aacute: 'Á',
|
|
1395
|
+
Acirc: 'Â',
|
|
1396
|
+
Atilde: 'Ã',
|
|
1397
|
+
Auml: 'Ä',
|
|
1398
|
+
Aring: 'Å',
|
|
1399
|
+
AElig: 'Æ',
|
|
1400
|
+
Ccedil: 'Ç',
|
|
1401
|
+
Egrave: 'È',
|
|
1402
|
+
Eacute: 'É',
|
|
1403
|
+
Ecirc: 'Ê',
|
|
1404
|
+
Euml: 'Ë',
|
|
1405
|
+
Igrave: 'Ì',
|
|
1406
|
+
Iacute: 'Í',
|
|
1407
|
+
Icirc: 'Î',
|
|
1408
|
+
Iuml: 'Ï',
|
|
1409
|
+
ETH: 'Ð',
|
|
1410
|
+
Ntilde: 'Ñ',
|
|
1411
|
+
Ograve: 'Ò',
|
|
1412
|
+
Oacute: 'Ó',
|
|
1413
|
+
Ocirc: 'Ô',
|
|
1414
|
+
Otilde: 'Õ',
|
|
1415
|
+
Ouml: 'Ö',
|
|
1416
|
+
Oslash: 'Ø',
|
|
1417
|
+
Ugrave: 'Ù',
|
|
1418
|
+
Uacute: 'Ú',
|
|
1419
|
+
Ucirc: 'Û',
|
|
1420
|
+
Uuml: 'Ü',
|
|
1421
|
+
Yacute: 'Ý',
|
|
1422
|
+
THORN: 'Þ',
|
|
1423
|
+
szlig: 'ß',
|
|
1424
|
+
agrave: 'à',
|
|
1425
|
+
aacute: 'á',
|
|
1426
|
+
acirc: 'â',
|
|
1427
|
+
atilde: 'ã',
|
|
1428
|
+
auml: 'ä',
|
|
1429
|
+
aring: 'å',
|
|
1430
|
+
aelig: 'æ',
|
|
1431
|
+
ccedil: 'ç',
|
|
1432
|
+
egrave: 'è',
|
|
1433
|
+
eacute: 'é',
|
|
1434
|
+
ecirc: 'ê',
|
|
1435
|
+
euml: 'ë',
|
|
1436
|
+
igrave: 'ì',
|
|
1437
|
+
iacute: 'í',
|
|
1438
|
+
icirc: 'î',
|
|
1439
|
+
iuml: 'ï',
|
|
1440
|
+
eth: 'ð',
|
|
1441
|
+
ntilde: 'ñ',
|
|
1442
|
+
ograve: 'ò',
|
|
1443
|
+
oacute: 'ó',
|
|
1444
|
+
ocirc: 'ô',
|
|
1445
|
+
otilde: 'õ',
|
|
1446
|
+
ouml: 'ö',
|
|
1447
|
+
oslash: 'ø',
|
|
1448
|
+
ugrave: 'ù',
|
|
1449
|
+
uacute: 'ú',
|
|
1450
|
+
ucirc: 'û',
|
|
1451
|
+
uuml: 'ü',
|
|
1452
|
+
yacute: 'ý',
|
|
1453
|
+
thorn: 'þ',
|
|
1454
|
+
yuml: 'ÿ',
|
|
1455
|
+
nbsp: '\u00a0',
|
|
1456
|
+
iexcl: '¡',
|
|
1457
|
+
cent: '¢',
|
|
1458
|
+
pound: '£',
|
|
1459
|
+
curren: '¤',
|
|
1460
|
+
yen: '¥',
|
|
1461
|
+
brvbar: '¦',
|
|
1462
|
+
sect: '§',
|
|
1463
|
+
uml: '¨',
|
|
1464
|
+
copy: '©',
|
|
1465
|
+
ordf: 'ª',
|
|
1466
|
+
laquo: '«',
|
|
1467
|
+
not: '¬',
|
|
1468
|
+
shy: '',
|
|
1469
|
+
reg: '®',
|
|
1470
|
+
macr: '¯',
|
|
1471
|
+
deg: '°',
|
|
1472
|
+
plusmn: '±',
|
|
1473
|
+
sup2: '²',
|
|
1474
|
+
sup3: '³',
|
|
1475
|
+
acute: '´',
|
|
1476
|
+
micro: 'µ',
|
|
1477
|
+
para: '¶',
|
|
1478
|
+
middot: '·',
|
|
1479
|
+
cedil: '¸',
|
|
1480
|
+
sup1: '¹',
|
|
1481
|
+
ordm: 'º',
|
|
1482
|
+
raquo: '»',
|
|
1483
|
+
frac14: '¼',
|
|
1484
|
+
frac12: '½',
|
|
1485
|
+
frac34: '¾',
|
|
1486
|
+
iquest: '¿',
|
|
1487
|
+
times: '×',
|
|
1488
|
+
divide: '÷',
|
|
1489
|
+
forall: '∀',
|
|
1490
|
+
part: '∂',
|
|
1491
|
+
exist: '∃',
|
|
1492
|
+
empty: '∅',
|
|
1493
|
+
nabla: '∇',
|
|
1494
|
+
isin: '∈',
|
|
1495
|
+
notin: '∉',
|
|
1496
|
+
ni: '∋',
|
|
1497
|
+
prod: '∏',
|
|
1498
|
+
sum: '∑',
|
|
1499
|
+
minus: '−',
|
|
1500
|
+
lowast: '∗',
|
|
1501
|
+
radic: '√',
|
|
1502
|
+
prop: '∝',
|
|
1503
|
+
infin: '∞',
|
|
1504
|
+
ang: '∠',
|
|
1505
|
+
and: '∧',
|
|
1506
|
+
or: '∨',
|
|
1507
|
+
cap: '∩',
|
|
1508
|
+
cup: '∪',
|
|
1509
|
+
'int': '∫',
|
|
1510
|
+
there4: '∴',
|
|
1511
|
+
sim: '∼',
|
|
1512
|
+
cong: '≅',
|
|
1513
|
+
asymp: '≈',
|
|
1514
|
+
ne: '≠',
|
|
1515
|
+
equiv: '≡',
|
|
1516
|
+
le: '≤',
|
|
1517
|
+
ge: '≥',
|
|
1518
|
+
sub: '⊂',
|
|
1519
|
+
sup: '⊃',
|
|
1520
|
+
nsub: '⊄',
|
|
1521
|
+
sube: '⊆',
|
|
1522
|
+
supe: '⊇',
|
|
1523
|
+
oplus: '⊕',
|
|
1524
|
+
otimes: '⊗',
|
|
1525
|
+
perp: '⊥',
|
|
1526
|
+
sdot: '⋅',
|
|
1527
|
+
Alpha: 'Α',
|
|
1528
|
+
Beta: 'Β',
|
|
1529
|
+
Gamma: 'Γ',
|
|
1530
|
+
Delta: 'Δ',
|
|
1531
|
+
Epsilon: 'Ε',
|
|
1532
|
+
Zeta: 'Ζ',
|
|
1533
|
+
Eta: 'Η',
|
|
1534
|
+
Theta: 'Θ',
|
|
1535
|
+
Iota: 'Ι',
|
|
1536
|
+
Kappa: 'Κ',
|
|
1537
|
+
Lambda: 'Λ',
|
|
1538
|
+
Mu: 'Μ',
|
|
1539
|
+
Nu: 'Ν',
|
|
1540
|
+
Xi: 'Ξ',
|
|
1541
|
+
Omicron: 'Ο',
|
|
1542
|
+
Pi: 'Π',
|
|
1543
|
+
Rho: 'Ρ',
|
|
1544
|
+
Sigma: 'Σ',
|
|
1545
|
+
Tau: 'Τ',
|
|
1546
|
+
Upsilon: 'Υ',
|
|
1547
|
+
Phi: 'Φ',
|
|
1548
|
+
Chi: 'Χ',
|
|
1549
|
+
Psi: 'Ψ',
|
|
1550
|
+
Omega: 'Ω',
|
|
1551
|
+
alpha: 'α',
|
|
1552
|
+
beta: 'β',
|
|
1553
|
+
gamma: 'γ',
|
|
1554
|
+
delta: 'δ',
|
|
1555
|
+
epsilon: 'ε',
|
|
1556
|
+
zeta: 'ζ',
|
|
1557
|
+
eta: 'η',
|
|
1558
|
+
theta: 'θ',
|
|
1559
|
+
iota: 'ι',
|
|
1560
|
+
kappa: 'κ',
|
|
1561
|
+
lambda: 'λ',
|
|
1562
|
+
mu: 'μ',
|
|
1563
|
+
nu: 'ν',
|
|
1564
|
+
xi: 'ξ',
|
|
1565
|
+
omicron: 'ο',
|
|
1566
|
+
pi: 'π',
|
|
1567
|
+
rho: 'ρ',
|
|
1568
|
+
sigmaf: 'ς',
|
|
1569
|
+
sigma: 'σ',
|
|
1570
|
+
tau: 'τ',
|
|
1571
|
+
upsilon: 'υ',
|
|
1572
|
+
phi: 'φ',
|
|
1573
|
+
chi: 'χ',
|
|
1574
|
+
psi: 'ψ',
|
|
1575
|
+
omega: 'ω',
|
|
1576
|
+
thetasym: 'ϑ',
|
|
1577
|
+
upsih: 'ϒ',
|
|
1578
|
+
piv: 'ϖ',
|
|
1579
|
+
OElig: 'Œ',
|
|
1580
|
+
oelig: 'œ',
|
|
1581
|
+
Scaron: 'Š',
|
|
1582
|
+
scaron: 'š',
|
|
1583
|
+
Yuml: 'Ÿ',
|
|
1584
|
+
fnof: 'ƒ',
|
|
1585
|
+
circ: 'ˆ',
|
|
1586
|
+
tilde: '˜',
|
|
1587
|
+
ensp: ' ',
|
|
1588
|
+
emsp: ' ',
|
|
1589
|
+
thinsp: ' ',
|
|
1590
|
+
zwnj: '',
|
|
1591
|
+
zwj: '',
|
|
1592
|
+
lrm: '',
|
|
1593
|
+
rlm: '',
|
|
1594
|
+
ndash: '–',
|
|
1595
|
+
mdash: '—',
|
|
1596
|
+
lsquo: '‘',
|
|
1597
|
+
rsquo: '’',
|
|
1598
|
+
sbquo: '‚',
|
|
1599
|
+
ldquo: '“',
|
|
1600
|
+
rdquo: '”',
|
|
1601
|
+
bdquo: '„',
|
|
1602
|
+
dagger: '†',
|
|
1603
|
+
Dagger: '‡',
|
|
1604
|
+
bull: '•',
|
|
1605
|
+
hellip: '…',
|
|
1606
|
+
permil: '‰',
|
|
1607
|
+
prime: '′',
|
|
1608
|
+
Prime: '″',
|
|
1609
|
+
lsaquo: '‹',
|
|
1610
|
+
rsaquo: '›',
|
|
1611
|
+
oline: '‾',
|
|
1612
|
+
euro: '€',
|
|
1613
|
+
trade: '™',
|
|
1614
|
+
larr: '←',
|
|
1615
|
+
uarr: '↑',
|
|
1616
|
+
rarr: '→',
|
|
1617
|
+
darr: '↓',
|
|
1618
|
+
harr: '↔',
|
|
1619
|
+
crarr: '↵',
|
|
1620
|
+
lceil: '⌈',
|
|
1621
|
+
rceil: '⌉',
|
|
1622
|
+
lfloor: '⌊',
|
|
1623
|
+
rfloor: '⌋',
|
|
1624
|
+
loz: '◊',
|
|
1625
|
+
spades: '♠',
|
|
1626
|
+
clubs: '♣',
|
|
1627
|
+
hearts: '♥',
|
|
1628
|
+
diams: '♦'
|
|
1629
|
+
};
|
|
1630
|
+
|
|
1631
|
+
/** @import * as Layout from './index.mjs' */
|
|
1632
|
+
|
|
1633
|
+
const tagNamePattern = /^(?<name>[\w\p{Unified_Ideograph}_][-\.\|:|d\w\p{Unified_Ideograph}_:]*)(?:|(?<is>[\w\p{Unified_Ideograph}_][-\.\|:|d\w\p{Unified_Ideograph}_]*))?$/u;
|
|
1634
|
+
|
|
1635
|
+
/**
|
|
1636
|
+
*
|
|
1637
|
+
* @param {string} c
|
|
1638
|
+
* @returns
|
|
1639
|
+
*/
|
|
1640
|
+
function isSpace(c) {
|
|
1641
|
+
return c === '0x80' || c <= ' ';
|
|
1642
|
+
}
|
|
1643
|
+
/**
|
|
1644
|
+
*
|
|
1645
|
+
* @param {string} c
|
|
1646
|
+
* @returns
|
|
1647
|
+
*/
|
|
1648
|
+
function isIdCode(c) {
|
|
1649
|
+
return c !== '=' && c !== '/' && c !== '>' && c && c !== '\'' && c !== '"' && !isSpace(c);
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
/**
|
|
1653
|
+
*
|
|
1654
|
+
* @param {string} source
|
|
1655
|
+
* @param {number} elStartEnd
|
|
1656
|
+
* @param {string} name
|
|
1657
|
+
* @param {*} closeMap
|
|
1658
|
+
* @returns
|
|
1659
|
+
*/
|
|
1660
|
+
function fixSelfClosed(source, elStartEnd, name, closeMap) {
|
|
1661
|
+
let pos = closeMap[name];
|
|
1662
|
+
if (pos == null) {
|
|
1663
|
+
pos = source.lastIndexOf('</' + name + '>');
|
|
1664
|
+
if (pos < elStartEnd) {
|
|
1665
|
+
pos = source.lastIndexOf('</' + name);
|
|
1666
|
+
}
|
|
1667
|
+
closeMap[name] = pos;
|
|
1668
|
+
}
|
|
1669
|
+
return pos < elStartEnd;
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
/**
|
|
1673
|
+
* @param {ConstructorParameters<typeof ParseError>} p
|
|
1674
|
+
*/
|
|
1675
|
+
function error(...p) {
|
|
1676
|
+
console.error(new ParseError(...p));
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
/**
|
|
1680
|
+
*
|
|
1681
|
+
* @param {string} a
|
|
1682
|
+
* @returns {string}
|
|
1683
|
+
*/
|
|
1684
|
+
function entityReplacer(a) {
|
|
1685
|
+
const k = a.slice(1, -1);
|
|
1686
|
+
if (k.charAt(0) === '#') {
|
|
1687
|
+
return String.fromCodePoint(parseInt(k.substring(1).replace('x', '0x')));
|
|
1688
|
+
}
|
|
1689
|
+
if (k in entityMap) { return entityMap[k]; }
|
|
1690
|
+
error('ENTITY', a);
|
|
1691
|
+
return a;
|
|
1692
|
+
}
|
|
1693
|
+
/**
|
|
1694
|
+
*
|
|
1695
|
+
* @param {string} source
|
|
1696
|
+
* @param {Layout.Options} [options]
|
|
1697
|
+
* @returns {(Layout.Node | string)[]}
|
|
1698
|
+
*/
|
|
1699
|
+
function parse(source, {
|
|
1700
|
+
creteCalc = () => { throw new ParseError('CALC'); },
|
|
1701
|
+
creteEvent = () => { throw new ParseError('EVENT'); },
|
|
1702
|
+
simpleTag = new Set,
|
|
1703
|
+
} = {}) {
|
|
1704
|
+
/** @type {(Layout.Node | string)[]} */
|
|
1705
|
+
const children = [];
|
|
1706
|
+
|
|
1707
|
+
const doc = { children };
|
|
1708
|
+
/** @type {(Layout.Node | null)[]} */
|
|
1709
|
+
const stack = [];
|
|
1710
|
+
/** @type {Layout.Node?} */
|
|
1711
|
+
let currentNode = null;
|
|
1712
|
+
/** @type {typeof doc | Layout.Node} */
|
|
1713
|
+
let current = doc;
|
|
1714
|
+
function endElement() {
|
|
1715
|
+
currentNode = stack.pop() || null;
|
|
1716
|
+
current = currentNode || doc;
|
|
1717
|
+
}
|
|
1718
|
+
/**
|
|
1719
|
+
*
|
|
1720
|
+
* @param {string} chars
|
|
1721
|
+
* @returns
|
|
1722
|
+
*/
|
|
1723
|
+
function characters(chars) {
|
|
1724
|
+
chars = chars.replace(/^\n|(?<=\n)\t+|\n\t*$/g, '');
|
|
1725
|
+
if (!chars) { return; }
|
|
1726
|
+
current.children.push(chars);
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
let closeMap = {};
|
|
1730
|
+
let index = 0;
|
|
1731
|
+
/**
|
|
1732
|
+
*
|
|
1733
|
+
* @param {number} end
|
|
1734
|
+
*/
|
|
1735
|
+
function appendText(end) {
|
|
1736
|
+
if (end <= index) { return; }
|
|
1737
|
+
const xt = source.substring(index, end).replace(/&#?\w+;/g, entityReplacer);
|
|
1738
|
+
characters(xt);
|
|
1739
|
+
index = end;
|
|
1740
|
+
}
|
|
1741
|
+
for (; ;) {
|
|
1742
|
+
const tagStart = source.indexOf('<', index);
|
|
1743
|
+
if (tagStart < 0) {
|
|
1744
|
+
const text = source.substring(index);
|
|
1745
|
+
if (!text.match(/^\s*$/)) {
|
|
1746
|
+
characters(text);
|
|
1747
|
+
}
|
|
1748
|
+
break;
|
|
1749
|
+
}
|
|
1750
|
+
if (tagStart > index) {
|
|
1751
|
+
appendText(tagStart);
|
|
1752
|
+
}
|
|
1753
|
+
if (source.charAt(tagStart + 1) === '/') {
|
|
1754
|
+
index = source.indexOf('>', tagStart + 3);
|
|
1755
|
+
let name = source.substring(tagStart + 2, index);
|
|
1756
|
+
if (index < 0) {
|
|
1757
|
+
name = source.substring(tagStart + 2).replace(/[\s<].*/, '');
|
|
1758
|
+
error('UNCOMPLETED', name, currentNode?.name);
|
|
1759
|
+
index = tagStart + 1 + name.length;
|
|
1760
|
+
} else if (name.match(/\s</)) {
|
|
1761
|
+
name = name.replace(/[\s<].*/, '');
|
|
1762
|
+
error('UNCOMPLETED', name);
|
|
1763
|
+
index = tagStart + 1 + name.length;
|
|
1764
|
+
}
|
|
1765
|
+
if (currentNode) {
|
|
1766
|
+
const currentName = currentNode.name;
|
|
1767
|
+
if (currentName === name) {
|
|
1768
|
+
endElement();
|
|
1769
|
+
} else if (currentName.toLowerCase() == name.toLowerCase()) {
|
|
1770
|
+
endElement();
|
|
1771
|
+
} else {
|
|
1772
|
+
throw new ParseError('CLOSE', name, currentNode.name);
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
index++;
|
|
1776
|
+
continue;
|
|
1777
|
+
}
|
|
1778
|
+
index = tagStart + 1;
|
|
1779
|
+
/**
|
|
1780
|
+
*
|
|
1781
|
+
* @param {string} c
|
|
1782
|
+
* @returns
|
|
1783
|
+
*/
|
|
1784
|
+
function getQuote(c) {
|
|
1785
|
+
let start = index + 1;
|
|
1786
|
+
index = source.indexOf(c, start);
|
|
1787
|
+
if (index < 0) { throw new ParseError('QUOTE', c); }
|
|
1788
|
+
const value = source.slice(start, index).replace(/&#?\w+;/g, entityReplacer);
|
|
1789
|
+
index++;
|
|
1790
|
+
return value;
|
|
1791
|
+
}
|
|
1792
|
+
function skipSpace() {
|
|
1793
|
+
let c = source.charAt(index);
|
|
1794
|
+
for (; c <= ' ' || c === '\u0080'; c = source.charAt(++index)) { }
|
|
1795
|
+
return c;
|
|
1796
|
+
|
|
1797
|
+
}
|
|
1798
|
+
function getId() {
|
|
1799
|
+
let start = index;
|
|
1800
|
+
let c = source.charAt(index);
|
|
1801
|
+
while (isIdCode(c)) {
|
|
1802
|
+
index++;
|
|
1803
|
+
c = source.charAt(index);
|
|
1804
|
+
}
|
|
1805
|
+
return source.slice(start, index);
|
|
1806
|
+
}
|
|
1807
|
+
let c = source.charAt(index);
|
|
1808
|
+
switch (c) {
|
|
1809
|
+
case '=': throw new ParseError('EQUAL');
|
|
1810
|
+
case '"': case '\'': throw new ParseError('ATTR_VALUE');
|
|
1811
|
+
case '>': case '/': throw new ParseError('SYMBOL', c);
|
|
1812
|
+
case '': throw new ParseError('EOF');
|
|
1813
|
+
}
|
|
1814
|
+
const name = getId();
|
|
1815
|
+
const tagRes = tagNamePattern.exec(name)?.groups;
|
|
1816
|
+
if (!tagRes) { throw new ParseError('TAG', name); }
|
|
1817
|
+
stack.push(currentNode);
|
|
1818
|
+
currentNode = createElement(tagRes.name, tagRes.is);
|
|
1819
|
+
current.children.push(currentNode);
|
|
1820
|
+
current = currentNode;
|
|
1821
|
+
const addAttribute = createAttributeAdder(currentNode, creteCalc, creteEvent);
|
|
1822
|
+
|
|
1823
|
+
let run = true;
|
|
1824
|
+
let closed = false;
|
|
1825
|
+
parseAttr: for (; run;) {
|
|
1826
|
+
let c = skipSpace();
|
|
1827
|
+
switch (c) {
|
|
1828
|
+
case '': error('EOF'); index++; break parseAttr;
|
|
1829
|
+
case '>': index++; break parseAttr;
|
|
1830
|
+
case '/': closed = true; break parseAttr;
|
|
1831
|
+
case '"': case '\'': throw new ParseError('ATTR_VALUE');
|
|
1832
|
+
case '=': throw new ParseError('SYMBOL', c);
|
|
1833
|
+
}
|
|
1834
|
+
const id = getId();
|
|
1835
|
+
if (!id) { error('EOF'); index++; break parseAttr; }
|
|
1836
|
+
c = skipSpace();
|
|
1837
|
+
switch (c) {
|
|
1838
|
+
case '': error('EOF'); index++; break parseAttr;
|
|
1839
|
+
case '>': addAttribute(id, ''); index++; break parseAttr;
|
|
1840
|
+
case '/': addAttribute(id, ''); closed = true; break parseAttr;
|
|
1841
|
+
case '=': index++; break;
|
|
1842
|
+
case '\'': case '"': addAttribute(id, getQuote(c)); continue;
|
|
1843
|
+
default: addAttribute(id, ''); continue;
|
|
1844
|
+
}
|
|
1845
|
+
c = skipSpace();
|
|
1846
|
+
switch (c) {
|
|
1847
|
+
case '': addAttribute(id, ''); error('EOF'); index++; break parseAttr;
|
|
1848
|
+
case '>': addAttribute(id, ''); index++; break parseAttr;
|
|
1849
|
+
case '/': addAttribute(id, ''); closed = true; break parseAttr;
|
|
1850
|
+
case '\'': case '"': addAttribute(id, getQuote(c)); continue;
|
|
1851
|
+
}
|
|
1852
|
+
addAttribute(id, getId());
|
|
1853
|
+
}
|
|
1854
|
+
if (closed) {
|
|
1855
|
+
while (true) {
|
|
1856
|
+
index++;
|
|
1857
|
+
const c = source.charAt(index);
|
|
1858
|
+
if (c === '/') { continue; }
|
|
1859
|
+
if (c <= ' ' || c === '\u0080') { continue; }
|
|
1860
|
+
break;
|
|
1861
|
+
}
|
|
1862
|
+
const c = source.charAt(index);
|
|
1863
|
+
switch (c) {
|
|
1864
|
+
case '=': throw new ParseError('EQUAL');
|
|
1865
|
+
case '"': case '\'': throw new ParseError('ATTR_VALUE'); // No known test case
|
|
1866
|
+
case '': error('EOF'); break;
|
|
1867
|
+
case '>': index++; break;
|
|
1868
|
+
default: throw new ParseError('CLOSE_SYMBOL');
|
|
1869
|
+
}
|
|
1870
|
+
endElement();
|
|
1871
|
+
} else if (simpleTag.has(name) || fixSelfClosed(source, index, name, closeMap)) {
|
|
1872
|
+
endElement();
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
return children;
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
/** @import * as Layout from './index.mjs' */
|
|
1879
|
+
|
|
1880
|
+
/**
|
|
1881
|
+
*
|
|
1882
|
+
* @param {*} c
|
|
1883
|
+
* @returns
|
|
1884
|
+
*/
|
|
1885
|
+
function _xmlEncoder(c) {
|
|
1886
|
+
return c == '<' && '<' ||
|
|
1887
|
+
c == '>' && '>' ||
|
|
1888
|
+
c == '&' && '&' ||
|
|
1889
|
+
c == '"' && '"' ||
|
|
1890
|
+
'&#' + c.charCodeAt() + ';';
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
/**
|
|
1894
|
+
*
|
|
1895
|
+
* @param {Layout.Node} node
|
|
1896
|
+
* @param {number} [level]
|
|
1897
|
+
* @returns {Iterable<string>}
|
|
1898
|
+
*/
|
|
1899
|
+
function* nodeToString(node, level = 0) {
|
|
1900
|
+
const { attrs, events, directives, children, is, name, classes, styles, aliases, vars } = node;
|
|
1901
|
+
const pad = level > 0 ? ''.padEnd(level, '\t') : '';
|
|
1902
|
+
|
|
1903
|
+
yield pad;
|
|
1904
|
+
yield* ['<', name || '-'];
|
|
1905
|
+
if (is) { yield* ['|', is]; }
|
|
1906
|
+
|
|
1907
|
+
for (const [name, value] of Object.entries(directives)) {
|
|
1908
|
+
if (value === false || value == null) { continue; }
|
|
1909
|
+
const val = typeof value === 'function' ? String(value) : value;
|
|
1910
|
+
yield* [' !', name];
|
|
1911
|
+
if (val && typeof val === 'string') {
|
|
1912
|
+
yield* ['="', val.replace(/[<&"]/g, _xmlEncoder), '"'];
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
for (const [name, value] of Object.entries(aliases)) {
|
|
1916
|
+
if (value == null) { continue; }
|
|
1917
|
+
const val = typeof value === 'function' ? String(value) : value;
|
|
1918
|
+
yield* [' *', name];
|
|
1919
|
+
if (val && typeof val === 'string') {
|
|
1920
|
+
yield* ['="', val.replace(/[<&"]/g, _xmlEncoder), '"'];
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
for (const [name, value] of Object.entries(vars)) {
|
|
1924
|
+
if (value == null) { continue; }
|
|
1925
|
+
const val = typeof value === 'function' ? String(value) : value;
|
|
1926
|
+
yield* [' +', name];
|
|
1927
|
+
if (val && typeof val === 'string') {
|
|
1928
|
+
yield* ['="', val.replace(/[<&"]/g, _xmlEncoder), '"'];
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
for (const [name, value] of Object.entries(attrs)) {
|
|
1932
|
+
if (value == null) { continue; }
|
|
1933
|
+
if (typeof value === 'string') {
|
|
1934
|
+
yield* [' ', name];
|
|
1935
|
+
if (value) {
|
|
1936
|
+
yield* ['="', value.replace(/[<&"]/g, _xmlEncoder), '"'];
|
|
1937
|
+
}
|
|
1938
|
+
continue;
|
|
1939
|
+
}
|
|
1940
|
+
const val = typeof value === 'function' ? String(value) : typeof value === 'object' ? value.name : value;
|
|
1941
|
+
if (val && typeof val === 'string') {
|
|
1942
|
+
yield* [' :', name, '="', val.replace(/[<&"]/g, _xmlEncoder) || '', '"'];
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
for (const [name, value] of Object.entries(events)) {
|
|
1946
|
+
if (value == null) { continue; }
|
|
1947
|
+
const val = typeof value === 'function' ? String(value) : value;
|
|
1948
|
+
if (val && typeof val === 'string') {
|
|
1949
|
+
yield* [' @', name, '="', val.replace(/[<&"]/g, _xmlEncoder), '"'];
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
for (const [name, value] of Object.entries(classes)) {
|
|
1953
|
+
if (value == null || value == false) { continue; }
|
|
1954
|
+
const val = typeof value === 'function' ? String(value) : value;
|
|
1955
|
+
yield* [' .', name];
|
|
1956
|
+
if (val && typeof val === 'string') {
|
|
1957
|
+
yield* [' .', name, '="', val.replace(/[<&"]/g, _xmlEncoder), '"'];
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
for (const [name, value] of Object.entries(styles)) {
|
|
1961
|
+
if (value == null) { continue; }
|
|
1962
|
+
const val = typeof value === 'function' ? String(value) : value;
|
|
1963
|
+
if (val && typeof val === 'string') {
|
|
1964
|
+
yield* [' style:', name, '="', val.replace(/[<&"]/g, _xmlEncoder), '"'];
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
if (!children.length) {
|
|
1968
|
+
yield '/>';
|
|
1969
|
+
if (level >= 0) { yield '\n'; }
|
|
1970
|
+
return;
|
|
1971
|
+
}
|
|
1972
|
+
if (children.length === 1) {
|
|
1973
|
+
const [child] = children;
|
|
1974
|
+
if (typeof child === 'string' && child.length < 80 && !child.includes('\n')) {
|
|
1975
|
+
yield '>';
|
|
1976
|
+
yield* [child.replace(/[<&\t]/g, _xmlEncoder).replace(/]]>/g, ']]>')];
|
|
1977
|
+
yield* ['</', name, '>'];
|
|
1978
|
+
if (level >= 0) { yield '\n'; }
|
|
1979
|
+
return;
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
yield '>';
|
|
1983
|
+
if (level >= 0) { yield '\n'; }
|
|
1984
|
+
yield* listToString(children, level >= 0 ? level + 1 : -1);
|
|
1985
|
+
yield* [pad, '</', name, '>'];
|
|
1986
|
+
if (level >= 0) { yield '\n'; }
|
|
1987
|
+
|
|
1988
|
+
}
|
|
1989
|
+
/**
|
|
1990
|
+
*
|
|
1991
|
+
* @param {(Layout.Node |string)[]} nodes
|
|
1992
|
+
* @param {number} [level]
|
|
1993
|
+
* @returns {Iterable<string>}
|
|
1994
|
+
*/
|
|
1995
|
+
function* listToString(nodes, level = 0) {
|
|
1996
|
+
if (!nodes.length) { return ''; }
|
|
1997
|
+
|
|
1998
|
+
const pad = level > 0 ? ''.padEnd(level, '\t') : '';
|
|
1999
|
+
for (const child of nodes) {
|
|
2000
|
+
if (typeof child === 'string') {
|
|
2001
|
+
let text = child.replace(/[<&\t]/g, _xmlEncoder).replace(/]]>/g, ']]>');
|
|
2002
|
+
if (pad) {
|
|
2003
|
+
text = text.replace(/(?<=^|\n)/g, pad);
|
|
2004
|
+
}
|
|
2005
|
+
yield text;
|
|
2006
|
+
if (level >= 0) { yield '\n'; }
|
|
2007
|
+
} else {
|
|
2008
|
+
yield* nodeToString(child, level);
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
/**
|
|
2013
|
+
*
|
|
2014
|
+
* @param {Layout.Node | (Layout.Node |string)[]} value
|
|
2015
|
+
* @param {boolean} [formable]
|
|
2016
|
+
* @returns {string}
|
|
2017
|
+
*/
|
|
2018
|
+
function toString(value, formable) {
|
|
2019
|
+
const level = formable ? 0 : -1;
|
|
2020
|
+
if (Array.isArray(value)) { return [...listToString(value, level)].join(''); }
|
|
2021
|
+
return [nodeToString(value, level)].join();
|
|
2022
|
+
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
/**
|
|
2026
|
+
* @typedef {object} Directives
|
|
2027
|
+
*
|
|
2028
|
+
* @property {boolean} [fragment]
|
|
2029
|
+
*
|
|
2030
|
+
* @property {string | Function} [if]
|
|
2031
|
+
* @property {boolean} [else]
|
|
2032
|
+
*
|
|
2033
|
+
* @property {string} [value] 值关联(关联为列表)
|
|
2034
|
+
* @property {boolean} [enum] 列表属性枚举
|
|
2035
|
+
*
|
|
2036
|
+
* @property {string} [bind]
|
|
2037
|
+
* @property {string | Function} [text]
|
|
2038
|
+
* @property {string | Function} [html]
|
|
2039
|
+
*
|
|
2040
|
+
* @property {string | Function} [comment] 注释
|
|
2041
|
+
*/
|
|
2042
|
+
|
|
2043
|
+
|
|
2044
|
+
|
|
2045
|
+
/**
|
|
2046
|
+
* @typedef {object} Options
|
|
2047
|
+
* @property {(t: string) => (vars: Record<string, any>) => any} [options.creteCalc]
|
|
2048
|
+
* @property {(t: string) => ($event: any, vars: Record<string, any>) => any} [options.creteEvent]
|
|
2049
|
+
* @property {Set<string>} [options.simpleTag]
|
|
2050
|
+
*/
|
|
2051
|
+
/**
|
|
2052
|
+
* @typedef {object} Node
|
|
2053
|
+
* @property {string} name
|
|
2054
|
+
* @property {string?} [is]
|
|
2055
|
+
* @property {string} [id]
|
|
2056
|
+
* @property {Record<string, string | {name: string} | ((global: any) => void)>} attrs
|
|
2057
|
+
* @property {Record<string, string | boolean | ((global: any) => void)>} classes
|
|
2058
|
+
* @property {Record<string, string | ((global: any) => void)>} styles
|
|
2059
|
+
* @property {Record<string, string | (($event: any, global: any) => void)>} events
|
|
2060
|
+
* @property {Record<string, string | ((global: any) => void)>} vars
|
|
2061
|
+
* @property {Record<string, string | Function>} aliases
|
|
2062
|
+
* @property {Directives} directives
|
|
2063
|
+
* @property {(Node | string)[]} children
|
|
2064
|
+
*/
|
|
2065
|
+
|
|
2066
|
+
var index$1 = /*#__PURE__*/Object.freeze({
|
|
2067
|
+
__proto__: null,
|
|
2068
|
+
parse: parse,
|
|
2069
|
+
stringify: toString
|
|
2070
|
+
});
|
|
2071
|
+
|
|
2072
|
+
let needsEnqueue = true;
|
|
2073
|
+
|
|
2074
|
+
const w = new exports.Signal.subtle.Watcher(() => {
|
|
2075
|
+
if (needsEnqueue) {
|
|
2076
|
+
needsEnqueue = false;
|
|
2077
|
+
queueMicrotask(processPending);
|
|
2078
|
+
}
|
|
2079
|
+
});
|
|
2080
|
+
|
|
2081
|
+
function processPending() {
|
|
2082
|
+
needsEnqueue = true;
|
|
2083
|
+
|
|
2084
|
+
for (const s of w.getPending()) {
|
|
2085
|
+
s.get();
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
w.watch();
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
/**
|
|
2092
|
+
* 创建可赋值计算值
|
|
2093
|
+
* @template T
|
|
2094
|
+
* @param {() => T} getter 取值方法
|
|
2095
|
+
* @param {(value: T) => void} callback 取值方法
|
|
2096
|
+
* @returns {() => void}
|
|
2097
|
+
*/
|
|
2098
|
+
function watch(getter, callback) {
|
|
2099
|
+
|
|
2100
|
+
let run = false;
|
|
2101
|
+
/** @type {any} */
|
|
2102
|
+
let value;
|
|
2103
|
+
const computed = new exports.Signal.Computed(() => {
|
|
2104
|
+
const val = getter();
|
|
2105
|
+
if (run && Object.is(val, value)) { return; }
|
|
2106
|
+
value = val;
|
|
2107
|
+
run = true;
|
|
2108
|
+
callback(val);
|
|
2109
|
+
});
|
|
2110
|
+
|
|
2111
|
+
w.watch(computed);
|
|
2112
|
+
computed.get();
|
|
2113
|
+
|
|
2114
|
+
return () => { w.unwatch(computed); };
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
/** @typedef {{get(): any; set?(v: any): void; exec?: null; store?: Store; calc?: null; }} ValueDefine */
|
|
2118
|
+
/** @typedef {{get?: null; exec(...p: any[]): any; calc?: null}} ExecDefine */
|
|
2119
|
+
/** @typedef {{get?: null; calc(...p: any[]): any; exec?: null;}} CalcDefine */
|
|
2120
|
+
/**
|
|
2121
|
+
*
|
|
2122
|
+
* @param {Store} val
|
|
2123
|
+
* @param {string | number} [key]
|
|
2124
|
+
* @returns {Iterable<[string, ValueDefine | ExecDefine | CalcDefine]>}
|
|
2125
|
+
*/
|
|
2126
|
+
function *toItem(val, key = '', sign = '$') {
|
|
2127
|
+
yield [`${key}`, {get: () => val.value, set: v => val.value = v, store: val}];
|
|
2128
|
+
yield [`${key}${sign}value`, {get: () => val.value, set: v => val.value = v}];
|
|
2129
|
+
yield [`${key}${sign}state`, {get: () => val.state, set: v => val.state = v}];
|
|
2130
|
+
yield [`${key}${sign}null`, {get: () => val.null}];
|
|
2131
|
+
yield [`${key}${sign}index`, {get: () => val.index}];
|
|
2132
|
+
yield [`${key}${sign}no`, {get: () => val.no}];
|
|
2133
|
+
yield [`${key}${sign}length`, {get: () => val.length}];
|
|
2134
|
+
yield [`${key}${sign}creatable`, {get: () => val.creatable}];
|
|
2135
|
+
yield [`${key}${sign}immutable`, {get: () => val.immutable}];
|
|
2136
|
+
yield [`${key}${sign}new`, {get: () => val.new}];
|
|
2137
|
+
yield [`${key}${sign}editable`, {get: () => val.editable}];
|
|
2138
|
+
yield [`${key}${sign}hidden`, {get: () => val.hidden}];
|
|
2139
|
+
yield [`${key}${sign}clearable`, {get: () => val.clearable}];
|
|
2140
|
+
yield [`${key}${sign}required`, {get: () => val.required}];
|
|
2141
|
+
yield [`${key}${sign}disabled`, {get: () => val.disabled}];
|
|
2142
|
+
yield [`${key}${sign}readonly`, {get: () => val.readonly}];
|
|
2143
|
+
if (!(val instanceof ArrayStore)) { return; }
|
|
2144
|
+
yield [`${key}${sign}insert`, {exec: (index, value) => val.insert(index, value)}];
|
|
2145
|
+
yield [`${key}${sign}add`, {exec: (v) => val.add(v)}];
|
|
2146
|
+
yield [`${key}${sign}remove`, {exec: (index) => val.remove(index)}];
|
|
2147
|
+
yield [`${key}${sign}move`, {exec: (from, to) => val.move(from, to)}];
|
|
2148
|
+
yield [`${key}${sign}exchange`, {exec: (a, b) => val.exchange(a, b)}];
|
|
2149
|
+
}
|
|
2150
|
+
/**
|
|
2151
|
+
*
|
|
2152
|
+
* @param {Store?} parent
|
|
2153
|
+
* @param {Store} val
|
|
2154
|
+
* @param {string | number} [key]
|
|
2155
|
+
* @returns {Iterable<[string, ValueDefine | ExecDefine | CalcDefine]>}
|
|
2156
|
+
*/
|
|
2157
|
+
function *toParentItem(parent, val, key = '', sign = '$') {
|
|
2158
|
+
if (!(parent instanceof ArrayStore)) {
|
|
2159
|
+
yield [`${key}${sign}upMovable`, {get: () => false}];
|
|
2160
|
+
yield [`${key}${sign}downMovable`, {get: () => false}];
|
|
2161
|
+
return
|
|
2162
|
+
}
|
|
2163
|
+
yield [`${key}${sign}upMovable`, {get: () => {
|
|
2164
|
+
const s = val.index;
|
|
2165
|
+
if (typeof s !== 'number') { return false; }
|
|
2166
|
+
if (s <= 0) { return false; }
|
|
2167
|
+
return true;
|
|
2168
|
+
}}];
|
|
2169
|
+
yield [`${key}${sign}downMovable`, {get: () => {
|
|
2170
|
+
const s = val.index;
|
|
2171
|
+
if (typeof s !== 'number') { return false; }
|
|
2172
|
+
if (s >= parent.length - 1) { return false; }
|
|
2173
|
+
return true;
|
|
2174
|
+
}}];
|
|
2175
|
+
yield [`${key}${sign}remove`, {exec: () => parent.remove(Number(val.index))}];
|
|
2176
|
+
yield [`${key}${sign}upMove`, {exec: () => {
|
|
2177
|
+
const s = val.index;
|
|
2178
|
+
if (typeof s !== 'number') { return; }
|
|
2179
|
+
if (s <= 0) { return; }
|
|
2180
|
+
parent.move(s, s - 1);
|
|
2181
|
+
}}];
|
|
2182
|
+
yield [`${key}${sign}downMove`, {exec: () => {
|
|
2183
|
+
const s = val.index;
|
|
2184
|
+
if (typeof s !== 'number') { return; }
|
|
2185
|
+
if (s >= parent.length - 1) { return; }
|
|
2186
|
+
parent.move(s, s + 1);
|
|
2187
|
+
}}];
|
|
2188
|
+
}
|
|
2189
|
+
class Environment {
|
|
2190
|
+
/**
|
|
2191
|
+
* @param {string | Function} value
|
|
2192
|
+
*/
|
|
2193
|
+
exec(value) {
|
|
2194
|
+
if (typeof value === 'string') {
|
|
2195
|
+
const item = this.#items[value];
|
|
2196
|
+
if (typeof item?.get !== 'function') { return }
|
|
2197
|
+
return item.get();
|
|
2198
|
+
}
|
|
2199
|
+
if (typeof value === 'function') {
|
|
2200
|
+
return value(this.getters);
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
/**
|
|
2204
|
+
* @param {string | Function} value
|
|
2205
|
+
* @param {(value: any) => void} cb
|
|
2206
|
+
*/
|
|
2207
|
+
watch(value, cb) { return watch(() => this.exec(value), cb); }
|
|
2208
|
+
|
|
2209
|
+
/**
|
|
2210
|
+
* @param {string} name
|
|
2211
|
+
* @param {string} type
|
|
2212
|
+
* @param {(value: any) => void} cb
|
|
2213
|
+
*/
|
|
2214
|
+
bind(name, type, cb) {
|
|
2215
|
+
const item = this.#items[name];
|
|
2216
|
+
if (!item?.get) { return; }
|
|
2217
|
+
const { store } = item;
|
|
2218
|
+
if (!store) { return; }
|
|
2219
|
+
switch(type) {
|
|
2220
|
+
case 'value': return watch(() => store.value, cb);
|
|
2221
|
+
case 'state': return watch(() => store.state, cb);
|
|
2222
|
+
case 'required': return watch(() => store.required, cb);
|
|
2223
|
+
case 'clearable': return watch(() => store.clearable, cb);
|
|
2224
|
+
case 'hidden': return watch(() => store.hidden, cb);
|
|
2225
|
+
case 'disabled': return watch(() => store.disabled, cb);
|
|
2226
|
+
case 'readonly': return watch(() => store.readonly || !store.editable, cb);
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
/**
|
|
2230
|
+
* @param {string} name
|
|
2231
|
+
* @returns {Record<string, ((cb: (value: any) => void) => () => void) | void> | void}
|
|
2232
|
+
*/
|
|
2233
|
+
bindAll(name) {
|
|
2234
|
+
const item = this.#items[name];
|
|
2235
|
+
if (!item?.get) { return; }
|
|
2236
|
+
const { store } = item;
|
|
2237
|
+
if (!store) {
|
|
2238
|
+
const get = item.get;
|
|
2239
|
+
if (typeof get !== 'function') { return; }
|
|
2240
|
+
return { '$value': cb => watch(get, cb) }
|
|
2241
|
+
}
|
|
2242
|
+
return {
|
|
2243
|
+
'$value': cb => watch(() => store.value, cb),
|
|
2244
|
+
'$state': cb => watch(() => store.state, cb),
|
|
2245
|
+
'$required': cb => watch(() => store.required, cb),
|
|
2246
|
+
'$clearable': cb => watch(() => store.clearable, cb),
|
|
2247
|
+
'$hidden': cb => watch(() => store.hidden, cb),
|
|
2248
|
+
'$disabled': cb => watch(() => store.disabled, cb),
|
|
2249
|
+
'$readonly': cb => watch(() => store.readonly || !store.editable, cb),
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
/**
|
|
2253
|
+
* @param {string} name
|
|
2254
|
+
* @param {string} type
|
|
2255
|
+
* @returns {((value: any) => void) | void}
|
|
2256
|
+
*/
|
|
2257
|
+
bindSet(name, type) {
|
|
2258
|
+
const item = this.#items[name];
|
|
2259
|
+
if (!item?.get) { return; }
|
|
2260
|
+
const { store } = item;
|
|
2261
|
+
if (!store) { return; }
|
|
2262
|
+
switch(type) {
|
|
2263
|
+
case 'value': return v => {store.value = v; };
|
|
2264
|
+
case 'state': return v => {store.state = v; };
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
/**
|
|
2268
|
+
* @param {string} name
|
|
2269
|
+
* @returns {Record<string, ((value: any) => void) | void> | void}
|
|
2270
|
+
*/
|
|
2271
|
+
bindStateAllSet(name) {
|
|
2272
|
+
const item = this.#items[name];
|
|
2273
|
+
if (!item?.get) { return; }
|
|
2274
|
+
const { store } = item;
|
|
2275
|
+
if (!store) {
|
|
2276
|
+
const set = item.set;
|
|
2277
|
+
if (typeof set !== 'function') { return; }
|
|
2278
|
+
return { '$value': set }
|
|
2279
|
+
}
|
|
2280
|
+
return {
|
|
2281
|
+
'$value': v => {store.value = v; },
|
|
2282
|
+
'$state': v => {store.state = v; },
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
|
|
2286
|
+
/**
|
|
2287
|
+
* @param {string | (($event: any, global: any) => any)} event
|
|
2288
|
+
* @returns {(($event: any, global: any) => any)?}
|
|
2289
|
+
*/
|
|
2290
|
+
getEvent(event) {
|
|
2291
|
+
if (typeof event === 'function') { return event }
|
|
2292
|
+
const item = this.#items[event];
|
|
2293
|
+
if (!item) { return null }
|
|
2294
|
+
const {exec, calc} = item;
|
|
2295
|
+
if (typeof exec === 'function') { return exec }
|
|
2296
|
+
if (typeof calc === 'function') { return calc }
|
|
2297
|
+
return null
|
|
2298
|
+
|
|
2299
|
+
}
|
|
2300
|
+
/**
|
|
2301
|
+
*
|
|
2302
|
+
* @param {Environment | Record<string, Store | {get?(): any; set?(v: any): void; exec?(...p: any[]): any; calc?(...p: any[]): any }>?} [global]
|
|
2303
|
+
*/
|
|
2304
|
+
constructor(global) {
|
|
2305
|
+
if (global instanceof Environment) {
|
|
2306
|
+
this.#global = global.#global;
|
|
2307
|
+
const schemaItems = this.#schemaItems;
|
|
2308
|
+
for (const [k, v] of Object.entries(global.#schemaItems)) {
|
|
2309
|
+
schemaItems[k] = v;
|
|
2310
|
+
}
|
|
2311
|
+
const explicit = this.#explicit;
|
|
2312
|
+
for (const [k, v] of Object.entries(global.#explicit)) {
|
|
2313
|
+
explicit[k] = v;
|
|
2314
|
+
}
|
|
2315
|
+
return;
|
|
2316
|
+
}
|
|
2317
|
+
const items = Object.create(null);
|
|
2318
|
+
this.#global = items;
|
|
2319
|
+
if (!global) { return }
|
|
2320
|
+
if (typeof global !== 'object') { return; }
|
|
2321
|
+
for (const [key, value] of Object.entries(global)) {
|
|
2322
|
+
if (!key || key.includes('$')) { continue; }
|
|
2323
|
+
if (!value || typeof value !== 'object') { return; }
|
|
2324
|
+
if (value instanceof Store) {
|
|
2325
|
+
for (const [k, v] of toItem(value, key)) {
|
|
2326
|
+
items[k] = v;
|
|
2327
|
+
}
|
|
2328
|
+
continue;
|
|
2329
|
+
}
|
|
2330
|
+
const {get,set,exec,calc} = value;
|
|
2331
|
+
if (typeof get === 'function') {
|
|
2332
|
+
items[key] = typeof set === 'function' ? {get,set} : {get};
|
|
2333
|
+
continue;
|
|
2334
|
+
}
|
|
2335
|
+
if (typeof calc === 'function') {
|
|
2336
|
+
items[key] = {calc};
|
|
2337
|
+
continue;
|
|
2338
|
+
}
|
|
2339
|
+
if (typeof exec === 'function') {
|
|
2340
|
+
items[key] = {exec};
|
|
2341
|
+
continue;
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
/** @type {Record<string, ValueDefine | ExecDefine | CalcDefine>} */
|
|
2346
|
+
#global
|
|
2347
|
+
/** @type {Record<string, ValueDefine | ExecDefine | CalcDefine>} */
|
|
2348
|
+
#schemaItems = Object.create(null);
|
|
2349
|
+
/** @type {Record<string, ValueDefine | ExecDefine | CalcDefine>} */
|
|
2350
|
+
#explicit = Object.create(null);
|
|
2351
|
+
/** @type {Store?} */
|
|
2352
|
+
#store = null
|
|
2353
|
+
/** @type {Store?} */
|
|
2354
|
+
#parent = null
|
|
2355
|
+
/** @type {Record<string, ValueDefine | ExecDefine | CalcDefine>?} */
|
|
2356
|
+
#allItems = null
|
|
2357
|
+
get #items() {
|
|
2358
|
+
const ai = this.#allItems;
|
|
2359
|
+
if (ai) { return ai; }
|
|
2360
|
+
/** @type {Record<string, ValueDefine | ExecDefine | CalcDefine>} */
|
|
2361
|
+
const ais = Object.create(null, Object.getOwnPropertyDescriptors({
|
|
2362
|
+
...this.#schemaItems,
|
|
2363
|
+
...this.#global,
|
|
2364
|
+
...this.#explicit,
|
|
2365
|
+
}));
|
|
2366
|
+
const store = this.#store;
|
|
2367
|
+
const parent = this.#parent;
|
|
2368
|
+
if (store) {
|
|
2369
|
+
for (const [key, item] of toItem(store)) {
|
|
2370
|
+
ais[key] = item;
|
|
2371
|
+
}
|
|
2372
|
+
for (const [key, item] of toParentItem(parent, store)) {
|
|
2373
|
+
ais[key] = item;
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
this.#allItems = ais;
|
|
2377
|
+
return ais;
|
|
2378
|
+
}
|
|
2379
|
+
/**
|
|
2380
|
+
*
|
|
2381
|
+
* @param {Store} store
|
|
2382
|
+
* @param {Store} [parent]
|
|
2383
|
+
*/
|
|
2384
|
+
setValue(store, parent) {
|
|
2385
|
+
const cloned = new Environment(this);
|
|
2386
|
+
cloned.#store = store;
|
|
2387
|
+
if (parent) { cloned.#parent = parent; }
|
|
2388
|
+
if (store instanceof ArrayStore) { return cloned; }
|
|
2389
|
+
const items = cloned.#schemaItems;
|
|
2390
|
+
for (const [name, val] of store) {
|
|
2391
|
+
for (const [b, x] of toItem(val, name)) {
|
|
2392
|
+
items[b] = x;
|
|
2393
|
+
}
|
|
2394
|
+
for (const [b, x] of toItem(val, name, '$$')) {
|
|
2395
|
+
items[b] = x;
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
return cloned;
|
|
2399
|
+
}
|
|
2400
|
+
/**
|
|
2401
|
+
*
|
|
2402
|
+
* @param {Record<string, string | Function>} aliases
|
|
2403
|
+
* @param {Record<string, any>} vars
|
|
2404
|
+
*/
|
|
2405
|
+
set(aliases, vars) {
|
|
2406
|
+
if (Object.keys(aliases).length + Object.keys(vars).length === 0) { return this; }
|
|
2407
|
+
const cloned = new Environment(this);
|
|
2408
|
+
cloned.#store = this.#store;
|
|
2409
|
+
cloned.#parent = this.#parent;
|
|
2410
|
+
const explicit = cloned.#explicit;
|
|
2411
|
+
const items = cloned.#items;
|
|
2412
|
+
for (const [key, name] of Object.entries(aliases)) {
|
|
2413
|
+
if (typeof name === 'function') {
|
|
2414
|
+
const getters = cloned.getters;
|
|
2415
|
+
cloned.#getters = null;
|
|
2416
|
+
const val = new exports.Signal.Computed(() => name(getters));
|
|
2417
|
+
explicit[key] = items[key] = {
|
|
2418
|
+
get: () => { return val.get(); },
|
|
2419
|
+
};
|
|
2420
|
+
continue;
|
|
2421
|
+
}
|
|
2422
|
+
const item = items[name];
|
|
2423
|
+
if (!item) { continue; }
|
|
2424
|
+
if (!item.get || !item.store) {
|
|
2425
|
+
explicit[key] = items[key] = item;
|
|
2426
|
+
continue;
|
|
2427
|
+
}
|
|
2428
|
+
for (const [k, it] of toItem(item.store, key)) {
|
|
2429
|
+
explicit[k] = items[k] = it;
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
for (const [k,v] of Object.entries(vars)) {
|
|
2433
|
+
|
|
2434
|
+
const val = new exports.Signal.State(/** @type {any} */(null));
|
|
2435
|
+
if (typeof v === 'function') {
|
|
2436
|
+
const settable = cloned.settable;
|
|
2437
|
+
cloned.#settable = null;
|
|
2438
|
+
val.set(v(settable));
|
|
2439
|
+
} else if (v && typeof v === 'string') {
|
|
2440
|
+
const item = items[v];
|
|
2441
|
+
if (!item?.get) { continue }
|
|
2442
|
+
val.set(item.get());
|
|
2443
|
+
}
|
|
2444
|
+
explicit[k] = items[k] = {
|
|
2445
|
+
get: () => { return val.get(); },
|
|
2446
|
+
set: (v) => { val.set(v); },
|
|
2447
|
+
};
|
|
2448
|
+
}
|
|
2449
|
+
return cloned;
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2452
|
+
/** @type {Record<string, any>?} */
|
|
2453
|
+
#all = null;
|
|
2454
|
+
get all() {
|
|
2455
|
+
const gt = this.#all;
|
|
2456
|
+
if (gt) { return gt; }
|
|
2457
|
+
/** @type {Record<string, any>} */
|
|
2458
|
+
const ngt = {};
|
|
2459
|
+
for (const [key, item] of Object.entries(this.#items)) {
|
|
2460
|
+
if (item.get) {
|
|
2461
|
+
Object.defineProperty(ngt, key, {
|
|
2462
|
+
get: item.get,
|
|
2463
|
+
set: item.set,
|
|
2464
|
+
configurable: true,
|
|
2465
|
+
enumerable: true,
|
|
2466
|
+
});
|
|
2467
|
+
} else if (item.calc) {
|
|
2468
|
+
Object.defineProperty(ngt, key, {
|
|
2469
|
+
value: item.calc,
|
|
2470
|
+
writable: false,
|
|
2471
|
+
configurable: true,
|
|
2472
|
+
enumerable: false,
|
|
2473
|
+
});
|
|
2474
|
+
} else {
|
|
2475
|
+
Object.defineProperty(ngt, key, {
|
|
2476
|
+
value: item.exec,
|
|
2477
|
+
writable: false,
|
|
2478
|
+
configurable: true,
|
|
2479
|
+
enumerable: false,
|
|
2480
|
+
});
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
this.#all = ngt;
|
|
2484
|
+
return ngt;
|
|
2485
|
+
}
|
|
2486
|
+
/** @type {Record<string, any>?} */
|
|
2487
|
+
#settable = null;
|
|
2488
|
+
get settable() {
|
|
2489
|
+
const gt = this.#settable;
|
|
2490
|
+
if (gt) { return gt; }
|
|
2491
|
+
/** @type {Record<string, any>} */
|
|
2492
|
+
const ngt = {};
|
|
2493
|
+
for (const [key, item] of Object.entries(this.#items)) {
|
|
2494
|
+
if (item.get) {
|
|
2495
|
+
Object.defineProperty(ngt, key, {
|
|
2496
|
+
get: item.get,
|
|
2497
|
+
set: item.set,
|
|
2498
|
+
configurable: true,
|
|
2499
|
+
enumerable: true,
|
|
2500
|
+
});
|
|
2501
|
+
} else if (item.calc) {
|
|
2502
|
+
Object.defineProperty(ngt, key, {
|
|
2503
|
+
value: item.calc,
|
|
2504
|
+
writable: false,
|
|
2505
|
+
configurable: true,
|
|
2506
|
+
enumerable: false,
|
|
2507
|
+
});
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
this.#settable = ngt;
|
|
2511
|
+
return ngt;
|
|
2512
|
+
}
|
|
2513
|
+
/** @type {Record<string, any>?} */
|
|
2514
|
+
#getters = null;
|
|
2515
|
+
get getters() {
|
|
2516
|
+
const gt = this.#getters;
|
|
2517
|
+
if (gt) { return gt; }
|
|
2518
|
+
/** @type {Record<string, any>} */
|
|
2519
|
+
const ngt = {};
|
|
2520
|
+
for (const [key, item] of Object.entries(this.#items)) {
|
|
2521
|
+
if (item.get) {
|
|
2522
|
+
Object.defineProperty(ngt, key, {
|
|
2523
|
+
get: item.get,
|
|
2524
|
+
configurable: true,
|
|
2525
|
+
enumerable: true,
|
|
2526
|
+
});
|
|
2527
|
+
} else if (item.calc) {
|
|
2528
|
+
Object.defineProperty(ngt, key, {
|
|
2529
|
+
value: item.calc,
|
|
2530
|
+
writable: false,
|
|
2531
|
+
configurable: true,
|
|
2532
|
+
enumerable: false,
|
|
2533
|
+
});
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
this.#getters = ngt;
|
|
2537
|
+
return ngt;
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
|
|
2541
|
+
/** @import { Component } from '../types.mjs' */
|
|
2542
|
+
|
|
2543
|
+
/**
|
|
2544
|
+
* @param {Component.Handler} handler
|
|
2545
|
+
* @param {Environment} envs
|
|
2546
|
+
* @param {Record<string, string | {name: string} | ((...any: any) => void)>} attrs
|
|
2547
|
+
* @param {Record<string, Component.Attr>} componentAttrs
|
|
2548
|
+
* @param {string?} [bindValue]
|
|
2549
|
+
*/
|
|
2550
|
+
function bindAttrs(handler, envs, attrs, componentAttrs, bindValue) {
|
|
2551
|
+
|
|
2552
|
+
let bk = new Set();
|
|
2553
|
+
for (const [name, attr] of Object.entries(componentAttrs)) {
|
|
2554
|
+
const attrValue = attrs[name];
|
|
2555
|
+
if (name in attrs) {
|
|
2556
|
+
if (typeof attrValue !== 'function' && typeof attrValue !== 'object') {
|
|
2557
|
+
handler.set(name, attrValue);
|
|
2558
|
+
continue;
|
|
2559
|
+
}
|
|
2560
|
+
const attrSchema = typeof attrValue === 'function' ? attrValue : attrValue.name;
|
|
2561
|
+
if (attr.immutable) {
|
|
2562
|
+
handler.set(name, envs.exec(attrSchema));
|
|
2563
|
+
continue;
|
|
2564
|
+
}
|
|
2565
|
+
bk.add(envs.watch(attrSchema, v => handler.set(name, v)));
|
|
2566
|
+
continue;
|
|
2567
|
+
}
|
|
2568
|
+
const bind = attr.bind;
|
|
2569
|
+
if (!bindValue || !bind) {
|
|
2570
|
+
handler.set(name, attr.default);
|
|
2571
|
+
continue;
|
|
2572
|
+
}
|
|
2573
|
+
if (typeof bind === 'string') {
|
|
2574
|
+
const r = envs.bind(bindValue, bind, v => handler.set(name, v));
|
|
2575
|
+
if (r) {
|
|
2576
|
+
bk.add(r);
|
|
2577
|
+
} else {
|
|
2578
|
+
handler.set(name, attr.default);
|
|
2579
|
+
}
|
|
2580
|
+
continue;
|
|
2581
|
+
}
|
|
2582
|
+
if (!Array.isArray(bind)) {
|
|
2583
|
+
handler.set(name, attr.default);
|
|
2584
|
+
continue;
|
|
2585
|
+
}
|
|
2586
|
+
const [event, set, isState] = bind;
|
|
2587
|
+
if (!event || typeof set !== 'function') {
|
|
2588
|
+
continue;
|
|
2589
|
+
}
|
|
2590
|
+
if (!isState) {
|
|
2591
|
+
bk.add(envs.watch(bindValue, v => handler.set(name, v)));
|
|
2592
|
+
handler.addEvent(event, (...args) => { envs.all[bindValue] = set(...args);});
|
|
2593
|
+
continue;
|
|
2594
|
+
}
|
|
2595
|
+
const r = envs.bind(bindValue, 'state', v => handler.set(name, v));
|
|
2596
|
+
if (!r) { continue; }
|
|
2597
|
+
bk.add(r);
|
|
2598
|
+
const s = envs.bindSet(bindValue, 'state');
|
|
2599
|
+
if (!s) { continue; }
|
|
2600
|
+
handler.addEvent(event, (...args) => { s(set(...args));});
|
|
2601
|
+
}
|
|
2602
|
+
// TODO: 创建组件
|
|
2603
|
+
return ()=> {
|
|
2604
|
+
const list = bk;
|
|
2605
|
+
bk = new Set();
|
|
2606
|
+
for (const s of list) {
|
|
2607
|
+
s();
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
/** @import { Component } from '../types.mjs' */
|
|
2613
|
+
|
|
2614
|
+
/**
|
|
2615
|
+
* @param {Component.Handler} handler
|
|
2616
|
+
* @param {Environment} envs
|
|
2617
|
+
* @param {Record<string, string | {name: string} | ((...any: any) => void)>} attrs
|
|
2618
|
+
* @param {string?} [bindValue]
|
|
2619
|
+
*/
|
|
2620
|
+
function bindBaseAttrs(handler, envs, attrs, bindValue) {
|
|
2621
|
+
const tag = handler.tag;
|
|
2622
|
+
let bk = new Set();
|
|
2623
|
+
for (const [name, attr] of Object.entries(attrs)) {
|
|
2624
|
+
if (typeof attr !== 'function' && typeof attr !== 'object') {
|
|
2625
|
+
handler.set(name, attr);
|
|
2626
|
+
continue;
|
|
2627
|
+
}
|
|
2628
|
+
const attrSchema = typeof attr === 'function' ? attr : attr.name;
|
|
2629
|
+
if (typeof tag === 'string' && tag.toLocaleLowerCase() === 'input' && name.toLocaleLowerCase() === 'type') {
|
|
2630
|
+
const value = envs.exec(attrSchema);
|
|
2631
|
+
handler.set(name, value);
|
|
2632
|
+
continue;
|
|
2633
|
+
}
|
|
2634
|
+
bk.add(envs.watch(attrSchema, val => handler.set(name, val)));
|
|
2635
|
+
}
|
|
2636
|
+
if (bindValue) {
|
|
2637
|
+
for (const [key, effect] of Object.entries(envs.bindAll(bindValue) || {})) {
|
|
2638
|
+
if (typeof effect !== 'function') { continue; }
|
|
2639
|
+
bk.add(effect(val => handler.set(key, val)));
|
|
2640
|
+
}
|
|
2641
|
+
for (const [key, setter] of Object.entries(envs.bindStateAllSet(bindValue) || {})) {
|
|
2642
|
+
if (typeof setter !== 'function') { continue; }
|
|
2643
|
+
handler.addEvent(key, $event => setter($event));
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
|
|
2647
|
+
return ()=> {
|
|
2648
|
+
const list = bk;
|
|
2649
|
+
bk = new Set();
|
|
2650
|
+
for (const s of list) {
|
|
2651
|
+
s();
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
/**
|
|
2657
|
+
* @param {Node} node
|
|
2658
|
+
* @param {Environment} envs
|
|
2659
|
+
* @param {Record<string, string | boolean | ((...any: any) => void)>} classes
|
|
2660
|
+
*/
|
|
2661
|
+
function bindClasses(node, classes, envs) {
|
|
2662
|
+
if (!(node instanceof Element)) {
|
|
2663
|
+
return () => {};
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2666
|
+
/** @type {Set<() => void>?} */
|
|
2667
|
+
let bk = new Set();
|
|
2668
|
+
for (const [name, attr] of Object.entries(classes)) {
|
|
2669
|
+
if (!attr) { continue; }
|
|
2670
|
+
if (attr === true) {
|
|
2671
|
+
node.classList.add(name);
|
|
2672
|
+
continue;
|
|
2673
|
+
}
|
|
2674
|
+
bk.add(watch(() => Boolean(envs.exec(attr)), value => {
|
|
2675
|
+
if (value) {
|
|
2676
|
+
node.classList.add(name);
|
|
2677
|
+
} else {
|
|
2678
|
+
node.classList.remove(name);
|
|
2679
|
+
}
|
|
2680
|
+
}));
|
|
2681
|
+
}
|
|
2682
|
+
// TODO: 创建组件
|
|
2683
|
+
return ()=> {
|
|
2684
|
+
if (!bk) { return; }
|
|
2685
|
+
const list = bk;
|
|
2686
|
+
bk = null;
|
|
2687
|
+
for (const s of list) {
|
|
2688
|
+
s();
|
|
2689
|
+
}
|
|
2690
|
+
}
|
|
2691
|
+
}
|
|
2692
|
+
|
|
2693
|
+
/** @type {Record<string, string>} */
|
|
2694
|
+
const unit = {
|
|
2695
|
+
'width': 'px',
|
|
2696
|
+
'height': 'px',
|
|
2697
|
+
'top': 'px',
|
|
2698
|
+
'right': 'px',
|
|
2699
|
+
'bottom': 'px',
|
|
2700
|
+
'left': 'px',
|
|
2701
|
+
'border': 'px',
|
|
2702
|
+
'border-top': 'px',
|
|
2703
|
+
'border-right': 'px',
|
|
2704
|
+
'border-left': 'px',
|
|
2705
|
+
'border-bottom': 'px',
|
|
2706
|
+
'border-width': 'px',
|
|
2707
|
+
'border-top-width': 'px',
|
|
2708
|
+
'border-right-width': 'px',
|
|
2709
|
+
'border-left-width': 'px',
|
|
2710
|
+
'border-bottom-width': 'px',
|
|
2711
|
+
'border-radius': 'px',
|
|
2712
|
+
'border-top-left-radius': 'px',
|
|
2713
|
+
'border-top-right-radius': 'px',
|
|
2714
|
+
'border-bottom-left-radius': 'px',
|
|
2715
|
+
'border-bottom-right-radius': 'px',
|
|
2716
|
+
'padding': 'px',
|
|
2717
|
+
'padding-top': 'px',
|
|
2718
|
+
'padding-right': 'px',
|
|
2719
|
+
'padding-left': 'px',
|
|
2720
|
+
'padding-bottom': 'px',
|
|
2721
|
+
'margin': 'px',
|
|
2722
|
+
'margin-top': 'px',
|
|
2723
|
+
'margin-right': 'px',
|
|
2724
|
+
'margin-left': 'px',
|
|
2725
|
+
'margin-bottom': 'px',
|
|
2726
|
+
};
|
|
2727
|
+
/**
|
|
2728
|
+
*
|
|
2729
|
+
* @param {string} name
|
|
2730
|
+
* @param {any} value
|
|
2731
|
+
* @returns {[string, 'important' | undefined]?}
|
|
2732
|
+
*/
|
|
2733
|
+
function toStyle(name, value) {
|
|
2734
|
+
let important = Array.isArray(value) ? Boolean(value[1]) : false;
|
|
2735
|
+
let style = '';
|
|
2736
|
+
/** @typedef {[string, 'important' | undefined]} Result */
|
|
2737
|
+
if (typeof value === 'string') {
|
|
2738
|
+
style = value.replace(/!important\s*$/, '');
|
|
2739
|
+
if (!style) { return null; }
|
|
2740
|
+
important = style !== value;
|
|
2741
|
+
return [style, important ? 'important' : undefined];
|
|
2742
|
+
}
|
|
2743
|
+
const val = Array.isArray(value) ? value[0] : value;
|
|
2744
|
+
if (typeof val === 'number' || typeof val === 'bigint') {
|
|
2745
|
+
style = val && name in unit ? `${ val }${ unit[name] }` : `${ val }`;
|
|
2746
|
+
} else if (typeof val === 'string') {
|
|
2747
|
+
style = val;
|
|
2748
|
+
}
|
|
2749
|
+
if (!style) { return null; }
|
|
2750
|
+
return [style, important ? 'important' : undefined];
|
|
2751
|
+
|
|
2752
|
+
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
|
|
2756
|
+
/**
|
|
2757
|
+
* @param {Element} node
|
|
2758
|
+
* @param {Environment} envs
|
|
2759
|
+
* @param {Record<string, string | ((...any: any) => void)>} classes
|
|
2760
|
+
*/
|
|
2761
|
+
function bindStyles(node, classes, envs) {
|
|
2762
|
+
if (!(node instanceof HTMLElement) && !(node instanceof SVGElement)) {
|
|
2763
|
+
return () => {};
|
|
2764
|
+
}
|
|
2765
|
+
|
|
2766
|
+
/** @type {Set<() => void>?} */
|
|
2767
|
+
let bk = new Set();
|
|
2768
|
+
for (const [name, attr] of Object.entries(classes)) {
|
|
2769
|
+
bk.add(watch(() => toStyle(name, envs.exec(attr)), value => {
|
|
2770
|
+
if (value) {
|
|
2771
|
+
node.style.setProperty(name, ...value);
|
|
2772
|
+
} else {
|
|
2773
|
+
node.style.removeProperty(name);
|
|
2774
|
+
}
|
|
2775
|
+
}));
|
|
2776
|
+
}
|
|
2777
|
+
// TODO: 创建组件
|
|
2778
|
+
return ()=> {
|
|
2779
|
+
if (!bk) { return; }
|
|
2780
|
+
const list = bk;
|
|
2781
|
+
bk = null;
|
|
2782
|
+
for (const s of list) {
|
|
2783
|
+
s();
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
}
|
|
2787
|
+
|
|
2788
|
+
/**
|
|
2789
|
+
* @template {Record<string, any[]>} T
|
|
2790
|
+
*/
|
|
2791
|
+
class EventEmitter {
|
|
2792
|
+
/** @type {Map<keyof T, Set<(...p: any[]) => void>>} */
|
|
2793
|
+
#events = new Map()
|
|
2794
|
+
/**
|
|
2795
|
+
*
|
|
2796
|
+
* @template {keyof T} K
|
|
2797
|
+
* @param {K} event
|
|
2798
|
+
* @param {T[K]} p
|
|
2799
|
+
*/
|
|
2800
|
+
emit(event, ...p) {
|
|
2801
|
+
const key = typeof event === 'number' ? String(event) : event;
|
|
2802
|
+
const events = this.#events;
|
|
2803
|
+
for (const d of [...events.get(key) || []]) {
|
|
2804
|
+
d(...p);
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
/**
|
|
2808
|
+
*
|
|
2809
|
+
* @template {keyof T} K
|
|
2810
|
+
* @param {K} event
|
|
2811
|
+
* @param {(...p: T[K]) => void} listener
|
|
2812
|
+
* @returns {() => void}
|
|
2813
|
+
*/
|
|
2814
|
+
listen(event, listener) {
|
|
2815
|
+
/** @type {any} */
|
|
2816
|
+
const fn = listener.bind(this);
|
|
2817
|
+
const events = this.#events;
|
|
2818
|
+
const key = typeof event === 'number' ? String(event) : event;
|
|
2819
|
+
let set = events.get(key);
|
|
2820
|
+
if (!set) {
|
|
2821
|
+
set = new Set();
|
|
2822
|
+
events.set(key, set);
|
|
2823
|
+
}
|
|
2824
|
+
set.add(fn);
|
|
2825
|
+
return () => { set?.delete(fn); }
|
|
2826
|
+
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
|
|
2830
|
+
/** @import { Component } from '../types.mjs' */
|
|
2831
|
+
/** @import Environment from './Environment.mjs' */
|
|
2832
|
+
|
|
2833
|
+
|
|
2834
|
+
/** @type {Record<string, (evt: any, param: string[], global: any) => boolean | null | void>} */
|
|
2835
|
+
const eventFilters = {
|
|
2836
|
+
stop(evt) {
|
|
2837
|
+
if (evt instanceof Event) { evt.stopPropagation(); }
|
|
2838
|
+
},
|
|
2839
|
+
prevent(evt) {
|
|
2840
|
+
if (evt instanceof Event) { evt.preventDefault(); }
|
|
2841
|
+
},
|
|
2842
|
+
self(evt) {
|
|
2843
|
+
if (evt instanceof Event) { return evt.target === evt.currentTarget; }
|
|
2844
|
+
},
|
|
2845
|
+
enter(evt) {
|
|
2846
|
+
if (evt instanceof KeyboardEvent) { return evt.key === 'Enter'; }
|
|
2847
|
+
},
|
|
2848
|
+
tab(evt) {
|
|
2849
|
+
if (evt instanceof KeyboardEvent) { return evt.key === 'Tab'; }
|
|
2850
|
+
},
|
|
2851
|
+
esc(evt) {
|
|
2852
|
+
if (evt instanceof KeyboardEvent) { return evt.key === 'Escape'; }
|
|
2853
|
+
},
|
|
2854
|
+
space(evt) {
|
|
2855
|
+
if (evt instanceof KeyboardEvent) { return evt.key === ' '; }
|
|
2856
|
+
},
|
|
2857
|
+
backspace(evt) {
|
|
2858
|
+
if (evt instanceof KeyboardEvent) { return evt.key === 'Backspace'; }
|
|
2859
|
+
},
|
|
2860
|
+
delete(evt) {
|
|
2861
|
+
if (evt instanceof KeyboardEvent) { return evt.key === 'Delete'; }
|
|
2862
|
+
},
|
|
2863
|
+
delBack(evt) {
|
|
2864
|
+
if (evt instanceof KeyboardEvent) { return evt.key === 'Delete' || evt.key === 'Backspace'; }
|
|
2865
|
+
},
|
|
2866
|
+
'del-back'(evt) {
|
|
2867
|
+
if (evt instanceof KeyboardEvent) { return evt.key === 'Delete' || evt.key === 'Backspace'; }
|
|
2868
|
+
},
|
|
2869
|
+
insert(evt) {
|
|
2870
|
+
if (evt instanceof KeyboardEvent) { return evt.key === 'Insert'; }
|
|
2871
|
+
},
|
|
2872
|
+
repeat(evt) {
|
|
2873
|
+
if (evt instanceof KeyboardEvent) { return evt.repeat; }
|
|
2874
|
+
},
|
|
2875
|
+
|
|
2876
|
+
key(evt, param) {
|
|
2877
|
+
if (evt instanceof KeyboardEvent) {
|
|
2878
|
+
const key = evt.code.toLowerCase().replace(/-/g, '');
|
|
2879
|
+
for (const k of param) {
|
|
2880
|
+
if (key === k.toLowerCase().replace(/-/g, '')) { return true }
|
|
2881
|
+
}
|
|
2882
|
+
return false;
|
|
2883
|
+
}
|
|
2884
|
+
},
|
|
2885
|
+
main(evt) {
|
|
2886
|
+
if (evt instanceof MouseEvent) { return evt.button === 0; }
|
|
2887
|
+
},
|
|
2888
|
+
auxiliary(evt) {
|
|
2889
|
+
if (evt instanceof MouseEvent) { return evt.button === 1; }
|
|
2890
|
+
},
|
|
2891
|
+
secondary(evt) {
|
|
2892
|
+
if (evt instanceof MouseEvent) { return evt.button === 2; }
|
|
2893
|
+
},
|
|
2894
|
+
left(evt) {
|
|
2895
|
+
if (evt instanceof MouseEvent) { return evt.button === 0; }
|
|
2896
|
+
},
|
|
2897
|
+
middle(evt) {
|
|
2898
|
+
if (evt instanceof MouseEvent) { return evt.button === 1; }
|
|
2899
|
+
},
|
|
2900
|
+
right(evt) {
|
|
2901
|
+
if (evt instanceof MouseEvent) { return evt.button === 2; }
|
|
2902
|
+
},
|
|
2903
|
+
primary(evt) {
|
|
2904
|
+
if (evt instanceof PointerEvent) { return evt.isPrimary; }
|
|
2905
|
+
},
|
|
2906
|
+
mouse(evt) {
|
|
2907
|
+
if (evt instanceof PointerEvent) { return evt.pointerType === 'mouse'; }
|
|
2908
|
+
},
|
|
2909
|
+
pen(evt) {
|
|
2910
|
+
if (evt instanceof PointerEvent) { return evt.pointerType === 'pen'; }
|
|
2911
|
+
},
|
|
2912
|
+
touch(evt) {
|
|
2913
|
+
if (evt instanceof PointerEvent) { return evt.pointerType === 'touch'; }
|
|
2914
|
+
},
|
|
2915
|
+
pointer(evt, param) {
|
|
2916
|
+
if (evt instanceof PointerEvent) {
|
|
2917
|
+
const pointerType = evt.pointerType.toLowerCase().replace(/-/g, '');
|
|
2918
|
+
for (const k of param) {
|
|
2919
|
+
if (pointerType === k.toLowerCase().replace(/-/g, '')) { return true }
|
|
2920
|
+
}
|
|
2921
|
+
return false;
|
|
2922
|
+
}
|
|
2923
|
+
},
|
|
2924
|
+
|
|
2925
|
+
ctrl(evt) {
|
|
2926
|
+
if (evt instanceof MouseEvent|| evt instanceof KeyboardEvent || evt instanceof TouchEvent) {
|
|
2927
|
+
return evt.ctrlKey;
|
|
2928
|
+
}
|
|
2929
|
+
},
|
|
2930
|
+
alt(evt) {
|
|
2931
|
+
if (evt instanceof MouseEvent|| evt instanceof KeyboardEvent || evt instanceof TouchEvent) {
|
|
2932
|
+
return evt.altKey;
|
|
2933
|
+
}
|
|
2934
|
+
},
|
|
2935
|
+
shift(evt) {
|
|
2936
|
+
if (evt instanceof MouseEvent|| evt instanceof KeyboardEvent || evt instanceof TouchEvent) {
|
|
2937
|
+
return evt.shiftKey;
|
|
2938
|
+
}
|
|
2939
|
+
},
|
|
2940
|
+
meta(evt) {
|
|
2941
|
+
if (evt instanceof MouseEvent|| evt instanceof KeyboardEvent || evt instanceof TouchEvent) {
|
|
2942
|
+
return evt.metaKey;
|
|
2943
|
+
}
|
|
2944
|
+
},
|
|
2945
|
+
cmd(evt) {
|
|
2946
|
+
if (evt instanceof MouseEvent|| evt instanceof KeyboardEvent || evt instanceof TouchEvent) {
|
|
2947
|
+
return evt.ctrlKey || evt.metaKey;
|
|
2948
|
+
}
|
|
2949
|
+
},
|
|
2950
|
+
};
|
|
2951
|
+
/**
|
|
2952
|
+
*
|
|
2953
|
+
* @param {Component | string} component
|
|
2954
|
+
* @param {Environment} env
|
|
2955
|
+
* @returns
|
|
2956
|
+
*/
|
|
2957
|
+
function createContext(component, env) {
|
|
2958
|
+
const tag = typeof component === 'string' ? component : component.tag;
|
|
2959
|
+
const { attrs, events } = typeof component !== 'string' && component || {attrs: null, events: null };
|
|
2960
|
+
|
|
2961
|
+
let destroyed = false;
|
|
2962
|
+
let init = false;
|
|
2963
|
+
const tagAttrs = Object.create(null);
|
|
2964
|
+
|
|
2965
|
+
/** @type {[string, ($event: any) => void, AddEventListenerOptions][]} */
|
|
2966
|
+
const allEvents = [];
|
|
2967
|
+
const stateEmitter = new EventEmitter();
|
|
2968
|
+
/** @type {EventEmitter<Record<string, [any, any, string]>>} */
|
|
2969
|
+
const attrEmitter = new EventEmitter();
|
|
2970
|
+
/** @type {Component.Context} */
|
|
2971
|
+
const context = {
|
|
2972
|
+
events: allEvents,
|
|
2973
|
+
props: attrs ? new Set(Object.entries(attrs).filter(([,a]) => a.isProp).map(([e]) => e)) : null,
|
|
2974
|
+
tagAttrs,
|
|
2975
|
+
watchAttr(name, fn) { return attrEmitter.listen(name, fn); },
|
|
2976
|
+
get destroyed() { return destroyed},
|
|
2977
|
+
get init() { return init},
|
|
2978
|
+
listen(name, listener) { return stateEmitter.listen(name, listener); },
|
|
2979
|
+
};
|
|
2980
|
+
/** @type {Component.Handler} */
|
|
2981
|
+
const handler = {
|
|
2982
|
+
tag,
|
|
2983
|
+
set(name, value) {
|
|
2984
|
+
if (attrs && !(name in attrs)) { return; }
|
|
2985
|
+
if (!(name in tagAttrs)) { tagAttrs[name] = void 0; }
|
|
2986
|
+
const old = tagAttrs[name];
|
|
2987
|
+
if (old === value) { return; }
|
|
2988
|
+
tagAttrs[name] = value;
|
|
2989
|
+
attrEmitter.emit(name, value, old, name);
|
|
2990
|
+
},
|
|
2991
|
+
addEvent(name, fn) {
|
|
2992
|
+
if (typeof fn !== 'function') { return; }
|
|
2993
|
+
const [e, ...fs] = name.split('.').filter(Boolean);
|
|
2994
|
+
const filters = events ? events[e].filters : {};
|
|
2995
|
+
if (!filters) { return; }
|
|
2996
|
+
/** @type {AddEventListenerOptions} */
|
|
2997
|
+
const options = {};
|
|
2998
|
+
/** @type {[($event: any, param: string[], env: any) => boolean | null | void, string[], boolean][]} */
|
|
2999
|
+
const filterFns = [];
|
|
3000
|
+
if (filters) for (let f = fs.shift();f;f = fs.shift()) {
|
|
3001
|
+
const paramIndex = f.indexOf(':');
|
|
3002
|
+
const noParamName = paramIndex >= 0 ? f.slice(0, paramIndex) : f;
|
|
3003
|
+
const param = paramIndex >= 0 ? f.slice(paramIndex + 1).split(':') : [];
|
|
3004
|
+
const filterName = noParamName.replace(/^-+/, '');
|
|
3005
|
+
const sub = (noParamName.length - filterName.length) % 2 === 1;
|
|
3006
|
+
let filter = filters[filterName] || filterName;
|
|
3007
|
+
switch(filter) {
|
|
3008
|
+
case 'once':
|
|
3009
|
+
options.once = !sub;
|
|
3010
|
+
break;
|
|
3011
|
+
case 'passive':
|
|
3012
|
+
options.passive = !sub;
|
|
3013
|
+
break;
|
|
3014
|
+
case 'capture':
|
|
3015
|
+
options.capture = !sub;
|
|
3016
|
+
break;
|
|
3017
|
+
default:
|
|
3018
|
+
if (typeof filter === 'string') {
|
|
3019
|
+
filter = eventFilters[filter];
|
|
3020
|
+
}
|
|
3021
|
+
}
|
|
3022
|
+
if (typeof filter !== 'function') { continue; }
|
|
3023
|
+
filterFns.push([filter, param, sub]);
|
|
3024
|
+
}
|
|
3025
|
+
allEvents.push([e, $event => {
|
|
3026
|
+
const global = env.all;
|
|
3027
|
+
for (const [filter, param, sub] of filterFns) {
|
|
3028
|
+
if (filter($event, param, global) === sub) { return}
|
|
3029
|
+
}
|
|
3030
|
+
fn($event, global);
|
|
3031
|
+
}, options]);
|
|
3032
|
+
},
|
|
3033
|
+
destroy() {
|
|
3034
|
+
if (destroyed) { return }
|
|
3035
|
+
destroyed = true;
|
|
3036
|
+
stateEmitter.emit('destroy');
|
|
3037
|
+
},
|
|
3038
|
+
init() {
|
|
3039
|
+
if (init) { return }
|
|
3040
|
+
init = true;
|
|
3041
|
+
stateEmitter.emit('init', {events: allEvents});
|
|
3042
|
+
},
|
|
3043
|
+
|
|
3044
|
+
};
|
|
3045
|
+
return { context, handler };
|
|
3046
|
+
}
|
|
3047
|
+
|
|
3048
|
+
/** @import { Component } from '../types.mjs' */
|
|
3049
|
+
/**
|
|
3050
|
+
*
|
|
3051
|
+
* @param {any} val
|
|
3052
|
+
* @returns
|
|
3053
|
+
*/
|
|
3054
|
+
function toAttrValue(val) {
|
|
3055
|
+
if (typeof val === 'number') {
|
|
3056
|
+
return String(val);
|
|
3057
|
+
}
|
|
3058
|
+
if (typeof val === 'bigint') {
|
|
3059
|
+
return String(val);
|
|
3060
|
+
}
|
|
3061
|
+
if (typeof val === 'boolean') {
|
|
3062
|
+
return val ? '' : null;
|
|
3063
|
+
}
|
|
3064
|
+
if (typeof val === 'string') {
|
|
3065
|
+
return val;
|
|
3066
|
+
}
|
|
3067
|
+
if ((val ?? null) === null) {
|
|
3068
|
+
return null;
|
|
3069
|
+
}
|
|
3070
|
+
return String(val);
|
|
3071
|
+
}
|
|
3072
|
+
/**
|
|
3073
|
+
*
|
|
3074
|
+
* @param {any} val
|
|
3075
|
+
* @returns
|
|
3076
|
+
*/
|
|
3077
|
+
function toText$1(val) {
|
|
3078
|
+
if ((val ?? null) === null) {
|
|
3079
|
+
return '';
|
|
3080
|
+
}
|
|
3081
|
+
return String(val);
|
|
3082
|
+
}
|
|
3083
|
+
|
|
3084
|
+
|
|
3085
|
+
/**
|
|
3086
|
+
*
|
|
3087
|
+
* @param {Element} el
|
|
3088
|
+
* @param {string} attr
|
|
3089
|
+
*/
|
|
3090
|
+
function getAttrs(el, attr) {
|
|
3091
|
+
if (el instanceof HTMLInputElement && 'checked' === attr) {
|
|
3092
|
+
switch (el.type.toLowerCase()) {
|
|
3093
|
+
case 'checkbox':
|
|
3094
|
+
case 'radio':
|
|
3095
|
+
return Boolean;
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
if ((
|
|
3099
|
+
el instanceof HTMLSelectElement
|
|
3100
|
+
|| el instanceof HTMLInputElement
|
|
3101
|
+
|| el instanceof HTMLTextAreaElement
|
|
3102
|
+
) && 'value' === attr) {
|
|
3103
|
+
return toText$1;
|
|
3104
|
+
}
|
|
3105
|
+
if ((el instanceof HTMLDetailsElement) && 'open' === attr) {
|
|
3106
|
+
return Boolean;
|
|
3107
|
+
}
|
|
3108
|
+
if (el instanceof HTMLMediaElement) {
|
|
3109
|
+
if ('muted' === attr) {
|
|
3110
|
+
return Boolean;
|
|
3111
|
+
}
|
|
3112
|
+
if ('paused' === attr) {
|
|
3113
|
+
return Boolean;
|
|
3114
|
+
}
|
|
3115
|
+
if ('currentTime' === attr) {
|
|
3116
|
+
return true;
|
|
3117
|
+
}
|
|
3118
|
+
if ('playbackRate' === attr) {
|
|
3119
|
+
return true;
|
|
3120
|
+
}
|
|
3121
|
+
if ('volume' === attr) {
|
|
3122
|
+
return true;
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
return false;
|
|
3126
|
+
}
|
|
3127
|
+
|
|
3128
|
+
/**
|
|
3129
|
+
* @typedef {object} TagBind
|
|
3130
|
+
* @property {Record<string, (value: any, el: any) => void>} attrs
|
|
3131
|
+
* @property {Record<string, [name: string, set: (event: any, el: any) => any]>} events
|
|
3132
|
+
*/
|
|
3133
|
+
/** @type {Record<string, TagBind>} */
|
|
3134
|
+
const tagBindMap = {
|
|
3135
|
+
input: {
|
|
3136
|
+
attrs: {
|
|
3137
|
+
/** @param {any} v @param {HTMLInputElement} e */
|
|
3138
|
+
$disabled: (v, e) => {e.disabled = v;},
|
|
3139
|
+
/** @param {any} v @param {HTMLInputElement} e */
|
|
3140
|
+
$readonly: (v, e) => {e.readOnly = v;},
|
|
3141
|
+
/** @param {any} v @param {HTMLInputElement} e */
|
|
3142
|
+
$required: (v, e) => {e.required = v;},
|
|
3143
|
+
/** @param {any} v @param {HTMLInputElement} e */
|
|
3144
|
+
$value: (v, e) => {
|
|
3145
|
+
switch(e.type) {
|
|
3146
|
+
case 'checkbox':
|
|
3147
|
+
case 'radio':
|
|
3148
|
+
e.checked = Boolean(v);
|
|
3149
|
+
break;
|
|
3150
|
+
}
|
|
3151
|
+
e.value = toText$1(v);
|
|
3152
|
+
},
|
|
3153
|
+
},
|
|
3154
|
+
events: {
|
|
3155
|
+
$value: ['input', (v, e) => {
|
|
3156
|
+
switch(e.type) {
|
|
3157
|
+
case 'checkbox':
|
|
3158
|
+
case 'radio':
|
|
3159
|
+
return e.checked;
|
|
3160
|
+
case 'number':
|
|
3161
|
+
return Number(e.value);
|
|
3162
|
+
}
|
|
3163
|
+
return e.value;
|
|
3164
|
+
}],
|
|
3165
|
+
},
|
|
3166
|
+
},
|
|
3167
|
+
textarea: {
|
|
3168
|
+
attrs: {
|
|
3169
|
+
/** @param {any} v @param {HTMLInputElement} e */
|
|
3170
|
+
$disabled: (v, e) => {e.disabled = v;},
|
|
3171
|
+
/** @param {any} v @param {HTMLInputElement} e */
|
|
3172
|
+
$readonly: (v, e) => {e.readOnly = v;},
|
|
3173
|
+
/** @param {any} v @param {HTMLInputElement} e */
|
|
3174
|
+
$required: (v, e) => {e.required = v;},
|
|
3175
|
+
/** @param {any} v @param {HTMLInputElement} e */
|
|
3176
|
+
$value: (v, e) => { e.value = toText$1(v); },
|
|
3177
|
+
},
|
|
3178
|
+
events: {
|
|
3179
|
+
$value: ['input', (v, e) => { return e.value; }],
|
|
3180
|
+
},
|
|
3181
|
+
},
|
|
3182
|
+
select: {
|
|
3183
|
+
attrs: {
|
|
3184
|
+
/** @param {any} v @param {HTMLInputElement} e */
|
|
3185
|
+
$disabled: (v, e) => {e.disabled = v;},
|
|
3186
|
+
/** @param {any} v @param {HTMLInputElement} e */
|
|
3187
|
+
$readonly: (v, e) => {e.readOnly = v;},
|
|
3188
|
+
/** @param {any} v @param {HTMLInputElement} e */
|
|
3189
|
+
$required: (v, e) => {e.required = v;},
|
|
3190
|
+
/** @param {any} v @param {HTMLInputElement} e */
|
|
3191
|
+
$value: (v, e) => { e.value = toText$1(v); },
|
|
3192
|
+
},
|
|
3193
|
+
events: {
|
|
3194
|
+
$value: ['change', (v, e) => { return e.value; }],
|
|
3195
|
+
},
|
|
3196
|
+
},
|
|
3197
|
+
};
|
|
3198
|
+
|
|
3199
|
+
/**
|
|
3200
|
+
*
|
|
3201
|
+
* @param {Component.Context} context
|
|
3202
|
+
* @param {string} name
|
|
3203
|
+
* @param {string?} [is]
|
|
3204
|
+
*/
|
|
3205
|
+
function createTagComponent (context, name, is) {
|
|
3206
|
+
const node = document.createElement(name, {is: is || undefined});
|
|
3207
|
+
const { watchAttr, props } = context;
|
|
3208
|
+
|
|
3209
|
+
context.listen('init', ({events})=> {
|
|
3210
|
+
const e = tagBindMap[name.toLowerCase()];
|
|
3211
|
+
const eAttrs = e?.attrs || {};
|
|
3212
|
+
const eEvents = e?.events || {};
|
|
3213
|
+
for (const [type, listener, options] of events) {
|
|
3214
|
+
if (type[0] === '$') {
|
|
3215
|
+
const e = eEvents[type];
|
|
3216
|
+
if (e) {
|
|
3217
|
+
const [evt, set] = e;
|
|
3218
|
+
node.addEventListener(evt, e => listener(set(e, node)), options);
|
|
3219
|
+
}
|
|
3220
|
+
continue;
|
|
3221
|
+
}
|
|
3222
|
+
node.addEventListener(type, listener, options);
|
|
3223
|
+
}
|
|
3224
|
+
if (props) {
|
|
3225
|
+
for (const [name, attr] of Object.entries(context.tagAttrs)) {
|
|
3226
|
+
watchAttr(name, v => {
|
|
3227
|
+
// @ts-ignore
|
|
3228
|
+
if (props.has(name)) { node[name] = v; } else {
|
|
3229
|
+
const val = toAttrValue(v);
|
|
3230
|
+
if (val == null) {
|
|
3231
|
+
node.removeAttribute(name);
|
|
3232
|
+
} else {
|
|
3233
|
+
node.setAttribute(name, val);
|
|
3234
|
+
}
|
|
3235
|
+
}
|
|
3236
|
+
});
|
|
3237
|
+
// @ts-ignore
|
|
3238
|
+
if (props.has(name)) { node[name] = attr; } else {
|
|
3239
|
+
const val = toAttrValue(attr);
|
|
3240
|
+
if (val !== null) {
|
|
3241
|
+
node.setAttribute(name, val);
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
return;
|
|
3246
|
+
|
|
3247
|
+
}
|
|
3248
|
+
for (const [name, attr] of Object.entries(context.tagAttrs)) {
|
|
3249
|
+
if (node instanceof HTMLInputElement && name.toLocaleLowerCase() === 'type') {
|
|
3250
|
+
const value = toAttrValue(attr);
|
|
3251
|
+
if (value !== null) {
|
|
3252
|
+
node.setAttribute(name, value);
|
|
3253
|
+
}
|
|
3254
|
+
continue;
|
|
3255
|
+
}
|
|
3256
|
+
if (name === '$hidden') {
|
|
3257
|
+
if (attr) { node.hidden = attr; }
|
|
3258
|
+
watchAttr(name, (val) => { node.hidden = val; });
|
|
3259
|
+
continue;
|
|
3260
|
+
}
|
|
3261
|
+
|
|
3262
|
+
if (name[0] === '$') {
|
|
3263
|
+
const e = eAttrs[name];
|
|
3264
|
+
if (e) {
|
|
3265
|
+
e(attr, node);
|
|
3266
|
+
watchAttr(name, (attr) => e(attr, node));
|
|
3267
|
+
}
|
|
3268
|
+
continue;
|
|
3269
|
+
}
|
|
3270
|
+
const prop = getAttrs(node, name);
|
|
3271
|
+
if (typeof prop === 'function') {
|
|
3272
|
+
// @ts-ignore
|
|
3273
|
+
node[name] = prop(attr);
|
|
3274
|
+
watchAttr(name, (attr) => {
|
|
3275
|
+
// @ts-ignore
|
|
3276
|
+
node[name] = prop(attr);
|
|
3277
|
+
});
|
|
3278
|
+
continue;
|
|
3279
|
+
}
|
|
3280
|
+
if (prop) {
|
|
3281
|
+
// @ts-ignore
|
|
3282
|
+
node[name] = attr;
|
|
3283
|
+
watchAttr(name, (attr) => {
|
|
3284
|
+
// @ts-ignore
|
|
3285
|
+
node[name] = attr;
|
|
3286
|
+
});
|
|
3287
|
+
continue;
|
|
3288
|
+
}
|
|
3289
|
+
let value = toAttrValue(attr);
|
|
3290
|
+
if (value !== null) {
|
|
3291
|
+
node.setAttribute(name, value);
|
|
3292
|
+
}
|
|
3293
|
+
watchAttr(name, (val) => {
|
|
3294
|
+
const value = toAttrValue(val);
|
|
3295
|
+
if (value === null) {
|
|
3296
|
+
node.removeAttribute(name);
|
|
3297
|
+
} else {
|
|
3298
|
+
node.setAttribute(name, value);
|
|
3299
|
+
}
|
|
3300
|
+
});
|
|
3301
|
+
}
|
|
3302
|
+
});
|
|
3303
|
+
return node;
|
|
3304
|
+
}
|
|
3305
|
+
|
|
3306
|
+
/** @import * as Layout from '../Layout/index.mjs' */
|
|
3307
|
+
/** @import Store, { ArrayStore } from '../Store/index.mjs' */
|
|
3308
|
+
|
|
3309
|
+
/**
|
|
3310
|
+
*
|
|
3311
|
+
* @param {Layout.Node} layout
|
|
3312
|
+
* @param {Element} parent
|
|
3313
|
+
* @param {Node?} next
|
|
3314
|
+
* @param {ArrayStore} store
|
|
3315
|
+
* @param {Environment} env
|
|
3316
|
+
* @param {(layout: Layout.Node, parent: Element, next: Node | null, store: Store, env: any) => () => void} renderItem
|
|
3317
|
+
*/
|
|
3318
|
+
function renderArray(layout, parent, next, store, env, renderItem) {
|
|
3319
|
+
const start = parent.insertBefore(document.createComment(''), next);
|
|
3320
|
+
/** @type {Map<Store, [Comment, Comment, () => void]>} */
|
|
3321
|
+
let seMap = new Map();
|
|
3322
|
+
/** @param {Map<Store, [Comment, Comment, () => void]>} map */
|
|
3323
|
+
function destroyMap(map) {
|
|
3324
|
+
for (const [s, e, d] of map.values()) {
|
|
3325
|
+
d();
|
|
3326
|
+
s.remove();
|
|
3327
|
+
e.remove();
|
|
3328
|
+
}
|
|
3329
|
+
|
|
3330
|
+
}
|
|
3331
|
+
const childrenResult = watch(() => store.children, function render(children) {
|
|
3332
|
+
if (!start.parentNode) { return; }
|
|
3333
|
+
let nextNode = start.nextSibling;
|
|
3334
|
+
const oldSeMap = seMap;
|
|
3335
|
+
seMap = new Map();
|
|
3336
|
+
for (let child of children) {
|
|
3337
|
+
const old = oldSeMap.get(child);
|
|
3338
|
+
if (!old) {
|
|
3339
|
+
const ItemStart = parent.insertBefore(document.createComment(''), nextNode);
|
|
3340
|
+
const itemEnd = parent.insertBefore(document.createComment(''), nextNode);
|
|
3341
|
+
const d = renderItem(layout, parent, itemEnd, child, env.setValue(child, store));
|
|
3342
|
+
seMap.set(child, [ItemStart, itemEnd, d]);
|
|
3343
|
+
continue;
|
|
3344
|
+
}
|
|
3345
|
+
oldSeMap.delete(child);
|
|
3346
|
+
seMap.set(child, old);
|
|
3347
|
+
if (nextNode === old[0]) {
|
|
3348
|
+
nextNode = old[1].nextSibling;
|
|
3349
|
+
continue;
|
|
3350
|
+
}
|
|
3351
|
+
/** @type {Node?} */
|
|
3352
|
+
let c = old[0];
|
|
3353
|
+
while (c && c !== old[1]) {
|
|
3354
|
+
const o = c;
|
|
3355
|
+
c = c.nextSibling;
|
|
3356
|
+
parent.insertBefore(o, nextNode);
|
|
3357
|
+
}
|
|
3358
|
+
parent.insertBefore(old[1], nextNode);
|
|
3359
|
+
}
|
|
3360
|
+
destroyMap(oldSeMap);
|
|
3361
|
+
});
|
|
3362
|
+
|
|
3363
|
+
return () => {
|
|
3364
|
+
start.remove();
|
|
3365
|
+
childrenResult();
|
|
3366
|
+
};
|
|
3367
|
+
}
|
|
3368
|
+
|
|
3369
|
+
/** @import * as Layout from '../Layout/index.mjs' */
|
|
3370
|
+
/**
|
|
3371
|
+
*
|
|
3372
|
+
* @param {any} val
|
|
3373
|
+
* @returns
|
|
3374
|
+
*/
|
|
3375
|
+
function toText(val) {
|
|
3376
|
+
if ((val ?? null) === null) {
|
|
3377
|
+
return '';
|
|
3378
|
+
}
|
|
3379
|
+
return String(val);
|
|
3380
|
+
}
|
|
3381
|
+
|
|
3382
|
+
|
|
3383
|
+
/**
|
|
3384
|
+
* @param {Element} parent
|
|
3385
|
+
* @param {Node?} next
|
|
3386
|
+
* @param {Environment} envs
|
|
3387
|
+
* @param {Layout.Directives} layout
|
|
3388
|
+
*/
|
|
3389
|
+
function renderFillDirectives(parent, next, envs, { text, html }) {
|
|
3390
|
+
if (text != null) {
|
|
3391
|
+
const node = parent.insertBefore(document.createTextNode(''), next);
|
|
3392
|
+
const stop = envs.watch(text, val => node.textContent = toText(val));
|
|
3393
|
+
return () => {
|
|
3394
|
+
node.remove();
|
|
3395
|
+
stop();
|
|
3396
|
+
};
|
|
3397
|
+
}
|
|
3398
|
+
if (html == null) { return; }
|
|
3399
|
+
const start = parent.insertBefore(document.createComment(''), next);
|
|
3400
|
+
const end = parent.insertBefore(document.createComment(''), next);
|
|
3401
|
+
const div = document.createElement('div');
|
|
3402
|
+
/** @param {string} html */
|
|
3403
|
+
function add(html) {
|
|
3404
|
+
div.innerHTML = html;
|
|
3405
|
+
for (let node = div.firstChild; node; node = start.firstChild) {
|
|
3406
|
+
parent.insertBefore(node, end);
|
|
3407
|
+
}
|
|
3408
|
+
}
|
|
3409
|
+
function remove() {
|
|
3410
|
+
for (let node = start.nextSibling; node && node !== end; node = start.nextSibling) {
|
|
3411
|
+
node.remove();
|
|
3412
|
+
}
|
|
3413
|
+
}
|
|
3414
|
+
const result = envs.watch(html, val => {
|
|
3415
|
+
remove();
|
|
3416
|
+
add(toText(val));
|
|
3417
|
+
});
|
|
3418
|
+
return () => {
|
|
3419
|
+
result();
|
|
3420
|
+
remove();
|
|
3421
|
+
start.remove();
|
|
3422
|
+
end.remove();
|
|
3423
|
+
};
|
|
3424
|
+
}
|
|
3425
|
+
|
|
3426
|
+
/** @import * as Layout from '../Layout/index.mjs' */
|
|
3427
|
+
|
|
3428
|
+
/**
|
|
3429
|
+
* @param {(Layout.Node | string)[]} layouts
|
|
3430
|
+
* @param {Element} parent
|
|
3431
|
+
* @param {Node?} next
|
|
3432
|
+
* @param {Environment} envs
|
|
3433
|
+
* @param {(layout: Layout.Node) => () => void} renderItem
|
|
3434
|
+
* @returns {() => void}
|
|
3435
|
+
*/
|
|
3436
|
+
function renderList(layouts, parent, next, envs, renderItem) {
|
|
3437
|
+
|
|
3438
|
+
/** @type {Set<() => void>?} */
|
|
3439
|
+
let bkList = new Set();
|
|
3440
|
+
/** @type {[string | Function | null, Layout.Node][]} */
|
|
3441
|
+
let ifList = [];
|
|
3442
|
+
|
|
3443
|
+
/** @param {[string | Function | null, Layout.Node][]} list */
|
|
3444
|
+
function renderIf(list) {
|
|
3445
|
+
if (!list.length || !bkList) { return; }
|
|
3446
|
+
const end = parent.insertBefore(document.createComment(''), next);
|
|
3447
|
+
|
|
3448
|
+
|
|
3449
|
+
let lastIndex = -1;
|
|
3450
|
+
let destroy = () => { };
|
|
3451
|
+
/**
|
|
3452
|
+
*
|
|
3453
|
+
* @param {number} index
|
|
3454
|
+
* @returns
|
|
3455
|
+
*/
|
|
3456
|
+
function renderIndex(index) {
|
|
3457
|
+
const layout = list[index]?.[1];
|
|
3458
|
+
if (!layout) { return; }
|
|
3459
|
+
destroy = renderItem(layout);
|
|
3460
|
+
}
|
|
3461
|
+
bkList.add(() => {
|
|
3462
|
+
destroy();
|
|
3463
|
+
destroy = () => { };
|
|
3464
|
+
end.remove();
|
|
3465
|
+
});
|
|
3466
|
+
bkList.add(watch(
|
|
3467
|
+
() => list.findIndex(([ifv]) => ifv === null || envs.exec(ifv)),
|
|
3468
|
+
index => {
|
|
3469
|
+
if (index === lastIndex) { return; }
|
|
3470
|
+
lastIndex = index;
|
|
3471
|
+
destroy();
|
|
3472
|
+
destroy = () => { };
|
|
3473
|
+
renderIndex(lastIndex);
|
|
3474
|
+
},
|
|
3475
|
+
));
|
|
3476
|
+
}
|
|
3477
|
+
for (const layout of layouts) {
|
|
3478
|
+
if (typeof layout === 'string') {
|
|
3479
|
+
renderIf(ifList);
|
|
3480
|
+
ifList = [];
|
|
3481
|
+
const node = document.createTextNode(layout);
|
|
3482
|
+
parent.insertBefore(node, next);
|
|
3483
|
+
bkList.add(() => node.remove());
|
|
3484
|
+
continue;
|
|
3485
|
+
}
|
|
3486
|
+
if (ifList.length && layout.directives.else) {
|
|
3487
|
+
const ifv = layout.directives.if || null;
|
|
3488
|
+
ifList.push([ifv, layout]);
|
|
3489
|
+
if (!ifv) {
|
|
3490
|
+
renderIf(ifList);
|
|
3491
|
+
ifList = [];
|
|
3492
|
+
}
|
|
3493
|
+
continue;
|
|
3494
|
+
}
|
|
3495
|
+
renderIf(ifList);
|
|
3496
|
+
ifList = [];
|
|
3497
|
+
const ifv = layout.directives.if;
|
|
3498
|
+
if (ifv) {
|
|
3499
|
+
ifList.push([ifv, layout]);
|
|
3500
|
+
continue;
|
|
3501
|
+
}
|
|
3502
|
+
bkList.add(
|
|
3503
|
+
renderItem(layout)
|
|
3504
|
+
);
|
|
3505
|
+
}
|
|
3506
|
+
|
|
3507
|
+
return () => {
|
|
3508
|
+
if (!bkList) { return; }
|
|
3509
|
+
const list = bkList;
|
|
3510
|
+
bkList = null;
|
|
3511
|
+
for (const s of list) {
|
|
3512
|
+
s();
|
|
3513
|
+
}
|
|
3514
|
+
};
|
|
3515
|
+
}
|
|
3516
|
+
|
|
3517
|
+
/** @import Store from '../Store/index.mjs' */
|
|
3518
|
+
|
|
3519
|
+
/**
|
|
3520
|
+
* @param {Layout.Node} layout
|
|
3521
|
+
* @param {Element} parent
|
|
3522
|
+
* @param {Node?} next
|
|
3523
|
+
* @param {Environment} env
|
|
3524
|
+
* @param {(layout: Layout.Node) => () => void} renderItem
|
|
3525
|
+
* @returns {() => void}
|
|
3526
|
+
*/
|
|
3527
|
+
function renderFragment(layout, parent, next, env, renderItem) {
|
|
3528
|
+
return renderFillDirectives(parent, next, env, layout.directives) ||
|
|
3529
|
+
renderList(layout.children || [], parent, next, env, renderItem);
|
|
3530
|
+
|
|
3531
|
+
}
|
|
3532
|
+
/**
|
|
3533
|
+
* @param {Layout.Node} layout
|
|
3534
|
+
* @param {Element} parent
|
|
3535
|
+
* @param {Node?} next
|
|
3536
|
+
* @param {Store} store
|
|
3537
|
+
* @param {Environment} env
|
|
3538
|
+
* @param {string[]} componentPath
|
|
3539
|
+
* @param {((path: string[]) => Component?)?} [getComponent]
|
|
3540
|
+
*/
|
|
3541
|
+
function renderItem(layout, parent, next, store, env, componentPath, getComponent) {
|
|
3542
|
+
env = env.set(layout.aliases, layout.vars);
|
|
3543
|
+
if (!layout.name || layout.directives.fragment) {
|
|
3544
|
+
return renderFragment(layout, parent, next, env, l => {
|
|
3545
|
+
return render(l, parent, next, store, env, componentPath, getComponent);
|
|
3546
|
+
});
|
|
3547
|
+
}
|
|
3548
|
+
const path = [...componentPath, layout.name];
|
|
3549
|
+
const component = getComponent?.(path);
|
|
3550
|
+
if (getComponent && !component) { return () => { }; }
|
|
3551
|
+
const { context, handler } = createContext(component ? component : layout.name, env);
|
|
3552
|
+
|
|
3553
|
+
|
|
3554
|
+
const componentAttrs = component?.attrs;
|
|
3555
|
+
const attrs = componentAttrs
|
|
3556
|
+
? bindAttrs(handler, env, layout.attrs, componentAttrs, layout.directives.bind)
|
|
3557
|
+
: bindBaseAttrs(handler, env, layout.attrs, layout.directives.bind);
|
|
3558
|
+
|
|
3559
|
+
for (const [name, event] of Object.entries(layout.events)) {
|
|
3560
|
+
const fn = env.getEvent(event);
|
|
3561
|
+
if (fn) { handler.addEvent(name, fn); }
|
|
3562
|
+
}
|
|
3563
|
+
|
|
3564
|
+
const r = component ?
|
|
3565
|
+
typeof component.tag === 'function'
|
|
3566
|
+
? component.tag(context)
|
|
3567
|
+
: createTagComponent(context, component.tag, component.is)
|
|
3568
|
+
: createTagComponent(context, layout.name, layout.is);
|
|
3569
|
+
const root = Array.isArray(r) ? r[0] : r;
|
|
3570
|
+
const slot = Array.isArray(r) && r[1] || root;
|
|
3571
|
+
parent.insertBefore(root, next);
|
|
3572
|
+
const children =
|
|
3573
|
+
renderFillDirectives(slot, null, env, layout.directives)
|
|
3574
|
+
|| renderList(layout.children || [], slot, null, env, l => {
|
|
3575
|
+
return render(l, slot, null, store, env, componentPath, getComponent);
|
|
3576
|
+
});
|
|
3577
|
+
|
|
3578
|
+
|
|
3579
|
+
bindClasses(root, layout.classes, env);
|
|
3580
|
+
bindStyles(root, layout.styles, env);
|
|
3581
|
+
|
|
3582
|
+
handler.init();
|
|
3583
|
+
// TODO: 创建组件
|
|
3584
|
+
return () => {
|
|
3585
|
+
root.remove();
|
|
3586
|
+
handler.destroy();
|
|
3587
|
+
attrs();
|
|
3588
|
+
children();
|
|
3589
|
+
};
|
|
3590
|
+
}
|
|
3591
|
+
/**
|
|
3592
|
+
*
|
|
3593
|
+
* @param {Layout.Node} layout
|
|
3594
|
+
* @param {Element} parent
|
|
3595
|
+
* @param {Node?} next
|
|
3596
|
+
* @param {Store} store
|
|
3597
|
+
* @param {Environment} env
|
|
3598
|
+
* @param {string[]} componentPath
|
|
3599
|
+
* @param {((path: string[]) => Component?)?} [getComponent]
|
|
3600
|
+
* @returns {() => void}
|
|
3601
|
+
*/
|
|
3602
|
+
function render(layout, parent, next, store, env, componentPath, getComponent) {
|
|
3603
|
+
const { directives } = layout;
|
|
3604
|
+
const { value } = directives;
|
|
3605
|
+
if (value) {
|
|
3606
|
+
const newStore = store.child(value);
|
|
3607
|
+
if (!newStore) { return () => {}; }
|
|
3608
|
+
store = newStore;
|
|
3609
|
+
env = env.setValue(store);
|
|
3610
|
+
}
|
|
3611
|
+
if (!directives.enum) {
|
|
3612
|
+
return renderItem(layout, parent, next, store, env, componentPath, getComponent);
|
|
3613
|
+
}
|
|
3614
|
+
if (!(store instanceof ArrayStore)) { return () => { }; }
|
|
3615
|
+
return renderArray(layout, parent, next, store, env, (a, b, c, store, env) => {
|
|
3616
|
+
return renderItem(a, b, c, store, env, componentPath, getComponent);
|
|
3617
|
+
});
|
|
3618
|
+
}
|
|
3619
|
+
|
|
3620
|
+
/**
|
|
3621
|
+
* @overload
|
|
3622
|
+
* @param {Store} store
|
|
3623
|
+
* @param {(Layout.Node | string)[]} layouts
|
|
3624
|
+
* @param {Element} parent
|
|
3625
|
+
* @param {Record<string, Store | {get?(): any; set?(v: any): void; exec?(...p: any[]): any; calc?(...p: any[]): any }>} [global]
|
|
3626
|
+
* @param {(path: string[]) => Component?} [components]
|
|
3627
|
+
* @returns {() => void}
|
|
3628
|
+
*/
|
|
3629
|
+
/**
|
|
3630
|
+
* @overload
|
|
3631
|
+
* @param {Store} store
|
|
3632
|
+
* @param {(Layout.Node | string)[]} layouts
|
|
3633
|
+
* @param {Element} parent
|
|
3634
|
+
* @param {((path: string[]) => Component?)?} [components]
|
|
3635
|
+
* @returns {() => void}
|
|
3636
|
+
*/
|
|
3637
|
+
/**
|
|
3638
|
+
* @param {Store} store
|
|
3639
|
+
* @param {(Layout.Node | string)[]} layouts
|
|
3640
|
+
* @param {Element} parent
|
|
3641
|
+
* @param {((path: string[]) => Component?) | Record<string, Store | {get?(): any; set?(v: any): void; exec?(...p: any[]): any; calc?(...p: any[]): any }> | null} [opt1]
|
|
3642
|
+
* @param {((path: string[]) => Component?) | Record<string, Store | {get?(): any; set?(v: any): void; exec?(...p: any[]): any; calc?(...p: any[]): any }> | null} [opt2]
|
|
3643
|
+
*/
|
|
3644
|
+
function index (store, layouts, parent, opt1, opt2) {
|
|
3645
|
+
const options = [opt1, opt2];
|
|
3646
|
+
const components = options.find(v => typeof v === 'function');
|
|
3647
|
+
const global = options.find(v => typeof v === 'object');
|
|
3648
|
+
const env = new Environment(global).setValue(store);
|
|
3649
|
+
return renderList(layouts, parent, null, env, l => {
|
|
3650
|
+
return render(l, parent, null, store, env, [], components);
|
|
3651
|
+
});
|
|
3652
|
+
}
|
|
3653
|
+
|
|
3654
|
+
exports.Layout = index$1;
|
|
3655
|
+
exports.Store = Store;
|
|
3656
|
+
exports.render = index;
|
|
3657
|
+
|
|
3658
|
+
}));
|