@neeloong/form 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @neeloong/form v0.26.0
2
+ * @neeloong/form v0.28.0
3
3
  * (c) 2024-2026 Fierflame
4
4
  * @license Apache-2.0
5
5
  */
@@ -129,9 +129,10 @@ declare namespace StoreLayout {
129
129
  relate?: ((store: Store, el: Element | StoreLayout.Relatedness) => () => void) | undefined;
130
130
  editable?: boolean | undefined;
131
131
  signal?: AbortSignal | undefined;
132
+ sanitizeHtml?: ((arg0: string) => string) | undefined;
132
133
  call?: ((name: string, event: Event, store: Store<any, any, any>, options?: StoreLayout.Options | null) => void) | undefined;
133
134
  };
134
- type Renderer<T_1 = unknown> = (store: Store<any, any, any>, renderer?: T_1, options?: StoreLayout.Options | null) => HTMLElement | null;
135
+ type Renderer<T_1 = unknown> = (store: Store<any, any, any>, renderer?: T_1 | string, options?: StoreLayout.Options | null) => HTMLElement | null;
135
136
  }
136
137
 
137
138
  type Schema<M = any, S extends {
@@ -409,6 +410,31 @@ type Ref = {
409
410
  [k: string]: Ref | undefined;
410
411
  };
411
412
 
413
+ /** @import { Schema } from '../Schema.types.mjs' */
414
+ /**
415
+ * @template [T=any]
416
+ * @template [M=any]
417
+ * @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
418
+ * @extends {Store<T, M, S>}
419
+ */
420
+ declare class BindObjectStore<T = any, M = any, S extends {
421
+ [x: string]: Schema.State;
422
+ } = {
423
+ [x: string]: Schema.State;
424
+ }> extends Store<T, M, S> {
425
+ /**
426
+ * @param {Schema<any, Object.<string, Schema.State>>} schema 数据结构模式
427
+ * @param {Store<T, M, S>} store
428
+ */
429
+ constructor(schema: Schema<any, {
430
+ [x: string]: Schema.State;
431
+ }>, store: Store<T, M, S>);
432
+ [Symbol.iterator](): Generator<[string, Store<any, any, {
433
+ [x: string]: Schema.State;
434
+ }>], void, unknown>;
435
+ #private;
436
+ }
437
+
412
438
  /** @import { Ref } from './ref.mjs' */
413
439
  /** @import { Schema } from '../Schema.types.mjs' */
414
440
  /** @import { StoreLayout } from '../StoreLayout.types.mjs' */
@@ -449,7 +475,7 @@ declare class Store<T = any, M = any, S extends {
449
475
  new (...p: ConstructorParameters<typeof Store>): Store;
450
476
  }): void;
451
477
  /**
452
- * @param {Schema.Field<M, S>} schema 字段的 Schema 定义
478
+ * @param {Schema.Field<M, S> | Store<T,M,S>} schema 字段的 Schema 定义
453
479
  * @param {object} [options] 可选配置
454
480
  * @param {Store?} [options.parent]
455
481
  * @param {Partial<S>?} [options.states]
@@ -485,7 +511,7 @@ declare class Store<T = any, M = any, S extends {
485
511
  *
486
512
  * @param {((value: T?, index: any, store: Store) => void)?} [options.onUpdate]
487
513
  */
488
- constructor(schema: Schema.Field<M, S>, { null: isNull, ref, default: defaultValue, setValue, convert, onUpdate, states, validator, validators, index, size, new: isNew, parent: parentNode, hidden, clearable, required, disabled, readonly, removable, label, description, placeholder, min, max, step, minLength, maxLength, pattern, values }?: {
514
+ constructor(schema: Schema.Field<M, S> | Store<T, M, S>, { null: isNull, ref, default: defaultValue, setValue, convert, onUpdate, states, validator, validators, index, size, new: isNew, parent: parentNode, hidden, clearable, required, disabled, readonly, removable, label, description, placeholder, min, max, step, minLength, maxLength, pattern, values }?: {
489
515
  parent?: Store<any, any, {
490
516
  [x: string]: Schema.State;
491
517
  }> | null | undefined;
@@ -539,11 +565,13 @@ declare class Store<T = any, M = any, S extends {
539
565
  convert?: ((value: any) => any) | null | undefined;
540
566
  onUpdate?: ((value: T | null, index: any, store: Store) => void) | null | undefined;
541
567
  });
568
+ get schema(): Schema.Field<M, S>;
542
569
  /**
543
570
  * 触发事件并通知监听器
544
571
  * @template {keyof Schema.Events} K
545
572
  * @param {K} event
546
573
  * @param {Schema.Events[K]} value
574
+ * @returns {boolean}
547
575
  */
548
576
  emit<K extends keyof Schema.Events>(event: K, value: Schema.Events[K]): boolean;
549
577
  /**
@@ -559,7 +587,6 @@ declare class Store<T = any, M = any, S extends {
559
587
  /** 存储类类别,继承的自定义类需要设置自定义的此只读属性 */
560
588
  get kind(): string;
561
589
  get ref(): Ref;
562
- schema: Schema.Field<M, S>;
563
590
  get states(): S | null;
564
591
  get layout(): StoreLayout.Field<any>;
565
592
  /** @param {any} [value] @returns {any} */
@@ -699,17 +726,19 @@ declare class Store<T = any, M = any, S extends {
699
726
  * @template [M=any]
700
727
  * @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
701
728
  * @param {Schema<M, S>} schema 数据结构模式
729
+ * @param {AbortSignal} [signal]
730
+ * @returns {BindObjectStore}
702
731
  */
703
732
  bindObject<M_1 = any, S_1 extends {
704
733
  [x: string]: Schema.State;
705
734
  } = {
706
735
  [x: string]: Schema.State;
707
- }>(schema: Schema<M_1, S_1>): () => void;
736
+ }>(schema: Schema<M_1, S_1>, signal?: AbortSignal): BindObjectStore;
737
+ /** 内容是否已改变 */
738
+ get changed(): boolean;
708
739
  set value(v: T | null);
709
740
  /** 字段当前值 */
710
741
  get value(): T | null;
711
- /** 内容是否已改变 */
712
- get changed(): boolean;
713
742
  /** 重置数据 */
714
743
  reset(value?: unknown, isNew?: boolean): void;
715
744
  /**
package/index.full.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @neeloong/form v0.26.0
2
+ * @neeloong/form v0.28.0
3
3
  * (c) 2024-2026 Fierflame
4
4
  * @license Apache-2.0
5
5
  */
@@ -716,7 +716,7 @@
716
716
 
717
717
 
718
718
  /** @type {{new(...p: ConstructorParameters<typeof Store>): Store}?} */
719
- let ObjectStore$1 = null;
719
+ let ObjectStore$2 = null;
720
720
  /** @type {{new(...p: ConstructorParameters<typeof Store>): ArrayStore}?} */
721
721
  let ArrayStoreClass = null;
722
722
  /** @type {Record<string, {new(...p: ConstructorParameters<typeof Store>): Store}?>} */
@@ -741,14 +741,14 @@
741
741
  const C = TypeStores[type];
742
742
  if (C) { Class = C; }
743
743
  } else if (type && typeof type === 'object') {
744
- if (ObjectStore$1) { Class = ObjectStore$1; }
744
+ if (ObjectStore$2) { Class = ObjectStore$2; }
745
745
  }
746
746
  return new Class(schema, options);
747
747
  }
748
748
 
749
749
  /** @param {{new(...p: ConstructorParameters<typeof Store>): Store}} Class */
750
750
  function setObjectStore(Class) {
751
- ObjectStore$1 = Class;
751
+ ObjectStore$2 = Class;
752
752
  }
753
753
 
754
754
  /** @param {{new(...p: ConstructorParameters<typeof Store>): ArrayStore}} Class */
@@ -870,6 +870,52 @@
870
870
  return (value) => structuredClone(def(store, value));
871
871
  }
872
872
 
873
+ /** @import { Schema } from '../Schema.types.mjs' */
874
+
875
+ /**
876
+ * @template [T=any]
877
+ * @template [M=any]
878
+ * @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
879
+ * @extends {Store<T, M, S>}
880
+ */
881
+ class BindObjectStore extends Store {
882
+
883
+ get kind() { return 'object'; }
884
+ /** @type {Record<string, Store>} */
885
+ #children = Object.create(null);
886
+ *[Symbol.iterator]() { yield* Object.entries(this.#children); }
887
+ /**
888
+ *
889
+ * @param {string | number} key
890
+ * @returns {Store?}
891
+ */
892
+ child(key) { return this.#children[key] || null; }
893
+ /**
894
+ * @param {Schema<any, Object.<string, Schema.State>>} schema 数据结构模式
895
+ * @param {Store<T, M, S>} store
896
+ */
897
+ constructor(schema, store) {
898
+ super(store);
899
+ const children = this.#children;
900
+ for (const [index, field] of Object.entries(schema)) {
901
+ const bindStore = create(field, {
902
+ index, parent: this,
903
+ /** @param {*} value @param {*} index @param {Store} store */
904
+ onUpdate: (value, index, store) => {
905
+ if (store !== children[index]) { return; }
906
+ const val = this.value ?? null;
907
+ if (typeof val !== 'object' || Array.isArray(val)) { return; }
908
+ // @ts-ignore
909
+ this.value = { ...val, [index]: value };
910
+ },
911
+ });
912
+ children[index] = bindStore;
913
+ }
914
+ }
915
+ }
916
+ // @ts-ignore
917
+ setObjectStore(ObjectStore);
918
+
873
919
  /** @import { Ref } from './ref.mjs' */
874
920
  /** @import { Schema } from '../Schema.types.mjs' */
875
921
  /** @import { StoreLayout } from '../StoreLayout.types.mjs' */
@@ -881,6 +927,12 @@
881
927
  * @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
882
928
  */
883
929
  class Store {
930
+ /** @type {Store<T, M, S>?} */
931
+ #originStore = null;
932
+
933
+ /** @type {Schema.Field<M, S>} 字段的 Schema 定义 */
934
+ #schema;
935
+ get schema() { return this.#schema; }
884
936
  /** @type {Map<string, Set<(value: any, store: any) => void | boolean | null>>} */
885
937
  #events = new Map();
886
938
  /**
@@ -888,8 +940,11 @@
888
940
  * @template {keyof Schema.Events} K
889
941
  * @param {K} event
890
942
  * @param {Schema.Events[K]} value
943
+ * @returns {boolean}
891
944
  */
892
945
  emit(event, value) {
946
+ const originStore = this.#originStore;
947
+ if (originStore) { return originStore.emit(event, value); }
893
948
  const key = typeof event === 'number' ? String(event) : event;
894
949
  const events = this.#events;
895
950
  let canceled = false;
@@ -906,6 +961,8 @@
906
961
  * @returns {() => void}
907
962
  */
908
963
  listen(event, listener) {
964
+ const originStore = this.#originStore;
965
+ if (originStore) { return originStore.listen(event, p => listener.call(this, p, this)); }
909
966
  const fn = listener.bind(this);
910
967
  const events = this.#events;
911
968
  const key = typeof event === 'number' ? String(event) : event;
@@ -946,7 +1003,7 @@
946
1003
  #ref = null;
947
1004
  get ref() { return this.#ref || createRef(this); }
948
1005
  /**
949
- * @param {Schema.Field<M, S>} schema 字段的 Schema 定义
1006
+ * @param {Schema.Field<M, S> | Store<T,M,S>} schema 字段的 Schema 定义
950
1007
  * @param {object} [options] 可选配置
951
1008
  * @param {Store?} [options.parent]
952
1009
  * @param {Partial<S>?} [options.states]
@@ -990,7 +1047,74 @@
990
1047
  hidden, clearable, required, disabled, readonly, removable,
991
1048
  label, description, placeholder, min, max, step, minLength, maxLength, pattern, values: values$1
992
1049
  } = {}) {
993
- this.schema = schema;
1050
+ if (schema instanceof Store) {
1051
+ this.#originStore = schema;
1052
+ this.#schema = schema.#schema;
1053
+ this.#null = schema.#null;
1054
+ this.#ref = schema.#ref;
1055
+ this.#states = schema.#states;
1056
+ this.#layout = schema.#layout;
1057
+ this.#createDefault = schema.#createDefault;
1058
+ this.#setValue = schema.#setValue;
1059
+ this.#convert = schema.#convert;
1060
+ this.#onUpdate = schema.#onUpdate;
1061
+ this.#parent = schema.#parent;
1062
+ this.#root = schema.#root;
1063
+ this.#type = schema.#type;
1064
+ this.#meta = schema.#meta;
1065
+ this.#component = schema.#component;
1066
+ this.#selfLoading = schema.#selfLoading;
1067
+ this.#loading = schema.#loading;
1068
+ this.#size = schema.#size;
1069
+ this.#index = schema.#index;
1070
+ this.#creatable = schema.#creatable;
1071
+ this.#immutable = schema.#immutable;
1072
+ this.#new = schema.#new;
1073
+ this.#selfNew = schema.#selfNew;
1074
+ this.#selfHidden = schema.#selfHidden;
1075
+ this.#hidden = schema.#hidden;
1076
+ this.#selfClearable = schema.#selfClearable;
1077
+ this.#clearable = schema.#clearable;
1078
+ this.#selfRequired = schema.#selfRequired;
1079
+ this.#required = schema.#required;
1080
+ this.#selfDisabled = schema.#selfDisabled;
1081
+ this.#disabled = schema.#disabled;
1082
+ this.#selfReadonly = schema.#selfReadonly;
1083
+ this.#readonly = schema.#readonly;
1084
+ this.#selfRemovable = schema.#selfRemovable;
1085
+ this.#removable = schema.#removable;
1086
+ this.#selfLabel = schema.#selfLabel;
1087
+ this.#label = schema.#label;
1088
+ this.#selfDescription = schema.#selfDescription;
1089
+ this.#description = schema.#description;
1090
+ this.#selfPlaceholder = schema.#selfPlaceholder;
1091
+ this.#placeholder = schema.#placeholder;
1092
+ this.#selfMin = schema.#selfMin;
1093
+ this.#min = schema.#min;
1094
+ this.#selfMax = schema.#selfMax;
1095
+ this.#max = schema.#max;
1096
+ this.#selfStep = schema.#selfStep;
1097
+ this.#step = schema.#step;
1098
+ this.#selfMinLength = schema.#selfMinLength;
1099
+ this.#minLength = schema.#minLength;
1100
+ this.#selfMaxLength = schema.#selfMaxLength;
1101
+ this.#maxLength = schema.#maxLength;
1102
+ this.#selfPattern = schema.#selfPattern;
1103
+ this.#pattern = schema.#pattern;
1104
+ this.#selfValues = schema.#selfValues;
1105
+ this.#values = schema.#values;
1106
+ this.#errors = schema.#errors;
1107
+ this.#validatorResult = schema.#validatorResult;
1108
+ this.#changed = schema.#changed;
1109
+ this.#blurred = schema.#blurred;
1110
+ this.#cancelChange = schema.#cancelChange;
1111
+ this.#cancelBlur = schema.#cancelBlur;
1112
+ this.#set = schema.#set;
1113
+ this.#initValue = schema.#initValue;
1114
+ this.#value = schema.#value;
1115
+ return;
1116
+ }
1117
+ this.#schema = schema;
994
1118
  const parent = parentNode instanceof Store ? parentNode : null;
995
1119
  if (parent) {
996
1120
  this.#parent = parent;
@@ -1118,6 +1242,7 @@
1118
1242
  /** @type {StoreLayout.Field<any>} */
1119
1243
  #layout;
1120
1244
  get layout() { return this.#layout; }
1245
+ /** @type {(value?: any) => unknown} */
1121
1246
  #createDefault;
1122
1247
  /** @param {any} [value] @returns {any} */
1123
1248
  createDefault(value) { return this.#createDefault(value); }
@@ -1399,40 +1524,26 @@
1399
1524
  #initValue = new exports.Signal.State(/** @type {T?} */(null));
1400
1525
  #value = new exports.Signal.State(this.#initValue.get());
1401
1526
 
1527
+ /** @type {Set<Store>} */
1528
+ #subBindStores = new Set();
1402
1529
  /**
1403
1530
  * @template [M=any]
1404
1531
  * @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
1405
1532
  * @param {Schema<M, S>} schema 数据结构模式
1533
+ * @param {AbortSignal} [signal]
1534
+ * @returns {BindObjectStore}
1406
1535
  */
1407
- bindObject(schema) {
1408
- const bindStores = this.#bindStores;
1409
- /** @type {Store[]} */
1410
- const list = [];
1411
- for (const [index, field] of Object.entries(schema)) {
1412
- const bindStore = create(field, {
1413
- index, parent: this,
1414
- /** @param {*} value @param {*} currentIndex @param {Store} store */
1415
- onUpdate: (value, currentIndex, store) => {
1416
- if (index !== currentIndex) { return; }
1417
- if (bindStores.has(store)) { return; }
1418
- const val = this.#value ?? null;
1419
- if (typeof val !== 'object' || Array.isArray(val)) { return }
1420
- // @ts-ignore
1421
- this.value = { ...val, [currentIndex]: value };
1422
- },
1423
- });
1424
- list.push(bindStore);
1425
- bindStores.set(bindStore, index);
1426
- }
1536
+ bindObject(schema, signal) {
1537
+ const originStore = this.#originStore;
1538
+ if (originStore) { return originStore.bindObject(schema, signal); }
1539
+ const store = new BindObjectStore(schema, this);
1540
+ if (signal?.aborted) { return store; }
1541
+ const subBindStores = this.#subBindStores;
1542
+ subBindStores.add(store);
1543
+ signal?.addEventListener('abort', () => subBindStores.delete(store));
1427
1544
  this.#requestUpdate();
1428
- return () => {
1429
- for (const bindStore of list) {
1430
- bindStores.delete(bindStore);
1431
- }
1432
- };
1545
+ return store;
1433
1546
  }
1434
- /** @type {Map<Store, string>} */
1435
- #bindStores = new Map();
1436
1547
 
1437
1548
  /** 内容是否已改变 */
1438
1549
  get changed() { return !Object.is(this.#value.get(), this.#initValue.get()); }
@@ -1440,6 +1551,8 @@
1440
1551
  /** 字段当前值 */
1441
1552
  get value() { return this.#value.get(); }
1442
1553
  set value(v) {
1554
+ const originStore = this.#originStore;
1555
+ if (originStore) { originStore.value = v; return; }
1443
1556
  const newValue = this.#setValue?.(v);
1444
1557
  const val = newValue === undefined ? v : newValue;
1445
1558
  this.#value.set(val);
@@ -1460,6 +1573,8 @@
1460
1573
  }
1461
1574
  /** 重置数据 */
1462
1575
  reset(value = this.#set ? this.#initValue.get() : this.#createDefault(), isNew = this.#selfNew.get()) {
1576
+ const originStore = this.#originStore;
1577
+ if (originStore) { originStore.reset(value, isNew); return; }
1463
1578
  this.#reset(value, Boolean(isNew));
1464
1579
  }
1465
1580
  /**
@@ -1476,11 +1591,10 @@
1476
1591
  this.#cancelBlur();
1477
1592
  this.#set = true;
1478
1593
  if (!value || typeof value !== 'object') {
1479
- for (const [, field] of this) {
1480
- field.#reset(null, false);
1481
- }
1482
- for (const [field] of this.#bindStores) {
1483
- field.#reset(null, false);
1594
+ for (const bind of [this, ...this.#subBindStores]) {
1595
+ for (const [, field] of bind) {
1596
+ field.#reset(null, false);
1597
+ }
1484
1598
  }
1485
1599
  this.#value.set(value);
1486
1600
  this.#initValue.set(value);
@@ -1489,11 +1603,10 @@
1489
1603
  }
1490
1604
  /** @type {*} */
1491
1605
  const newValues = Array.isArray(value) ? [...value] : { ...value };
1492
- for (const [key, field] of this) {
1493
- newValues[key] = field.#reset(Object.hasOwn(newValues, key) ? newValues[key] : undefined, false);
1494
- }
1495
- for (const [field, key] of this.#bindStores) {
1496
- newValues[key] = field.#reset(Object.hasOwn(newValues, key) ? newValues[key] : undefined, false);
1606
+ for (const bind of [this, ...this.#subBindStores]) {
1607
+ for (const [key, field] of bind) {
1608
+ newValues[key] = field.#reset(Object.hasOwn(newValues, key) ? newValues[key] : undefined, false);
1609
+ }
1497
1610
  }
1498
1611
  this.#value.set(newValues);
1499
1612
  this.#initValue.set(newValues);
@@ -1527,23 +1640,16 @@
1527
1640
  // @ts-ignore
1528
1641
  let newValues = Array.isArray(val) ? [...val] : { ...val };
1529
1642
  let updated = false;
1530
- for (const [key, field] of this) {
1531
- // @ts-ignore
1532
- const data = Object.hasOwn(val, key) ? val[key] : undefined;
1533
- const newData = field.#toUpdate(data);
1534
- if (Object.is(data, newData)) { continue; }
1535
- // @ts-ignore
1536
- newValues[key] = newData;
1537
- updated = true;
1538
- }
1539
- for (const [field, key] of this.#bindStores) {
1540
- // @ts-ignore
1541
- const data = Object.hasOwn(val, key) ? val[key] : undefined;
1542
- const newData = field.#toUpdate(data);
1543
- if (Object.is(data, newData)) { continue; }
1544
- // @ts-ignore
1545
- newValues[key] = newData;
1546
- updated = true;
1643
+ for (const bind of [this,...this.#subBindStores]) {
1644
+ for (const [key, field] of bind) {
1645
+ // @ts-ignore
1646
+ const data = Object.hasOwn(val, key) ? val[key] : undefined;
1647
+ const newData = field.#toUpdate(data);
1648
+ if (Object.is(data, newData)) { continue; }
1649
+ // @ts-ignore
1650
+ newValues[key] = newData;
1651
+ updated = true;
1652
+ }
1547
1653
  }
1548
1654
  if (updated) {
1549
1655
  val = newValues;
@@ -1577,6 +1683,7 @@
1577
1683
  */
1578
1684
  validate(path) {
1579
1685
  if (path === true) {
1686
+ if (this.#originStore) { return Promise.resolve(null); }
1580
1687
  return Promise.all([this.#validatorResult.get(), this.#changed(), this.#blurred()])
1581
1688
  .then(v => {
1582
1689
  const errors = v.flat();
@@ -1584,7 +1691,7 @@
1584
1691
  });
1585
1692
  }
1586
1693
  const selfPath = Array.isArray(path) ? path : [];
1587
- if (this.#hidden.get()) { return Promise.resolve([]); }
1694
+ if (!this.#originStore && this.#hidden.get()) { return Promise.resolve([]); }
1588
1695
  const list = [this.validate(true).then(errors => {
1589
1696
  if (!errors?.length) { return []; }
1590
1697
  return [{ path: [...selfPath], store: /** @type {Store} */(this), errors }];
@@ -1592,8 +1699,8 @@
1592
1699
  for (const [key, field] of this) {
1593
1700
  list.push(field.validate([...selfPath, key]));
1594
1701
  }
1595
- for (const [field, key] of this.#bindStores) {
1596
- list.push(field.validate([...selfPath, key]));
1702
+ for (const sub of this.#subBindStores) {
1703
+ list.push(sub.validate(selfPath));
1597
1704
  }
1598
1705
  return Promise.all(list).then(v => v.flat());
1599
1706
  }
@@ -1607,7 +1714,7 @@
1607
1714
  * @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
1608
1715
  * @extends {Store<T, M, S>}
1609
1716
  */
1610
- class ObjectStore extends Store {
1717
+ let ObjectStore$1 = class ObjectStore extends Store {
1611
1718
  get kind() { return 'object'; }
1612
1719
  /** @type {Record<string, Store>} */
1613
1720
  #children;
@@ -1660,9 +1767,9 @@
1660
1767
  }
1661
1768
  this.#children = children;
1662
1769
  }
1663
- }
1770
+ };
1664
1771
  // @ts-ignore
1665
- setObjectStore(ObjectStore);
1772
+ setObjectStore(ObjectStore$1);
1666
1773
 
1667
1774
  /** @import { Schema } from '../Schema.types.mjs' */
1668
1775
 
@@ -5332,7 +5439,7 @@
5332
5439
  if (list instanceof ArrayStore) {
5333
5440
  return renderArray(parent, next, list, env, r, layout.sort);
5334
5441
  }
5335
- if (list instanceof ObjectStore) {
5442
+ if (list instanceof ObjectStore$1) {
5336
5443
  return renderObject(parent, next, list, env, r, layout.sort);
5337
5444
  }
5338
5445
  if (typeof list === 'function') {
@@ -5441,6 +5548,8 @@
5441
5548
  if (tagName === 'nl-form-field') {
5442
5549
  const field = node.getAttribute('name') || '';
5443
5550
  const mode = node.getAttribute('mode') || '';
5551
+ const renderer = node.getAttribute('renderer') || '';
5552
+ const editable = options?.editable && !node.hasAttribute('non-editable');
5444
5553
  const fieldStore = field ? store.child(field) : store;
5445
5554
  if (!fieldStore) { return; }
5446
5555
  /** @type {HTMLElement?} */
@@ -5450,11 +5559,11 @@
5450
5559
  const fieldLayout = field
5451
5560
  ? layout?.fields?.find(createFieldFilter(field)) || fieldStore.layout
5452
5561
  : { ...layout, html: '' };
5453
- el = Form(fieldStore, fieldRenderer, fieldLayout, options);
5562
+ el = Form(fieldStore, fieldRenderer, fieldLayout, {...options, editable});
5454
5563
  break;
5455
5564
  }
5456
5565
  default: {
5457
- el = fieldRenderer(fieldStore, layout.renderer, options);
5566
+ el = fieldRenderer(fieldStore, renderer || layout.renderer, {...options, editable});
5458
5567
  break;
5459
5568
  }
5460
5569
  }
@@ -5656,9 +5765,10 @@
5656
5765
  /**
5657
5766
  *
5658
5767
  * @param {string | ParentNode | null} [html]
5768
+ * @param {function(string): string} [sanitize]
5659
5769
  * @returns {ParentNode}
5660
5770
  */
5661
- function getHtmlContent(html) {
5771
+ function getHtmlContent(html, sanitize) {
5662
5772
  if (!html) {
5663
5773
  return document.createElement('template').content;
5664
5774
  }
@@ -5666,7 +5776,7 @@
5666
5776
  return /** @type {ParentNode} */(html.cloneNode(true));
5667
5777
  }
5668
5778
  const template = document.createElement('template');
5669
- template.innerHTML = html;
5779
+ template.innerHTML = sanitize ? sanitize(html) : html;
5670
5780
  return template.content;
5671
5781
  }
5672
5782
 
@@ -5683,7 +5793,7 @@
5683
5793
  if (options?.signal?.aborted) { return null; }
5684
5794
  const html = layout.html;
5685
5795
  if (html) {
5686
- const content = getHtmlContent(html);
5796
+ const content = getHtmlContent(html, options?.sanitizeHtml);
5687
5797
  renderHtml(store, fieldRenderer, content, options, layout);
5688
5798
  return content;
5689
5799
  }
@@ -6860,7 +6970,7 @@
6860
6970
  * @returns {ParentNode}
6861
6971
  */
6862
6972
  function Html(html, store, fieldRenderer, options, layout) {
6863
- const htmlContent = getHtmlContent(html);
6973
+ const htmlContent = getHtmlContent(html, options?.sanitizeHtml);
6864
6974
  renderHtml(store, fieldRenderer, htmlContent, options, layout);
6865
6975
  return htmlContent;
6866
6976
  }
@@ -6967,7 +7077,7 @@
6967
7077
  const html = layout.html;
6968
7078
  if (!html) { return null; }
6969
7079
  const [root, content] = createCell(options?.signal, layout, store);
6970
- const htmlContent = getHtmlContent(html);
7080
+ const htmlContent = getHtmlContent(html, options?.sanitizeHtml);
6971
7081
  renderHtml(store, fieldRenderer, htmlContent, options, layout);
6972
7082
  content.appendChild(htmlContent);
6973
7083
  return root;
@@ -7053,7 +7163,7 @@
7053
7163
  Form(store, fieldRenderer, storeLayout, options || null, root);
7054
7164
  return;
7055
7165
  }
7056
- const content = getHtmlContent(html);
7166
+ const content = getHtmlContent(html, options?.sanitizeHtml);
7057
7167
  renderHtml(store, fieldRenderer, content, options || null, storeLayout);
7058
7168
  root.appendChild(content);
7059
7169
  options?.signal?.addEventListener('abort', () => {
@@ -7063,7 +7173,7 @@
7063
7173
 
7064
7174
  exports.ArrayStore = ArrayStore;
7065
7175
  exports.Layout = index;
7066
- exports.ObjectStore = ObjectStore;
7176
+ exports.ObjectStore = ObjectStore$1;
7067
7177
  exports.Store = Store;
7068
7178
  exports.effect = effect;
7069
7179
  exports.render = render;