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