compelem 0.2.0-beta → 0.2.2-beta

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.js CHANGED
@@ -1,3148 +1,7 @@
1
1
  /**
2
- * compelem v0.2.0-beta.1731509434
2
+ * compelem v0.2.2-beta.1731842602
3
3
  * A modern, reactive, fast, lightweight and flexible lib for building web components
4
4
  * @holyhigh2
5
5
  * https://github.com/holyhigh2/compelem
6
6
  */
7
- import { toPath, isObject, isDefined, get, isUndefined, isEmpty, has, concat, set, cloneDeep, kebabCase, last, isEqual, startsWith, includes, clone, isFunction, isElement, isArray, initial, find, debounce, throttle, once, remove, map, size, isBlank, join, split, replace, compact, toArray, assign, first, each, isString, closest, bind as bind$1, trim, omitBy, camelCase, isNil, some, isNull, fval, test, merge, omit, flatMap, groupBy, reject, filter, slice, head, trimStart, trimEnd, replaceAll, snakeCase, toString, findIndex, call } from 'myfx';
8
-
9
- function showError(msg) {
10
- console.error(`[CompElem]`, msg);
11
- }
12
- function showTagError(tagName, msg) {
13
- console.error(`[CompElem <${tagName}>]`, msg);
14
- }
15
- function showWarn(...args) {
16
- console.warn(`[CompElem]`, ...args);
17
- }
18
- //为依赖收集提供标准地址
19
- function toUpdatePath(varPath) {
20
- return toPath(varPath).join("-");
21
- }
22
-
23
- //装饰器类型
24
- var DecoratorType;
25
- (function (DecoratorType) {
26
- DecoratorType["CLASS"] = "class";
27
- DecoratorType["FIELD"] = "field";
28
- DecoratorType["METHOD"] = "method";
29
- })(DecoratorType || (DecoratorType = {}));
30
- /**
31
- * 用于构造装饰器
32
- * @author holyhigh2
33
- */
34
- class Decorator {
35
- }
36
-
37
- const GetKeyFnName = 'getKey';
38
- const DecoratorsKey = '__decorators';
39
- /**
40
- * 装饰器包装类
41
- * 用于框架内部,表示class上的一个装饰器属性定义
42
- * 该定义在实例初始化时会产生装饰器实例属性
43
- */
44
- class DecoratorWrapper {
45
- //execute 参数
46
- args;
47
- //装饰器参数
48
- metadata;
49
- decoratorClass;
50
- instanceMap;
51
- key; //装饰器唯一key
52
- constructor(args, metadata, decoratorClass) {
53
- this.args = args;
54
- this.metadata = metadata;
55
- this.decoratorClass = decoratorClass;
56
- this.instanceMap = new WeakMap;
57
- }
58
- //在组件构造时调用
59
- create(comp) {
60
- let ins = new this.decoratorClass(...this.args);
61
- //1. 校验targets
62
- let targets = ins.targets;
63
- let decoType = undefined;
64
- let descriptor = this.metadata[2];
65
- if (isObject(descriptor) && isDefined(get(descriptor, 'configurable'))) {
66
- decoType = DecoratorType.METHOD;
67
- }
68
- else if (isUndefined(this.metadata[2])) {
69
- decoType = DecoratorType.FIELD;
70
- }
71
- if (isEmpty(targets) || !decoType || !targets.includes(decoType)) {
72
- showError(`Decorator '${this.decoratorClass.name}' is out of targets, expect '${targets.join(',')}' bug got '${decoType}'`);
73
- return;
74
- }
75
- ins.created(comp, ...this.metadata);
76
- this.instanceMap.set(comp, ins);
77
- }
78
- propsReady(comp, setReactive) {
79
- let ins = this.instanceMap.get(comp);
80
- ins.propsReady(comp, setReactive, ...this.metadata);
81
- }
82
- mounted(comp, setReactive) {
83
- let ins = this.instanceMap.get(comp);
84
- ins.mounted(comp, setReactive, ...this.metadata);
85
- }
86
- updated(comp, changed) {
87
- this.instanceMap.get(comp).updated(comp, changed);
88
- }
89
- }
90
- //每个装饰器类中不同组件类中的重复key
91
- const DecoKeyMap = new WeakMap();
92
- /**
93
- * 该函数用于创建一个装饰器
94
- * @param decoClass 装饰器构造
95
- * @returns 装饰器函数
96
- */
97
- function decorator(decoClass) {
98
- return (...args) => {
99
- return (...metadata) => {
100
- let constr = metadata[0].constructor;
101
- let ary = get(constr, DecoratorsKey);
102
- if (!has(constr, DecoratorsKey)) {
103
- //继承父类
104
- let parentAry = get(Object.getPrototypeOf(constr), DecoratorsKey);
105
- ary = parentAry ? concat(parentAry) : [];
106
- set(constr, DecoratorsKey, ary);
107
- }
108
- let getKey = get(decoClass, GetKeyFnName);
109
- if (getKey) {
110
- let compMap = DecoKeyMap.get(decoClass);
111
- if (!compMap) {
112
- compMap = new WeakMap;
113
- DecoKeyMap.set(decoClass, compMap);
114
- }
115
- let kMap = compMap.get(constr);
116
- if (!kMap) {
117
- kMap = {};
118
- compMap.set(constr, kMap);
119
- }
120
- let k = getKey(...args);
121
- if (kMap[k])
122
- return;
123
- kMap[k] = true;
124
- }
125
- ary?.push(new DecoratorWrapper(args, metadata, decoClass));
126
- };
127
- };
128
- }
129
-
130
- //每个类需要监控的属性
131
- const ObservedAttrsMap = new WeakMap;
132
- function prop(options) {
133
- if (arguments.length === 1) {
134
- return (target, propertyKey, descriptor) => {
135
- options.required = options.required || false;
136
- options.attribute = options.attribute === false ? false : true;
137
- defineProp(target, propertyKey, options, descriptor);
138
- };
139
- }
140
- let target = arguments[0], propertyKey = arguments[1], descriptor = arguments[2];
141
- defineProp(target, propertyKey, { type: undefined, required: false, attribute: true }, descriptor);
142
- }
143
- function defineProp(target, propertyKey, options, descriptor) {
144
- if (!/[a-z]/.test(propertyKey[0])) {
145
- showError(`Prop '${propertyKey}' must be in CamelCase`);
146
- }
147
- if (!has(target.constructor, '__deco_props')) {
148
- target.constructor.__deco_props = isEmpty(target.constructor.__deco_props) ? {} : cloneDeep(target.constructor.__deco_props);
149
- }
150
- if (descriptor) {
151
- if (descriptor.get)
152
- options.getter = descriptor.get;
153
- if (descriptor.set)
154
- options.setter = descriptor.set;
155
- }
156
- if (options.attribute) {
157
- let attrSet = ObservedAttrsMap.get(target.constructor);
158
- if (!attrSet) {
159
- attrSet = new Set();
160
- ObservedAttrsMap.set(target.constructor, attrSet);
161
- }
162
- let kbb = kebabCase(propertyKey);
163
- attrSet?.add(kbb);
164
- }
165
- target.constructor.__deco_props[propertyKey] = options;
166
- }
167
- /**
168
- * 同@prop装饰器,但可用于构造器中调用
169
- * @param ctor 类构造函数
170
- * @param propertyKey prop名称
171
- * @param options
172
- */
173
- function makeProp(ctor, propertyKey, options) {
174
- if (options) {
175
- options.required = options.required || false;
176
- options.attribute = options.attribute === false ? false : true;
177
- }
178
- defineProp(ctor.prototype, propertyKey, options || { type: undefined, required: false, attribute: true });
179
- }
180
- //内部接口
181
- const emptySet = new Set;
182
- function _getObservedAttrs(ctor) {
183
- return ObservedAttrsMap.get(ctor) ?? emptySet;
184
- }
185
-
186
- /**
187
- * 用于提供全局state状态管理
188
- * @author holyhigh2
189
- */
190
- const EVENT_UPDATE = 'update';
191
- const Collector = {
192
- startCss(comp) {
193
- this.__cssCollecting = comp;
194
- },
195
- endCss() {
196
- this.__cssCollecting = null;
197
- },
198
- setCssUpdater(updater) {
199
- this.__cssUpdater = updater;
200
- },
201
- startCompute(comp) {
202
- this.__computeCollecting = comp;
203
- },
204
- endCompute() {
205
- this.__computeCollecting = null;
206
- },
207
- setComputedProp(updater) {
208
- this.__computeUpdater = updater;
209
- },
210
- __computeCollecting: null,
211
- __computeUpdater: null,
212
- __cssCollecting: null,
213
- __cssUpdater: null,
214
- //仅用于指令在构造时获取
215
- __directiveQ: [],
216
- setDirectiveQ(val) {
217
- let lastVar = last(this.__directiveQ);
218
- if (lastVar && isEqual(lastVar, val))
219
- return;
220
- if (lastVar && lastVar.length < val.length && startsWith(val.join(','), lastVar.join(','))) {
221
- this.__directiveQ[this.__directiveQ.length - 1] = val;
222
- return;
223
- }
224
- this.__directiveQ.push(val);
225
- },
226
- popDirectiveQ() {
227
- let rs = concat(this.__directiveQ);
228
- this.__directiveQ = [];
229
- return rs;
230
- },
231
- startRender(context) {
232
- this.__renderCollecting = true;
233
- this.__renderContext = context;
234
- },
235
- endRender(component) {
236
- //注册依赖
237
- this.__renderCollection.forEach((varPath) => {
238
- component._regDeps(varPath, this.__renderContext);
239
- });
240
- this.__renderCollection.clear();
241
- this.__renderCollecting = false;
242
- this.__renderContext = null;
243
- },
244
- collect(prop) {
245
- this.__renderCollection.add(prop);
246
- },
247
- clear() {
248
- this.__directiveQ = [];
249
- },
250
- __renderCollection: new Set(),
251
- __renderContext: null,
252
- __renderCollecting: false,
253
- __skipCheck: false
254
- };
255
- const OBJECT_META_DATA = new WeakMap();
256
- const OBJECT_VAR_PATH = new WeakMap();
257
- const COMPUTED_MAP = new WeakMap();
258
- const CSS_MAP = new WeakMap();
259
- /**
260
- * 1. 初始化时obj都是普通对象
261
- * 2. OBJECT_VAR_PATH 首次是普通对象
262
- * 3. OBJECT_META_DATA 直接绑定代理对象
263
- * @param obj
264
- * @param context
265
- * @returns
266
- */
267
- function reactive(obj, context) {
268
- if (!isObject(obj))
269
- return obj;
270
- const proxyObject = obj.__proxy ? obj : new Proxy(obj, {
271
- get(target, prop, receiver) {
272
- const ks = Object.keys(target);
273
- const value = Reflect.get(target, prop, receiver);
274
- if (!includes(ks, prop)) {
275
- return value;
276
- }
277
- if (target.hasOwnProperty(prop)) {
278
- let chain = OBJECT_VAR_PATH.get(receiver) ?? [];
279
- let subChain = concat(chain, [prop]);
280
- let subChainStr = subChain.join('-');
281
- if (Collector.__renderCollecting) {
282
- Collector.collect(toUpdatePath(subChain));
283
- Collector.setDirectiveQ(subChain);
284
- }
285
- else if (Collector.__computeCollecting) {
286
- let watchVarMap = COMPUTED_MAP.get(Collector.__computeCollecting);
287
- if (!watchVarMap) {
288
- watchVarMap = {};
289
- COMPUTED_MAP.set(Collector.__computeCollecting, watchVarMap);
290
- }
291
- let list = watchVarMap[subChainStr];
292
- if (!list)
293
- list = watchVarMap[subChainStr] = [];
294
- list.push(Collector.__computeUpdater);
295
- }
296
- else if (Collector.__cssCollecting) {
297
- let watchVarMap = CSS_MAP.get(Collector.__cssCollecting);
298
- if (!watchVarMap) {
299
- watchVarMap = {};
300
- CSS_MAP.set(Collector.__cssCollecting, watchVarMap);
301
- }
302
- watchVarMap[subChainStr] = Collector.__cssUpdater;
303
- }
304
- }
305
- return value;
306
- },
307
- set(target, prop, newValue, receiver) {
308
- let sourceContext = OBJECT_META_DATA.get(receiver).from;
309
- let propDefs = get(sourceContext.constructor, '__deco_props');
310
- if (propDefs && propDefs[prop] && target.__isData) {
311
- if (propDefs[prop].sync) {
312
- sourceContext.emit(EVENT_UPDATE + ":" + prop, { value: newValue });
313
- }
314
- }
315
- let ov = target[prop];
316
- let stateDefs = get(sourceContext.constructor, '__deco_states');
317
- let hasChanged = get(propDefs, [prop, 'hasChanged']) || get(stateDefs, [prop, 'hasChanged']);
318
- if (hasChanged) {
319
- if (!hasChanged.call(sourceContext, newValue, ov))
320
- return false;
321
- }
322
- else {
323
- //防止重复设置,如Array.length
324
- if (target[prop] === newValue)
325
- return true;
326
- if (Number.isNaN(newValue) && Number.isNaN(target[prop]))
327
- return false;
328
- }
329
- //todo 如果对象保存一层副本,如果要保存全部内容需要自行实现
330
- if (isObject(ov)) {
331
- ov = clone(ov);
332
- }
333
- let deps = OBJECT_META_DATA.get(receiver)?.contextSet;
334
- //get oldValue from sourceContext
335
- let chain = OBJECT_VAR_PATH.get(receiver) ?? [];
336
- let subChain = concat(chain, [prop]);
337
- let nv = newValue;
338
- if (isObject(newValue) && !isFunction(newValue) && !isElement(newValue)) {
339
- deps.forEach(dep => {
340
- let pathMap = OBJECT_META_DATA.get(receiver)?.pathMap;
341
- let pathAry = pathMap?.get(dep);
342
- if (!pathAry)
343
- return;
344
- subChain = concat(pathAry, [prop]);
345
- OBJECT_VAR_PATH.set(nv, subChain);
346
- nv = reactive(nv, dep);
347
- OBJECT_VAR_PATH.set(nv, subChain);
348
- });
349
- }
350
- let rs = Reflect.set(target, prop, nv);
351
- let pathMap = OBJECT_META_DATA.get(receiver).pathMap;
352
- deps.forEach(dep => {
353
- //view update
354
- let pathAry = pathMap.get(dep);
355
- if (!pathAry)
356
- return;
357
- //数组length属性变动直接通知为数组自身变动
358
- subChain = concat(pathAry, prop == 'length' && isArray(receiver) ? [] : [prop]);
359
- dep._notify(ov, subChain);
360
- let varPath = subChain.join('-');
361
- //computed
362
- let watchVarMap = COMPUTED_MAP.get(dep);
363
- if (watchVarMap) {
364
- let computedList = watchVarMap[varPath];
365
- if (computedList) {
366
- computedList.forEach(computedGetter => {
367
- computedGetter.call(dep);
368
- });
369
- }
370
- let i = subChain.length - 1;
371
- while (i) {
372
- let subPath = subChain.slice(0, i).join('-');
373
- let computedList = watchVarMap[subPath];
374
- if (computedList) {
375
- computedList.forEach(computedGetter => {
376
- computedGetter.call(dep);
377
- });
378
- }
379
- i--;
380
- }
381
- }
382
- //css
383
- let cssMap = CSS_MAP.get(dep);
384
- if (cssMap) {
385
- let computedCss = cssMap[varPath];
386
- if (computedCss) {
387
- computedCss.call(dep);
388
- }
389
- let i = subChain.length - 1;
390
- while (i) {
391
- let subPath = subChain.slice(0, i).join('-');
392
- let computedCss = cssMap[subPath];
393
- if (computedCss) {
394
- computedCss.call(dep);
395
- }
396
- i--;
397
- }
398
- }
399
- });
400
- return rs;
401
- }
402
- });
403
- if (!obj.__proxy) {
404
- Object.defineProperty(obj, "__proxy", {
405
- enumerable: false,
406
- writable: false,
407
- configurable: false,
408
- value: true,
409
- });
410
- }
411
- let chain = OBJECT_VAR_PATH.get(obj) ?? [];
412
- if (Object.isExtensible(obj) && !OBJECT_META_DATA.get(proxyObject)) {
413
- let contextSet = new Set();
414
- contextSet.add(context);
415
- //对象所属context
416
- let pathMap = new WeakMap();
417
- pathMap.set(context, chain);
418
- OBJECT_META_DATA.set(proxyObject, {
419
- from: context,
420
- contextSet,
421
- pathMap
422
- });
423
- }
424
- else {
425
- let deps = OBJECT_META_DATA.get(proxyObject).contextSet;
426
- deps.add(context);
427
- let pathMap = OBJECT_META_DATA.get(proxyObject).pathMap;
428
- let chains = pathMap.get(context);
429
- let subChain = concat(chain);
430
- if (chains && chains.join('') !== subChain.join('')) {
431
- let parentVar = get(context, initial(chains));
432
- //处理数组元素更新,如 ary.1 -> ary.0
433
- if (!isArray(parentVar)) {
434
- showWarn(`The object is referenced by more than one @state '${subChain.join('.')},${chains.join('.')}'`);
435
- }
436
- chains = subChain;
437
- }
438
- else {
439
- pathMap.set(context, subChain);
440
- }
441
- }
442
- for (let k in obj) {
443
- const v = obj[k];
444
- if (isObject(v) && !isFunction(v) && !isElement(v) && !(v instanceof Text)) {
445
- OBJECT_VAR_PATH.set(v, concat(chain, [k]));
446
- obj[k] = reactive(v, context);
447
- OBJECT_VAR_PATH.set(obj[k], concat(chain, [k]));
448
- }
449
- }
450
- return proxyObject;
451
- }
452
-
453
- /*************************************************************
454
- * 扩展事件
455
- * @author holyhigh2
456
- *
457
- * resize
458
- * outside.[mousedown/up/click/dblclick] 默认click
459
- *
460
- *************************************************************/
461
- const ExtEvNames = ['resize', 'outside'];
462
- ///////////////////////////////////////////////// resize
463
- const AllResizeEls = new WeakMap;
464
- const AllOutsideDownEls = [];
465
- const resizeObserver = new ResizeObserver((entries) => {
466
- for (const entry of entries) {
467
- const contentBoxSize = Array.isArray(entry.contentBoxSize)
468
- ? entry.contentBoxSize[0]
469
- : entry.contentBoxSize;
470
- const borderBoxSize = Array.isArray(entry.borderBoxSize)
471
- ? entry.borderBoxSize[0]
472
- : entry.borderBoxSize;
473
- let cbk = AllResizeEls.get(entry.target);
474
- if (cbk) {
475
- let ev = new CustomEvent('resize', {
476
- bubbles: false,
477
- cancelable: false,
478
- detail: {
479
- borderBox: { w: borderBoxSize.inlineSize, h: borderBoxSize.blockSize },
480
- contentBox: { w: contentBoxSize.inlineSize, h: contentBoxSize.blockSize },
481
- },
482
- });
483
- cbk(ev);
484
- }
485
- }
486
- });
487
- function addResize(node, cbk) {
488
- AllResizeEls.set(node, cbk);
489
- resizeObserver.observe(node);
490
- }
491
- ///////////////////////////////////////////////// outside
492
- document.addEventListener('mousedown', e => {
493
- let t = e.target;
494
- AllOutsideDownEls.forEach(([node, cbk]) => {
495
- if (!node.contains(t)) {
496
- let ev = new CustomEvent('outside', {
497
- bubbles: false,
498
- cancelable: false,
499
- detail: {
500
- currentTarget: node,
501
- event: e
502
- },
503
- });
504
- cbk(ev);
505
- }
506
- });
507
- }, false);
508
- function addOutsideMouseDown(node, cbk) {
509
- AllOutsideDownEls.push([node, cbk]);
510
- }
511
- function isExtEvent(evName) {
512
- return ExtEvNames.includes(evName);
513
- }
514
- function addExtEvent(evName, node, cbk, parts) {
515
- if (evName === 'resize') {
516
- addResize(node, cbk);
517
- }
518
- else if (evName === 'outside') {
519
- switch (parts[0]) {
520
- case 'mousedown':
521
- addOutsideMouseDown(node, cbk);
522
- break;
523
- }
524
- }
525
- }
526
-
527
- const MODI_EV_DEBOUNCE = /,|^(debounce:.+)|(debounce$)/;
528
- const MODI_EV_THROTTLE = /,|^(throttle:.+)|(throttle$)/;
529
- const MODI_EV_SELF = 'self';
530
- const MODI_EV_STOP = 'stop';
531
- const MODI_EV_PREVENT = 'prevent';
532
- const MODI_EV_ONCE = 'once';
533
- const MODI_EV_MOUSE_LEFT = 'left';
534
- const MODI_EV_MOUSE_RIGHT = 'right';
535
- const MODI_EV_MOUSE_MIDDLE = 'middle';
536
- const MODI_EV_KEYBOARD_COMBO_CTRL = 'ctrl';
537
- const MODI_EV_KEYBOARD_COMBO_ALT = 'alt';
538
- const MODI_EV_KEYBOARD_COMBO_SHIFT = 'shift';
539
- const MODI_EV_KEYBOARD_COMBO_META = 'meta';
540
- const MODI_EV_KEYBOARD_KEY_MAP = {
541
- 'esc': 'escape'
542
- };
543
- const MODI_PARAM_DIVIDER = ":";
544
- /*************************************************************
545
- * 事件修饰符
546
- * @author holyhigh2
547
- *
548
- * 通用 debounce/stop/prevent/once/throttle/self 可组合
549
- * 鼠标 left/right/middle 不可组合
550
- * 键盘 ctrl/alt/shift/meta 可组合 esc/letters... 不可组合,多个key并列式表示可选
551
- *
552
- * 部分修饰符支持参数,使用冒号传参如:throttle:100 / debounce:100
553
- *************************************************************/
554
- function addEvent(fullName, cbk, node, component) {
555
- let parts = fullName.split('.');
556
- let evName = parts.shift();
557
- let isOnce = parts.includes(MODI_EV_ONCE);
558
- let c = cbk;
559
- let modi;
560
- if (modi = find(parts, x => MODI_EV_DEBOUNCE.test(x))) {
561
- let params = modi.split(MODI_PARAM_DIVIDER);
562
- c = debounce(c, parseInt(params[1]) || 100);
563
- }
564
- if (modi = find(parts, x => MODI_EV_THROTTLE.test(x))) {
565
- let params = modi.split(MODI_PARAM_DIVIDER);
566
- c = throttle(c, parseInt(params[1]) || 100);
567
- }
568
- if (isOnce) {
569
- c = once(c);
570
- }
571
- if (isExtEvent(evName)) {
572
- addExtEvent(evName, node, c, parts);
573
- return c;
574
- }
575
- let listener = (e) => {
576
- if (parts.includes(MODI_EV_PREVENT))
577
- e.preventDefault();
578
- if (parts.includes(MODI_EV_STOP))
579
- e.stopPropagation();
580
- if (parts.includes(MODI_EV_SELF) && e.target !== e.currentTarget)
581
- return;
582
- if (e instanceof MouseEvent) {
583
- if (parts.includes(MODI_EV_MOUSE_LEFT) && e.button != 0)
584
- return;
585
- if (parts.includes(MODI_EV_MOUSE_RIGHT) && e.button != 2)
586
- return;
587
- if (parts.includes(MODI_EV_MOUSE_MIDDLE) && e.button != 1)
588
- return;
589
- }
590
- else if (e instanceof KeyboardEvent) {
591
- if (remove(parts, p => p == MODI_EV_KEYBOARD_COMBO_CTRL)[0] && !e.ctrlKey)
592
- return;
593
- if (remove(parts, p => p == MODI_EV_KEYBOARD_COMBO_ALT)[0] && !e.altKey)
594
- return;
595
- if (remove(parts, p => p == MODI_EV_KEYBOARD_COMBO_SHIFT)[0] && !e.shiftKey)
596
- return;
597
- if (remove(parts, p => p == MODI_EV_KEYBOARD_COMBO_META)[0] && !e.metaKey)
598
- return;
599
- let checkKeys = map(parts, k => MODI_EV_KEYBOARD_KEY_MAP[k] || k);
600
- if (!checkKeys.includes(e.key.toLowerCase()))
601
- return;
602
- }
603
- c(e);
604
- };
605
- node.addEventListener(evName, listener);
606
- //record
607
- let evAry = component.__events[evName];
608
- if (!evAry)
609
- evAry = component.__events[evName] = [];
610
- evAry.push([node, listener]);
611
- return listener;
612
- }
613
-
614
- /**
615
- * 为组件/指令提供渲染接口
616
- * @author holyhigh2
617
- */
618
- function RenderContext(spuerClass) {
619
- //mixin class
620
- return class extends spuerClass {
621
- /**
622
- * 渲染实现
623
- */
624
- render(...args) { }
625
- //模板中变量位置信息
626
- __expPos = {};
627
- //对于each指令存在多个context,每个context需要单独更新 {contextKey:expPos}
628
- __expPosMap = {};
629
- //组件内所有的指令
630
- __directives = {}; /**
631
- * 指令/组件所在的插槽所属组件
632
- */
633
- slotComponent;
634
- /**
635
- * 渲染上下文所属组件
636
- */
637
- renderComponent;
638
- //////////////////////////////////// methods
639
- renderContext(...args) {
640
- return renderContext.call(this, ...args);
641
- }
642
- updateContext(...args) {
643
- let tmpl = size(args) == 1 && ((isArray(args[0]) && args[0][0] instanceof Template) || (args[0] instanceof Template)) ? args[0] : this.render(...args);
644
- if (tmpl instanceof Template) {
645
- this.__updateExpPos(tmpl, this.__expPos);
646
- }
647
- else if (isArray(tmpl) && tmpl[0] instanceof Template) {
648
- tmpl.forEach((tmp, i) => {
649
- this.__updateExpPos(tmp, this.__expPosMap[tmp.key ?? tmp.getKey()]);
650
- });
651
- }
652
- }
653
- __updateExpPos(tmpl, _expPos) {
654
- if (isBlank(join(tmpl.strings)))
655
- return;
656
- let { vars } = tmpl;
657
- _expPos && Object.values(_expPos).forEach(expPos => {
658
- let varIndex = expPos.index;
659
- let oldValue = expPos.value;
660
- let newValue = vars;
661
- let node = expPos.node;
662
- let indexSegs = split(varIndex, '-');
663
- indexSegs.forEach((seg, i) => {
664
- newValue = get(newValue, seg);
665
- if (newValue && newValue.vars && i < indexSegs.length - 1) {
666
- newValue = newValue.vars;
667
- }
668
- });
669
- //check
670
- if (!isObject(oldValue) && oldValue === newValue)
671
- return;
672
- let elNode = node;
673
- if (expPos.isDirective) {
674
- //指令
675
- newValue.di = oldValue.di;
676
- newValue.di.renderParams = newValue.varChain;
677
- newValue.di._renderArgs = newValue.args;
678
- newValue.point = oldValue.point;
679
- newValue.varPath = oldValue.varPath;
680
- let nodes = getDirectiveNodes(newValue.point.startNode, newValue.point.endNode);
681
- newValue.update(nodes, newValue.args, oldValue.args);
682
- }
683
- else if (expPos.isToggleProp) {
684
- //布尔特性
685
- if ((!!newValue) === oldValue)
686
- return;
687
- elNode.toggleAttribute(expPos.attrName, !!newValue);
688
- set(elNode, expPos.attrName, !!newValue);
689
- }
690
- else if (expPos.isProp) {
691
- //子组件属性
692
- if (!isObject(newValue) && newValue === oldValue)
693
- return;
694
- if (isObject(newValue) && isEqual(newValue, oldValue))
695
- return;
696
- //如果node是slot则触发组件的slot更新
697
- if (node instanceof CompElem) {
698
- node._updateProps({ [expPos.attrName]: newValue });
699
- }
700
- else if (node instanceof HTMLSlotElement) {
701
- this.renderComponent._updateSlot(node.getAttribute('name') || 'default', expPos.attrName, newValue);
702
- }
703
- }
704
- else if (expPos.eventName) {
705
- elNode.removeEventListener(expPos.eventName, oldValue);
706
- newValue = newValue.bind(this.renderComponent);
707
- newValue = addEvent(expPos.attrName, newValue, elNode, this.renderComponent);
708
- }
709
- else if (expPos.attrName) {
710
- //特性
711
- if (!isEqual(oldValue, newValue)) {
712
- switch (expPos.attrName) {
713
- case 'value':
714
- if (node instanceof HTMLInputElement) {
715
- node.value = newValue;
716
- break;
717
- }
718
- default:
719
- node.setAttribute(expPos.attrName, replace(expPos.attrTmpl, PLACEHOLDER_EXP, newValue + ''));
720
- }
721
- }
722
- }
723
- else if (expPos.isTmpl) {
724
- //这里一定是子视图更新,子视图仅更新内部__expose
725
- if (!isEqual(newValue, oldValue)) {
726
- let [subNodes, subExpPos, subExpPosMap] = renderContext.call(this, newValue /*newValue */);
727
- if (isEmpty(subExpPos)) {
728
- DomUtil.remove(expPos.textNode, expPos.node);
729
- DomUtil.insertBefore(expPos.node, subNodes);
730
- }
731
- else {
732
- this.__updateExpPos(newValue, subExpPos);
733
- }
734
- }
735
- }
736
- else if (expPos.isText) {
737
- let textNode = expPos.textNode.nextSibling;
738
- if (textNode && textNode === expPos.node.previousSibling) {
739
- textNode.textContent = newValue;
740
- }
741
- else {
742
- DomUtil.remove(expPos.textNode, expPos.node);
743
- DomUtil.insertBefore(expPos.node, [newValue]);
744
- }
745
- }
746
- expPos.value = newValue;
747
- });
748
- }
749
- };
750
- }
751
- function renderContext(...args) {
752
- let tmpl = args.length === 1 && args[0] instanceof Template ? args[0] : this.render(...args);
753
- let domTree;
754
- let diWrappers = [];
755
- let expPos = undefined;
756
- let expPosMap = undefined;
757
- if (tmpl instanceof Template) {
758
- let html = buildHTML(tmpl);
759
- // this.__expPos = {}
760
- expPos = {};
761
- domTree = buildTmplate(expPos, diWrappers, html, tmpl.vars, this.renderComponent);
762
- }
763
- if (isArray(tmpl) && tmpl[0] instanceof Template) {
764
- // this.__expPosMap = {}
765
- let doms = [];
766
- expPosMap = {};
767
- tmpl.forEach(tmp => {
768
- let html = buildHTML(tmp);
769
- let __expPos = {};
770
- domTree = buildTmplate(__expPos, diWrappers, html, tmp.vars, this.renderComponent);
771
- doms.push(...domTree);
772
- expPosMap[tmp.key ?? tmp.getKey()] = __expPos;
773
- // this.__expPosMap[tmp.key ?? tmp.getKey()] = __expPos
774
- });
775
- domTree = doms;
776
- }
777
- else if (tmpl instanceof Function) {
778
- //todo 目前仅支持slot,后续如有异步指令再行重构
779
- this.slotComponent._asyncDirectives.set(tmpl, this);
780
- }
781
- if (diWrappers.length < 1)
782
- return [domTree, expPos, expPosMap];
783
- diWrappers.forEach(diWrapper => {
784
- let nodes = compact(toArray(diWrapper.render(this.renderComponent)));
785
- if (!isEmpty(nodes)) {
786
- let fragment = document.createDocumentFragment();
787
- fragment.append(...nodes);
788
- diWrapper.point.endNode.parentNode.insertBefore(fragment, diWrapper.point.endNode);
789
- }
790
- });
791
- return [domTree, expPos, expPosMap];
792
- }
793
- function getDirectiveNodes(startNode, endNode) {
794
- let nextNode = startNode.nextSibling;
795
- if (!endNode)
796
- return [nextNode];
797
- let rs = [];
798
- while (nextNode && nextNode !== endNode) {
799
- rs.push(nextNode);
800
- nextNode = nextNode?.nextSibling;
801
- }
802
- return rs;
803
- }
804
-
805
- const ATTR_CSS_LINK = "css-link";
806
- const PropTypeMap = {
807
- boolean: Boolean,
808
- string: String,
809
- number: Number,
810
- object: Object,
811
- array: Array,
812
- function: Function,
813
- bigint: BigInt,
814
- symbol: Symbol,
815
- undefined: Object
816
- };
817
- const PrivatePreffix = '#';
818
- /**
819
- * CompElem基类,意为组件元素。提供了基本内置属性及生命周期等必备接口
820
- * 每个组件都需要继承自该类
821
- *
822
- * @author holyhigh2
823
- */
824
- class CompElem extends RenderContext(HTMLElement) {
825
- static __l_globalRule = document.createElement("style");
826
- static {
827
- document.head.appendChild(CompElem.__l_globalRule);
828
- }
829
- #slotPropsMap = {};
830
- #data = { '#slots': {} };
831
- #reactiveData = {};
832
- #updateTimer;
833
- #updateSources = {};
834
- #shadow;
835
- #selfObserver;
836
- //保存所有渲染上下文 {CompElem/Directive}
837
- #renderContextList = {};
838
- __events = {};
839
- get reactiveData() {
840
- return this.#reactiveData;
841
- }
842
- get attrs() {
843
- return this.#attrs;
844
- }
845
- get props() {
846
- return this.#props;
847
- }
848
- get renderRoot() {
849
- return this.#renderRoot;
850
- }
851
- get renderRoots() {
852
- return this.#renderRoots;
853
- }
854
- get parentComponent() {
855
- return this.#parentComponent;
856
- }
857
- get slotHooks() {
858
- return this.#slotHooks;
859
- }
860
- get styles() {
861
- return get(this.constructor, '_component_style_attached', []); //this.#styles;
862
- }
863
- get isMounted() {
864
- return this.#mounted;
865
- }
866
- //slots列表中绝对不会出现slot元素
867
- get slots() {
868
- return this.#data['#slots'];
869
- }
870
- #attrs;
871
- #props;
872
- #renderRoot;
873
- #renderRoots;
874
- #parentComponent;
875
- #slotsEl = {};
876
- #slotHooks = {};
877
- #slotNodes = {};
878
- #mounted = false;
879
- #instanceCss = new CSSStyleSheet();
880
- /**
881
- * 是否自动插入插槽,如果需要控制插槽类型时,可以设置为false
882
- */
883
- static get autoSlot() {
884
- return true;
885
- }
886
- //////////////////////////////////// styles
887
- /**
888
- * 组件样式,CSSStyleSheet可动态变更
889
- */
890
- static get styles() {
891
- return [];
892
- }
893
- static get globalStyles() {
894
- return [];
895
- }
896
- get css() {
897
- return '';
898
- }
899
- #inited = false;
900
- constructor(...args) {
901
- super();
902
- //init props via constructor
903
- if (size(args) === 1) {
904
- this.#props = {};
905
- assign(this.#props, first(args));
906
- }
907
- this.renderComponent = this;
908
- let render = this.render;
909
- this.render = () => {
910
- let rs;
911
- Collector.startRender(this);
912
- rs = render.call(this);
913
- Collector.endRender(this.renderComponent);
914
- return rs;
915
- };
916
- /////////////////////////////////////////////////// styles
917
- //global styles
918
- let globalStyles = get(this.constructor, "globalStyles");
919
- let beAttached = get(this.constructor, '_global_style_attached');
920
- if (!isEmpty(globalStyles) && beAttached !== '1') {
921
- let globalTextContent = "";
922
- each(globalStyles, (st) => {
923
- if (isString(st)) {
924
- globalTextContent += st + "\n";
925
- }
926
- });
927
- CompElem.__l_globalRule.textContent += globalTextContent;
928
- set(this.constructor, '_global_style_attached', '1');
929
- }
930
- //component styles
931
- let beAttached2 = get(this.constructor, '_component_style_attached');
932
- let styleSheets = beAttached2 ?? [];
933
- if (!beAttached2) {
934
- each(get(this.constructor, "styles"), (st) => {
935
- if (isString(st)) {
936
- let sheet = new CSSStyleSheet();
937
- sheet.replace(st);
938
- styleSheets.push(sheet);
939
- }
940
- else {
941
- styleSheets.push(st);
942
- }
943
- });
944
- set(this.constructor, '_component_style_attached', styleSheets);
945
- }
946
- /////////////////////////////////////////////////// shadow
947
- this.#shadow = this.attachShadow({
948
- mode: "open",
949
- slotAssignment: get(this.constructor, "autoSlot", true) ? "named" : "manual",
950
- });
951
- this.#shadow.adoptedStyleSheets = concat(styleSheets, this.#instanceCss);
952
- //check link
953
- let cssLink = this.attributes.getNamedItem(ATTR_CSS_LINK)?.value;
954
- if (cssLink) {
955
- const link = document.createElement("style");
956
- link.textContent = `@import "${cssLink}"`;
957
- this.#shadow.appendChild(link);
958
- }
959
- let filterSlotFn = debounce(this.#filterSlot, 20);
960
- this.#selfObserver = new MutationObserver(mutations => {
961
- mutations.forEach(mutation => {
962
- if (mutation.type === 'childList') {
963
- filterSlotFn.call(this);
964
- }
965
- else if (mutation.type === 'attributes') {
966
- if (mutation.attributeName)
967
- this.#attrChanged(mutation.attributeName, mutation.oldValue, this.getAttribute(mutation.attributeName));
968
- }
969
- });
970
- });
971
- //slots prop map
972
- this._slotsPropMap = { default: [] };
973
- /////////////////////////////////////////////////// decorators create
974
- let ary = get(this.constructor, DecoratorsKey);
975
- each(ary, dw => {
976
- dw.create(this);
977
- });
978
- }
979
- connectedCallback() {
980
- //parent
981
- let node = closest(this.parentNode, (node) => node instanceof CompElem || node.host instanceof CompElem, "parentNode");
982
- this.#parentComponent = node
983
- ? node instanceof CompElem
984
- ? node
985
- : node.host
986
- : null;
987
- this.connected();
988
- this.__init();
989
- }
990
- disconnectedCallback() {
991
- this.#selfObserver.disconnect();
992
- }
993
- //////////////////////////////////// lifecycles
994
- //********************************** 首次渲染
995
- //构造时上级传递的参数
996
- __init() {
997
- if (this.#inited)
998
- return;
999
- /////////////////////////////////////////////////// slots
1000
- this.#updateSlotsAry();
1001
- //check props
1002
- this.#initProps();
1003
- this.#initStates();
1004
- //define reactive
1005
- each(this.#data, (v, k) => {
1006
- let descr = Reflect.getOwnPropertyDescriptor(this.#data, k);
1007
- Object.defineProperty(this, k, {
1008
- get() {
1009
- let v = Reflect.get(this.#reactiveData, k);
1010
- return descr?.get ? descr?.get() : v;
1011
- },
1012
- set(v) {
1013
- if (descr?.set) {
1014
- descr?.set(v);
1015
- }
1016
- else {
1017
- Reflect.set(this.#reactiveData, k, v);
1018
- }
1019
- },
1020
- });
1021
- });
1022
- Object.defineProperty(this.#data, '__isData', {
1023
- enumerable: false,
1024
- value: true
1025
- });
1026
- this.#reactiveData = reactive(this.#data, this);
1027
- /////////////////////////////////////////////////// decorators propsReady
1028
- const that = this;
1029
- let ary = get(this.constructor, DecoratorsKey);
1030
- each(ary, dw => {
1031
- dw.propsReady(this, (key, value) => {
1032
- that.#reactiveData[key] = value;
1033
- return that.#reactiveData[key];
1034
- });
1035
- });
1036
- this.propsReady();
1037
- //computed props
1038
- let computedMap = get(this.constructor, "__deco_computed");
1039
- each(computedMap, ({ key, getter }, propKey) => {
1040
- Collector.startCompute(this);
1041
- Collector.setComputedProp(() => {
1042
- this.#reactiveData[propKey] = getter.call(this);
1043
- });
1044
- this.#data[propKey] = getter.call(this);
1045
- Collector.endCompute();
1046
- });
1047
- each(computedMap, (v, k) => {
1048
- Object.defineProperty(this, k, {
1049
- get() {
1050
- return Reflect.get(this.#reactiveData, k);
1051
- },
1052
- set(v) {
1053
- showTagError(this.tagName, "Cannot set a computed property '" + k + "'");
1054
- },
1055
- });
1056
- });
1057
- //render
1058
- let [nodes, expPos, expPosMap] = this.renderContext();
1059
- this.__expPos = expPos;
1060
- if (nodes) {
1061
- let children = toArray(nodes);
1062
- each(children, (c) => {
1063
- this.#shadow.appendChild(c);
1064
- });
1065
- this.#renderRoots = children;
1066
- this.#renderRoot = children[0];
1067
- }
1068
- //filter slot before append to dom
1069
- this.#filterSlot();
1070
- this.#selfObserver.observe(this, { childList: true, attributes: true });
1071
- //events
1072
- let eventList = get(this.constructor, "__deco_events");
1073
- each(eventList, (ev) => {
1074
- let name = ev.name;
1075
- let options = assign({ target: document, once: false, passive: false, capture: false }, ev.options);
1076
- let listener = bind$1(ev.fn, this);
1077
- let target = options.target;
1078
- if (isFunction(target)) {
1079
- target = target.call(this, this);
1080
- }
1081
- target.addEventListener(name, listener, options);
1082
- });
1083
- //slot hook
1084
- each(this.#slotHooks, (v, k) => {
1085
- this.#updateSlot(k);
1086
- });
1087
- //instance dynamic style
1088
- Collector.startCss(this);
1089
- Collector.setCssUpdater(() => {
1090
- let css = this.css;
1091
- this.#instanceCss.replace(css);
1092
- });
1093
- let css = this.css;
1094
- if (trim(css)) {
1095
- this.#instanceCss.replace(css);
1096
- }
1097
- Collector.endCss();
1098
- setTimeout(() => {
1099
- this.#mounted = true;
1100
- this.mounted();
1101
- each(ary, dw => {
1102
- dw.mounted(this, (key, value) => {
1103
- that.#reactiveData[key] = value;
1104
- return that.#reactiveData[key];
1105
- });
1106
- });
1107
- }, 0);
1108
- this.#inited = true;
1109
- }
1110
- /**
1111
- * 初始化属性及状态,该回调内可以访问props和state
1112
- * 此时组件dom并未构建,但已有parent 属性,没有root属性
1113
- */
1114
- connected() { }
1115
- /**
1116
- * props初始化完成回调
1117
- */
1118
- propsReady() { }
1119
- /**
1120
- * dom渲染完毕后调用,该回调内可以query注解初始化完成
1121
- */
1122
- mounted() { }
1123
- #onSlogChange(slot, name) {
1124
- //1. 更新 _slotsPropMap & slots
1125
- this.#updateSlotsAry();
1126
- //2. 设置attrs
1127
- let props = get(this.#slotPropsMap[name], 'props');
1128
- if (props) {
1129
- each(this.slots, (nodeAry, k) => {
1130
- nodeAry.filter(node => node.nodeType === Node.ELEMENT_NODE).forEach((node) => {
1131
- if (node instanceof CompElem) {
1132
- // node._setParentProps(props)
1133
- node._updateProps(props);
1134
- return;
1135
- }
1136
- each(props, (v, k) => {
1137
- if (node instanceof HTMLSlotElement) {
1138
- let compOfSlot = get(node, '__l_comp');
1139
- if (compOfSlot) {
1140
- let sname = node.name || 'default';
1141
- let slotMap = compOfSlot.#slotPropsMap[sname];
1142
- if (!slotMap) {
1143
- slotMap = compOfSlot.#slotPropsMap[sname] = { props: {} };
1144
- }
1145
- if (!slotMap.props) {
1146
- slotMap.props = {};
1147
- }
1148
- slotMap.props[k] = v;
1149
- compOfSlot.#onSlogChange(node, sname);
1150
- }
1151
- }
1152
- else {
1153
- node.setAttribute(k, v);
1154
- }
1155
- });
1156
- });
1157
- });
1158
- }
1159
- //3. callback
1160
- this.slotchange(slot, name);
1161
- }
1162
- slotchange(slot, name) {
1163
- }
1164
- //********************************** 更新
1165
- /**
1166
- * 是否需要更新,可获取变更属性
1167
- * 返回true时更新
1168
- */
1169
- shouldUpdate(changed) {
1170
- return true;
1171
- }
1172
- /**
1173
- * 1. 调用render
1174
- * 2. 更新@query/all
1175
- * 3. 更新ref
1176
- * 4. 更新prop到attr的映射
1177
- * @param changed
1178
- */
1179
- updated(changed) { }
1180
- /**
1181
- * 抛出自定义事件
1182
- * @param evName 事件名称
1183
- * @param args 自定义参数
1184
- */
1185
- emit(evName, arg = {}, options) {
1186
- if (options && options.event) {
1187
- arg.event = options.event;
1188
- }
1189
- arg.target = this;
1190
- this.dispatchEvent(new CustomEvent(evName, {
1191
- bubbles: get(options, "bubbles", false),
1192
- composed: get(options, "composed", false),
1193
- cancelable: true,
1194
- detail: arg,
1195
- }));
1196
- }
1197
- #rootEvs = {};
1198
- /**
1199
- * 在root上绑定事件
1200
- * @param evName
1201
- * @param hook
1202
- */
1203
- on(evName, hook) {
1204
- if (!this.#rootEvs[evName]) {
1205
- this.#rootEvs[evName] = [];
1206
- }
1207
- let cbk = hook.bind(this);
1208
- this.#rootEvs[evName].push(cbk);
1209
- this.addEventListener(evName, cbk);
1210
- }
1211
- /**
1212
- * 下一帧执行
1213
- * @param cbk
1214
- */
1215
- nextTick(cbk) {
1216
- requestAnimationFrame(cbk);
1217
- }
1218
- /**
1219
- * 强制更新一次视图
1220
- */
1221
- forceUpdate() {
1222
- each(this.#reactiveData, (v, k) => {
1223
- this.#updateSources[k] = {
1224
- value: undefined,
1225
- chain: undefined,
1226
- };
1227
- });
1228
- this.#update();
1229
- }
1230
- /**
1231
- * 由监控变量调用
1232
- * @param stateKey
1233
- * @param ov
1234
- * @param rootStateKey 如果是对象内部属性变更,会返回根属性名
1235
- * @returns
1236
- */
1237
- _notify(ov, chain) {
1238
- let varPath = [];
1239
- each(chain, (seg) => {
1240
- varPath.push(seg);
1241
- let v = get(this, varPath);
1242
- let pathStr = toUpdatePath(varPath);
1243
- if (pathStr === "#slots") {
1244
- pathStr = 'slots';
1245
- }
1246
- this.#updateSources[pathStr] = { value: v, chain: pathStr === "slots" ? ['slots'] : varPath, oldValue: ov, end: varPath.length === chain.length };
1247
- });
1248
- //debounce
1249
- if (this.#updateTimer) {
1250
- clearTimeout(this.#updateTimer);
1251
- }
1252
- this.#updateTimer = setTimeout(this.#update.bind(this), 10);
1253
- }
1254
- #update() {
1255
- const changed = Object.seal(clone(omitBy(this.#updateSources, (v, k) => k[0] === PrivatePreffix)));
1256
- //update decorators
1257
- let ary = get(this.constructor, DecoratorsKey);
1258
- each(ary, dw => {
1259
- dw.updated(this, changed);
1260
- });
1261
- let toBreak = !this.shouldUpdate(changed);
1262
- if (toBreak)
1263
- return;
1264
- let renderContextList = new Set();
1265
- //1. filter context
1266
- each(this.#updateSources, ({ value, chain, oldValue }, k) => {
1267
- if (this.#renderContextList[k]) {
1268
- this.#renderContextList[k].forEach(cx => {
1269
- renderContextList.add(cx);
1270
- });
1271
- }
1272
- });
1273
- //2. update context
1274
- renderContextList.forEach(context => {
1275
- context.updateContext(...(context._renderArgs ? context._renderArgs : []));
1276
- });
1277
- //update slot view
1278
- each(this.#updateSlots, (v) => {
1279
- this.#updateSlot(v);
1280
- });
1281
- this.updated(changed);
1282
- this.#updateSources = {};
1283
- }
1284
- /**
1285
- * 1. 初始props中并未包含的属性,可从attributes取,且定义类型不是string时自动转换
1286
- * 2. 如果attributes中也未出现且必填报错
1287
- * 3. 否则设置默认值
1288
- * @returns 非props的attr集合
1289
- */
1290
- #initProps() {
1291
- let propDefs = get(this.constructor, "__deco_props");
1292
- let attrs = this.attributes;
1293
- let tagName = this.tagName;
1294
- let parentProps = this.#props;
1295
- let filterAttrs = {};
1296
- each(attrs, ({ name, value }) => {
1297
- if (name[0] === ATTR_PREFIX_EVENT ||
1298
- name[0] === ATTR_PREFIX_PROP ||
1299
- name[0] === ATTR_PREFIX_BOOLEAN ||
1300
- name === ATTR_REF || name === 'slot')
1301
- return;
1302
- let camelName = camelCase(name);
1303
- if (propDefs && !propDefs[camelName]) {
1304
- filterAttrs[name] = value;
1305
- }
1306
- });
1307
- this.#attrs = this.#attrs ? assign(this.#attrs, filterAttrs) : filterAttrs;
1308
- each(propDefs, (def, key) => {
1309
- let propDef = propDefs[key];
1310
- let isInited = has(parentProps, key);
1311
- let defaultVal = get(this, key);
1312
- if (!('_defaultValue' in propDef)) {
1313
- //在构造结束后
1314
- propDef._defaultValue = defaultVal;
1315
- if (!propDef.type) {
1316
- if (isUndefined(defaultVal)) {
1317
- showTagError(tagName, "Prop '" + key + "' has neither propType nor defaultValue be used for type inference");
1318
- }
1319
- let type = typeof defaultVal;
1320
- if (isArray(defaultVal))
1321
- type = 'array';
1322
- let inferredType = PropTypeMap[type];
1323
- propDef.type = inferredType;
1324
- }
1325
- }
1326
- let val = undefined;
1327
- if (isInited) {
1328
- val = isNil(parentProps[key]) ? defaultVal : parentProps[key];
1329
- }
1330
- else {
1331
- val = defaultVal;
1332
- let attr = attrs.getNamedItem(kebabCase(key)) ||
1333
- attrs.getNamedItem(ATTR_PREFIX_PROP + kebabCase(key));
1334
- if (attr) {
1335
- isInited = true;
1336
- val = attr.value;
1337
- }
1338
- }
1339
- //required check
1340
- let isRequired = propDef.required;
1341
- if (isRequired && !isInited) {
1342
- showTagError(tagName, "Prop '" + key + "' is required");
1343
- return false;
1344
- }
1345
- val = this.#propTypeCheck(propDefs, key, val);
1346
- let getter = get(propDefs, [key, 'getter']);
1347
- if (getter)
1348
- getter = bind$1(getter, this);
1349
- let setter = get(propDefs, [key, 'setter']);
1350
- if (setter)
1351
- setter = bind$1(setter, this);
1352
- if (getter || setter) {
1353
- Object.defineProperty(this.#data, key, {
1354
- set: setter || function (v) { },
1355
- get: getter
1356
- });
1357
- }
1358
- if (propDef.attribute && isDefined(val) && !isObject(val)) {
1359
- this.setAttribute(kebabCase(key), trim(val));
1360
- }
1361
- this.#data[key] = val;
1362
- });
1363
- }
1364
- //属性值检测
1365
- #propTypeCheck(propDefs, propKey, newValue) {
1366
- let propDef = propDefs[propKey];
1367
- if (!propDef)
1368
- return newValue;
1369
- let validator = propDef.isValid;
1370
- let expectType = propDef.type;
1371
- let expectTypeAry = isArray(expectType) ? expectType : [expectType];
1372
- let typeConverter = propDef.converter;
1373
- let val = newValue;
1374
- if (!some(expectTypeAry, (et) => et === String) && isString(val) && !isNull(val)) {
1375
- try {
1376
- val = typeConverter ? typeConverter(val) : fval(val, { html });
1377
- }
1378
- catch (error) {
1379
- showTagError(this.tagName, `Convert attribute '${propKey}' error with ` + val);
1380
- }
1381
- } //endif
1382
- //extra work
1383
- expectTypeAry.forEach(et => {
1384
- if (et.name === 'Boolean') {
1385
- if (isString(val) && /(?:^true$)|(?:^false$)/.test(val)) {
1386
- val = fval(val);
1387
- }
1388
- else if (isUndefined(val) || isBlank(val)) {
1389
- val = true;
1390
- }
1391
- }
1392
- });
1393
- let realType = typeof val;
1394
- let matched = isDefined(val) ? false : true;
1395
- each(expectTypeAry, (et) => {
1396
- if (
1397
- //base form
1398
- test(realType, et.name, "i") ||
1399
- //object form
1400
- val instanceof et) {
1401
- matched = true;
1402
- return false;
1403
- }
1404
- });
1405
- if (!matched) {
1406
- showTagError(this.tagName, `Invalid prop '${propKey}'. expected '${expectTypeAry.map((t) => t.name || t)}' but got '${realType}'`);
1407
- }
1408
- if (validator) {
1409
- if (!validator.call(this, val, this.#data)) {
1410
- showTagError(this.tagName, `Invalid prop '${propKey}'. IsValid() check failed`);
1411
- }
1412
- }
1413
- return val;
1414
- }
1415
- #initStates() {
1416
- let stateDefs = get(this.constructor, "__deco_states");
1417
- each(stateDefs, (def, key) => {
1418
- let stateDef = stateDefs[key];
1419
- let val = get(this, key);
1420
- if (stateDef) {
1421
- let propName = stateDef.prop;
1422
- val = propName ? cloneDeep(this.#data[propName]) : get(this, key);
1423
- }
1424
- this.#data[key] = val;
1425
- });
1426
- }
1427
- /**
1428
- * 由外部调用,在初始化及更新时。
1429
- * @param props
1430
- * @param attrs
1431
- */
1432
- #propsReady = debounce(this.propsReady, 100);
1433
- /**
1434
- * @deprecated
1435
- */
1436
- _setParentProps(props, attrs) {
1437
- if (this.#inited) {
1438
- let propDefs = get(this.constructor, "__deco_props");
1439
- //存在attrs表示已初始化完成
1440
- each(props, (v, k) => {
1441
- let ck = camelCase(k);
1442
- let propDef = propDefs[ck];
1443
- if (!propDef)
1444
- return;
1445
- let ov = this.#data[ck];
1446
- v = this.#propTypeCheck(propDefs, ck, v);
1447
- if (propDef.hasChanged && !propDef.hasChanged.call(this, v, ov))
1448
- return;
1449
- this.#data[ck] = v;
1450
- this._notify(ov, [ck]);
1451
- });
1452
- assign(this.#props, props);
1453
- assign(this.#attrs, attrs);
1454
- this.#propsReady();
1455
- }
1456
- }
1457
- //todo 这里需要直接修改prop
1458
- _updateProps(props) {
1459
- let propDefs = get(this.constructor, "__deco_props");
1460
- //存在attrs表示已初始化完成
1461
- each(props, (v, k) => {
1462
- let ck = camelCase(k);
1463
- let propDef = propDefs[ck];
1464
- if (!propDef)
1465
- return;
1466
- let ov = this.#data[ck];
1467
- v = this.#propTypeCheck(propDefs, ck, v);
1468
- if (propDef.hasChanged && !propDef.hasChanged.call(this, v, ov))
1469
- return;
1470
- Collector.__skipCheck = true;
1471
- set(this, ck, v);
1472
- Collector.__skipCheck = false;
1473
- });
1474
- assign(this.#props, props);
1475
- this.#propsReady();
1476
- }
1477
- _initProps(props, attrs) {
1478
- this.#props = merge(this.#props || {}, props);
1479
- this.#attrs = merge({}, attrs);
1480
- }
1481
- /**
1482
- * 绑定slot标签,render时调用
1483
- */
1484
- _bindSlot(slot, name, props) {
1485
- //1. 设置map
1486
- if (!this.#slotsEl[name]) {
1487
- this.#slotsEl[name] = slot;
1488
- Object.defineProperty(slot, '__l_comp', {
1489
- value: this
1490
- });
1491
- }
1492
- slot.addEventListener('slotchange', (e) => {
1493
- if (this.#inited)
1494
- this.#onSlogChange(slot, name === 'default' ? '' : name);
1495
- });
1496
- //3. 保存参数
1497
- if (!isEmpty(props)) {
1498
- let slotMap = this.#slotPropsMap[name];
1499
- if (!slotMap) {
1500
- slotMap = this.#slotPropsMap[name] = {};
1501
- }
1502
- if (props.nodeFilter) {
1503
- slotMap.filter = props.nodeFilter;
1504
- }
1505
- slotMap.props = omit(props, 'nodeFilter');
1506
- }
1507
- }
1508
- _bindSlotHook(name, hook) {
1509
- this.#slotHooks[name] = hook;
1510
- }
1511
- //slot变量变动时触发
1512
- #updateSlots = new Set();
1513
- _updateSlot(name, propName, value) {
1514
- let slotEl = this.#slotsEl[name];
1515
- let hook = this.#slotHooks[name];
1516
- if (!hook && !slotEl)
1517
- return;
1518
- let slotMap = this.#slotPropsMap[name];
1519
- if (propName) {
1520
- if (!slotMap.props) {
1521
- slotMap.props = {};
1522
- }
1523
- slotMap.props[propName] = value;
1524
- }
1525
- if (!!hook) {
1526
- this.#updateSlots.add(name);
1527
- }
1528
- else {
1529
- //update nodes
1530
- let els = slotEl.assignedElements({ flatten: true });
1531
- each(els, el => {
1532
- el.setAttribute(propName, value + '');
1533
- });
1534
- }
1535
- }
1536
- #updateSlotsAry() {
1537
- const cs = flatMap(this.childNodes, node => {
1538
- if (node.nodeType === Node.COMMENT_NODE)
1539
- return [];
1540
- if (node instanceof HTMLSlotElement)
1541
- return node.assignedNodes({ flatten: true });
1542
- return node;
1543
- });
1544
- let groups = groupBy(cs, node => {
1545
- // if (node.nodeType === Node.COMMENT_NODE) return ''
1546
- if (node.nodeType === Node.TEXT_NODE)
1547
- return 'default';
1548
- if (node instanceof Element) {
1549
- return node.getAttribute('slot') || 'default';
1550
- }
1551
- });
1552
- if (isEmpty(groups)) {
1553
- if (!isEmpty(this.#data['#slots'])) {
1554
- this.#inited ? this.#reactiveData['#slots'] = {} : this.#data['#slots'] = {};
1555
- }
1556
- return;
1557
- }
1558
- each(groups, (nodeAry, k) => {
1559
- if (!k)
1560
- return;
1561
- while (nodeAry.length > 0) {
1562
- let node = nodeAry[0];
1563
- if ((node.nodeType === Node.TEXT_NODE && isBlank(node.textContent)) ||
1564
- (node instanceof HTMLSlotElement && isEmpty(node.assignedNodes({ flatten: true })))) {
1565
- nodeAry.shift();
1566
- continue;
1567
- }
1568
- break;
1569
- }
1570
- while (nodeAry.length > 0) {
1571
- let node = last(nodeAry);
1572
- if ((node.nodeType === Node.TEXT_NODE && isBlank(node.textContent)) ||
1573
- (node instanceof HTMLSlotElement && isEmpty(node.assignedNodes({ flatten: true })))) {
1574
- nodeAry.pop();
1575
- continue;
1576
- }
1577
- break;
1578
- }
1579
- });
1580
- let rs = {};
1581
- each(groups, (v, k) => {
1582
- if (!isEmpty(v)) {
1583
- rs[k] = v;
1584
- }
1585
- });
1586
- this.#inited ? this.#reactiveData['#slots'] = rs : this.#data['#slots'] = rs;
1587
- }
1588
- #updateSlot(name) {
1589
- let hook = this.#slotHooks[name];
1590
- if (!hook)
1591
- return;
1592
- let slotMap = this.#slotPropsMap[name];
1593
- let slot = this.#data['#slots'][name];
1594
- //slot not ready yet
1595
- //1. 可能是if/each等指令还未插入
1596
- if (!slot)
1597
- return;
1598
- //组件通知渲染异步指令
1599
- this.renderAsync(hook, get(slotMap, 'props'));
1600
- const rc = this._asyncDirectives.get(hook);
1601
- //todo 如果要做成通用异步指令,元素必须插入到指令挂载的位置,并且slot的插入节点还要去掉注释
1602
- let [nodes, expPos, expPosMap] = rc?.renderContext(hook(get(slotMap, 'props')));
1603
- let nnodes = reject(toArray(nodes), n => n.nodeType === Node.COMMENT_NODE);
1604
- if (nnodes) {
1605
- let slottedNodes = this.#slotNodes[name];
1606
- if (!isEmpty(slottedNodes)) {
1607
- each(slottedNodes, n => {
1608
- n.parentNode?.removeChild(n);
1609
- });
1610
- }
1611
- this.#slotNodes[name] = nnodes;
1612
- this.append(...nnodes);
1613
- this.#updateSlots.clear();
1614
- }
1615
- }
1616
- _asyncDirectives = new WeakMap();
1617
- renderAsync(cbk, ...args) {
1618
- }
1619
- //children变化时触发
1620
- #filterSlot() {
1621
- if (isEmpty(this.#slotPropsMap))
1622
- return;
1623
- each(this.slots, (slottedNodes, k) => {
1624
- if (isEmpty(slottedNodes))
1625
- return;
1626
- let slotMap = this.#slotPropsMap[k];
1627
- let filterNodes = slottedNodes;
1628
- if (slotMap) {
1629
- let filterFn = slotMap.filter;
1630
- if (isFunction(filterFn)) {
1631
- filterNodes = filterFn(slottedNodes);
1632
- }
1633
- else if (isObject(filterFn)) {
1634
- let type = filterFn.type;
1635
- let maxCount = filterFn.maxCount;
1636
- if (type) {
1637
- let ts = isArray(type) ? type : [type];
1638
- filterNodes = filter(slottedNodes, n => some(ts, t => n instanceof t));
1639
- }
1640
- if (maxCount > 0) {
1641
- filterNodes = slice(slottedNodes, 0, maxCount);
1642
- }
1643
- }
1644
- }
1645
- if (this.#shadow.slotAssignment === 'named') {
1646
- let removeNodes = [];
1647
- each(slottedNodes, c => {
1648
- if (!filterNodes.includes(c)) {
1649
- removeNodes.push(c);
1650
- }
1651
- });
1652
- while (removeNodes.length > 0) {
1653
- let n = removeNodes.pop();
1654
- n.parentNode?.removeChild(n);
1655
- }
1656
- }
1657
- else {
1658
- this.#slotsEl[k].assign(...filterNodes);
1659
- }
1660
- if (this.#inited)
1661
- this.#onSlogChange(this.#slotsEl[k], k === 'default' ? '' : k);
1662
- });
1663
- }
1664
- #attrChanged(name, oldValue, newValue) {
1665
- if (!this.isMounted)
1666
- return;
1667
- let observedAttrs = _getObservedAttrs(this.constructor);
1668
- if (observedAttrs.has(name)) {
1669
- if (isNull(newValue)) {
1670
- let propDefs = get(this.constructor, "__deco_props");
1671
- //使用默认值
1672
- newValue = propDefs[name]._defaultValue;
1673
- }
1674
- this._updateProps({ [name]: newValue });
1675
- // this._setParentProps({ [name]: newValue }, { [name]: newValue })
1676
- }
1677
- }
1678
- _regDeps(varPath, renderContext) {
1679
- let list = this.#renderContextList[varPath];
1680
- if (!list) {
1681
- list = this.#renderContextList[varPath] = new Set();
1682
- }
1683
- list.add(renderContext);
1684
- }
1685
- }
1686
-
1687
- /**
1688
- * @author holyhigh2
1689
- */
1690
- var DirectiveUpdateTag;
1691
- (function (DirectiveUpdateTag) {
1692
- DirectiveUpdateTag["NONE"] = "NONE";
1693
- DirectiveUpdateTag["REMOVE"] = "REMOVE";
1694
- DirectiveUpdateTag["REPLACE"] = "REPLACE";
1695
- DirectiveUpdateTag["UPDATE"] = "UPDATE";
1696
- DirectiveUpdateTag["APPEND"] = "APPEND";
1697
- })(DirectiveUpdateTag || (DirectiveUpdateTag = {}));
1698
- /**
1699
- * 模板中的表达式位置
1700
- */
1701
- class ExpPos {
1702
- //表达式位置,多层使用-分割
1703
- index;
1704
- value;
1705
- isText = false;
1706
- //是否模板
1707
- isTmpl = false;
1708
- isDirective = false;
1709
- //表达式所在节点,可能是元素/文本
1710
- node;
1711
- //如果是文本位置,与node一起构成插入范围
1712
- textNode;
1713
- //是否组件
1714
- isComponent = false;
1715
- //如果在属性中,属性名
1716
- attrName;
1717
- //属性值模板
1718
- attrTmpl;
1719
- //是否组件属性
1720
- isProp = false;
1721
- //是否布尔属性
1722
- isToggleProp = false;
1723
- //事件名称
1724
- eventName;
1725
- constructor(varIndex, node, attrName, attrTmpl) {
1726
- this.index = varIndex + '';
1727
- this.node = node;
1728
- if (attrName)
1729
- this.attrName = attrName;
1730
- if (attrTmpl) {
1731
- this.attrTmpl = attrTmpl;
1732
- }
1733
- }
1734
- }
1735
-
1736
- const DI_KEY = "__directives";
1737
- /**
1738
- * 属性定义
1739
- */
1740
- var EnterPointType;
1741
- (function (EnterPointType) {
1742
- EnterPointType["ATTR"] = "attr";
1743
- EnterPointType["PROP"] = "prop";
1744
- EnterPointType["TEXT"] = "text";
1745
- EnterPointType["CLASS"] = "class";
1746
- EnterPointType["STYLE"] = "style";
1747
- EnterPointType["SLOT"] = "slot";
1748
- EnterPointType["TAG"] = "tag"; //在标签内但不是属性内
1749
- })(EnterPointType || (EnterPointType = {}));
1750
- /**
1751
- * 交互点信息
1752
- */
1753
- class EnterPoint {
1754
- startNode; //依赖节点
1755
- endNode; //依赖节点2
1756
- type; //依赖类型
1757
- attrName; //依赖属性名
1758
- varIndex;
1759
- expressionChain; //所在层级序号 [parentVarIndex-varIndex-]+,如1-6 表示根的第2个表达式下的context的第7个表达式
1760
- nodes; //如果是插入节点,保存插入的节点数组
1761
- constructor(level, node, attrName, type) {
1762
- this.startNode = node;
1763
- this.attrName = attrName;
1764
- this.type = type;
1765
- }
1766
- setVarIndex(varIndex) {
1767
- this.varIndex = varIndex;
1768
- }
1769
- }
1770
- var MovePosition;
1771
- (function (MovePosition) {
1772
- MovePosition["AFTER_BEGIN"] = "afterbegin";
1773
- })(MovePosition || (MovePosition = {}));
1774
- /**
1775
- * Delay the actual time of execution of directive
1776
- */
1777
- class DirectiveWrapper extends Function {
1778
- diClass;
1779
- args;
1780
- di;
1781
- varPath;
1782
- point;
1783
- slotComponent;
1784
- varChain;
1785
- constructor(diClass, ...args) {
1786
- super();
1787
- this.diClass = diClass;
1788
- this.args = args;
1789
- this.varChain = Collector.popDirectiveQ();
1790
- }
1791
- //校验scope
1792
- checkScope(scopeType) {
1793
- let scopes = get(this.diClass, 'scopes');
1794
- if (!isEmpty(scopes) && !test(scopes.join(','), scopeType)) {
1795
- showError(`Directive '${this.diClass.name}' is out of scopes, expect '${scopes.join(',')}' bug got '${scopeType}'`);
1796
- return;
1797
- }
1798
- }
1799
- render(component) {
1800
- let diMap = get(component, DI_KEY);
1801
- let di = this.di || diMap[this.varPath];
1802
- if (!di) {
1803
- di = new this.diClass(this.point);
1804
- di.renderComponent = component;
1805
- di.slotComponent = this.slotComponent;
1806
- di.renderParams = this.varChain;
1807
- }
1808
- this.di = di;
1809
- di._renderArgs = this.args;
1810
- let [nodes, expPos, expPosMap] = di.renderContext(...this.args);
1811
- if (expPosMap) {
1812
- di.__expPosMap = expPosMap;
1813
- }
1814
- else if (expPos) {
1815
- di.__expPos = expPos;
1816
- }
1817
- return nodes;
1818
- }
1819
- update(nodes, newArgs, oldArgs) {
1820
- let tag = this.di.update(nodes, newArgs, oldArgs);
1821
- if (tag === DirectiveUpdateTag.REMOVE) {
1822
- nodes.forEach(n => {
1823
- n.parentNode?.removeChild(n);
1824
- });
1825
- }
1826
- else if (tag === DirectiveUpdateTag.REPLACE) {
1827
- let newNodes = [];
1828
- nodes.forEach(n => {
1829
- n.parentNode?.removeChild(n);
1830
- });
1831
- let rs = this.di.render(...newArgs);
1832
- let [nnodes, expPos, expPosMap] = this.di.renderContext(rs);
1833
- if (expPosMap) {
1834
- this.di.__expPosMap = expPosMap;
1835
- }
1836
- else if (expPos) {
1837
- this.di.__expPos = expPos;
1838
- }
1839
- newNodes = toArray(nnodes);
1840
- let fragment = document.createDocumentFragment();
1841
- fragment.append(...newNodes);
1842
- this.point.endNode.parentNode.insertBefore(fragment, this.point.endNode);
1843
- }
1844
- else if (tag === DirectiveUpdateTag.UPDATE) {
1845
- let newKeys = {};
1846
- let newKeyMap = {};
1847
- let nodesToUpdate;
1848
- //原节点顺序
1849
- let oldSeq = [];
1850
- let newSeq = [];
1851
- let updateRs = this.di.render(...newArgs);
1852
- if (isArray(updateRs) && updateRs[0] instanceof Template) {
1853
- updateRs.forEach(tmpl => {
1854
- let k = tmpl.key ?? tmpl.getKey();
1855
- newKeys[k] = '1';
1856
- newKeyMap[k] = tmpl;
1857
- newSeq.push(k);
1858
- });
1859
- }
1860
- //UPDATE仅处理元素节点
1861
- nodes = filter(compact(nodes), n => n.nodeType === Node.ELEMENT_NODE);
1862
- nodesToUpdate = filter(compact(toArray(nodesToUpdate)), n => n.nodeType === Node.ELEMENT_NODE);
1863
- let oldNodeMap = {};
1864
- let dupKey = '';
1865
- let keyQ = {};
1866
- map(nodes, (node) => {
1867
- let treeNode = node;
1868
- let k = treeNode.getAttribute("key");
1869
- if (!k)
1870
- return;
1871
- if (oldNodeMap[k]) {
1872
- dupKey = k;
1873
- return false;
1874
- }
1875
- oldNodeMap[k] = treeNode;
1876
- oldSeq.push(k);
1877
- keyQ[k] = '1';
1878
- });
1879
- if (dupKey) {
1880
- showError(`${camelCase(this.diClass.name)} - duplicate key '${dupKey}'`);
1881
- }
1882
- let newNodeMap = {};
1883
- let updateQ = newKeys;
1884
- const parentNode = this.point.startNode.parentNode;
1885
- //compare
1886
- let adds = [];
1887
- let dels = [];
1888
- //计算del
1889
- each(keyQ, (v, k) => {
1890
- if (!updateQ[k]) {
1891
- dels.push(k);
1892
- delete keyQ[k];
1893
- remove(oldSeq, k);
1894
- }
1895
- });
1896
- //计算move
1897
- if (!isEmpty(newSeq)) {
1898
- let lastMoveNodeId = '';
1899
- let lastMoveIndex = -1;
1900
- let lastGroup = [];
1901
- let idWeightMap = {};
1902
- newSeq.forEach((nodeId, i) => {
1903
- let oldI = oldSeq.findIndex(c => c === nodeId);
1904
- if (oldI > -1 && oldI !== i) {
1905
- if (lastMoveIndex < 0 || lastMoveIndex - oldI == 1) {
1906
- let lastEl = last(lastGroup);
1907
- lastGroup.push({ nodeId, targetId: i === 0 ? MovePosition.AFTER_BEGIN : (lastEl ? lastEl.nodeId : newSeq[i - 1]) });
1908
- }
1909
- else {
1910
- idWeightMap[lastGroup.length] = { group: lastGroup, targetId: '' };
1911
- lastGroup = [];
1912
- lastGroup.push({ nodeId, targetId: oldSeq[oldI] });
1913
- }
1914
- lastMoveIndex = oldI;
1915
- }
1916
- else if (oldI < 0) {
1917
- let prev = lastMoveNodeId ? oldNodeMap[lastMoveNodeId] || this.point.endNode : this.point.startNode;
1918
- //add
1919
- adds.push({ prevNode: prev, newkey: nodeId });
1920
- }
1921
- lastMoveNodeId = nodeId;
1922
- });
1923
- if (isEmpty(idWeightMap) && lastGroup.length > 0) {
1924
- idWeightMap[lastGroup.length] = { group: lastGroup, targetId: '' };
1925
- }
1926
- let keys = Object.keys(idWeightMap);
1927
- let keyNums = keys.map(k => parseInt(k)).sort((a, b) => a - b);
1928
- if (keys.length < 2 && keys.length > 0) {
1929
- //如果仅有一组,留最后一个节点
1930
- let { group } = idWeightMap[keyNums[0]];
1931
- initial(group).forEach(({ targetId, nodeId }) => {
1932
- let srcEl = oldNodeMap[nodeId];
1933
- let target;
1934
- if (targetId === MovePosition.AFTER_BEGIN) {
1935
- target = this.point.startNode;
1936
- target.after(srcEl);
1937
- }
1938
- else {
1939
- target = oldNodeMap[targetId];
1940
- target.after(srcEl);
1941
- }
1942
- });
1943
- }
1944
- else {
1945
- //如果多组,留最后一组
1946
- console.debug('todo....');
1947
- }
1948
- }
1949
- adds.forEach(v => {
1950
- let k = v.newkey;
1951
- let treeNode = newNodeMap[k] || this.#addNode(newKeyMap[k], k);
1952
- let prevNode = v.prevNode;
1953
- if (prevNode === this.point.endNode) {
1954
- prevNode.before(treeNode);
1955
- }
1956
- else if (prevNode === this.point.startNode) {
1957
- prevNode.after(treeNode);
1958
- }
1959
- else {
1960
- prevNode.after(treeNode);
1961
- }
1962
- });
1963
- dels.forEach(k => {
1964
- this.#removeNode(k);
1965
- // remove(adjustedQ, ak => ak === k)
1966
- let treeNode = oldNodeMap[k];
1967
- if (treeNode) {
1968
- parentNode.removeChild(treeNode);
1969
- }
1970
- });
1971
- this.di.updateContext(updateRs);
1972
- }
1973
- }
1974
- getDirective() {
1975
- return this.di;
1976
- }
1977
- #addNode(tmpl, key) {
1978
- //追加expPos
1979
- let [nodes, expPos, expPosMap] = this.di.renderContext(tmpl);
1980
- let node = head(nodes);
1981
- this.di.__expPosMap[key] = expPos;
1982
- // this.di.__expPosMap[key] = clone(this.di.__expPos)
1983
- return node;
1984
- }
1985
- #removeNode(key) {
1986
- this.di.__expPosMap[key] = null;
1987
- delete this.di.__expPosMap[key];
1988
- }
1989
- }
1990
- /**
1991
- * 返回指令调用函数
1992
- * @param di
1993
- * @returns
1994
- */
1995
- function directive(diClass) {
1996
- return (...args) => {
1997
- let wrapper = null;
1998
- //todo 可能存在非返回模板函数开启了依赖监控
1999
- args.forEach((v, i) => {
2000
- if (isFunction(v)) {
2001
- let cbk = v;
2002
- args[i] = function (...ps) {
2003
- let di = wrapper.di;
2004
- Collector.startRender(di);
2005
- let rs = cbk(...ps);
2006
- Collector.endRender(di.renderComponent);
2007
- return rs;
2008
- };
2009
- }
2010
- });
2011
- wrapper = new DirectiveWrapper(diClass, ...args);
2012
- return wrapper;
2013
- };
2014
- }
2015
-
2016
- const ATTR_PREFIX_EVENT = "@";
2017
- const ATTR_PREFIX_PROP = ".";
2018
- const ATTR_PREFIX_BOOLEAN = "?";
2019
- const ATTR_PREFIX_REF = "*";
2020
- const ATTR_PROP_DELIMITER = ":";
2021
- const ATTR_REF = "ref";
2022
- const EXP_ATTR_CHECK = /[.?-a-z]+\s*=\s*(['"])\s*([^='"]*<\!--l_ui-pl_df-->){2,}.*?\1/ims;
2023
- const EXP_PLACEHOLDER = /<\s*[a-z0-9-]+([^>]*<\!--l_ui-pl_df-->)*[^>]*?(?<!-)>/imgs;
2024
- const SLOT_KEY_PROPS = 'slot-props';
2025
- /**
2026
- * 提供渲染函数相关操作
2027
- * @author holyhigh2
2028
- */
2029
- /**
2030
- * 高性能dom生成及变量绑定算法
2031
- * 1. 使用占位符拼接HTML字符串,占位符与变量需要按照顺序对应
2032
- * 2. 插入dom片段,并遍历元素+注释节点, 搜索占位符
2033
- * 1. 按顺序遍历所有attr,发现一个属性值含有占位符时,标记节点及属性名,以便变量可以进行绑定( 如果key是事件/ref则内容仅允许一个占位符)
2034
- * 2. 如果是注释节点
2035
- * 1. 在后面追加同内容注释节点,标记两个节点,以便变量可以进行绑定
2036
- * 2. 在中间插入变量内容
2037
- * 3. 只有表达式是一个指令时才能绑定依赖
2038
- * @param tmpl
2039
- * @param slotArgs
2040
- * @returns
2041
- */
2042
- function buildHTML(tmpl) {
2043
- let html = "";
2044
- let tmplList = isArray(tmpl) ? tmpl : [tmpl];
2045
- tmplList.forEach(({ strings, vars }) => {
2046
- let strList = toArray(strings);
2047
- strList[0] = trimStart(strList[0]);
2048
- strList[strList.length - 1] = trimEnd(strList[strList.length - 1]);
2049
- let l = strList.length - 1;
2050
- strList.forEach((str, i) => {
2051
- let val = get(vars, i, "");
2052
- val = l === i ? "" : PLACEHOLDER;
2053
- html += str + val;
2054
- });
2055
- });
2056
- //attr check
2057
- let rs = html.match(EXP_ATTR_CHECK);
2058
- if (rs) {
2059
- let errorMsg = replaceAll(rs[0], PLACEHOLDER, '${...}');
2060
- showError(`Parse error: attribute value can be set only one interpolation —— \n ${errorMsg}`);
2061
- return '';
2062
- }
2063
- let i = 0;
2064
- html = html.replace(EXP_PLACEHOLDER, (a, b) => {
2065
- let rs = replaceAll(a, PLACEHOLDER, () => PLACEHOLDER.replace('-->', '') + (i++));
2066
- return rs;
2067
- });
2068
- return html;
2069
- }
2070
- const PLACEHOLDER = "<!--l_ui-pl_df-->";
2071
- const PLACEHOLDER_PREFFIX = "<!--l_ui-pl_df";
2072
- const PLACEHOLDER_EXP = /<!--l_ui-pl_df\d*(-->)?/;
2073
- /**
2074
- * 构建模板为DOM结构
2075
- * @param html
2076
- */
2077
- function buildTmplate(expPos, directives, html, vars, component, slotArgs, level = 0, expressionChain = '') {
2078
- const container = document.createElement("div");
2079
- container.innerHTML = html;
2080
- //遍历dom
2081
- const nodeIterator = document.createNodeIterator(container, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT);
2082
- let currentNode;
2083
- let varIndex = 0;
2084
- let slotComponent = null;
2085
- while ((currentNode = nodeIterator.nextNode())) {
2086
- if (currentNode instanceof HTMLElement || currentNode instanceof SVGElement) {
2087
- if (currentNode instanceof CompElem) {
2088
- slotComponent = currentNode;
2089
- }
2090
- else {
2091
- if (!slotComponent?.contains(currentNode)) {
2092
- slotComponent = null;
2093
- }
2094
- }
2095
- let props = {};
2096
- let attrs = toArray(currentNode.attributes);
2097
- each(attrs, (attr) => {
2098
- let { name, value } = attr;
2099
- if (name === SLOT_KEY_PROPS) {
2100
- let slotName = currentNode.name || 'default';
2101
- if (slotComponent) {
2102
- let ary = slotComponent._slotsPropMap[slotName];
2103
- if (!ary) {
2104
- ary = slotComponent._slotsPropMap[slotName] = [];
2105
- }
2106
- ary.push(currentNode);
2107
- }
2108
- }
2109
- if (startsWith(name, PLACEHOLDER_PREFFIX)) {
2110
- let val = vars[varIndex];
2111
- //support directive only for now
2112
- if (val instanceof DirectiveWrapper) {
2113
- val.checkScope(EnterPointType.TAG);
2114
- let point = new EnterPoint(level, currentNode, name.substring(1), EnterPointType.TAG);
2115
- val.point = point;
2116
- val.varPath = expressionChain + varIndex;
2117
- val.slotComponent = slotComponent;
2118
- directives.push(val);
2119
- let pos = expPos[expressionChain + varIndex] = new ExpPos(expressionChain + varIndex, currentNode);
2120
- pos.isDirective = true;
2121
- pos.value = val;
2122
- pos.isComponent = !!slotComponent;
2123
- varIndex++;
2124
- }
2125
- currentNode.removeAttribute(name);
2126
- return;
2127
- }
2128
- //@event.stop.prevent.debounce
2129
- if (name[0] === ATTR_PREFIX_EVENT) {
2130
- let cbk = (e) => { };
2131
- let pos = null;
2132
- if (PLACEHOLDER_EXP.test(value)) {
2133
- let val = vars[varIndex];
2134
- if (!isFunction(val)) {
2135
- showTagError(currentNode.tagName, `Event '${name}' must be a function`);
2136
- return;
2137
- }
2138
- cbk = val.bind(component);
2139
- pos = expPos[expressionChain + varIndex] = new ExpPos(expressionChain + varIndex, currentNode, name.replace(/\.|\?|@/, ''), value);
2140
- pos.isComponent = !!slotComponent;
2141
- varIndex++;
2142
- }
2143
- let parts = name.substring(1).split('.');
2144
- let evName = parts.shift();
2145
- cbk = addEvent(name.substring(1), cbk, currentNode, component);
2146
- currentNode.removeAttribute(name);
2147
- if (pos) {
2148
- pos.eventName = evName;
2149
- pos.value = cbk;
2150
- }
2151
- return;
2152
- }
2153
- if (name === ATTR_REF) {
2154
- if (PLACEHOLDER_EXP.test(value)) {
2155
- let val = vars[varIndex];
2156
- if (!has(val, 'current')) {
2157
- showTagError(currentNode.tagName, `Ref must be a RefObject`);
2158
- return;
2159
- }
2160
- varIndex++;
2161
- val.current = currentNode;
2162
- }
2163
- currentNode.removeAttribute(name);
2164
- return;
2165
- }
2166
- //校验变量必须是表达式
2167
- if (name[0] === ATTR_PREFIX_PROP && !PLACEHOLDER_EXP.test(value)) {
2168
- showTagError(currentNode.tagName, `Prop '${name}' must be an interpolation`);
2169
- return;
2170
- }
2171
- if (PLACEHOLDER_EXP.test(value)) {
2172
- let val = vars[varIndex];
2173
- let pos = expPos[expressionChain + varIndex] = new ExpPos(expressionChain + varIndex, currentNode, name.replace(/\.|\?|@/, ''), value);
2174
- pos.isComponent = !!slotComponent;
2175
- if (name[0] === ATTR_PREFIX_PROP ||
2176
- name[0] === ATTR_PREFIX_BOOLEAN ||
2177
- name[0] === ATTR_PREFIX_REF) {
2178
- if (val instanceof DirectiveWrapper) {
2179
- val.checkScope(EnterPointType.PROP);
2180
- directives.push(val);
2181
- let point = new EnterPoint(level, currentNode, name.substring(1), EnterPointType.PROP);
2182
- val.varPath = expressionChain + varIndex;
2183
- val.point = point;
2184
- val.slotComponent = slotComponent;
2185
- pos.value = val;
2186
- pos.isDirective = true;
2187
- }
2188
- else if (name[0] === ATTR_PREFIX_BOOLEAN) {
2189
- pos.isToggleProp = true;
2190
- pos.value = !!val;
2191
- if (pos.value)
2192
- currentNode.setAttribute(name.substring(1), '');
2193
- }
2194
- else if (name[0] === ATTR_PREFIX_REF) {
2195
- pos.value = val;
2196
- let refNames = name.substring(1);
2197
- const [refNamec, prop] = refNames.split(ATTR_PROP_DELIMITER);
2198
- let refName = refNamec;
2199
- switch (prop) {
2200
- case 'camel':
2201
- refName = camelCase(refName);
2202
- break;
2203
- case 'kebab':
2204
- refName = kebabCase(refName);
2205
- break;
2206
- case 'snake':
2207
- refName = snakeCase(refName);
2208
- break;
2209
- }
2210
- pos.attrName = refName;
2211
- currentNode.setAttribute(refName, val);
2212
- }
2213
- else {
2214
- if (!(currentNode instanceof CompElem) && currentNode.tagName !== 'SLOT') {
2215
- showTagError(currentNode.tagName, `Prop '${name}' can only be set on a CompElem or a slot`);
2216
- delete expPos[expressionChain + varIndex];
2217
- }
2218
- else {
2219
- let propName = camelCase(name.substring(1));
2220
- if (!(propName in currentNode) && currentNode.tagName !== 'SLOT') {
2221
- showTagError(currentNode.tagName, `Prop '${name}' is not defined in ${currentNode.tagName}`);
2222
- }
2223
- pos.value = val;
2224
- pos.isProp = true;
2225
- props[propName] = val;
2226
- }
2227
- }
2228
- currentNode.removeAttribute(name);
2229
- val = '';
2230
- }
2231
- else {
2232
- pos.value = val;
2233
- if (val instanceof DirectiveWrapper) {
2234
- let type = EnterPointType.ATTR;
2235
- if (name === "class") {
2236
- type = EnterPointType.CLASS;
2237
- }
2238
- else if (name === "style") {
2239
- type = EnterPointType.STYLE;
2240
- }
2241
- val.checkScope(type);
2242
- directives.push(val);
2243
- pos.isDirective = true;
2244
- let point = new EnterPoint(level, currentNode, name, type);
2245
- val.point = point;
2246
- val.slotComponent = slotComponent;
2247
- val.varPath = expressionChain + varIndex;
2248
- val = '';
2249
- }
2250
- value = replace(value, PLACEHOLDER_EXP, val);
2251
- //回填
2252
- attr.value = value;
2253
- }
2254
- varIndex++;
2255
- }
2256
- });
2257
- if (currentNode instanceof CompElem) {
2258
- // currentNode._setParentProps(props)
2259
- currentNode._initProps(props);
2260
- }
2261
- else if (currentNode instanceof HTMLSlotElement) {
2262
- component._bindSlot(currentNode, currentNode.name || 'default', props);
2263
- }
2264
- }
2265
- else {
2266
- let comment = currentNode;
2267
- if (`<!--${comment.nodeValue}-->` !== PLACEHOLDER) {
2268
- continue;
2269
- }
2270
- let pos = expPos[expressionChain + varIndex] = new ExpPos(expressionChain + varIndex, currentNode);
2271
- pos.isComponent = !!slotComponent;
2272
- pos.isText = true;
2273
- let val = vars[varIndex];
2274
- let startComment;
2275
- //插入start占位符
2276
- startComment = document.createComment(`compelem-ui-${level}-${varIndex}-child-start`);
2277
- comment.parentNode.insertBefore(startComment, comment);
2278
- comment.nodeValue = `compelem-ui-${level}-${varIndex}-child-end`;
2279
- pos.textNode = startComment;
2280
- if (val instanceof DirectiveWrapper) {
2281
- pos.isDirective = true;
2282
- pos.value = val;
2283
- let pType = slotComponent ? EnterPointType.SLOT : EnterPointType.TEXT;
2284
- directives.push(val);
2285
- let point = new EnterPoint(level, startComment, "", pType);
2286
- point.endNode = comment;
2287
- val.point = point;
2288
- val.slotComponent = slotComponent;
2289
- val.varPath = expressionChain + varIndex;
2290
- val = '';
2291
- }
2292
- else if (val instanceof Template) {
2293
- pos.isTmpl = true;
2294
- pos.value = val;
2295
- let html = buildHTML(val);
2296
- val = buildTmplate(expPos, directives, html, val.vars, component, slotArgs, level, expressionChain + `${varIndex}-`);
2297
- }
2298
- else {
2299
- pos.value = val;
2300
- }
2301
- varIndex++;
2302
- if (isUndefined(val))
2303
- continue;
2304
- if (val instanceof NodeList) {
2305
- let fragment = document.createDocumentFragment();
2306
- fragment.append(...val);
2307
- comment.parentNode.insertBefore(fragment, comment);
2308
- }
2309
- else if (val instanceof Element) {
2310
- comment.parentNode.insertBefore(val, comment);
2311
- }
2312
- else if (trim(val)) {
2313
- let text = document.createTextNode(val);
2314
- comment.parentNode.insertBefore(text, comment);
2315
- }
2316
- }
2317
- }
2318
- return container.childNodes;
2319
- }
2320
- const DomUtil = {
2321
- insertBefore: function (node, newNodes) {
2322
- let fragment = document.createDocumentFragment();
2323
- fragment.append(...newNodes);
2324
- node.parentNode.insertBefore(fragment, node);
2325
- },
2326
- remove: function (startNode, endNode) {
2327
- let nextNode = startNode.nextSibling;
2328
- while (nextNode !== endNode) {
2329
- nextNode?.parentNode?.removeChild(nextNode);
2330
- nextNode = startNode.nextSibling;
2331
- }
2332
- }
2333
- };
2334
- const EXP_KEY$1 = /\s+\.?key\s*=/;
2335
- class Template {
2336
- strings;
2337
- vars;
2338
- //如果模板仅有一个root节点且含有key属性
2339
- key;
2340
- constructor(strings, vars) {
2341
- this.strings = concat(strings);
2342
- this.vars = vars;
2343
- }
2344
- //解析模板中的key
2345
- getKey() {
2346
- let vars = this.vars;
2347
- let k = '';
2348
- each(this.strings, (str, i) => {
2349
- if (EXP_KEY$1.test(str)) {
2350
- k = toString(vars[i]);
2351
- return false;
2352
- }
2353
- });
2354
- this.key = k;
2355
- return k;
2356
- }
2357
- /**
2358
- * 追加tmpl
2359
- * 交接处模板进行合并
2360
- * @param tmpl
2361
- */
2362
- append(tmpl) {
2363
- let lastStr = last(this.strings);
2364
- tmpl.strings.forEach((str, i) => {
2365
- if (i == 0) {
2366
- this.strings[this.strings.length - 1] = lastStr + str;
2367
- return;
2368
- }
2369
- this.strings.push(str);
2370
- });
2371
- this.vars = concat(this.vars, tmpl.vars);
2372
- return this;
2373
- }
2374
- /**
2375
- * 获取html字符串
2376
- */
2377
- getHTML() {
2378
- let html = '';
2379
- let strList = toArray(this.strings);
2380
- strList[0] = trimStart(strList[0]);
2381
- strList[strList.length - 1] = trimEnd(strList[strList.length - 1]);
2382
- let l = strList.length - 1;
2383
- strList.forEach((str, i) => {
2384
- let val = get(this.vars, i, "");
2385
- if (val instanceof Template) {
2386
- val = val.getHTML();
2387
- }
2388
- else {
2389
- val = l === i ? "" : val;
2390
- }
2391
- html += str + val;
2392
- });
2393
- return html;
2394
- }
2395
- }
2396
- //////////////////////////////////////////////////// interfaces
2397
- /**
2398
- * 标签函数,用于构建模板
2399
- * @param strings
2400
- * @param vars
2401
- */
2402
- function html(strings, ...vars) {
2403
- return new Template(isString(strings) ? [strings] : strings, vars);
2404
- }
2405
- /**
2406
- * 使用初始值创建一个引用对象
2407
- * @param initValue
2408
- * @returns
2409
- */
2410
- function createRef(initValue) {
2411
- return { current: initValue };
2412
- }
2413
-
2414
- function computed(target, propertyKey, descriptor) {
2415
- if (!descriptor.get) {
2416
- showError(`Prop '${propertyKey}' must be a getter`);
2417
- }
2418
- if (!has(target.constructor, '__deco_computed')) {
2419
- target.constructor.__deco_computed = isEmpty(target.constructor.__deco_computed) ? {} : cloneDeep(target.constructor.__deco_computed);
2420
- }
2421
- target.constructor.__deco_computed[propertyKey] = { key: propertyKey, getter: descriptor.get };
2422
- }
2423
-
2424
- /**
2425
- * 绑定非视图事件,如window/document等
2426
- * @param eventName 事件名
2427
- * @param immediate 立即执行
2428
- * @param deep 深度监控
2429
- */
2430
- function event(eventName, options) {
2431
- return (target, name, descriptor) => {
2432
- if (!has(target.constructor, '__deco_events')) {
2433
- target.constructor.__deco_events = isEmpty(target.constructor.__deco_events) ? [] : cloneDeep(target.constructor.__deco_events);
2434
- }
2435
- target.constructor.__deco_events.push({ name: eventName, options, fn: target[name] });
2436
- };
2437
- }
2438
-
2439
- /**
2440
- * 缓存策略
2441
- */
2442
- var QueryCache;
2443
- (function (QueryCache) {
2444
- QueryCache["ONCE"] = "once";
2445
- QueryCache["UPDATABLE"] = "updatable"; //每次update结束都会更新缓存
2446
- })(QueryCache || (QueryCache = {}));
2447
- /**
2448
- * css查询装饰器
2449
- * @example
2450
- * @query('l-popup', QueryCache.ONCE)
2451
- */
2452
- class QueryDecorator extends Decorator {
2453
- created(component, ...args) {
2454
- }
2455
- mounted(component, setReactive, ...args) {
2456
- }
2457
- get targets() {
2458
- return [DecoratorType.FIELD];
2459
- }
2460
- selector;
2461
- cache;
2462
- result;
2463
- constructor(selector, cache) {
2464
- super();
2465
- this.selector = selector;
2466
- this.cache = cache;
2467
- }
2468
- static getKey(selector) {
2469
- return selector;
2470
- }
2471
- getter(component) {
2472
- this.result = component.shadowRoot?.querySelector(this.selector);
2473
- }
2474
- propsReady(component, setReactive, classProto, fieldName, ...args) {
2475
- const that = this;
2476
- Object.defineProperty(component, fieldName, {
2477
- get() {
2478
- if (that.result && that.cache) {
2479
- return that.result;
2480
- }
2481
- that.getter(component);
2482
- return that.result;
2483
- }
2484
- });
2485
- }
2486
- updated(component, changed) {
2487
- if (this.cache !== QueryCache.UPDATABLE)
2488
- return;
2489
- this.getter(component);
2490
- }
2491
- }
2492
- class QueryAllDecorator extends QueryDecorator {
2493
- getter(component) {
2494
- this.result = component.shadowRoot?.querySelectorAll(this.selector);
2495
- }
2496
- }
2497
- const query = decorator(QueryDecorator);
2498
- const queryAll = decorator(QueryAllDecorator);
2499
-
2500
- function state(options) {
2501
- if (arguments.length === 1) {
2502
- return (target, stateKey) => {
2503
- defineState(target, stateKey, options);
2504
- };
2505
- }
2506
- let target = arguments[0], stateKey = arguments[1];
2507
- defineState(target, stateKey, { prop: "" });
2508
- }
2509
- function defineState(target, stateKey, options) {
2510
- if (!has(target.constructor, "__deco_states")) {
2511
- target.constructor.__deco_states = isEmpty(target.constructor.__deco_states) ? {} : cloneDeep(target.constructor.__deco_states);
2512
- }
2513
- target.constructor.__deco_states[stateKey] = options;
2514
- }
2515
- /**
2516
- * 同@state装饰器,但可用于构造器中调用
2517
- * @param ctor 类构造函数
2518
- * @param stateKey state 名称
2519
- * @param options
2520
- */
2521
- function makeState(ctor, stateKey, options) {
2522
- defineState(ctor.prototype, stateKey, options || { prop: "" });
2523
- }
2524
-
2525
- /**
2526
- * class用注解,用于自动注册自定义组件
2527
- * @param name 自定义组件名称
2528
- */
2529
- function tag(name) {
2530
- return (target) => {
2531
- if (target) {
2532
- customElements.define(name, target);
2533
- }
2534
- };
2535
- }
2536
-
2537
- /**
2538
- * prop/state监视
2539
- * @example
2540
- * @watch('a.b.c')
2541
- */
2542
- class WatchDecorator extends Decorator {
2543
- created(component, ...args) {
2544
- }
2545
- propsReady(component, setReactive, ...args) {
2546
- }
2547
- get targets() {
2548
- return [DecoratorType.METHOD];
2549
- }
2550
- sources;
2551
- options;
2552
- handler;
2553
- constructor(source, options) {
2554
- super();
2555
- this.sources = isArray(source) ? source : [source];
2556
- this.options = options;
2557
- }
2558
- static getKey(source) {
2559
- return isArray(source) ? source.sort().join('') : source;
2560
- }
2561
- mounted(component, setReactive, classProto, fnName, ...args) {
2562
- let handler = this.handler = component[fnName];
2563
- let immediate = get(this.options, "immediate", false);
2564
- let onceWatch = get(this.options, "once", false);
2565
- if (onceWatch) {
2566
- handler = once(handler.bind(component));
2567
- }
2568
- let invocations = [];
2569
- this.sources.forEach(src => {
2570
- let nv = get(component, src.replaceAll('-', '.'));
2571
- if (immediate) {
2572
- invocations.push({
2573
- handler, value: nv, varPath: src
2574
- });
2575
- }
2576
- });
2577
- invocations.forEach(({ handler, value, varPath }) => {
2578
- handler.call(component, get(component, varPath), value, varPath);
2579
- });
2580
- }
2581
- updated(component, changed) {
2582
- this.sources.forEach(src => {
2583
- each(changed, ({ value, chain, oldValue, end }, k) => {
2584
- let srcPath = src.replaceAll('.', '-');
2585
- //监视路径不长于变量路径
2586
- if (!startsWith(k, srcPath))
2587
- return;
2588
- if (k === srcPath && end) {
2589
- this.handler && this.handler.call(component, value, oldValue, k);
2590
- }
2591
- //watches deep
2592
- let i = chain.length - 1;
2593
- while (i) {
2594
- let varPath = chain.slice(0, i);
2595
- if (end && varPath.join('-') === srcPath && get(this.options, 'deep')) {
2596
- let v = get(component, varPath);
2597
- this.handler.call(component, v, v, varPath.join('-'));
2598
- }
2599
- i--;
2600
- }
2601
- });
2602
- });
2603
- }
2604
- }
2605
- const watch = decorator(WatchDecorator);
2606
-
2607
- /**
2608
- * 用于解析HTML模板
2609
- * @author holyhigh2
2610
- */
2611
- class Directive extends RenderContext(Object) {
2612
- //render参数,仅保存上次指令所在context变更时的数据,用于指令内部context更新时
2613
- _renderArgs;
2614
- /**
2615
- * 指令使用范围,超出范围会报错
2616
- */
2617
- static get scopes() {
2618
- return [];
2619
- }
2620
- /**
2621
- * 指令渲染参数变量链
2622
- */
2623
- renderParams;
2624
- }
2625
-
2626
- const Ignores = ['key'];
2627
- /**
2628
- * 绑定属性到节点上,如果节点是组件会使用in操作符判断是否props
2629
- * @param styles 对象/数组/字符串
2630
- */
2631
- class Bind extends Directive {
2632
- update(nodes, newArgs, oldArgs) {
2633
- return DirectiveUpdateTag.NONE;
2634
- }
2635
- static get scopes() {
2636
- return [EnterPointType.TAG];
2637
- }
2638
- constructor(point) {
2639
- super();
2640
- this.point = point;
2641
- }
2642
- render(obj) {
2643
- let el = this.point.startNode;
2644
- if (el instanceof CompElem) {
2645
- //判断是否prop
2646
- let props = {};
2647
- let attrs = {};
2648
- each(obj, (v, k) => {
2649
- if (Ignores.includes(k))
2650
- return;
2651
- if (k in el) {
2652
- props[k] = v;
2653
- }
2654
- else {
2655
- attrs[k] = v + '';
2656
- }
2657
- });
2658
- // el._setParentProps(props, attrs)
2659
- el._initProps(props, attrs);
2660
- }
2661
- else {
2662
- each(obj, (v, k) => {
2663
- el.setAttribute(k, v);
2664
- });
2665
- }
2666
- }
2667
- }
2668
- const bind = directive(Bind);
2669
-
2670
- /**
2671
- * 根据变量内容自动插入class,仅能用于class属性
2672
- * @param styles 对象/数组/字符串
2673
- */
2674
- class Classes extends Directive {
2675
- update(nodes, newArgs, oldArgs) {
2676
- this.render(newArgs[0]);
2677
- return DirectiveUpdateTag.NONE;
2678
- }
2679
- static get scopes() {
2680
- return [EnterPointType.CLASS];
2681
- }
2682
- constructor(point) {
2683
- super(point);
2684
- this.point = point;
2685
- }
2686
- lastCls;
2687
- render(clazz) {
2688
- let rs = [];
2689
- if (isArray(clazz)) {
2690
- rs = compact(clazz);
2691
- }
2692
- else if (isObject(clazz)) {
2693
- rs = flatMap(clazz, (v, k) => v ? k : []);
2694
- }
2695
- else if (isString(clazz)) {
2696
- rs = clazz.split(' ');
2697
- }
2698
- let el = this.point.startNode;
2699
- each(this.lastCls, cls => {
2700
- el.classList.remove(cls);
2701
- });
2702
- each(rs, cls => {
2703
- el.classList.add(cls);
2704
- });
2705
- this.lastCls = concat(rs);
2706
- }
2707
- }
2708
- const classes = directive(Classes);
2709
-
2710
- const EXP_KEY = /\s+\.?key\s*=/;
2711
- /**
2712
- * 循环列表并自动优化列表更新
2713
- * foreach循环的只能是节点,且必须有key属性。非节点元素会被过滤掉
2714
- * 使用序号作为key时可能会导致异常问题
2715
- */
2716
- class ForEach extends Directive {
2717
- update(nodes, newArgs, oldArgs) {
2718
- if (isEmpty(nodes) && isEmpty(newArgs[0]))
2719
- return DirectiveUpdateTag.NONE;
2720
- if (!isEmpty(this.renderParams)) {
2721
- let rp = last(this.renderParams);
2722
- if (!isArray(rp)) {
2723
- rp = [rp];
2724
- }
2725
- this.renderParams = rp;
2726
- }
2727
- return DirectiveUpdateTag.UPDATE;
2728
- }
2729
- constructor(point) {
2730
- super();
2731
- if (!isEmpty(this.renderParams))
2732
- this.renderParams = toArray(last(this.renderParams));
2733
- }
2734
- static get scopes() {
2735
- return [EnterPointType.TEXT, EnterPointType.SLOT];
2736
- }
2737
- render(value, cbk) {
2738
- //1. 产生模板
2739
- let tmpls = map(value, (v, k) => {
2740
- return cbk(v, k);
2741
- });
2742
- //2. 合并模板
2743
- let keyAry = [];
2744
- let strs = [];
2745
- tmpls.forEach((tmpl) => {
2746
- let lastStr = last(strs);
2747
- let vars = tmpl.vars;
2748
- let hasNoKey = true;
2749
- tmpl.strings.forEach((str, i) => {
2750
- if (EXP_KEY.test(str)) {
2751
- let key = vars[i] + '';
2752
- if (keyAry.includes(key)) {
2753
- showError(`forEach - duplicate key '${key}'`);
2754
- }
2755
- keyAry.push(key);
2756
- hasNoKey = false;
2757
- }
2758
- if (i == 0 && lastStr) {
2759
- strs[strs.length - 1] = lastStr + str;
2760
- return;
2761
- }
2762
- strs.push(str);
2763
- });
2764
- if (hasNoKey) {
2765
- showError("forEach - missing 'key' prop");
2766
- }
2767
- });
2768
- return tmpls;
2769
- }
2770
- }
2771
- const forEach = directive(ForEach);
2772
-
2773
- /**
2774
- * 条件为真时返回参数1,否则返回参数2,仅能用于文本节点
2775
- * @param condition 条件
2776
- * @param tmpl 模板
2777
- */
2778
- class IfElse extends Directive {
2779
- //todo 缓存后会导致缓存内容无法更新,需要按照新的结构修改后进行缓存
2780
- ifNodes;
2781
- elseNodes;
2782
- static get scopes() {
2783
- return [EnterPointType.TEXT, EnterPointType.SLOT];
2784
- }
2785
- update(nodes, newArgs, oldArgs) {
2786
- if (!!newArgs[0] === !!oldArgs[0]) {
2787
- return DirectiveUpdateTag.UPDATE;
2788
- }
2789
- if (newArgs[0]) {
2790
- //缓存else
2791
- // if (isEmpty(this.elseNodes)) {
2792
- // this.elseNodes = concat(nodes)
2793
- // }
2794
- return DirectiveUpdateTag.REPLACE;
2795
- }
2796
- else {
2797
- //缓存if
2798
- // if (isEmpty(this.ifNodes)) {
2799
- // this.ifNodes = concat(nodes)
2800
- // }
2801
- return DirectiveUpdateTag.REPLACE;
2802
- }
2803
- }
2804
- render(condition, tmplFn1, tmplFn2) {
2805
- return condition ? tmplFn1(condition) : tmplFn2(condition);
2806
- }
2807
- }
2808
- const ifElse = directive(IfElse);
2809
-
2810
- /**
2811
- * 条件为真时返回内容,仅能用于文本节点
2812
- * @param condition 条件
2813
- * @param tmpl 模板
2814
- */
2815
- class IfTrue extends Directive {
2816
- static get scopes() {
2817
- return [EnterPointType.TEXT, EnterPointType.SLOT];
2818
- }
2819
- update(nodes, newArgs, oldArgs) {
2820
- if (newArgs[0] === oldArgs[0])
2821
- return DirectiveUpdateTag.UPDATE;
2822
- if (newArgs[0]) {
2823
- return DirectiveUpdateTag.REPLACE;
2824
- }
2825
- this.cacheNodes = nodes;
2826
- return DirectiveUpdateTag.REMOVE;
2827
- }
2828
- render(condition, tmplFn) {
2829
- return condition ? tmplFn() : html ``;
2830
- }
2831
- }
2832
- const ifTrue = directive(IfTrue);
2833
-
2834
- var ModelTriggerType;
2835
- (function (ModelTriggerType) {
2836
- ModelTriggerType["CHANGE"] = "change";
2837
- ModelTriggerType["INPUT"] = "input";
2838
- })(ModelTriggerType || (ModelTriggerType = {}));
2839
- /**
2840
- * 实现双向绑定(仅支持静态路径,动态增加的属性路径无法识别)
2841
- * 当用于组件时,监控 @update:value 事件
2842
- * 当用于元素时,
2843
- * - 对于 input/textarea 监控 @input,并设置 value 属性
2844
- * - 对于 checkbox/radio 监控 @change,并设置 checked 属性
2845
- * - 对于 select 监控 @change,并设置 value 属性
2846
- * @param modelValue 双向绑定的组件变量
2847
- */
2848
- class Model extends Directive {
2849
- update(nodes, newArgs, oldArgs) {
2850
- if (!this.modelPath)
2851
- this.modelPath = last(this.renderParams);
2852
- if (!isEqual(newArgs, oldArgs)) {
2853
- const node = this.point.startNode;
2854
- if (node instanceof CompElem) {
2855
- // node._setParentProps({ value: newArgs[0] });
2856
- node._updateProps({ value: newArgs[0] });
2857
- }
2858
- else if (node instanceof HTMLTextAreaElement || node instanceof HTMLSelectElement) {
2859
- node.setAttribute('value', newArgs[0] + '');
2860
- }
2861
- else if (node instanceof HTMLInputElement) {
2862
- switch (node.type) {
2863
- case 'checkbox':
2864
- case 'radio':
2865
- if (!!newArgs[0]) {
2866
- node.setAttribute('checked', '');
2867
- }
2868
- else {
2869
- node.removeAttribute('checked');
2870
- }
2871
- break;
2872
- case 'text':
2873
- case 'email':
2874
- case 'number':
2875
- case 'password':
2876
- case 'search':
2877
- case 'tel':
2878
- case 'url':
2879
- node.setAttribute('value', newArgs[0] + '');
2880
- break;
2881
- default:
2882
- node.setAttribute('value', newArgs[0] + '');
2883
- break;
2884
- }
2885
- }
2886
- }
2887
- return DirectiveUpdateTag.NONE;
2888
- }
2889
- static get scopes() {
2890
- return [EnterPointType.TAG];
2891
- }
2892
- modelPath;
2893
- point;
2894
- constructor(point) {
2895
- super();
2896
- this.point = point;
2897
- }
2898
- render(modelValue) {
2899
- if (!this.modelPath)
2900
- this.modelPath = last(this.renderParams);
2901
- const node = this.point.startNode;
2902
- if (get(node, '_model') === 'binded')
2903
- return;
2904
- if (!isObject(modelValue) && !trim(modelValue))
2905
- modelValue = '';
2906
- if (node instanceof CompElem) {
2907
- //todo _setParentProps接口不应该外部使用
2908
- // node._setParentProps({ value: modelValue });
2909
- node._initProps({ value: modelValue });
2910
- node.addEventListener('update:value', (e) => {
2911
- set(this.renderComponent, this.modelPath, e.detail.value);
2912
- });
2913
- set(node, '_model', 'binded');
2914
- }
2915
- else if (node instanceof HTMLTextAreaElement) {
2916
- node.setAttribute('value', modelValue + '');
2917
- node.addEventListener('input', (e) => {
2918
- let t = e.target;
2919
- set(this.renderComponent, this.modelPath, t.value);
2920
- });
2921
- set(node, '_model', 'binded');
2922
- }
2923
- else if (node instanceof HTMLInputElement) {
2924
- let propName = '';
2925
- let evName = '';
2926
- switch (node.type) {
2927
- case 'checkbox':
2928
- case 'radio':
2929
- propName = 'checked';
2930
- evName = 'change';
2931
- break;
2932
- case 'text':
2933
- case 'email':
2934
- case 'number':
2935
- case 'password':
2936
- case 'search':
2937
- case 'tel':
2938
- case 'url':
2939
- propName = 'value';
2940
- evName = 'input';
2941
- break;
2942
- default:
2943
- propName = 'value';
2944
- evName = 'input';
2945
- break;
2946
- }
2947
- node.setAttribute(propName, modelValue + '');
2948
- node.addEventListener(evName, (e) => {
2949
- let t = e.target;
2950
- set(this.renderComponent, this.modelPath, t.value);
2951
- });
2952
- set(node, '_model', 'binded');
2953
- }
2954
- else if (node instanceof HTMLSelectElement) {
2955
- node.setAttribute('value', modelValue + '');
2956
- node.addEventListener('change', (e) => {
2957
- let t = e.target;
2958
- set(this.renderComponent, this.modelPath, t.value);
2959
- });
2960
- set(node, '_model', 'binded');
2961
- }
2962
- }
2963
- }
2964
- const model = directive(Model);
2965
-
2966
- /**
2967
- * display的快捷指令
2968
- * 如果
2969
- * @param isvisible 是否显示
2970
- */
2971
- class Show extends Directive {
2972
- update(nodes, newArgs, oldArgs) {
2973
- this.render(newArgs[0]);
2974
- return DirectiveUpdateTag.NONE;
2975
- }
2976
- display = undefined;
2977
- static get scopes() {
2978
- return [EnterPointType.TAG];
2979
- }
2980
- constructor(point) {
2981
- super();
2982
- this.point = point;
2983
- }
2984
- render(isVisible) {
2985
- let el = this.point.startNode;
2986
- if (isUndefined(this.display)) {
2987
- this.display = el.style.display;
2988
- }
2989
- this.renderComponent.nextTick(() => {
2990
- el.style.display = isVisible ? this.display : 'none';
2991
- });
2992
- }
2993
- }
2994
- const show = directive(Show);
2995
-
2996
- /**
2997
- * 创建一个动态插槽内容
2998
- * @param cbk 回调函数,函数接收插槽上定义得变量
2999
- * @param slotName 插槽名词,默认default
3000
- */
3001
- class Slot extends Directive {
3002
- update(nodes, newArgs, oldArgs) {
3003
- return DirectiveUpdateTag.NONE;
3004
- }
3005
- static get scopes() {
3006
- return [EnterPointType.SLOT];
3007
- }
3008
- render(cbk, slotName) {
3009
- cbk = cbk.bind(this.renderComponent);
3010
- this.slotComponent._bindSlotHook(slotName || 'default', cbk);
3011
- return cbk;
3012
- }
3013
- }
3014
- const slot = directive(Slot);
3015
-
3016
- /**
3017
- * 根据变量内容自动插入class,仅能用于style属性
3018
- * @param styles 对象/字符串
3019
- */
3020
- class Styles extends Directive {
3021
- update(nodes, newArgs, oldArgs) {
3022
- this.render(newArgs[0]);
3023
- return DirectiveUpdateTag.NONE;
3024
- }
3025
- constructor(point) {
3026
- super();
3027
- this.point = point;
3028
- }
3029
- static get scopes() {
3030
- return [EnterPointType.STYLE];
3031
- }
3032
- render(styles) {
3033
- let rs = '';
3034
- if (isObject(styles)) {
3035
- rs = join(map(styles, (v, k) => kebabCase(k) + ":" + v), ';');
3036
- }
3037
- else if (isString(styles)) {
3038
- rs = styles;
3039
- }
3040
- each(rs.split(';'), prop => {
3041
- let kv = prop.split(':');
3042
- this.point.startNode.style.setProperty(trim(kv[0]), trim(kv[1]));
3043
- });
3044
- }
3045
- }
3046
- const styles = directive(Styles);
3047
-
3048
- /**
3049
- * 类似Model,实现属性的同步跟踪
3050
- * 设置组件prop,并监控 @update:prop 事件
3051
- * @param syncValue 双向绑定的组件变量
3052
- */
3053
- class Sync extends Directive {
3054
- update(nodes, newArgs, oldArgs) {
3055
- if (!isEqual(newArgs, oldArgs)) {
3056
- this.targetComponent._updateProps({ [this.attrName]: newArgs[0] });
3057
- // this.targetComponent._setParentProps({ [this.attrName]: newArgs[0] });
3058
- }
3059
- return DirectiveUpdateTag.NONE;
3060
- }
3061
- static get scopes() {
3062
- return [EnterPointType.PROP];
3063
- }
3064
- modelPath;
3065
- attrName;
3066
- targetComponent;
3067
- constructor(point) {
3068
- super();
3069
- this.targetComponent = point.startNode;
3070
- this.attrName = point.attrName;
3071
- }
3072
- render(syncValue) {
3073
- if (!this.modelPath)
3074
- this.modelPath = last(this.renderParams);
3075
- //todo _setParentProps接口不应该外部使用
3076
- this.targetComponent._initProps({ [this.attrName]: syncValue });
3077
- // this.targetComponent._setParentProps({ [this.attrName]: syncValue });
3078
- this.targetComponent.addEventListener('update:' + this.attrName, (e) => {
3079
- set(this.renderComponent, this.modelPath, e.detail.value);
3080
- });
3081
- }
3082
- }
3083
- const sync = directive(Sync);
3084
-
3085
- /**
3086
- * 分支指令,具有switch / if else 两种模式
3087
- * @example
3088
- * switch 模式
3089
- * ${when(var, {
3090
- closed: () => html``, //case 1
3091
- connecting: () => html``, //case 2
3092
- default: () => html``// default
3093
- })}
3094
-
3095
- if else 模式
3096
- * ${when(this.editingTitle, [
3097
- [(v: any) => v.substring(2) > 0, () => html`<div style="${PageHome.tunnelLight}"></div>`],
3098
- [(v: any) => v == 'closed', () => html`<div style="${PageHome.tunnelLight}"></div>`],
3099
- [() => true, () => html`默认`]
3100
- ])}
3101
- *
3102
- * @param condition 条件
3103
- * @param tmpl 模板
3104
- */
3105
- class When extends Directive {
3106
- static get scopes() {
3107
- return [EnterPointType.TEXT, EnterPointType.SLOT];
3108
- }
3109
- update(nodes, newArgs, oldArgs) {
3110
- if (isEqual(newArgs, oldArgs)) {
3111
- return DirectiveUpdateTag.NONE;
3112
- }
3113
- //todo 缓存
3114
- return DirectiveUpdateTag.REPLACE;
3115
- }
3116
- render(value, cases) {
3117
- let defaultFn = () => html ``;
3118
- let conditionList = [];
3119
- let tmplList = [];
3120
- each(cases, (v, k) => {
3121
- if (isFunction(v)) {
3122
- conditionList.push(k);
3123
- tmplList.push(v);
3124
- }
3125
- else {
3126
- let condiFn = v[0];
3127
- let tmplFn = v[1];
3128
- conditionList.push(condiFn);
3129
- tmplList.push(tmplFn);
3130
- }
3131
- if (k === 'default') {
3132
- defaultFn = v;
3133
- }
3134
- });
3135
- let i = findIndex(conditionList, c => {
3136
- if (isFunction(c)) {
3137
- return c(value);
3138
- }
3139
- else {
3140
- return c == value;
3141
- }
3142
- });
3143
- return call(tmplList[i] ?? defaultFn);
3144
- }
3145
- }
3146
- const when = directive(When);
3147
-
3148
- export { CompElem, Decorator, DecoratorType, DecoratorWrapper, DecoratorsKey, Directive, DirectiveUpdateTag, DirectiveWrapper, EnterPoint, EnterPointType, ExpPos, GetKeyFnName, ModelTriggerType, QueryCache, Template, _getObservedAttrs, bind, buildHTML, classes, computed, createRef, decorator, directive, event, forEach, html, ifElse, ifTrue, makeProp, makeState, model, prop, query, queryAll, show, slot, state, styles, sync, tag, watch, when };
7
+ import{toPath as t,isFunction as e,isObject as s,isDefined as n,get as r,isUndefined as i,isEmpty as o,has as a,concat as l,set as c,defaults as d,merge as h,cloneDeep as p,each as u,kebabCase as f,last as m,isEqual as _,startsWith as g,includes as v,clone as E,isElement as C,isArray as b,initial as N,find as y,debounce as P,throttle as T,once as x,remove as S,map as M,size as A,isBlank as k,join as L,split as O,replace as w,compact as D,toArray as R,assign as $,first as j,isString as I,closest as H,bind as B,trim as U,omitBy as F,camelCase as V,isNil as z,some as W,isNull as K,fval as Q,test as G,omit as X,flatMap as q,groupBy as Y,reject as J,filter as Z,slice as tt,head as et,trimStart as st,trimEnd as nt,replaceAll as rt,snakeCase as it,toString as ot,findIndex as at,call as lt}from"myfx";function ct(t){console.error("[CompElem]",t)}function dt(t,e){console.error(`[CompElem <${t}>]`,e)}function ht(e){return t(e).join("-")}function pt(t){return Object.getPrototypeOf(t)}var ut;!function(t){t.CLASS="class",t.FIELD="field",t.METHOD="method"}(ut||(ut={}));class ft{static call(t,s,n,...r){if(gt.get(s)){s(...r)(t,n,e(n)?{configurable:!0}:null).create(t)}else s(t,n,...r)}}const mt="getKey",_t="__decorators",gt=new WeakMap;class vt{args;metadata;decoratorClass;instanceMap;key;constructor(t,e,s){this.args=t,this.metadata=e,this.decoratorClass=s,this.instanceMap=new WeakMap}create(t){let e,a=new this.decoratorClass(...this.args),l=a.targets,c=this.metadata[2];s(c)&&n(r(c,"configurable"))?e=ut.METHOD:i(this.metadata[2])&&(e=ut.FIELD),!o(l)&&e&&l.includes(e)?(a.created(t,...this.metadata),this.instanceMap.set(t,a)):ct(`Decorator '${this.decoratorClass.name}' is out of targets, expect '${l.join(",")}' bug got '${e}'`)}propsReady(t,e){this.instanceMap.get(t).propsReady(t,e,...this.metadata)}mounted(t,e){this.instanceMap.get(t).mounted(t,e,...this.metadata)}updated(t,e){this.instanceMap.get(t).updated(t,e)}}const Et=new WeakMap;function Ct(t){let e=(...e)=>(...s)=>{let n=s[0].constructor,i=r(n,_t);if(!a(n,_t)){let t=r(Object.getPrototypeOf(n),_t);i=t?l(t):[],c(n,_t,i)}let o,d={},h=r(t,mt);if(h){let s=Et.get(t);if(s||(s=new WeakMap,Et.set(t,s)),d=s.get(n),d||(d={},s.set(n,d)),o=h(...e),d[o])return d[o]}let p=new vt(e,s,t);return d[o]=p,i?.push(p),p};return gt.set(e,!0),e}const bt=new WeakMap;function Nt(t){if(1===arguments.length)return(e,s,n)=>{t.required=t.required||!1,t.attribute=!1!==t.attribute,yt(e,s,t,n)};let e=arguments[0],s=arguments[1],n=arguments[2];t={type:void 0,required:!1,attribute:!0},n&&"function"==typeof n.type&&(t=d(n,t),n=void 0),yt(e,s,t,n)}function yt(t,e,s,n){let r;if(/[a-z]/.test(e[0])||ct(`Prop '${e}' must be in CamelCase`),!a(t.constructor,"__deco_props")){const e={};let s=t.constructor;for(;(s=pt(s))!==zt;)h(e,s.__deco_props?p(s.__deco_props):{});t.constructor.__deco_props=e,r=new Set,u(e,((t,e)=>{if(t.attribute){let t=f(e);r?.add(t)}})),bt.set(t.constructor,r)}if(n&&(n.get&&(s.getter=n.get),n.set&&(s.setter=n.set)),s.attribute){r||(r=bt.get(t.constructor));let s=f(e);r?.add(s)}t.constructor.__deco_props[e]=s}const Pt=new Set;function Tt(t){return bt.get(t)??Pt}const xt={startCss(t){this.__cssCollecting=t},endCss(){this.__cssCollecting=null},setCssUpdater(t){this.__cssUpdater=t},startCompute(t){this.__computeCollecting=t},endCompute(){this.__computeCollecting=null},setComputedProp(t){this.__computeUpdater=t},__computeCollecting:null,__computeUpdater:null,__cssCollecting:null,__cssUpdater:null,__directiveQ:[],setDirectiveQ(t){let e=m(this.__directiveQ);e&&_(e,t)||(e&&e.length<t.length&&g(t.join(","),e.join(","))?this.__directiveQ[this.__directiveQ.length-1]=t:this.__directiveQ.push(t))},popDirectiveQ(){let t=l(this.__directiveQ);return this.__directiveQ=[],t},startRender(t){this.__renderCollecting=!0,this.__renderContext=t},endRender(t){this.__renderCollection.forEach((e=>{t._regDeps(e,this.__renderContext)})),this.__renderCollection.clear(),this.__renderCollecting=!1,this.__renderContext=null},collect(t){this.__renderCollection.add(t)},clear(){this.__directiveQ=[]},__renderCollection:new Set,__renderContext:null,__renderCollecting:!1,__skipCheck:!1},St=new WeakMap,Mt=new WeakMap,At=new WeakMap,kt=new WeakMap;function Lt(t,n){if(!s(t))return t;const i=t.__proxy?t:new Proxy(t,{get(t,e,s){const n=Object.keys(t),r=Reflect.get(t,e,s);if(!v(n,e))return r;if(t.hasOwnProperty(e)){let t=Mt.get(s)??[],n=l(t,[e]),r=n.join("-");if(xt.__renderCollecting)xt.collect(ht(n)),xt.setDirectiveQ(n);else if(xt.__computeCollecting){let t=At.get(xt.__computeCollecting);t||(t={},At.set(xt.__computeCollecting,t));let e=t[r];e||(e=t[r]=[]),e.push(xt.__computeUpdater)}else if(xt.__cssCollecting){let t=kt.get(xt.__cssCollecting);t||(t={},kt.set(xt.__cssCollecting,t)),t[r]=xt.__cssUpdater}}return r},set(t,n,i,o){let a=St.get(o).from,c=r(a.constructor,"__deco_props");c&&c[n]&&t.__isData&&c[n].sync&&a.emit("update:"+n,{value:i});let d=t[n],h=r(a.constructor,"__deco_states"),p=r(c,[n,"hasChanged"])||r(h,[n,"hasChanged"]);if(p){if(!p.call(a,i,d))return!1}else{if(t[n]===i)return!0;if(Number.isNaN(i)&&Number.isNaN(t[n]))return!1}s(d)&&(d=E(d));let u=St.get(o)?.contextSet,f=Mt.get(o)??[],m=l(f,[n]),_=i;!s(i)||e(i)||C(i)||u.forEach((t=>{let e=St.get(o)?.pathMap,s=e?.get(t);s&&(m=l(s,[n]),Mt.set(_,m),_=Lt(_,t),Mt.set(_,m))}));let g=Reflect.set(t,n,_),v=St.get(o).pathMap;return u.forEach((t=>{let e=v.get(t);if(!e)return;m=l(e,"length"==n&&b(o)?[]:[n]),t._notify(d,m);let s=m.join("-"),r=At.get(t);if(r){let e=r[s];e&&e.forEach((e=>{e.call(t)}));let n=m.length-1;for(;n;){let e=r[m.slice(0,n).join("-")];e&&e.forEach((e=>{e.call(t)})),n--}}let i=kt.get(t);if(i){let e=i[s];e&&e.call(t);let n=m.length-1;for(;n;){let e=i[m.slice(0,n).join("-")];e&&e.call(t),n--}}})),g}});t.__proxy||Object.defineProperty(t,"__proxy",{enumerable:!1,writable:!1,configurable:!1,value:!0});let o=Mt.get(t)??[];if(Object.isExtensible(t)&&!St.get(i)){let t=new Set;t.add(n);let e=new WeakMap;e.set(n,o),St.set(i,{from:n,contextSet:t,pathMap:e})}else{St.get(i).contextSet.add(n);let t=St.get(i).pathMap,e=t.get(n),s=l(o);if(e&&e.join("")!==s.join("")){let t=r(n,N(e));b(t)||function(...t){console.warn("[CompElem]",...t)}(`The object is referenced by more than one @state '${s.join(".")},${e.join(".")}'`),e=s}else t.set(n,s)}for(let r in t){const i=t[r];!s(i)||e(i)||C(i)||i instanceof Text||(Mt.set(i,l(o,[r])),t[r]=Lt(i,n),Mt.set(t[r],l(o,[r])))}return i}const Ot=["resize","outside"],wt=new WeakMap,Dt=[],Rt=new ResizeObserver((t=>{for(const e of t){const t=Array.isArray(e.contentBoxSize)?e.contentBoxSize[0]:e.contentBoxSize,s=Array.isArray(e.borderBoxSize)?e.borderBoxSize[0]:e.borderBoxSize;let n=wt.get(e.target);if(n){n(new CustomEvent("resize",{bubbles:!1,cancelable:!1,detail:{borderBox:{w:s.inlineSize,h:s.blockSize},contentBox:{w:t.inlineSize,h:t.blockSize}}}))}}}));function $t(t,e,s,n){if("resize"===t)!function(t,e){wt.set(t,e),Rt.observe(t)}(e,s);else if("outside"===t&&"mousedown"===n[0])!function(t,e){Dt.push([t,e])}(e,s)}document.addEventListener("mousedown",(t=>{let e=t.target;Dt.forEach((([s,n])=>{if(!s.contains(e)){n(new CustomEvent("outside",{bubbles:!1,cancelable:!1,detail:{currentTarget:s,event:t}}))}}))}),!1);const jt=/,|^(debounce:.+)|(debounce$)/,It=/,|^(throttle:.+)|(throttle$)/,Ht={esc:"escape"};function Bt(t,e,s,n){let r,i=t.split("."),o=i.shift(),a=i.includes("once"),l=e;if(r=y(i,(t=>jt.test(t)))){let t=r.split(":");l=P(l,parseInt(t[1])||100)}if(r=y(i,(t=>It.test(t)))){let t=r.split(":");l=T(l,parseInt(t[1])||100)}if(a&&(l=x(l)),function(t){return Ot.includes(t)}(o))return $t(o,s,l,i),l;let c=t=>{if(i.includes("prevent")&&t.preventDefault(),i.includes("stop")&&t.stopPropagation(),!i.includes("self")||t.target===t.currentTarget){if(t instanceof MouseEvent){if(i.includes("left")&&0!=t.button)return;if(i.includes("right")&&2!=t.button)return;if(i.includes("middle")&&1!=t.button)return}else if(t instanceof KeyboardEvent){if(S(i,(t=>"ctrl"==t))[0]&&!t.ctrlKey)return;if(S(i,(t=>"alt"==t))[0]&&!t.altKey)return;if(S(i,(t=>"shift"==t))[0]&&!t.shiftKey)return;if(S(i,(t=>"meta"==t))[0]&&!t.metaKey)return;if(!M(i,(t=>Ht[t]||t)).includes(t.key.toLowerCase()))return}l(t)}};s.addEventListener(o,c);let d=n.__events[o];return d||(d=n.__events[o]=[]),d.push([s,c]),c}function Ut(t){return class extends t{render(...t){}__expPos={};__expPosMap={};__directives={};slotComponent;renderComponent;renderContext(...t){return Ft.call(this,...t)}updateContext(...t){let e=1==A(t)&&(b(t[0])&&t[0][0]instanceof fe||t[0]instanceof fe)?t[0]:this.render(...t);e instanceof fe?this.__updateExpPos(e,this.__expPos):b(e)&&e[0]instanceof fe&&e.forEach(((t,e)=>{this.__updateExpPos(t,this.__expPosMap[t.key??t.getKey()])}))}__updateExpPos(t,e){if(k(L(t.strings)))return;let{vars:n}=t;e&&Object.values(e).forEach((t=>{let e=t.index,i=t.value,a=n,l=t.node,d=O(e,"-");if(d.forEach(((t,e)=>{a=r(a,t),a&&a.vars&&e<d.length-1&&(a=a.vars)})),!s(i)&&i===a)return;let h=l;if(t.isDirective){a.di=i.di,a.di.renderParams=a.varChain,a.di._renderArgs=a.args,a.point=i.point,a.varPath=i.varPath;let t=function(t,e){let s=t.nextSibling;if(!e)return[s];let n=[];for(;s&&s!==e;)n.push(s),s=s?.nextSibling;return n}(a.point.startNode,a.point.endNode);a.update(t,a.args,i.args)}else if(t.isToggleProp){if(!!a===i)return;h.toggleAttribute(t.attrName,!!a),c(h,t.attrName,!!a)}else if(t.isProp){if(!s(a)&&a===i)return;if(s(a)&&_(a,i))return;l instanceof zt?l._updateProps({[t.attrName]:a}):l instanceof HTMLSlotElement&&this.renderComponent._updateSlot(l.getAttribute("name")||"default",t.attrName,a)}else if(t.eventName)h.removeEventListener(t.eventName,i),a=a.bind(this.renderComponent),a=Bt(t.attrName,a,h,this.renderComponent);else if(t.attrName){if(!_(i,a))switch(t.attrName){case"value":if(l instanceof HTMLInputElement){l.value=a;break}default:l.setAttribute(t.attrName,w(t.attrTmpl,de,a+""))}}else if(t.isTmpl){if(!_(a,i)){let[e,s,n]=Ft.call(this,a);o(s)?(pe.remove(t.textNode,t.node),pe.insertBefore(t.node,e)):this.__updateExpPos(a,s)}}else if(t.isText){let e=t.textNode.nextSibling;e&&e===t.node.previousSibling?e.textContent=a:(pe.remove(t.textNode,t.node),pe.insertBefore(t.node,[a]))}t.value=a}))}}}function Ft(...t){let e,s,n,r=1===t.length&&t[0]instanceof fe?t[0]:this.render(...t),i=[];if(r instanceof fe){let t=ae(r);s={},e=he(s,i,t,r.vars,this.renderComponent)}if(b(r)&&r[0]instanceof fe){let t=[];n={},r.forEach((s=>{let r=ae(s),o={};e=he(o,i,r,s.vars,this.renderComponent),t.push(...e),n[s.key??s.getKey()]=o})),e=t}else r instanceof Function&&this.slotComponent._asyncDirectives.set(r,this);return i.length<1||i.forEach((t=>{let e=D(R(t.render(this.renderComponent)));if(!o(e)){let s=document.createDocumentFragment();s.append(...e),t.point.endNode.parentNode.insertBefore(s,t.point.endNode)}})),[e,s,n]}const Vt={boolean:Boolean,string:String,number:Number,object:Object,array:Array,function:Function,bigint:BigInt,symbol:Symbol,undefined:Object};class zt extends(Ut(HTMLElement)){static __l_globalRule=document.createElement("style");static{document.head.appendChild(zt.__l_globalRule)}#t={};#e={"#slots":{}};#s={};#n;#r={};#i;#o;#a={};__events={};get reactiveData(){return this.#s}get attrs(){return this.#l}get props(){return this.#c}get renderRoot(){return this.#d}get renderRoots(){return this.#h}get parentComponent(){return this.#p}get slotHooks(){return this.#u}get styles(){return r(this.constructor,"_component_style_attached",[])}get isMounted(){return this.#f}get slots(){return this.#e["#slots"]}#l;#c;#d;#h;#p;#m={};#u={};#_={};#f=!1;#g=new CSSStyleSheet;static get autoSlot(){return!0}static get styles(){return[]}static get globalStyles(){return[]}get css(){return""}#v=!1;constructor(...t){super(),1===A(t)&&(this.#c={},$(this.#c,j(t))),this.renderComponent=this;let e=this.render;this.render=()=>{let t;return xt.startRender(this),t=e.call(this),xt.endRender(this.renderComponent),t};let s=r(this.constructor,"globalStyles"),n=r(this.constructor,"_global_style_attached");if(!o(s)&&"1"!==n){let t="";u(s,(e=>{I(e)&&(t+=e+"\n")})),zt.__l_globalRule.textContent+=t,c(this.constructor,"_global_style_attached","1")}let i=r(this.constructor,"_component_style_attached"),a=i??[];i||(u(r(this.constructor,"styles"),(t=>{if(I(t)){let e=new CSSStyleSheet;e.replace(t),a.push(e)}else a.push(t)})),c(this.constructor,"_component_style_attached",a)),this.#i=this.attachShadow({mode:"open",slotAssignment:r(this.constructor,"autoSlot",!0)?"named":"manual"}),this.#i.adoptedStyleSheets=l(a,this.#g);let d=this.attributes.getNamedItem("css-link")?.value;if(d){const t=document.createElement("style");t.textContent=`@import "${d}"`,this.#i.appendChild(t)}let h=P(this.#E,20);this.#o=new MutationObserver((t=>{t.forEach((t=>{"childList"===t.type?h.call(this):"attributes"===t.type&&t.attributeName&&this.#C(t.attributeName,t.oldValue,this.getAttribute(t.attributeName))}))})),this._slotsPropMap={default:[]};let p=r(this.constructor,_t);u(p,(t=>{t.create(this)}))}connectedCallback(){let t=H(this.parentNode,(t=>t instanceof zt||t.host instanceof zt),"parentNode");this.#p=t?t instanceof zt?t:t.host:null,this.connected(),this.__init()}disconnectedCallback(){this.#o.disconnect()}__init(){if(this.#v)return;this.#b(),this.#N(),this.#y(),u(this.#e,((t,e)=>{let s=Reflect.getOwnPropertyDescriptor(this.#e,e);Object.defineProperty(this,e,{get(){let t=Reflect.get(this.#s,e);return s?.get?s?.get():t},set(t){s?.set?s?.set(t):Reflect.set(this.#s,e,t)}})})),Object.defineProperty(this.#e,"__isData",{enumerable:!1,value:!0}),this.#s=Lt(this.#e,this);const t=this;let s=r(this.constructor,_t);u(s,(e=>{e.propsReady(this,((e,s)=>(t.#s[e]=s,t.#s[e])))})),this.propsReady();let n=r(this.constructor,"__deco_computed");u(n,(({key:t,getter:e},s)=>{xt.startCompute(this),xt.setComputedProp((()=>{this.#s[s]=e.call(this)})),this.#e[s]=e.call(this),xt.endCompute()})),u(n,((t,e)=>{Object.defineProperty(this,e,{get(){return Reflect.get(this.#s,e)},set(t){dt(this.tagName,"Cannot set a computed property '"+e+"'")}})}));let[i,o,a]=this.renderContext();if(this.__expPos=o,i){let t=R(i);u(t,(t=>{this.#i.appendChild(t)})),this.#h=t,this.#d=t[0]}this.#E(),this.#o.observe(this,{childList:!0,attributes:!0});let l=r(this.constructor,"__deco_events");u(l,(t=>{let s=t.name,n=$({target:document,once:!1,passive:!1,capture:!1},t.options),r=B(t.fn,this),i=n.target;e(i)&&(i=i.call(this,this)),i.addEventListener(s,r,n)})),u(this.#u,((t,e)=>{this.#P(e)})),xt.startCss(this),xt.setCssUpdater((()=>{let t=this.css;this.#g.replace(t)}));let c=this.css;U(c)&&this.#g.replace(c),xt.endCss(),setTimeout((()=>{this.#f=!0,this.mounted(),u(s,(e=>{e.mounted(this,((e,s)=>(t.#s[e]=s,t.#s[e])))}))}),0),this.#v=!0}connected(){}propsReady(){}render(){throw Error(`[CompElem <${this.tagName}>] Missing render()`)}mounted(){}#T(t,e){this.#b();let s=r(this.#t[e],"props");s&&u(this.slots,((t,e)=>{t.filter((t=>t.nodeType===Node.ELEMENT_NODE)).forEach((t=>{t instanceof zt?t._updateProps(s):u(s,((e,s)=>{if(t instanceof HTMLSlotElement){let n=r(t,"__l_comp");if(n){let r=t.name||"default",i=n.#t[r];i||(i=n.#t[r]={props:{}}),i.props||(i.props={}),i.props[s]=e,n.#T(t,r)}}else t.setAttribute(s,e)}))}))})),this.slotchange(t,e)}slotchange(t,e){}shouldUpdate(t){return!0}updated(t){}emit(t,e={},s){s&&s.event&&(e.event=s.event),e.target=this,this.dispatchEvent(new CustomEvent(t,{bubbles:r(s,"bubbles",!1),composed:r(s,"composed",!1),cancelable:!0,detail:e}))}#x={};on(t,e){this.#x[t]||(this.#x[t]=[]);let s=e.bind(this);this.#x[t].push(s),this.addEventListener(t,s)}nextTick(t){requestAnimationFrame(t)}forceUpdate(){u(this.#s,((t,e)=>{this.#r[e]={value:void 0,chain:void 0}})),this.#S()}_notify(t,e){let s=[];u(e,(n=>{s.push(n);let i=r(this,s),o=ht(s);this.#r[o]={value:i,chain:"slots"===o?["slots"]:s,oldValue:t,end:s.length===e.length}})),this.#n&&clearTimeout(this.#n),this.#n=setTimeout(this.#S.bind(this),10)}#S(){const t=Object.seal(E(F(this.#r,((t,e)=>"#"===e[0]))));let e=r(this.constructor,_t);if(u(e,(e=>{e.updated(this,t)})),!this.shouldUpdate(t))return;let s=new Set;u(this.#r,(({value:t,chain:e,oldValue:n},r)=>{this.#a[r]&&this.#a[r].forEach((t=>{s.add(t)}))})),s.forEach((t=>{t.updateContext(...t._renderArgs?t._renderArgs:[])})),u(this.#M,(t=>{this.#P(t)})),this.updated(t),this.#r={}}#N(){let t=r(this.constructor,"__deco_props"),e=this.attributes,o=this.tagName,l=this.#c,c={};u(e,(({name:e,value:s})=>{if(e[0]===Jt||e[0]===Zt||e[0]===te||e===ne||"slot"===e)return;let n=V(e);t&&!t[n]&&(c[e]=s)})),this.#l=this.#l?$(this.#l,c):c,u(t,((c,d)=>{let h,p=t[d],u=a(l,d),m=r(this,d);if(!("_defaultValue"in p)&&(p._defaultValue=m,!p.type)){i(m)&&dt(o,"Prop '"+d+"' has neither propType nor defaultValue be used for type inference");let t=typeof m;b(m)&&(t="array");let e=Vt[t];p.type=e}if(u)h=z(l[d])?m:l[d];else{h=m;let t=e.getNamedItem(f(d))||e.getNamedItem(Zt+f(d));t&&(u=!0,h=t.value)}if(p.required&&!u)return dt(o,"Prop '"+d+"' is required"),!1;h=this.#A(t,d,h);let _=r(t,[d,"getter"]);_&&(_=B(_,this));let g=r(t,[d,"setter"]);g&&(g=B(g,this)),(_||g)&&Object.defineProperty(this.#e,d,{set:g||function(t){},get:_}),p.attribute&&n(h)&&!s(h)&&this.setAttribute(f(d),U(h)),this.#e[d]=h}))}#A(t,e,s){let r=t[e];if(!r)return s;let o=r.isValid,a=r.type,l=b(a)?a:[a],c=r.converter,d=s;if(!W(l,(t=>t===String))&&I(d)&&!K(d))try{d=c?c(d):Q(d,{html:me})}catch(t){dt(this.tagName,`Convert attribute '${e}' error with `+d)}l.forEach((t=>{"Boolean"===t.name&&(I(d)&&/(?:^true$)|(?:^false$)/.test(d)?d=Q(d):(i(d)||k(d))&&(d=!0))}));let h=typeof d,p=!n(d);return u(l,(t=>{if(G(h,t.name,"i")||d instanceof t)return p=!0,!1})),p||dt(this.tagName,`Invalid prop '${e}'. expected '${l.map((t=>t.name||t))}' but got '${h}'`),o&&(o.call(this,d,this.#e)||dt(this.tagName,`Invalid prop '${e}'. IsValid() check failed`)),d}#y(){let t=r(this.constructor,"__deco_states");u(t,((e,s)=>{let n=t[s],i=r(this,s);if(n){let t=n.prop;i=t?p(this.#e[t]):r(this,s)}this.#e[s]=i}))}#k=P(this.propsReady,100);_setParentProps(t,e){if(this.#v){let s=r(this.constructor,"__deco_props");u(t,((t,e)=>{let n=V(e),r=s[n];if(!r)return;let i=this.#e[n];t=this.#A(s,n,t),r.hasChanged&&!r.hasChanged.call(this,t,i)||(this.#e[n]=t,this._notify(i,[n]))})),$(this.#c,t),$(this.#l,e),this.#k()}}_updateProps(t){let e=r(this.constructor,"__deco_props");u(t,((t,s)=>{let n=V(s),r=e[n];if(!r)return;let i=this.#e[n];t=this.#A(e,n,t),r.hasChanged&&!r.hasChanged.call(this,t,i)||(xt.__skipCheck=!0,c(this,n,t),xt.__skipCheck=!1)})),$(this.#c,t),this.#k()}_initProps(t,e){this.#c=h(this.#c||{},t),this.#l=h({},e)}_bindSlot(t,e,s){if(this.#m[e]||(this.#m[e]=t,Object.defineProperty(t,"__l_comp",{value:this})),t.addEventListener("slotchange",(s=>{this.#v&&this.#T(t,"default"===e?"":e)})),!o(s)){let t=this.#t[e];t||(t=this.#t[e]={}),s.nodeFilter&&(t.filter=s.nodeFilter),t.props=X(s,"nodeFilter")}}_bindSlotHook(t,e){this.#u[t]=e}#M=new Set;_updateSlot(t,e,s){let n=this.#m[t],r=this.#u[t];if(!r&&!n)return;let i=this.#t[t];if(e&&(i.props||(i.props={}),i.props[e]=s),r)this.#M.add(t);else{let t=n.assignedElements({flatten:!0});u(t,(t=>{t.setAttribute(e,s+"")}))}}#b(){const t=q(this.childNodes,(t=>t.nodeType===Node.COMMENT_NODE?[]:t instanceof HTMLSlotElement?t.assignedNodes({flatten:!0}):t));let e=Y(t,(t=>t.nodeType===Node.TEXT_NODE?"default":t instanceof Element?t.getAttribute("slot")||"default":void 0));if(o(e))return void(o(this.#e["#slots"])||(this.#v?this.#s["#slots"]={}:this.#e["#slots"]={}));u(e,((t,e)=>{if(e){for(;t.length>0;){let e=t[0];if(!(e.nodeType===Node.TEXT_NODE&&k(e.textContent)||e instanceof HTMLSlotElement&&o(e.assignedNodes({flatten:!0}))))break;t.shift()}for(;t.length>0;){let e=m(t);if(!(e.nodeType===Node.TEXT_NODE&&k(e.textContent)||e instanceof HTMLSlotElement&&o(e.assignedNodes({flatten:!0}))))break;t.pop()}}}));let s={};u(e,((t,e)=>{o(t)||(s[e]=t)})),this.#v?this.#s["#slots"]=s:this.#e["#slots"]=s}#P(t){let e=this.#u[t];if(!e)return;let s=this.#t[t];if(!this.#e["#slots"][t])return;this.renderAsync(e,r(s,"props"));const n=this._asyncDirectives.get(e);let[i,a,l]=n?.renderContext(e(r(s,"props"))),c=J(R(i),(t=>t.nodeType===Node.COMMENT_NODE));if(c){let e=this.#_[t];o(e)||u(e,(t=>{t.parentNode?.removeChild(t)})),this.#_[t]=c,this.append(...c),this.#M.clear()}}_asyncDirectives=new WeakMap;renderAsync(t,...e){}#E(){o(this.#t)||u(this.slots,((t,n)=>{if(o(t))return;let r=this.#t[n],i=t;if(r){let n=r.filter;if(e(n))i=n(t);else if(s(n)){let e=n.type,s=n.maxCount;if(e){let s=b(e)?e:[e];i=Z(t,(t=>W(s,(e=>t instanceof e))))}s>0&&(i=tt(t,0,s))}}if("named"===this.#i.slotAssignment){let e=[];for(u(t,(t=>{i.includes(t)||e.push(t)}));e.length>0;){let t=e.pop();t.parentNode?.removeChild(t)}}else this.#m[n].assign(...i);this.#v&&this.#T(this.#m[n],"default"===n?"":n)}))}#C(t,e,s){if(!this.isMounted)return;if(Tt(this.constructor).has(t)){if(K(s)){s=r(this.constructor,"__deco_props")[t]._defaultValue}this._updateProps({[t]:s})}}_regDeps(t,e){let s=this.#a[t];s||(s=this.#a[t]=new Set),s.add(e);let n="",r=t.split("-");r.pop(),r.forEach((t=>{n=o(n)?t:n+"-"+t;let s=this.#a[n];s||(s=this.#a[n]=new Set),s.add(e)}))}}var Wt;!function(t){t.NONE="NONE",t.REMOVE="REMOVE",t.REPLACE="REPLACE",t.UPDATE="UPDATE",t.APPEND="APPEND"}(Wt||(Wt={}));class Kt{index;value;isText=!1;isTmpl=!1;isDirective=!1;node;textNode;isComponent=!1;attrName;attrTmpl;isProp=!1;isToggleProp=!1;eventName;constructor(t,e,s,n){this.index=t+"",this.node=e,s&&(this.attrName=s),n&&(this.attrTmpl=n)}}var Qt,Gt;!function(t){t.ATTR="attr",t.PROP="prop",t.TEXT="text",t.CLASS="class",t.STYLE="style",t.SLOT="slot",t.TAG="tag"}(Qt||(Qt={}));class Xt{startNode;endNode;type;attrName;varIndex;expressionChain;nodes;constructor(t,e,s,n){this.startNode=e,this.attrName=s,this.type=n}setVarIndex(t){this.varIndex=t}}!function(t){t.AFTER_BEGIN="afterbegin"}(Gt||(Gt={}));class qt extends Function{diClass;args;di;varPath;point;slotComponent;varChain;constructor(t,...e){super(),this.diClass=t,this.args=e,this.varChain=xt.popDirectiveQ()}checkScope(t){let e=r(this.diClass,"scopes");o(e)||G(e.join(","),t)||ct(`Directive '${this.diClass.name}' is out of scopes, expect '${e.join(",")}' bug got '${t}'`)}render(t){let e=r(t,"__directives"),s=this.di||e[this.varPath];s||(s=new this.diClass(this.point),s.renderComponent=t,s.slotComponent=this.slotComponent,s.renderParams=this.varChain),this.di=s,s._renderArgs=this.args;let[n,i,o]=s.renderContext(...this.args);return o?s.__expPosMap=o:i&&(s.__expPos=i),n}update(t,e,s){let n=this.di.update(t,e,s);if(n===Wt.REMOVE)t.forEach((t=>{t.parentNode?.removeChild(t)}));else if(n===Wt.REPLACE){let s=[];t.forEach((t=>{t.parentNode?.removeChild(t)}));let n=this.di.render(...e),[r,i,o]=this.di.renderContext(n);o?this.di.__expPosMap=o:i&&(this.di.__expPos=i),s=R(r);let a=document.createDocumentFragment();a.append(...s),this.point.endNode.parentNode.insertBefore(a,this.point.endNode)}else if(n===Wt.UPDATE){let s,n={},r={},i=[],a=[],l=this.di.render(...e);b(l)&&l[0]instanceof fe&&l.forEach((t=>{let e=t.key??t.getKey();n[e]="1",r[e]=t,a.push(e)})),t=Z(D(t),(t=>t.nodeType===Node.ELEMENT_NODE)),s=Z(D(R(s)),(t=>t.nodeType===Node.ELEMENT_NODE));let c={},d="",h={};M(t,(t=>{let e=t,s=e.getAttribute("key");if(s){if(c[s])return d=s,!1;c[s]=e,i.push(s),h[s]="1"}})),d&&ct(`${V(this.diClass.name)} - duplicate key '${d}'`);let p={},f=n;const _=this.point.startNode.parentNode;let g=[],v=[];if(u(h,((t,e)=>{f[e]||(v.push(e),delete h[e],S(i,e))})),!o(a)){let t="",e=-1,s=[],n={};a.forEach(((r,o)=>{let l=i.findIndex((t=>t===r));if(l>-1&&l!==o){if(e<0||e-l==1){let t=m(s);s.push({nodeId:r,targetId:0===o?Gt.AFTER_BEGIN:t?t.nodeId:a[o-1]})}else n[s.length]={group:s,targetId:""},s=[],s.push({nodeId:r,targetId:i[l]});e=l}else if(l<0){let e=t?c[t]||this.point.endNode:this.point.startNode;g.push({prevNode:e,newkey:r})}t=r})),o(n)&&s.length>0&&(n[s.length]={group:s,targetId:""});let r=Object.keys(n),l=r.map((t=>parseInt(t))).sort(((t,e)=>t-e));if(r.length<2&&r.length>0){let{group:t}=n[l[0]];N(t).forEach((({targetId:t,nodeId:e})=>{let s,n=c[e];t===Gt.AFTER_BEGIN?(s=this.point.startNode,s.after(n)):(s=c[t],s.after(n))}))}}g.forEach((t=>{let e=t.newkey,s=p[e]||this.#L(r[e],e),n=t.prevNode;n===this.point.endNode?n.before(s):(this.point.startNode,n.after(s))})),v.forEach((t=>{this.#O(t);let e=c[t];e&&_.removeChild(e)})),this.di.updateContext(l)}}getDirective(){return this.di}#L(t,e){let[s,n,r]=this.di.renderContext(t),i=et(s);return this.di.__expPosMap[e]=n,i}#O(t){this.di.__expPosMap[t]=null,delete this.di.__expPosMap[t]}}function Yt(t){return(...s)=>{let n=null;return s.forEach(((t,r)=>{if(e(t)){let e=t;s[r]=function(...t){let s=n.di;xt.startRender(s);let r=e(...t);return xt.endRender(s.renderComponent),r}}})),n=new qt(t,...s),n}}const Jt="@",Zt=".",te="?",ee="*",se=":",ne="ref",re=/[.?-a-z]+\s*=\s*(['"])\s*([^='"]*<\!--l_ui-pl_df-->){2,}.*?\1/ims,ie=/<\s*[a-z0-9-]+([^>]*<\!--l_ui-pl_df-->)*[^>]*?(?<!-)>/gims,oe="slot-props";function ae(t){let e="";(b(t)?t:[t]).forEach((({strings:t,vars:s})=>{let n=R(t);n[0]=st(n[0]),n[n.length-1]=nt(n[n.length-1]);let i=n.length-1;n.forEach(((t,n)=>{let o=r(s,n,"");o=i===n?"":le,e+=t+o}))}));let s=e.match(re);if(s){return ct(`Parse error: attribute value can be set only one interpolation —— \n ${rt(s[0],le,"${...}")}`),""}let n=0;return e=e.replace(ie,((t,e)=>rt(t,le,(()=>le.replace("--\x3e","")+n++)))),e}const le="\x3c!--l_ui-pl_df--\x3e",ce="\x3c!--l_ui-pl_df",de=/<!--l_ui-pl_df\d*(-->)?/;function he(t,s,n,r,o,l,c=0,d=""){const h=document.createElement("div");h.innerHTML=n;const p=document.createNodeIterator(h,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_COMMENT);let m,_=0,v=null;for(;m=p.nextNode();)if(m instanceof HTMLElement||m instanceof SVGElement){m instanceof zt?v=m:v?.contains(m)||(v=null);let n={},i=R(m.attributes);u(i,(i=>{let{name:l,value:h}=i;if(l===oe){let t=m.name||"default";if(v){let e=v._slotsPropMap[t];e||(e=v._slotsPropMap[t]=[]),e.push(m)}}if(g(l,ce)){let e=r[_];if(e instanceof qt){e.checkScope(Qt.TAG);let n=new Xt(c,m,l.substring(1),Qt.TAG);e.point=n,e.varPath=d+_,e.slotComponent=v,s.push(e);let r=t[d+_]=new Kt(d+_,m);r.isDirective=!0,r.value=e,r.isComponent=!!v,_++}m.removeAttribute(l)}else{if(l[0]===Jt){let s=t=>{},n=null;if(de.test(h)){let i=r[_];if(!e(i))return void dt(m.tagName,`Event '${l}' must be a function`);s=i.bind(o),n=t[d+_]=new Kt(d+_,m,l.replace(/\.|\?|@/,""),h),n.isComponent=!!v,_++}let i=l.substring(1).split(".").shift();return s=Bt(l.substring(1),s,m,o),m.removeAttribute(l),void(n&&(n.eventName=i,n.value=s))}if(l!==ne)if(l[0]!==Zt||de.test(h)){if(de.test(h)){let e=r[_],o=t[d+_]=new Kt(d+_,m,l.replace(/\.|\?|@/,""),h);if(o.isComponent=!!v,l[0]===Zt||l[0]===te||l[0]===ee){if(e instanceof qt){e.checkScope(Qt.PROP),s.push(e);let t=new Xt(c,m,l.substring(1),Qt.PROP);e.varPath=d+_,e.point=t,e.slotComponent=v,o.value=e,o.isDirective=!0}else if(l[0]===te)o.isToggleProp=!0,o.value=!!e,o.value&&m.setAttribute(l.substring(1),"");else if(l[0]===ee){o.value=e;let t=l.substring(1);const[s,n]=t.split(se);let r=s;switch(n){case"camel":r=V(r);break;case"kebab":r=f(r);break;case"snake":r=it(r)}o.attrName=r,m.setAttribute(r,e)}else if(m instanceof zt||"SLOT"===m.tagName){let t=V(l.substring(1));t in m||"SLOT"===m.tagName||dt(m.tagName,`Prop '${l}' is not defined in ${m.tagName}`),o.value=e,o.isProp=!0,n[t]=e}else dt(m.tagName,`Prop '${l}' can only be set on a CompElem or a slot`),delete t[d+_];m.removeAttribute(l),e=""}else{if(o.value=e,e instanceof qt){let t=Qt.ATTR;"class"===l?t=Qt.CLASS:"style"===l&&(t=Qt.STYLE),e.checkScope(t),s.push(e),o.isDirective=!0;let n=new Xt(c,m,l,t);e.point=n,e.slotComponent=v,e.varPath=d+_,e=""}h=w(h,de,e),i.value=h}_++}}else dt(m.tagName,`Prop '${l}' must be an interpolation`);else{if(de.test(h)){let t=r[_];if(!a(t,"current"))return void dt(m.tagName,"Ref must be a RefObject");_++,t.current=m}m.removeAttribute(l)}}})),m instanceof zt?m._initProps(n):m instanceof HTMLSlotElement&&o._bindSlot(m,m.name||"default",n)}else{let e=m;if(`\x3c!--${e.nodeValue}--\x3e`!==le)continue;let n=t[d+_]=new Kt(d+_,m);n.isComponent=!!v,n.isText=!0;let a,h=r[_];if(a=document.createComment(`compelem-ui-${c}-${_}-child-start`),e.parentNode.insertBefore(a,e),e.nodeValue=`compelem-ui-${c}-${_}-child-end`,n.textNode=a,h instanceof qt){n.isDirective=!0,n.value=h;let t=v?Qt.SLOT:Qt.TEXT;s.push(h);let r=new Xt(c,a,"",t);r.endNode=e,h.point=r,h.slotComponent=v,h.varPath=d+_,h=""}else if(h instanceof fe){n.isTmpl=!0,n.value=h;let e=ae(h);h=he(t,s,e,h.vars,o,l,c,d+`${_}-`)}else n.value=h;if(_++,i(h))continue;if(h instanceof NodeList){let t=document.createDocumentFragment();t.append(...h),e.parentNode.insertBefore(t,e)}else if(h instanceof Element)e.parentNode.insertBefore(h,e);else if(U(h)){let t=document.createTextNode(h);e.parentNode.insertBefore(t,e)}}return h.childNodes}const pe={insertBefore:function(t,e){let s=document.createDocumentFragment();s.append(...e),t.parentNode.insertBefore(s,t)},remove:function(t,e){let s=t.nextSibling;for(;s!==e;)s?.parentNode?.removeChild(s),s=t.nextSibling}},ue=/\s+\.?key\s*=/;class fe{strings;vars;key;constructor(t,e){this.strings=l(t),this.vars=e}getKey(){let t=this.vars,e="";return u(this.strings,((s,n)=>{if(ue.test(s))return e=ot(t[n]),!1})),this.key=e,e}append(t){let e=m(this.strings);return t.strings.forEach(((t,s)=>{0!=s?this.strings.push(t):this.strings[this.strings.length-1]=e+t})),this.vars=l(this.vars,t.vars),this}getHTML(){let t="",e=R(this.strings);e[0]=st(e[0]),e[e.length-1]=nt(e[e.length-1]);let s=e.length-1;return e.forEach(((e,n)=>{let i=r(this.vars,n,"");i=i instanceof fe?i.getHTML():s===n?"":i,t+=e+i})),t}}function me(t,...e){return new fe(I(t)?[t]:t,e)}function _e(t){return{current:t}}function ge(t,e,s){s.get||ct(`Prop '${e}' must be a getter`),a(t.constructor,"__deco_computed")||(t.constructor.__deco_computed=o(t.constructor.__deco_computed)?{}:p(t.constructor.__deco_computed)),t.constructor.__deco_computed[e]={key:e,getter:s.get}}function ve(t,e){return(s,n,r)=>{a(s.constructor,"__deco_events")||(s.constructor.__deco_events=o(s.constructor.__deco_events)?[]:p(s.constructor.__deco_events)),s.constructor.__deco_events.push({name:t,options:e,fn:s[n]})}}var Ee;!function(t){t.ONCE="once",t.UPDATABLE="updatable"}(Ee||(Ee={}));class Ce extends ft{created(t,...e){}mounted(t,e,...s){}get targets(){return[ut.FIELD]}selector;cache;result;constructor(t,e){super(),this.selector=t,this.cache=e}static getKey(t){return t}getter(t){this.result=t.shadowRoot?.querySelector(this.selector)}propsReady(t,e,s,n,...r){const i=this;Object.defineProperty(t,n,{get:()=>(i.result&&i.cache||i.getter(t),i.result)})}updated(t,e){this.cache===Ee.UPDATABLE&&this.getter(t)}}const be=Ct(Ce),Ne=Ct(class extends Ce{getter(t){this.result=t.shadowRoot?.querySelectorAll(this.selector)}});function ye(t){if(1===arguments.length)return(e,s)=>{Pe(e,s,t)};Pe(arguments[0],arguments[1],{prop:""})}function Pe(t,e,s){if(!a(t.constructor,"__deco_states")){const e={};let s=t.constructor;for(;(s=pt(s))!==zt;)h(e,s.__deco_states?p(s.__deco_states):{});t.constructor.__deco_states=e}t.constructor.__deco_states[e]=s}function Te(t,e,s){Pe(t.prototype,e,s||{prop:""})}function xe(t){return e=>{e&&customElements.define(t,e)}}const Se=Ct(class extends ft{created(t,...e){}propsReady(t,e,...s){}get targets(){return[ut.METHOD]}sources;options;handler;constructor(t,e,s){super(),this.sources=b(t)?t:[t],this.options=e,this.handler=s}static getKey(t){return b(t)?t.sort().join(""):t}mounted(t,s,n,i,...o){this.handler||(this.handler=e(i)?i:t[i]);let a=this.handler,l=r(this.options,"immediate",!1);r(this.options,"once",!1)&&(a=x(a.bind(t)));let c=[];this.sources.forEach((e=>{let s=r(t,e.replaceAll("-","."));l&&c.push({handler:a,value:s,varPath:e})})),c.forEach((({handler:e,value:s,varPath:n})=>{e.call(t,r(t,n),s,n)}))}updated(t,e){this.sources.forEach((s=>{u(e,(({value:e,chain:n,oldValue:i,end:o},a)=>{let l=s.replaceAll(".","-");if(!g(a,l))return;a===l&&o&&this.handler&&this.handler.call(t,e,i,a);let c=n.length-1;for(;c;){let e=n.slice(0,c);if(o&&e.join("-")===l&&r(this.options,"deep")){let s=r(t,e);this.handler.call(t,s,s,e.join("-"))}c--}}))}))}});class Me extends(Ut(Object)){_renderArgs;static get scopes(){return[]}renderParams}const Ae=["key"];const ke=Yt(class extends Me{update(t,e,s){return Wt.NONE}static get scopes(){return[Qt.TAG]}constructor(t){super(),this.point=t}render(t){let e=this.point.startNode;if(e instanceof zt){let s={},n={};u(t,((t,r)=>{Ae.includes(r)||(r in e?s[r]=t:n[r]=t+"")})),e._initProps(s,n)}else u(t,((t,s)=>{e.setAttribute(s,t)}))}});const Le=Yt(class extends Me{update(t,e,s){return this.render(e[0]),Wt.NONE}static get scopes(){return[Qt.CLASS]}constructor(t){super(t),this.point=t}lastCls;render(t){let e=[];b(t)?e=D(t):s(t)?e=q(t,((t,e)=>t?e:[])):I(t)&&(e=t.split(" "));let n=this.point.startNode;u(this.lastCls,(t=>{n.classList.remove(t)})),u(e,(t=>{n.classList.add(t)})),this.lastCls=l(e)}}),Oe=/\s+\.?key\s*=/;const we=Yt(class extends Me{update(t,e,s){if(o(t)&&o(e[0]))return Wt.NONE;if(!o(this.renderParams)){let t=m(this.renderParams);b(t)||(t=[t]),this.renderParams=t}return Wt.UPDATE}constructor(t){super(),o(this.renderParams)||(this.renderParams=R(m(this.renderParams)))}static get scopes(){return[Qt.TEXT,Qt.SLOT]}render(t,e){let s=M(t,((t,s)=>e(t,s))),n=[],r=[];return s.forEach((t=>{let e=m(r),s=t.vars,i=!0;t.strings.forEach(((t,o)=>{if(Oe.test(t)){let t=s[o]+"";n.includes(t)&&ct(`forEach - duplicate key '${t}'`),n.push(t),i=!1}0==o&&e?r[r.length-1]=e+t:r.push(t)})),i&&ct("forEach - missing 'key' prop")})),s}});const De=Yt(class extends Me{ifNodes;elseNodes;static get scopes(){return[Qt.TEXT,Qt.SLOT]}update(t,e,s){return!!e[0]==!!s[0]?Wt.UPDATE:(e[0],Wt.REPLACE)}render(t,e,s){return t?e(t):s(t)}});const Re=Yt(class extends Me{static get scopes(){return[Qt.TEXT,Qt.SLOT]}update(t,e,s){return e[0]===s[0]?Wt.UPDATE:e[0]?Wt.REPLACE:(this.cacheNodes=t,Wt.REMOVE)}render(t,e){return t?e():me``}});var $e;!function(t){t.CHANGE="change",t.INPUT="input"}($e||($e={}));const je=Yt(class extends Me{update(t,e,s){if(this.modelPath||(this.modelPath=m(this.renderParams)),!_(e,s)){const t=this.point.startNode;if(t instanceof zt)t._updateProps({value:e[0]});else if(t instanceof HTMLTextAreaElement||t instanceof HTMLSelectElement)t.setAttribute("value",e[0]+"");else if(t instanceof HTMLInputElement)switch(t.type){case"checkbox":case"radio":e[0]?t.setAttribute("checked",""):t.removeAttribute("checked");break;default:t.setAttribute("value",e[0]+"")}}return Wt.NONE}static get scopes(){return[Qt.TAG]}modelPath;point;constructor(t){super(),this.point=t}render(e,n){this.modelPath||(this.modelPath=m(this.renderParams)),n&&(this.modelPath=t(n));const i=this.point.startNode;if("binded"!==r(i,"_model"))if(s(e)||U(e)||(e=""),i instanceof zt)i._initProps({value:e}),i.addEventListener("update:value",(t=>{c(this.renderComponent,this.modelPath,t.detail.value)})),c(i,"_model","binded");else if(i instanceof HTMLTextAreaElement)i.setAttribute("value",e+""),i.addEventListener("input",(t=>{let e=t.target;c(this.renderComponent,this.modelPath,e.value)})),c(i,"_model","binded");else if(i instanceof HTMLInputElement){let t="",s="";switch(i.type){case"checkbox":case"radio":t="checked",s="change";break;default:t="value",s="input"}i.setAttribute(t,e+""),i.addEventListener(s,(t=>{let e=t.target;c(this.renderComponent,this.modelPath,e.value)})),c(i,"_model","binded")}else i instanceof HTMLSelectElement&&(i.setAttribute("value",e+""),i.addEventListener("change",(t=>{let e=t.target;c(this.renderComponent,this.modelPath,e.value)})),c(i,"_model","binded"))}});const Ie=Yt(class extends Me{update(t,e,s){return this.render(e[0]),Wt.NONE}display=void 0;static get scopes(){return[Qt.TAG]}constructor(t){super(),this.point=t}render(t){let e=this.point.startNode;i(this.display)&&(this.display=e.style.display),this.renderComponent.nextTick((()=>{e.style.display=t?this.display:"none"}))}});const He=Yt(class extends Me{update(t,e,s){return Wt.NONE}static get scopes(){return[Qt.SLOT]}render(t,e){return t=t.bind(this.renderComponent),this.slotComponent._bindSlotHook(e||"default",t),t}});const Be=Yt(class extends Me{update(t,e,s){return this.render(e[0]),Wt.NONE}constructor(t){super(),this.point=t}static get scopes(){return[Qt.STYLE]}render(t){let e="";s(t)?e=L(M(t,((t,e)=>f(e)+":"+t)),";"):I(t)&&(e=t),u(e.split(";"),(t=>{let e=t.split(":");this.point.startNode.style.setProperty(U(e[0]),U(e[1]))}))}});const Ue=Yt(class extends Me{update(t,e,s){return _(e,s)||this.targetComponent._updateProps({[this.attrName]:e[0]}),Wt.NONE}static get scopes(){return[Qt.PROP]}modelPath;attrName;targetComponent;constructor(t){super(),this.targetComponent=t.startNode,this.attrName=t.attrName}render(t){this.modelPath||(this.modelPath=m(this.renderParams)),this.targetComponent._initProps({[this.attrName]:t}),this.targetComponent.addEventListener("update:"+this.attrName,(t=>{c(this.renderComponent,this.modelPath,t.detail.value)}))}});const Fe=Yt(class extends Me{static get scopes(){return[Qt.TEXT,Qt.SLOT]}update(t,e,s){return _(e,s)?Wt.NONE:Wt.REPLACE}render(t,s){let n=()=>me``,r=[],i=[];u(s,((t,s)=>{if(e(t))r.push(s),i.push(t);else{let e=t[0],s=t[1];r.push(e),i.push(s)}"default"===s&&(n=t)}));let o=at(r,(s=>e(s)?s(t):s==t));return lt(i[o]??n)}});export{zt as CompElem,ft as Decorator,ut as DecoratorType,vt as DecoratorWrapper,Me as Directive,Wt as DirectiveUpdateTag,qt as DirectiveWrapper,Xt as EnterPoint,Qt as EnterPointType,Kt as ExpPos,mt as GetKeyFnName,$e as ModelTriggerType,Ee as QueryCache,fe as Template,gt as _DecoratorMap,_t as _DecoratorsKey,Tt as _getObservedAttrs,ke as bind,ae as buildHTML,Le as classes,ge as computed,_e as createRef,Ct as decorator,Yt as directive,ve as event,we as forEach,me as html,De as ifElse,Re as ifTrue,Te as makeState,je as model,Nt as prop,be as query,Ne as queryAll,Ie as show,He as slot,ye as state,Be as styles,Ue as sync,xe as tag,Se as watch,Fe as when};