@neeloong/form 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @neeloong/form v0.9.0
2
+ * @neeloong/form v0.10.0
3
3
  * (c) 2024-2025 Fierflame
4
4
  * @license Apache-2.0
5
5
  */
@@ -283,13 +283,14 @@ function merge(...v) {
283
283
  /** @import { AsyncValidator, Schema, Validator } from '../types.mjs' */
284
284
 
285
285
  /**
286
+ * 管理单个表单字段的状态和行为
286
287
  * @template [T=any]
287
288
  */
288
289
  class Store {
289
290
  /** @type {Map<string, Set<(value: any, store: any) => void | boolean | null>>} */
290
291
  #events = new Map()
291
292
  /**
292
- *
293
+ * 触发事件并通知监听器
293
294
  * @template {keyof Schema.Events} K
294
295
  * @param {K} event
295
296
  * @param {Schema.Events[K]} value
@@ -304,7 +305,7 @@ class Store {
304
305
  return !canceled;
305
306
  }
306
307
  /**
307
- *
308
+ * 监听事件
308
309
  * @template {keyof Schema.Events} K
309
310
  * @param {K} event
310
311
  * @param {(this: this, p: Schema.Events[K], store: this) => void | boolean | null} listener
@@ -324,14 +325,16 @@ class Store {
324
325
 
325
326
  }
326
327
  /**
327
- * @param {Schema} schema
328
- * @param {object} [options]
329
- * @param {boolean} [options.new]
328
+ * 从数据结构模式创建存储
329
+ * @param {Schema} schema 数据结构模式
330
+ * @param {object} [options] 选项
331
+ * @param {boolean} [options.new] 是否为新建环境
330
332
  */
331
333
  static create(schema, options = {}) {
332
334
  return create({type: schema}, { ...options, parent: null });
333
335
  }
334
336
  /**
337
+ * 设置自定义类型的存储类
335
338
  * @param {string} type
336
339
  * @param {{new(...p: ConstructorParameters<typeof Store>): Store}} Class
337
340
  */
@@ -339,14 +342,16 @@ class Store {
339
342
  return setStore$1(type, Class);
340
343
  }
341
344
  #null = false;
345
+ /** 是否为无效空存储 */
342
346
  get null() { return this.#null; }
347
+ /** 存储类类别,继承的自定义类需要设置自定义的此只读属性 */
343
348
  get kind() { return ''; }
344
349
  /** @type {Ref?} */
345
350
  #ref = null;
346
351
  get ref() { return this.#ref || createRef(this); }
347
352
  /**
348
- * @param {Schema.Field} schema
349
- * @param {object} [options]
353
+ * @param {Schema.Field} schema 字段的 Schema 定义
354
+ * @param {object} [options] 可选配置
350
355
  * @param {*} [options.parent]
351
356
  * @param {*} [options.state]
352
357
  * @param {number | string | null} [options.index]
@@ -510,19 +515,28 @@ class Store {
510
515
  #meta;
511
516
  /** @readonly @type {any} */
512
517
  #component;
518
+ /** 存储对象自身 */
513
519
  get store() { return this; }
520
+ /** 父级存储对象 */
514
521
  get parent() { return this.#parent; }
522
+ /** 根节点的存储对象 */
515
523
  get root() { return this.#root; }
524
+ /** 字段类型 */
516
525
  get type() { return this.#type; }
526
+ /** 字段元信息 */
517
527
  get meta() { return this.#meta; }
528
+ /** 自定义渲染组件信息 */
518
529
  get component() { return this.#component; }
519
530
 
520
531
  /** @type {Signal.State<number> | Signal.Computed<number>} */
521
532
  #length;
533
+ /** 长度信息 */
522
534
  get length() { return this.#length.get(); }
523
535
  #index = new Signal.State(/** @type {string | number} */(''));
536
+ /** 索引信息 */
524
537
  get index() { return this.#index.get(); }
525
538
  set index(v) { this.#index.set(v); }
539
+ /** 数组项目的序号 */
526
540
  get no() {
527
541
  if (this.#null) { return ''; }
528
542
  const index = this.index;
@@ -530,8 +544,10 @@ class Store {
530
544
  }
531
545
 
532
546
  #creatable = true;
547
+ /** 值是否可创建(`$new` 为 `true` 时,字段只读) */
533
548
  get creatable() { return this.#creatable; }
534
549
  #immutable = false;
550
+ /** 值是否不可改变(`$new` 为 `false` 时,字段只读) */
535
551
  get immutable() { return this.#immutable; }
536
552
 
537
553
  /** @readonly @type {Signal.Computed<boolean>} */
@@ -540,6 +556,7 @@ class Store {
540
556
  #selfNew
541
557
  get selfNew() { return this.#selfNew.get(); }
542
558
  set selfNew(v) { this.#selfNew.set(Boolean(v)); }
559
+ /** 是否新建项 */
543
560
  get new() { return this.#new.get(); }
544
561
  set new(v) { this.#selfNew.set(Boolean(v)); }
545
562
 
@@ -549,6 +566,7 @@ class Store {
549
566
  #hidden
550
567
  get selfHidden() { return this.#selfHidden.get(); }
551
568
  set selfHidden(v) { this.#selfHidden.set(typeof v === 'boolean' ? v : null); }
569
+ /** 是否可隐藏 */
552
570
  get hidden() { return this.#hidden.get(); }
553
571
  set hidden(v) { this.#selfHidden.set(typeof v === 'boolean' ? v : null); }
554
572
 
@@ -558,6 +576,7 @@ class Store {
558
576
  #clearable
559
577
  get selfClearable() { return this.#selfClearable.get(); }
560
578
  set selfClearable(v) { this.#selfClearable.set(typeof v === 'boolean' ? v : null); }
579
+ /** 是否可清除 */
561
580
  get clearable() { return this.#clearable.get(); }
562
581
  set clearable(v) { this.#selfClearable.set(typeof v === 'boolean' ? v : null); }
563
582
 
@@ -567,6 +586,7 @@ class Store {
567
586
  #required
568
587
  get selfRequired() { return this.#selfRequired.get(); }
569
588
  set selfRequired(v) { this.#selfRequired.set(typeof v === 'boolean' ? v : null); }
589
+ /** 是否必填 */
570
590
  get required() { return this.#required.get(); }
571
591
  set required(v) { this.#selfRequired.set(typeof v === 'boolean' ? v : null); }
572
592
 
@@ -576,6 +596,7 @@ class Store {
576
596
  #disabled
577
597
  get selfDisabled() { return this.#selfDisabled.get(); }
578
598
  set selfDisabled(v) { this.#selfDisabled.set(typeof v === 'boolean' ? v : null); }
599
+ /** 是否禁用字段 */
579
600
  get disabled() { return this.#disabled.get(); }
580
601
  set disabled(v) { this.#selfDisabled.set(typeof v === 'boolean' ? v : null); }
581
602
 
@@ -585,6 +606,7 @@ class Store {
585
606
  #readonly
586
607
  get selfReadonly() { return this.#selfReadonly.get(); }
587
608
  set selfReadonly(v) { this.#selfReadonly.set(typeof v === 'boolean' ? v : null); }
609
+ /** 是否只读 */
588
610
  get readonly() { return this.#readonly.get(); }
589
611
  set readonly(v) { this.#selfReadonly.set(typeof v === 'boolean' ? v : null); }
590
612
 
@@ -597,6 +619,7 @@ class Store {
597
619
  #label
598
620
  get selfLabel() { return this.#selfLabel.get(); }
599
621
  set selfLabel(v) { this.#selfLabel.set(string(v)); }
622
+ /** 字段的标签信息 */
600
623
  get label() { return this.#label.get(); }
601
624
  set label(v) { this.#selfLabel.set(string(v)); }
602
625
 
@@ -607,6 +630,7 @@ class Store {
607
630
  #description
608
631
  get selfDescription() { return this.#selfDescription.get(); }
609
632
  set selfDescription(v) { this.#selfDescription.set(string(v)); }
633
+ /** 字段的描述信息 */
610
634
  get description() { return this.#description.get(); }
611
635
  set description(v) { this.#selfDescription.set(string(v)); }
612
636
 
@@ -616,6 +640,7 @@ class Store {
616
640
  #placeholder
617
641
  get selfPlaceholder() { return this.#selfPlaceholder.get(); }
618
642
  set selfPlaceholder(v) { this.#selfPlaceholder.set(string(v)); }
643
+ /** 字段的占位符信息 */
619
644
  get placeholder() { return this.#placeholder.get(); }
620
645
  set placeholder(v) { this.#selfPlaceholder.set(string(v)); }
621
646
 
@@ -626,6 +651,7 @@ class Store {
626
651
  #min
627
652
  get selfMin() { return this.#selfMin.get(); }
628
653
  set selfMin(v) { this.#selfMin.set(number(v)); }
654
+ /** 数值字段的最小值限制 */
629
655
  get min() { return this.#min.get(); }
630
656
  set min(v) { this.#selfMin.set(number(v)); }
631
657
 
@@ -636,6 +662,7 @@ class Store {
636
662
  #max
637
663
  get selfMax() { return this.#selfMax.get(); }
638
664
  set selfMax(v) { this.#selfMax.set(number(v)); }
665
+ /** 数值字段的最大值限制 */
639
666
  get max() { return this.#max.get(); }
640
667
  set max(v) { this.#selfMax.set(number(v)); }
641
668
 
@@ -646,6 +673,7 @@ class Store {
646
673
  #step
647
674
  get selfStep() { return this.#selfStep.get(); }
648
675
  set selfStep(v) { this.#selfStep.set(number(v)); }
676
+ /** 数值字段的步长 */
649
677
  get step() { return this.#step.get(); }
650
678
  set step(v) { this.#selfStep.set(number(v)); }
651
679
 
@@ -655,6 +683,7 @@ class Store {
655
683
  #minLength
656
684
  get selfMinLength() { return this.#selfMinLength.get(); }
657
685
  set selfMinLength(v) { this.#selfMinLength.set(number(v)); }
686
+ /** 最小长度 */
658
687
  get minLength() { return this.#minLength.get(); }
659
688
  set minLength(v) { this.#selfMinLength.set(number(v)); }
660
689
 
@@ -664,6 +693,7 @@ class Store {
664
693
  #maxLength
665
694
  get selfMaxLength() { return this.#selfMaxLength.get(); }
666
695
  set selfMaxLength(v) { this.#selfMaxLength.set(number(v)); }
696
+ /** 最大长度 */
667
697
  get maxLength() { return this.#maxLength.get(); }
668
698
  set maxLength(v) { this.#selfMaxLength.set(number(v)); }
669
699
 
@@ -673,6 +703,7 @@ class Store {
673
703
  #pattern
674
704
  get selfPattern() { return this.#selfPattern.get(); }
675
705
  set selfPattern(v) { this.#selfPattern.set(regex(v)); }
706
+ /** 模式 */
676
707
  get pattern() { return this.#pattern.get(); }
677
708
  set pattern(v) { this.#selfPattern.set(regex(v)); }
678
709
 
@@ -683,6 +714,7 @@ class Store {
683
714
  #values
684
715
  get selfValues() { return this.#selfValues.get(); }
685
716
  set selfValues(v) { this.#selfValues.set(values$1(v)); }
717
+ /** 可选值列表 */
686
718
  get values() { return this.#values.get(); }
687
719
  set values(v) { this.#selfValues.set(values$1(v)); }
688
720
 
@@ -699,13 +731,15 @@ class Store {
699
731
  #cancelChange
700
732
  /** @type {() => void} */
701
733
  #cancelBlur
734
+ /** 所有校验错误列表 */
702
735
  get errors() { return this.#errors.get(); }
736
+ /** 字段校验错误信息 */
703
737
  get error() { return this.#errors.get()[0]; }
704
738
 
705
739
  /** @returns {IterableIterator<[key: string | number, value: Store]>} */
706
740
  *[Symbol.iterator]() {}
707
741
  /**
708
- *
742
+ * 获取子存储
709
743
  * @param {string | number} key
710
744
  * @returns {Store?}
711
745
  */
@@ -718,8 +752,10 @@ class Store {
718
752
 
719
753
  #state = new Signal.State(/** @type {any} */(null));
720
754
 
755
+ /** 内容是否已改变 */
721
756
  get changed() { return this.#value.get() === this.#initValue.get(); }
722
757
 
758
+ /** 字段当前值 */
723
759
  get value() { return this.#value.get(); }
724
760
  set value(v) {
725
761
  const newValue = this.#setValue?.(v);
@@ -732,6 +768,7 @@ class Store {
732
768
  this.#requestUpdate();
733
769
  }
734
770
 
771
+ /** 字段状态 */
735
772
  get state() { return this.#state.get(); }
736
773
  set state(v) {
737
774
  const newState = this.#setState?.(v);
@@ -749,6 +786,7 @@ class Store {
749
786
  this.#runUpdate(oldValue, oldState);
750
787
  });
751
788
  }
789
+ /** 重置数据 */
752
790
  reset(value = this.#initValue.get()) {
753
791
  this.#reset(value);
754
792
  }
@@ -841,18 +879,19 @@ class Store {
841
879
  return [val, sta];
842
880
  }
843
881
  /**
844
- *
882
+ * 异步校验
845
883
  * @overload
846
884
  * @param {null} [path]
847
885
  * @returns {Promise<string[] | null>}
848
886
  */
849
887
  /**
888
+ * 异步校验
850
889
  * @overload
851
- * @param {(string | number)[]} path
890
+ * @param {(string | number)[]} path 到当前层级的路径
852
891
  * @returns {Promise<{ path: (string | number)[]; store: Store; errors: string[]}[]>}
853
892
  */
854
893
  /**
855
- *
894
+ * 异步校验
856
895
  * @param {(string | number)[]?} [path]
857
896
  * @returns {Promise<string[] | { path: (string | number)[]; store: Store; errors: string[] | null;}[] | null>}
858
897
  */
@@ -1280,9 +1319,11 @@ function parse$1(value, createCalc) {
1280
1319
  /**
1281
1320
  * @param {Layout.Node} node
1282
1321
  * @param {Exclude<Layout.Options['createCalc'], undefined>} createCalc
1322
+ * @param {Exclude<Layout.Options['createInit'], undefined>} createInit
1283
1323
  * @param {Exclude<Layout.Options['createEvent'], undefined>} createEvent
1324
+ * @param {boolean} enableHTML
1284
1325
  */
1285
- function createAttributeAdder(node, createCalc, createEvent) {
1326
+ function createAttributeAdder(node, createCalc, createInit, createEvent, enableHTML) {
1286
1327
  const { attrs, events, classes, styles, vars, aliases, params, enhancements } = node;
1287
1328
  /**
1288
1329
  * @param {string} qName
@@ -1338,7 +1379,7 @@ function createAttributeAdder(node, createCalc, createEvent) {
1338
1379
  return;
1339
1380
  }
1340
1381
  if (decorator === '+') {
1341
- vars[name] = !value ? {value: undefined} : parse$1(value, createCalc);
1382
+ vars[name] = !value ? {value: undefined} : parse$1(value, createInit);
1342
1383
  return;
1343
1384
  }
1344
1385
  if (decorator === '*') {
@@ -1366,7 +1407,7 @@ function createAttributeAdder(node, createCalc, createEvent) {
1366
1407
  node.text = parse$1(value, createCalc);
1367
1408
  break;
1368
1409
  case 'html':
1369
- node.html = parse$1(value, createCalc);
1410
+ if (enableHTML) { node.html = parse$1(value, createCalc); }
1370
1411
  break;
1371
1412
  case 'template': node.template = value; break;
1372
1413
  case 'bind': node.bind = value || true; break;
@@ -1710,15 +1751,17 @@ function entityReplacer(a) {
1710
1751
  return a;
1711
1752
  }
1712
1753
  /**
1713
- *
1714
- * @param {string} source
1715
- * @param {Layout.Options} [options]
1754
+ * 解析模板内容
1755
+ * @param {string} source 输入源字符串
1756
+ * @param {Layout.Options} [options] 解析选项
1716
1757
  * @returns {(Layout.Node | string)[]}
1717
1758
  */
1718
1759
  function parse(source, {
1719
1760
  createCalc = () => { throw new ParseError('CALC'); },
1761
+ createInit = createCalc,
1720
1762
  createEvent = () => { throw new ParseError('EVENT'); },
1721
1763
  simpleTag = new Set,
1764
+ enableHTML = false,
1722
1765
  } = {}) {
1723
1766
  /** @type {(Layout.Node | string)[]} */
1724
1767
  const children = [];
@@ -1769,7 +1812,20 @@ function parse(source, {
1769
1812
  if (tagStart > index) {
1770
1813
  appendText(tagStart);
1771
1814
  }
1772
- if (source.charAt(tagStart + 1) === '/') {
1815
+ const nextChar = source.charAt(tagStart + 1);
1816
+ if (nextChar === '!') {
1817
+ let begin = tagStart + 2;
1818
+ let sign = '>';
1819
+ if (source.slice(tagStart + 2, tagStart + 4) === '--') {
1820
+ begin += 4;
1821
+ sign = '-->';
1822
+ }
1823
+ index = source.indexOf(sign, begin);
1824
+ if (index < 0) { break; }
1825
+ index++;
1826
+ continue;
1827
+ }
1828
+ if (nextChar === '/') {
1773
1829
  index = source.indexOf('>', tagStart + 3);
1774
1830
  let name = source.substring(tagStart + 2, index);
1775
1831
  if (index < 0) {
@@ -1837,7 +1893,7 @@ function parse(source, {
1837
1893
  currentNode = createElement(tagRes.name, tagRes.is);
1838
1894
  current.children.push(currentNode);
1839
1895
  current = currentNode;
1840
- const addAttribute = createAttributeAdder(currentNode, createCalc, createEvent);
1896
+ const addAttribute = createAttributeAdder(currentNode, createCalc, createInit, createEvent, enableHTML);
1841
1897
 
1842
1898
  let run = true;
1843
1899
  let closed = false;
@@ -2041,12 +2097,12 @@ function* listToString(nodes, level = 0) {
2041
2097
  }
2042
2098
  }
2043
2099
  /**
2044
- *
2045
- * @param {Layout.Node | (Layout.Node |string)[]} value
2046
- * @param {boolean} [formable]
2100
+ * 将模板转为字符串
2101
+ * @param {Layout.Node | (Layout.Node |string)[]} value 要转换的节点或节点数组
2102
+ * @param {boolean} [formable] 是否对代码进行格式化
2047
2103
  * @returns {string}
2048
2104
  */
2049
- function toString(value, formable) {
2105
+ function stringify(value, formable) {
2050
2106
  const level = formable ? 0 : -1;
2051
2107
  if (Array.isArray(value)) { return [...listToString(value, level)].join(''); }
2052
2108
  return [nodeToString(value, level)].join();
@@ -2054,95 +2110,90 @@ function toString(value, formable) {
2054
2110
  }
2055
2111
 
2056
2112
  /**
2057
- * @typedef {object} Directives
2058
- *
2059
- */
2060
-
2061
-
2062
-
2063
- /**
2064
- * @typedef {object} Enhancement
2065
- * @property {Record<string, Node.Name | Node.Event>} events
2066
- * @property {Record<string, Node.Name | Node.Calc | Node.Value>} attrs
2067
- * @property {Node.Name | Node.Calc | Node.Value} [value]
2068
- * @property {boolean | string} [bind]
2113
+ * @typedef {object} Enhancement 增强信息
2114
+ * @property {Record<string, Node.Name | Node.Event>} events 事件
2115
+ * @property {Record<string, Node.Name | Node.Calc | Node.Value>} attrs 属性
2116
+ * @property {Node.Name | Node.Calc | Node.Value} [value] 主值
2117
+ * @property {boolean | string} [bind] 绑定信息
2069
2118
  */
2070
2119
 
2071
2120
  /**
2072
- * @typedef {object} Options
2073
- * @property {(t: string) => Calc} [options.createCalc]
2074
- * @property {(t: string) => EventListener} [options.createEvent]
2075
- * @property {Set<string>} [options.simpleTag]
2121
+ * @typedef {object} Options 解析选项
2122
+ * @property {boolean} [enableHTML] 启用 `!html` 指令
2123
+ * @property {(t: string) => Calc} [createCalc] 创建计算属性的工厂函数
2124
+ * @property {(t: string) => Calc} [createInit] 创建变量初始化的工厂函数
2125
+ * @property {(t: string) => EventListener} [createEvent] 创建事件监听器的工厂函数
2126
+ * @property {Set<string>} [simpleTag] 简单标签的集合
2076
2127
  */
2077
2128
  /**
2078
2129
  * @template [T=any]
2079
- * @typedef {{value: T; name?: undefined; calc?: undefined; event?: undefined}} Node.Value
2130
+ * @typedef {{value: T; name?: undefined; calc?: undefined; event?: undefined}} Node.Value 基础值
2080
2131
  */
2081
2132
  /**
2082
- * @typedef {{name: string; value?: undefined; calc?: undefined; event?: undefined}} Node.Name
2133
+ * @typedef {{name: string; value?: undefined; calc?: undefined; event?: undefined}} Node.Name 名称
2083
2134
  */
2084
2135
  /**
2085
- * @typedef {{event: EventListener; name?: undefined; calc?: undefined; value?: undefined}} Node.Event
2136
+ * @typedef {{event: EventListener; name?: undefined; calc?: undefined; value?: undefined}} Node.Event 事件
2086
2137
  */
2087
2138
  /**
2088
- * @typedef {{calc: Calc; name?: undefined; value?: undefined; event?: undefined}} Node.Calc
2139
+ * @typedef {{calc: Calc; name?: undefined; value?: undefined; event?: undefined}} Node.Calc 计算
2089
2140
  */
2090
2141
  /**
2091
- * @typedef {object} Node
2092
- * @property {string} name
2142
+ * @typedef {object} Node 布局节点
2143
+ * @property {string} name 标签名
2093
2144
  * @property {string?} [is]
2094
2145
  * @property {string} [id]
2095
- * @property {Record<string, Node.Name | Node.Calc | Node.Value>} attrs
2096
- * @property {Record<string, Node.Name | Node.Calc | Node.Value>} params
2097
- * @property {Record<string, Node.Name | Node.Calc | Node.Value>} classes
2098
- * @property {Record<string, Node.Name | Node.Calc | Node.Value>} styles
2099
- * @property {Record<string, Node.Name | Node.Event>} events
2100
- * @property {Record<string, Node.Name | Node.Calc | Node.Value>} vars
2101
- * @property {Record<string, Node.Name | Node.Calc | Node.Value>} aliases
2102
- * @property {Record<string, Enhancement>} enhancements
2146
+ * @property {Record<string, Node.Name | Node.Calc | Node.Value>} attrs 属性
2147
+ * @property {Record<string, Node.Name | Node.Calc | Node.Value>} params 模板参数定义
2148
+ * @property {Record<string, Node.Name | Node.Calc | Node.Value>} classes 类名
2149
+ * @property {Record<string, Node.Name | Node.Calc | Node.Value>} styles 样式
2150
+ * @property {Record<string, Node.Name | Node.Event>} events 事件
2151
+ * @property {Record<string, Node.Name | Node.Calc | Node.Value>} vars 局部变量
2152
+ * @property {Record<string, Node.Name | Node.Calc | Node.Value>} aliases 别名/计算名
2153
+ * @property {Record<string, Enhancement>} enhancements 增强
2103
2154
  *
2104
- * @property {string} [template]
2105
- * @property {boolean | string} [fragment]
2155
+ * @property {string} [template] 模板定义的名称
2156
+ * @property {boolean | string} [fragment] 是否为片段或模板调用
2106
2157
  *
2107
- * @property {Node.Name | Node.Calc | Node.Value} [if]
2108
- * @property {boolean} [else]
2158
+ * @property {Node.Name | Node.Calc | Node.Value} [if] 分歧条件
2159
+ * @property {boolean} [else] 否定
2109
2160
  *
2110
2161
  * @property {string} [value] 值关联
2111
2162
  * @property {Node.Name | Node.Calc | Node.Value} [enum] 列表属性枚举
2112
2163
  *
2113
- * @property {boolean | string} [bind]
2114
- * @property {Node.Name | Node.Value | Node.Calc} [text]
2115
- * @property {Node.Name | Node.Value | Node.Calc} [html]
2164
+ * @property {boolean | string} [bind] 绑定内容
2165
+ * @property {Node.Name | Node.Value | Node.Calc} [text] 文本渲染
2166
+ * @property {Node.Name | Node.Value | Node.Calc} [html] HTML 渲染
2116
2167
  *
2117
2168
  * @property {string} [comment] 注释
2118
2169
  *
2119
- * @property {(Node | string)[]} children
2170
+ * @property {(Node | string)[]} children 子元素
2120
2171
  */
2121
2172
 
2122
2173
  /**
2123
- * @callback Calc
2124
- * @param {Record<string, any>} env
2174
+ * @callback Calc 计算函数
2175
+ * @param {Record<string, any>} env 上下文环境
2125
2176
  * @returns {any}
2126
2177
  */
2127
2178
 
2128
2179
 
2129
2180
  /**
2130
- * @callback EventListener
2131
- * @param {*} $event
2132
- * @param {Record<string, any>} env
2181
+ * @callback EventListener 事件监听器
2182
+ * @param {*} $event 事件
2183
+ * @param {Record<string, any>} env 上下文环境
2133
2184
  * @returns {void}
2134
2185
  */
2135
2186
 
2136
2187
  var index$1 = /*#__PURE__*/Object.freeze({
2137
2188
  __proto__: null,
2138
2189
  parse: parse,
2139
- stringify: toString
2190
+ stringify: stringify
2140
2191
  });
2141
2192
 
2142
2193
  /**
2143
- *
2144
- * @param {() => void} fn
2145
- * @returns {() => void}
2194
+ * 相应式执行
2195
+ * @param {() => void} fn 执行函数
2196
+ * @returns {() => void} 取消函数
2146
2197
  */
2147
2198
  function effect(fn) {
2148
2199
  let needsEnqueue = true;
@@ -2170,7 +2221,7 @@ function effect(fn) {
2170
2221
  * @template T
2171
2222
  * @param {() => T} getter 取值方法
2172
2223
  * @param {(value: T) => void} callback 取值方法
2173
- * @param {boolean} immediate
2224
+ * @param {boolean} immediate 是否立即执行一次
2174
2225
  * @returns {() => void}
2175
2226
  */
2176
2227
  function watch(getter, callback, immediate) {
@@ -2917,11 +2968,12 @@ class Environment {
2917
2968
  }
2918
2969
 
2919
2970
  /** @import { Component } from '../types.mjs' */
2971
+ /** @import { ComponentHandler } from './types.mjs' */
2920
2972
  /** @import * as Layout from '../Layout/index.mjs' */
2921
2973
 
2922
2974
 
2923
2975
  /**
2924
- * @param {Component.Handler} handler
2976
+ * @param {ComponentHandler} handler
2925
2977
  * @param {Environment} envs
2926
2978
  * @param {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value>} attrs
2927
2979
  * @param {Record<string, Component.Attr>} componentAttrs
@@ -2990,12 +3042,12 @@ function bindAttrs(handler, envs, attrs, componentAttrs, bindValue) {
2990
3042
  }
2991
3043
  }
2992
3044
 
2993
- /** @import { Component } from '../types.mjs' */
3045
+ /** @import { ComponentHandler } from './types.mjs' */
2994
3046
  /** @import * as Layout from '../Layout/index.mjs' */
2995
3047
 
2996
3048
 
2997
3049
  /**
2998
- * @param {Component.Handler} handler
3050
+ * @param {ComponentHandler} handler
2999
3051
  * @param {Environment} envs
3000
3052
  * @param {Record<string, Layout.Node.Name | Layout.Node.Calc | Layout.Node.Value>} attrs
3001
3053
  */
@@ -3146,7 +3198,12 @@ function bindStyles(node, envs, styles, styleAttr) {
3146
3198
  return () => {};
3147
3199
  }
3148
3200
  if (styleAttr) {
3149
- node.setAttribute('style', node.getAttribute('style') + ';' + envs.exec(styleAttr));
3201
+ const oldStyle = node.getAttribute('style') || '';
3202
+ const newStyle = envs.exec(styleAttr) || '';
3203
+ const style = [oldStyle,newStyle].filter(Boolean).join(';');
3204
+ if (style) {
3205
+ node.setAttribute('style', style);
3206
+ }
3150
3207
  }
3151
3208
 
3152
3209
  /** @type {Set<() => void>?} */
@@ -3385,6 +3442,7 @@ function bindFilters(env, fn, filterFns) {
3385
3442
  }
3386
3443
 
3387
3444
  /** @import { Component, Relatedness } from '../types.mjs' */
3445
+ /** @import { ComponentHandler } from './types.mjs' */
3388
3446
  /** @import Store from '../Store/index.mjs' */
3389
3447
  /** @import Environment from './Environment/index.mjs' */
3390
3448
 
@@ -3419,8 +3477,8 @@ function createContext(component, env, store, relate) {
3419
3477
  const context = {
3420
3478
  events: allEvents,
3421
3479
  props: attrs ? new Set(Object.entries(attrs).filter(([, a]) => a.isProp).map(([e]) => e)) : null,
3422
- tagAttrs,
3423
- watchAttr(name, fn) {
3480
+ attrs: tagAttrs,
3481
+ watch(name, fn) {
3424
3482
  if (destroyed) { return () => { }; }
3425
3483
  const state = attrStates[name];
3426
3484
  if (!state) { return () => { }; }
@@ -3456,7 +3514,7 @@ function createContext(component, env, store, relate) {
3456
3514
  get init() { return mountedState.get(); },
3457
3515
  listen(name, listener) { return stateEmitter.listen(name, listener); },
3458
3516
  };
3459
- /** @type {Component.Handler} */
3517
+ /** @type {ComponentHandler} */
3460
3518
  const handler = {
3461
3519
  tag,
3462
3520
  set(name, value) {
@@ -3671,7 +3729,7 @@ const tagBindMap = {
3671
3729
  */
3672
3730
  function createTagComponent (context, name, is) {
3673
3731
  const node = document.createElement(name, {is: is || undefined});
3674
- const { watchAttr, props } = context;
3732
+ const { watch, props } = context;
3675
3733
  if(['input', 'textarea', 'select'].includes(name.toLowerCase())) {
3676
3734
  context.relate(node);
3677
3735
  }
@@ -3692,8 +3750,8 @@ function createTagComponent (context, name, is) {
3692
3750
  node.addEventListener(type, listener, options);
3693
3751
  }
3694
3752
  if (props) {
3695
- for (const [name, attr] of Object.entries(context.tagAttrs)) {
3696
- watchAttr(name, v => {
3753
+ for (const [name, attr] of Object.entries(context.attrs)) {
3754
+ watch(name, v => {
3697
3755
  // @ts-ignore
3698
3756
  if (props.has(name)) { node[name] = v; } else {
3699
3757
  const val = toAttrValue(v);
@@ -3715,7 +3773,7 @@ function createTagComponent (context, name, is) {
3715
3773
  return;
3716
3774
 
3717
3775
  }
3718
- for (const [name, attr] of Object.entries(context.tagAttrs)) {
3776
+ for (const [name, attr] of Object.entries(context.attrs)) {
3719
3777
  if (node instanceof HTMLInputElement && name.toLocaleLowerCase() === 'type') {
3720
3778
  const value = toAttrValue(attr);
3721
3779
  if (value !== null) {
@@ -3725,7 +3783,7 @@ function createTagComponent (context, name, is) {
3725
3783
  }
3726
3784
  if (name === '$hidden') {
3727
3785
  if (attr) { node.hidden = attr; }
3728
- watchAttr(name, (val) => { node.hidden = val; });
3786
+ watch(name, (val) => { node.hidden = val; });
3729
3787
  continue;
3730
3788
  }
3731
3789
 
@@ -3733,7 +3791,7 @@ function createTagComponent (context, name, is) {
3733
3791
  const e = eAttrs[name];
3734
3792
  if (e) {
3735
3793
  e(attr, node);
3736
- watchAttr(name, (attr) => e(attr, node));
3794
+ watch(name, (attr) => e(attr, node));
3737
3795
  }
3738
3796
  continue;
3739
3797
  }
@@ -3741,7 +3799,7 @@ function createTagComponent (context, name, is) {
3741
3799
  if (typeof prop === 'function') {
3742
3800
  // @ts-ignore
3743
3801
  node[name] = prop(attr);
3744
- watchAttr(name, (attr) => {
3802
+ watch(name, (attr) => {
3745
3803
  // @ts-ignore
3746
3804
  node[name] = prop(attr);
3747
3805
  });
@@ -3750,7 +3808,7 @@ function createTagComponent (context, name, is) {
3750
3808
  if (prop) {
3751
3809
  // @ts-ignore
3752
3810
  node[name] = attr;
3753
- watchAttr(name, (attr) => {
3811
+ watch(name, (attr) => {
3754
3812
  // @ts-ignore
3755
3813
  node[name] = attr;
3756
3814
  });
@@ -3760,7 +3818,7 @@ function createTagComponent (context, name, is) {
3760
3818
  if (value !== null) {
3761
3819
  node.setAttribute(name, value);
3762
3820
  }
3763
- watchAttr(name, (val) => {
3821
+ watch(name, (val) => {
3764
3822
  const value = toAttrValue(val);
3765
3823
  if (value === null) {
3766
3824
  node.removeAttribute(name);
@@ -4105,11 +4163,11 @@ function renderEnum(parent, next, getter, env, renderItem) {
4105
4163
  };
4106
4164
  }
4107
4165
 
4108
- /** @import { Component } from '../types.mjs' */
4166
+ /** @import { ComponentHandler } from './types.mjs' */
4109
4167
 
4110
4168
 
4111
4169
  /**
4112
- * @param {Component.Handler} handler
4170
+ * @param {ComponentHandler} handler
4113
4171
  * @param {Environment} env
4114
4172
  * @param {string | boolean | null} [bind]
4115
4173
  */
@@ -4225,7 +4283,7 @@ function bindEnhancements(tag, enhancementDefine, env, enhancements, root, slot)
4225
4283
  get value() { return null; },
4226
4284
  events: allEvents,
4227
4285
  attrs: attrs,
4228
- watchAttr(name, fn) {
4286
+ watch(name, fn) {
4229
4287
  if (destroyed) { return () => { }; }
4230
4288
  let old = attrs[name];
4231
4289
  const w = watch(() => attrs[name], v => {
@@ -4382,14 +4440,14 @@ function render(layout, parent, next, env, templates, componentPath, enhancement
4382
4440
  }
4383
4441
 
4384
4442
  /**
4385
- * @param {Store} store
4386
- * @param {(Layout.Node | string)[]} layouts
4387
- * @param {Element} parent
4388
- * @param {object} [options]
4389
- * @param {Record<string, Store | {get?(): any; set?(v: any): void; exec?(...p: any[]): any; calc?(...p: any[]): any }>} [options.global]
4390
- * @param {(path: string[]) => Component?} [options.component]
4391
- * @param {(store: Store, el: Element | Relatedness) => () => void} [options.relate]
4392
- * @param {Record<string, Enhancement>} [options.enhancements]
4443
+ * @param {Store} store 存储实例
4444
+ * @param {(Layout.Node | string)[]} layouts 布局信息
4445
+ * @param {Element} parent 渲染节点
4446
+ * @param {object} [options] 选项
4447
+ * @param {Record<string, Store | {get?(): any; set?(v: any): void; exec?(...p: any[]): any; calc?(...p: any[]): any }>} [options.global] 全局数据
4448
+ * @param {Component.Getter?} [options.component] 自定义组件
4449
+ * @param {(store: Store, el: Element | Relatedness) => () => void} [options.relate] 关联函数
4450
+ * @param {Record<string, Enhancement>} [options.enhancements] 增强信息
4393
4451
  * @returns {() => void}
4394
4452
  */
4395
4453
  function index (store, layouts, parent, {component, global, relate, enhancements} = {}) {