@neeloong/form 0.22.0 → 0.24.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 +1178 -1125
- package/index.full.js +481 -524
- package/index.full.min.js +5 -5
- package/index.full.min.mjs +7 -7
- package/index.min.mjs +2 -2
- package/index.mjs +481 -524
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @neeloong/form v0.
|
|
2
|
+
* @neeloong/form v0.24.0
|
|
3
3
|
* (c) 2024-2026 Fierflame
|
|
4
4
|
* @license Apache-2.0
|
|
5
5
|
*/
|
|
@@ -36,7 +36,7 @@ function createBooleanStates(self, defState, fn, parent) {
|
|
|
36
36
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
/** @import { Schema } from '../types.mjs' */
|
|
39
|
+
/** @import { Schema } from '../Schema.types.mjs' */
|
|
40
40
|
/** @param {*} v */
|
|
41
41
|
const string = v => typeof v === 'string' && v || null;
|
|
42
42
|
/** @param {*} v */
|
|
@@ -133,7 +133,7 @@ function createRef(store) {
|
|
|
133
133
|
return r;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
/** @import { Schema } from '../types.mjs' */
|
|
136
|
+
/** @import { Schema } from '../Schema.types.mjs' */
|
|
137
137
|
/** @import ArrayStore from './ArrayStore.mjs' */
|
|
138
138
|
|
|
139
139
|
|
|
@@ -185,7 +185,7 @@ function setStore$1(type, Class) {
|
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
/** @import Store from './Store.mjs' */
|
|
188
|
-
/** @import {
|
|
188
|
+
/** @import { Schema } from '../Schema.types.mjs' */
|
|
189
189
|
/**
|
|
190
190
|
*
|
|
191
191
|
* @param {*} v
|
|
@@ -200,7 +200,7 @@ function toResult(v) {
|
|
|
200
200
|
/**
|
|
201
201
|
*
|
|
202
202
|
* @param {Store} store
|
|
203
|
-
* @param {...Validator | undefined | null | (Validator | undefined | null)[]} validators
|
|
203
|
+
* @param {...Schema.Validator | undefined | null | (Schema.Validator | undefined | null)[]} validators
|
|
204
204
|
* @returns
|
|
205
205
|
*/
|
|
206
206
|
function createValidator(store, ...validators) {
|
|
@@ -223,7 +223,7 @@ function createValidator(store, ...validators) {
|
|
|
223
223
|
/**
|
|
224
224
|
*
|
|
225
225
|
* @param {Store} store
|
|
226
|
-
* @param {...AsyncValidator | undefined | null | (AsyncValidator | undefined | null)[]} validators
|
|
226
|
+
* @param {...Schema.AsyncValidator | undefined | null | (Schema.AsyncValidator | undefined | null)[]} validators
|
|
227
227
|
* @returns {[exec: () => Promise<string[]>, state: Signal.Computed<string[]>, stop: () => void]}
|
|
228
228
|
*/
|
|
229
229
|
function createAsyncValidator(store, ...validators) {
|
|
@@ -238,7 +238,7 @@ function createAsyncValidator(store, ...validators) {
|
|
|
238
238
|
const st = new Signal.State(/** @type {string[]} */([]));
|
|
239
239
|
/**
|
|
240
240
|
*
|
|
241
|
-
* @param {AsyncValidator} validator
|
|
241
|
+
* @param {Schema.AsyncValidator} validator
|
|
242
242
|
* @param {AbortSignal} signal
|
|
243
243
|
*/
|
|
244
244
|
async function run(validator, signal) {
|
|
@@ -292,7 +292,8 @@ function makeDefault(store, def) {
|
|
|
292
292
|
}
|
|
293
293
|
|
|
294
294
|
/** @import { Ref } from './ref.mjs' */
|
|
295
|
-
/** @import {
|
|
295
|
+
/** @import { Schema } from '../Schema.types.mjs' */
|
|
296
|
+
/** @import { StoreLayout } from '../StoreLayout.types.mjs' */
|
|
296
297
|
|
|
297
298
|
/**
|
|
298
299
|
* 管理单个表单字段的状态和行为
|
|
@@ -389,8 +390,8 @@ class Store {
|
|
|
389
390
|
* @param {number} [options.maxLength]
|
|
390
391
|
* @param {RegExp} [options.pattern]
|
|
391
392
|
* @param {(Schema.Value.Group | Schema.Value | string | number)[]} [options.values] 可选值
|
|
392
|
-
* @param {Validator | Validator[] | null} [options.validator]
|
|
393
|
-
* @param {{[k in keyof Schema.Events]?: AsyncValidator | AsyncValidator[] | null}} [options.validators]
|
|
393
|
+
* @param {Schema.Validator | Schema.Validator[] | null} [options.validator]
|
|
394
|
+
* @param {{[k in keyof Schema.Events]?: Schema.AsyncValidator | Schema.AsyncValidator[] | null}} [options.validators]
|
|
394
395
|
*
|
|
395
396
|
* @param {Ref?} [options.ref]
|
|
396
397
|
*
|
|
@@ -422,6 +423,7 @@ class Store {
|
|
|
422
423
|
this.#type = schema.type;
|
|
423
424
|
this.#meta = schema.meta;
|
|
424
425
|
this.#component = schema.component;
|
|
426
|
+
this.#layout = schema.layout || {};
|
|
425
427
|
|
|
426
428
|
const selfNewState = new Signal.State(Boolean(isNew));
|
|
427
429
|
this.#selfNew = selfNewState;
|
|
@@ -512,6 +514,9 @@ class Store {
|
|
|
512
514
|
this.listen(k, f);
|
|
513
515
|
}
|
|
514
516
|
}
|
|
517
|
+
/** @type {StoreLayout.Field<any>} */
|
|
518
|
+
#layout
|
|
519
|
+
get layout() { return this.#layout; }
|
|
515
520
|
#createDefault;
|
|
516
521
|
/** @param {any} [value] @returns {any} */
|
|
517
522
|
createDefault(value) { return this.#createDefault(value); }
|
|
@@ -933,7 +938,7 @@ class Store {
|
|
|
933
938
|
}
|
|
934
939
|
}
|
|
935
940
|
|
|
936
|
-
/** @import { Schema } from '../types.mjs' */
|
|
941
|
+
/** @import { Schema } from '../Schema.types.mjs' */
|
|
937
942
|
|
|
938
943
|
/**
|
|
939
944
|
* @template {Record<string, any>} [T=Record<string, any>]
|
|
@@ -997,7 +1002,7 @@ class ObjectStore extends Store {
|
|
|
997
1002
|
// @ts-ignore
|
|
998
1003
|
setObjectStore(ObjectStore);
|
|
999
1004
|
|
|
1000
|
-
/** @import { Schema } from '../types.mjs' */
|
|
1005
|
+
/** @import { Schema } from '../Schema.types.mjs' */
|
|
1001
1006
|
|
|
1002
1007
|
|
|
1003
1008
|
|
|
@@ -1051,7 +1056,7 @@ class ArrayStore extends Store {
|
|
|
1051
1056
|
}
|
|
1052
1057
|
|
|
1053
1058
|
};
|
|
1054
|
-
super(schema, {
|
|
1059
|
+
super({ ...schema, immutable: false }, {
|
|
1055
1060
|
index, new: isNew, parent,
|
|
1056
1061
|
size: new Signal.Computed(() => childrenState.get().length),
|
|
1057
1062
|
setValue(v) {
|
|
@@ -1088,7 +1093,10 @@ class ArrayStore extends Store {
|
|
|
1088
1093
|
},
|
|
1089
1094
|
};
|
|
1090
1095
|
this.#create = (index, isNew) => {
|
|
1091
|
-
const child = create(
|
|
1096
|
+
const child = create(
|
|
1097
|
+
{ ...schema, creatable: true },
|
|
1098
|
+
{ ...childCommonOptions, index, new: isNew },
|
|
1099
|
+
);
|
|
1092
1100
|
child.index = index;
|
|
1093
1101
|
return child;
|
|
1094
1102
|
};
|
|
@@ -2314,13 +2322,36 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
2314
2322
|
|
|
2315
2323
|
/**
|
|
2316
2324
|
* 相应式执行
|
|
2325
|
+
* @overload
|
|
2317
2326
|
* @param {() => void} fn 执行函数
|
|
2327
|
+
* @param {null} [signal]
|
|
2318
2328
|
* @returns {() => void} 取消函数
|
|
2319
2329
|
*/
|
|
2320
|
-
|
|
2330
|
+
/**
|
|
2331
|
+
* 相应式执行
|
|
2332
|
+
* @overload
|
|
2333
|
+
* @param {() => void} fn 执行函数
|
|
2334
|
+
* @param {AbortSignal} signal
|
|
2335
|
+
* @returns {void} 取消函数
|
|
2336
|
+
*/
|
|
2337
|
+
/**
|
|
2338
|
+
* 相应式执行
|
|
2339
|
+
* @overload
|
|
2340
|
+
* @param {() => void} fn 执行函数
|
|
2341
|
+
* @param {AbortSignal?} [signal]
|
|
2342
|
+
* @returns {(() => void) | void} 取消函数
|
|
2343
|
+
*/
|
|
2344
|
+
/**
|
|
2345
|
+
* 相应式执行
|
|
2346
|
+
* @param {() => void} fn 执行函数
|
|
2347
|
+
* @param {AbortSignal?} [signal]
|
|
2348
|
+
* @returns {(() => void) | void} 取消函数
|
|
2349
|
+
*/
|
|
2350
|
+
function effect(fn, signal) {
|
|
2351
|
+
if (signal?.aborted) { return; }
|
|
2321
2352
|
let needsEnqueue = true;
|
|
2322
2353
|
const w = new Signal.subtle.Watcher(() => {
|
|
2323
|
-
if (!needsEnqueue) { return }
|
|
2354
|
+
if (!needsEnqueue) { return; }
|
|
2324
2355
|
needsEnqueue = false;
|
|
2325
2356
|
queueMicrotask(() => {
|
|
2326
2357
|
needsEnqueue = true;
|
|
@@ -2334,19 +2365,54 @@ function effect(fn) {
|
|
|
2334
2365
|
|
|
2335
2366
|
w.watch(computed);
|
|
2336
2367
|
computed.get();
|
|
2368
|
+
if (!signal) { return () => { w.unwatch(computed); }; }
|
|
2369
|
+
signal.addEventListener('abort', () => {
|
|
2370
|
+
w.unwatch(computed);
|
|
2371
|
+
}, { once: true });
|
|
2337
2372
|
|
|
2338
|
-
return () => { w.unwatch(computed); };
|
|
2339
2373
|
}
|
|
2340
2374
|
|
|
2341
2375
|
/**
|
|
2342
2376
|
* 创建可赋值计算值
|
|
2343
2377
|
* @template T
|
|
2378
|
+
* @overload
|
|
2344
2379
|
* @param {() => T} getter 取值方法
|
|
2345
2380
|
* @param {(value: T) => void} callback 取值方法
|
|
2346
2381
|
* @param {boolean} immediate 是否立即执行一次
|
|
2382
|
+
* @param {null} [signal]
|
|
2347
2383
|
* @returns {() => void}
|
|
2348
2384
|
*/
|
|
2349
|
-
|
|
2385
|
+
|
|
2386
|
+
/**
|
|
2387
|
+
* 创建可赋值计算值
|
|
2388
|
+
* @template T
|
|
2389
|
+
* @overload
|
|
2390
|
+
* @param {() => T} getter 取值方法
|
|
2391
|
+
* @param {(value: T) => void} callback 取值方法
|
|
2392
|
+
* @param {boolean} immediate 是否立即执行一次
|
|
2393
|
+
* @param {AbortSignal?} [signal]
|
|
2394
|
+
* @returns {(() => void) | void}
|
|
2395
|
+
*/
|
|
2396
|
+
/**
|
|
2397
|
+
* 创建可赋值计算值
|
|
2398
|
+
* @template T
|
|
2399
|
+
* @overload
|
|
2400
|
+
* @param {() => T} getter 取值方法
|
|
2401
|
+
* @param {(value: T) => void} callback 取值方法
|
|
2402
|
+
* @param {boolean} immediate 是否立即执行一次
|
|
2403
|
+
* @param {AbortSignal} signal
|
|
2404
|
+
* @returns {void}
|
|
2405
|
+
*/
|
|
2406
|
+
/**
|
|
2407
|
+
* 创建可赋值计算值
|
|
2408
|
+
* @template T
|
|
2409
|
+
* @param {() => T} getter 取值方法
|
|
2410
|
+
* @param {(value: T) => void} callback 取值方法
|
|
2411
|
+
* @param {boolean} immediate 是否立即执行一次
|
|
2412
|
+
* @param {AbortSignal?} [signal]
|
|
2413
|
+
* @returns {(() => void) | void}
|
|
2414
|
+
*/
|
|
2415
|
+
function watch(getter, callback, immediate, signal) {
|
|
2350
2416
|
let run = false;
|
|
2351
2417
|
/** @type {any} */
|
|
2352
2418
|
let value;
|
|
@@ -2361,7 +2427,7 @@ function watch(getter, callback, immediate) {
|
|
|
2361
2427
|
if (Object.is(val, value)) { return; }
|
|
2362
2428
|
value = val;
|
|
2363
2429
|
callback(val);
|
|
2364
|
-
});
|
|
2430
|
+
}, signal);
|
|
2365
2431
|
}
|
|
2366
2432
|
|
|
2367
2433
|
const bindable = {
|
|
@@ -3428,8 +3494,7 @@ class EventEmitter {
|
|
|
3428
3494
|
}
|
|
3429
3495
|
}
|
|
3430
3496
|
|
|
3431
|
-
/** @import { Component
|
|
3432
|
-
/** @import Store from '../Store/index.mjs' */
|
|
3497
|
+
/** @import { Component } from '../types.mjs' */
|
|
3433
3498
|
/** @import Environment from './Environment/index.mjs' */
|
|
3434
3499
|
/** @import * as Layout from '../Layout/index.mjs' */
|
|
3435
3500
|
|
|
@@ -3599,7 +3664,8 @@ function bindFilters(env, fn, filterFns) {
|
|
|
3599
3664
|
}
|
|
3600
3665
|
}
|
|
3601
3666
|
|
|
3602
|
-
/** @import { Component
|
|
3667
|
+
/** @import { Component } from '../types.mjs' */
|
|
3668
|
+
/** @import { StoreLayout } from '../StoreLayout.types.mjs' */
|
|
3603
3669
|
/** @import { ComponentHandler } from './types.mjs' */
|
|
3604
3670
|
/** @import Store from '../Store/index.mjs' */
|
|
3605
3671
|
/** @import Environment from './Environment/index.mjs' */
|
|
@@ -3610,7 +3676,7 @@ function bindFilters(env, fn, filterFns) {
|
|
|
3610
3676
|
* @param {Component | string} component
|
|
3611
3677
|
* @param {Environment} env
|
|
3612
3678
|
* @param {Store?} store
|
|
3613
|
-
* @param {((store: Store, el: Element | Relatedness) => () => void)?} [relate]
|
|
3679
|
+
* @param {((store: Store, el: Element | StoreLayout.Relatedness) => () => void)?} [relate]
|
|
3614
3680
|
* @returns
|
|
3615
3681
|
*/
|
|
3616
3682
|
function createContext(component, env, store, relate) {
|
|
@@ -4488,7 +4554,7 @@ function divergent(layout, parent, next, env, renderItem) {
|
|
|
4488
4554
|
* @param {Record<string, [Layout.Template, Environment]>} templates
|
|
4489
4555
|
* @param {string[]} componentPath
|
|
4490
4556
|
* @param {Record<string, Enhancement>} enhancements
|
|
4491
|
-
* @param {((store: Store, el: Element | Relatedness) => () => void)?} [relate]
|
|
4557
|
+
* @param {((store: Store, el: Element | StoreLayout.Relatedness) => () => void)?} [relate]
|
|
4492
4558
|
* @param {Component.Getter?} [getComponent]
|
|
4493
4559
|
*/
|
|
4494
4560
|
function renderNode(layout, parent, next, env, templates, componentPath, enhancements, relate, getComponent) {
|
|
@@ -4570,7 +4636,7 @@ function createTemplates(env, parentTemplates, newTemplates) {
|
|
|
4570
4636
|
* @param {Record<string, [Layout.Template, Environment]>} parentTemplates
|
|
4571
4637
|
* @param {string[]} componentPath
|
|
4572
4638
|
* @param {Record<string, Enhancement>} enhancements
|
|
4573
|
-
* @param {((store: Store, el: Element | Relatedness) => () => void)?} [relate]
|
|
4639
|
+
* @param {((store: Store, el: Element | StoreLayout.Relatedness) => () => void)?} [relate]
|
|
4574
4640
|
* @param {Component.Getter?} [getComponent]
|
|
4575
4641
|
* @returns {() => void}
|
|
4576
4642
|
*/
|
|
@@ -4635,7 +4701,7 @@ function renderChild(layout, parent, next, parentEnv, parentTemplates, component
|
|
|
4635
4701
|
* @param {Record<string, [Layout.Template, Environment]>} templates
|
|
4636
4702
|
* @param {string[]} componentPath
|
|
4637
4703
|
* @param {Record<string, Enhancement>} enhancements
|
|
4638
|
-
* @param {((store: Store, el: Element | Relatedness) => () => void)?} [relate]
|
|
4704
|
+
* @param {((store: Store, el: Element | StoreLayout.Relatedness) => () => void)?} [relate]
|
|
4639
4705
|
* @param {Component.Getter?} [getComponent]
|
|
4640
4706
|
* @returns {() => void}
|
|
4641
4707
|
*/
|
|
@@ -4658,7 +4724,7 @@ function renderChildren(layouts, parent, next, env, templates, componentPath, en
|
|
|
4658
4724
|
* @param {object} [options] 选项
|
|
4659
4725
|
* @param {Record<string, Store | {get?(): any; set?(v: any): void; exec?(...p: any[]): any; calc?(...p: any[]): any }>} [options.global] 全局数据
|
|
4660
4726
|
* @param {Component.Getter?} [options.component] 自定义组件
|
|
4661
|
-
* @param {(store: Store, el: Element | Relatedness) => () => void} [options.relate] 关联函数
|
|
4727
|
+
* @param {(store: Store, el: Element | StoreLayout.Relatedness) => () => void} [options.relate] 关联函数
|
|
4662
4728
|
* @param {Record<string, Enhancement>} [options.enhancements] 增强信息
|
|
4663
4729
|
* @returns {() => void}
|
|
4664
4730
|
*/
|
|
@@ -4671,69 +4737,69 @@ function render(store, layouts, parent, { component, global, relate, enhancement
|
|
|
4671
4737
|
}
|
|
4672
4738
|
|
|
4673
4739
|
/** @import { Store } from '../Store/index.mjs' */
|
|
4674
|
-
/** @import { StoreLayout } from '../types.mjs' */
|
|
4675
|
-
|
|
4740
|
+
/** @import { StoreLayout } from '../StoreLayout.types.mjs' */
|
|
4676
4741
|
|
|
4677
4742
|
/**
|
|
4678
4743
|
*
|
|
4744
|
+
* @template T
|
|
4679
4745
|
* @param {string} field
|
|
4746
|
+
* @returns {(v: StoreLayout.Item<T>) => v is StoreLayout.Field<T>}
|
|
4680
4747
|
*/
|
|
4681
4748
|
function createFieldFilter(field) {
|
|
4682
|
-
|
|
4683
4749
|
/**
|
|
4684
4750
|
*
|
|
4685
|
-
* @param {StoreLayout.Item} v
|
|
4686
|
-
* @returns {v is StoreLayout.Field}
|
|
4751
|
+
* @param {StoreLayout.Item<T>} v
|
|
4752
|
+
* @returns {v is StoreLayout.Field<T>}
|
|
4687
4753
|
*/
|
|
4688
|
-
|
|
4689
|
-
return function (v) {
|
|
4754
|
+
return v => {
|
|
4690
4755
|
if (v.type && v.type !== 'field') { return false; }
|
|
4691
4756
|
return v.field === field;
|
|
4692
4757
|
|
|
4693
4758
|
};
|
|
4694
4759
|
}
|
|
4695
4760
|
/**
|
|
4696
|
-
*
|
|
4697
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
4761
|
+
* @template T
|
|
4762
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
4698
4763
|
* @param {Store} store
|
|
4699
4764
|
* @param {Node} node
|
|
4700
4765
|
* @param {StoreLayout.Options?} options
|
|
4701
|
-
* @param {StoreLayout
|
|
4766
|
+
* @param {StoreLayout<T>} layout
|
|
4702
4767
|
* @param {Node} [anchor]
|
|
4703
4768
|
* @param {(child?: Store<any, any> | undefined) => void} [dragenter]
|
|
4769
|
+
* @returns {void}
|
|
4704
4770
|
*/
|
|
4705
4771
|
function renderHtml(store, fieldRenderer, node, options, layout, anchor, dragenter) {
|
|
4706
|
-
|
|
4707
|
-
const destroyList = [];
|
|
4772
|
+
if (options?.signal?.aborted) { return; }
|
|
4708
4773
|
if (node instanceof Element) {
|
|
4709
4774
|
const tagName = node.tagName.toLowerCase();
|
|
4710
|
-
if (!node.parentNode) { return
|
|
4775
|
+
if (!node.parentNode) { return; }
|
|
4711
4776
|
if (tagName === 'nl-form-field') {
|
|
4712
4777
|
const field = node.getAttribute('name') || '';
|
|
4713
4778
|
const mode = node.getAttribute('mode') || '';
|
|
4714
4779
|
const fieldStore = field ? store.child(field) : store;
|
|
4715
|
-
|
|
4716
|
-
|
|
4780
|
+
if (!fieldStore) { return; }
|
|
4781
|
+
const fieldLayout = field
|
|
4782
|
+
? layout?.fields?.find(createFieldFilter(field)) || fieldStore.layout
|
|
4783
|
+
: { ...layout, html: '' };
|
|
4717
4784
|
switch (mode) {
|
|
4718
4785
|
case 'grid': {
|
|
4719
|
-
const
|
|
4720
|
-
node.replaceWith(el);
|
|
4721
|
-
return
|
|
4786
|
+
const el = Form(store, fieldRenderer, fieldLayout, options);
|
|
4787
|
+
if (el) { node.replaceWith(el); }
|
|
4788
|
+
return;
|
|
4722
4789
|
}
|
|
4723
4790
|
}
|
|
4724
|
-
const res = fieldRenderer(fieldStore, options);
|
|
4791
|
+
const res = fieldRenderer(fieldStore, layout.renderer, options);
|
|
4725
4792
|
if (res) {
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
return destroy;
|
|
4793
|
+
node.replaceWith(res);
|
|
4794
|
+
return;
|
|
4729
4795
|
}
|
|
4730
4796
|
const value = node.getAttribute('placeholder') || '';
|
|
4731
4797
|
node.replaceWith(document.createTextNode(value));
|
|
4732
|
-
return
|
|
4798
|
+
return;
|
|
4733
4799
|
}
|
|
4734
4800
|
if (tagName === 'nl-form-button') {
|
|
4735
4801
|
const button = document.createElement('button');
|
|
4736
|
-
button.
|
|
4802
|
+
button.classList.add('NeeloongForm-item-button');
|
|
4737
4803
|
const click = node.getAttribute('click') || '';
|
|
4738
4804
|
const call = options?.call;
|
|
4739
4805
|
if (click && typeof call === 'function') {
|
|
@@ -4743,7 +4809,7 @@ function renderHtml(store, fieldRenderer, node, options, layout, anchor, dragent
|
|
|
4743
4809
|
button.appendChild(n);
|
|
4744
4810
|
}
|
|
4745
4811
|
node.replaceWith(button);
|
|
4746
|
-
return
|
|
4812
|
+
return;
|
|
4747
4813
|
}
|
|
4748
4814
|
const name = node.getAttribute('nl-form-field');
|
|
4749
4815
|
if (name) {
|
|
@@ -4752,32 +4818,37 @@ function renderHtml(store, fieldRenderer, node, options, layout, anchor, dragent
|
|
|
4752
4818
|
|
|
4753
4819
|
const fieldStore = field ? store.child(field) : store;
|
|
4754
4820
|
if (!fieldStore) {
|
|
4755
|
-
return
|
|
4821
|
+
return;
|
|
4756
4822
|
}
|
|
4757
4823
|
node.removeAttribute('nl-form-field');
|
|
4758
|
-
const fieldLayout = field
|
|
4759
|
-
|
|
4824
|
+
const fieldLayout = field
|
|
4825
|
+
? layout.fields?.find(createFieldFilter(field)) || fieldStore.layout
|
|
4826
|
+
: { ...layout, html: '' };
|
|
4827
|
+
if (!array) {
|
|
4828
|
+
renderHtml(fieldStore, fieldRenderer, node, options, fieldLayout, anchor);
|
|
4829
|
+
return;
|
|
4830
|
+
}
|
|
4760
4831
|
if (!(fieldStore instanceof ArrayStore)) {
|
|
4761
4832
|
node.remove();
|
|
4762
|
-
return
|
|
4833
|
+
return;
|
|
4763
4834
|
}
|
|
4764
4835
|
const parentElement = node.parentElement;
|
|
4765
4836
|
if (!parentElement) {
|
|
4766
4837
|
node.remove();
|
|
4767
|
-
return
|
|
4838
|
+
return;
|
|
4768
4839
|
}
|
|
4769
4840
|
const comment = parentElement.insertBefore(document.createComment(''), node) || null;
|
|
4770
4841
|
node.remove();
|
|
4771
4842
|
|
|
4772
|
-
/** @type {Map<Store, [Node,
|
|
4843
|
+
/** @type {Map<Store, [Node, AbortController]>} */
|
|
4773
4844
|
let seMap = new Map();
|
|
4774
|
-
/** @param {Map<Store, [
|
|
4845
|
+
/** @param {Map<Store, [Node, AbortController]>} map */
|
|
4775
4846
|
function destroyMap(map) {
|
|
4776
|
-
for (const [el,
|
|
4777
|
-
destroy();
|
|
4847
|
+
for (const [el, ac] of map.values()) {
|
|
4778
4848
|
if (el instanceof Element) {
|
|
4779
4849
|
el.remove();
|
|
4780
4850
|
}
|
|
4851
|
+
ac.abort();
|
|
4781
4852
|
}
|
|
4782
4853
|
}
|
|
4783
4854
|
let dragRow = -1;
|
|
@@ -4794,22 +4865,26 @@ function renderHtml(store, fieldRenderer, node, options, layout, anchor, dragent
|
|
|
4794
4865
|
}
|
|
4795
4866
|
};
|
|
4796
4867
|
|
|
4797
|
-
|
|
4868
|
+
watch(() => fieldStore.children, children => {
|
|
4798
4869
|
let nextNode = comment.nextSibling;
|
|
4799
4870
|
const oldSeMap = seMap;
|
|
4800
4871
|
seMap = new Map();
|
|
4801
4872
|
for (const child of children) {
|
|
4802
4873
|
const old = oldSeMap.get(child);
|
|
4803
4874
|
if (!old) {
|
|
4875
|
+
const ac = new AbortController();
|
|
4804
4876
|
const el = parentElement.insertBefore(node.cloneNode(true), nextNode);
|
|
4805
|
-
|
|
4877
|
+
renderHtml(child, fieldRenderer, el, {
|
|
4878
|
+
...options,
|
|
4879
|
+
signal: options?.signal ? AbortSignal.any([options?.signal, ac.signal]) : ac.signal,
|
|
4880
|
+
}, fieldLayout, el);
|
|
4806
4881
|
el.addEventListener('dragenter', () => { newDragenter(child); });
|
|
4807
4882
|
el.addEventListener('dragstart', (event) => {
|
|
4808
4883
|
if (event.target !== event.currentTarget) { return; }
|
|
4809
4884
|
dragRow = Number(child.index);
|
|
4810
4885
|
});
|
|
4811
4886
|
el.addEventListener('dragend', () => { dragRow = -1; });
|
|
4812
|
-
seMap.set(child, [el,
|
|
4887
|
+
seMap.set(child, [el, ac]);
|
|
4813
4888
|
continue;
|
|
4814
4889
|
}
|
|
4815
4890
|
oldSeMap.delete(child);
|
|
@@ -4821,13 +4896,13 @@ function renderHtml(store, fieldRenderer, node, options, layout, anchor, dragent
|
|
|
4821
4896
|
parentElement.insertBefore(old[0], nextNode);
|
|
4822
4897
|
}
|
|
4823
4898
|
destroyMap(oldSeMap);
|
|
4824
|
-
}, true);
|
|
4899
|
+
}, true, options?.signal);
|
|
4825
4900
|
|
|
4826
|
-
|
|
4901
|
+
options?.signal?.addEventListener('abort', () => {
|
|
4827
4902
|
comment.remove();
|
|
4828
4903
|
destroyMap(seMap);
|
|
4829
|
-
|
|
4830
|
-
|
|
4904
|
+
}, { once: true });
|
|
4905
|
+
return;
|
|
4831
4906
|
|
|
4832
4907
|
}
|
|
4833
4908
|
if (node.getAttribute('nl-form-remove') !== null) {
|
|
@@ -4870,11 +4945,11 @@ function renderHtml(store, fieldRenderer, node, options, layout, anchor, dragent
|
|
|
4870
4945
|
const field = node.getAttribute(attr);
|
|
4871
4946
|
const fieldStore = field ? store.child(field) : store;
|
|
4872
4947
|
if (!fieldStore) { continue; }
|
|
4873
|
-
|
|
4948
|
+
effect(() => {
|
|
4874
4949
|
try {
|
|
4875
4950
|
node.setAttribute(name, fieldStore.value);
|
|
4876
4951
|
} catch { }
|
|
4877
|
-
})
|
|
4952
|
+
}, options?.signal);
|
|
4878
4953
|
} else if (prefix === 'nl-form-event' && typeof call === 'function') {
|
|
4879
4954
|
const event = node.getAttribute(attr);
|
|
4880
4955
|
if (!event) { continue; }
|
|
@@ -4886,15 +4961,9 @@ function renderHtml(store, fieldRenderer, node, options, layout, anchor, dragent
|
|
|
4886
4961
|
}
|
|
4887
4962
|
if (node instanceof Element || node instanceof DocumentFragment) {
|
|
4888
4963
|
for (const n of [...node.children]) {
|
|
4889
|
-
|
|
4964
|
+
renderHtml(store, fieldRenderer, n, options, layout, anchor);
|
|
4890
4965
|
}
|
|
4891
4966
|
}
|
|
4892
|
-
return () => {
|
|
4893
|
-
for (const destroy of destroyList) {
|
|
4894
|
-
destroy();
|
|
4895
|
-
}
|
|
4896
|
-
};
|
|
4897
|
-
|
|
4898
4967
|
}
|
|
4899
4968
|
|
|
4900
4969
|
/**
|
|
@@ -4916,38 +4985,46 @@ function getHtmlContent(html) {
|
|
|
4916
4985
|
|
|
4917
4986
|
/**
|
|
4918
4987
|
*
|
|
4988
|
+
* @template T
|
|
4919
4989
|
* @param {Store<any, any>} store
|
|
4920
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
4921
|
-
* @param {StoreLayout
|
|
4990
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
4991
|
+
* @param {StoreLayout<T>} layout
|
|
4922
4992
|
* @param {StoreLayout.Options?} options
|
|
4923
|
-
* @returns {
|
|
4993
|
+
* @returns {ParentNode?}
|
|
4924
4994
|
*/
|
|
4925
4995
|
function FormFieldInline(store, fieldRenderer, layout, options) {
|
|
4926
|
-
|
|
4996
|
+
if (options?.signal?.aborted) { return null; }
|
|
4997
|
+
const html = layout.html;
|
|
4998
|
+
if (html) {
|
|
4999
|
+
const content = getHtmlContent(html);
|
|
5000
|
+
renderHtml(store, fieldRenderer, content, options, layout);
|
|
5001
|
+
return content;
|
|
5002
|
+
}
|
|
5003
|
+
return fieldRenderer(store, layout.renderer, options);
|
|
4927
5004
|
}
|
|
4928
5005
|
|
|
4929
5006
|
/** @import { Store } from '../Store/index.mjs' */
|
|
4930
|
-
/** @import { StoreLayout } from '../types.mjs' */
|
|
5007
|
+
/** @import { StoreLayout } from '../StoreLayout.types.mjs' */
|
|
4931
5008
|
|
|
4932
5009
|
/**
|
|
4933
5010
|
*
|
|
5011
|
+
* @template T
|
|
4934
5012
|
* @param {Store<any, any>} store
|
|
4935
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
4936
|
-
* @param {StoreLayout.Field
|
|
5013
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
5014
|
+
* @param {StoreLayout.Field<T>} layout
|
|
4937
5015
|
* @param {object} option
|
|
4938
|
-
* @param {StoreLayout.Column[]} option.columns
|
|
5016
|
+
* @param {StoreLayout.Column<T>[]} option.columns
|
|
4939
5017
|
* @param {() => void} option.remove
|
|
4940
5018
|
* @param {() => void} option.dragenter
|
|
4941
5019
|
* @param {() => void} option.dragstart
|
|
4942
5020
|
* @param {() => void} option.dragend
|
|
4943
5021
|
* @param {{get(): boolean}} option.deletable
|
|
4944
5022
|
* @param {StoreLayout.Options?} options
|
|
4945
|
-
|
|
4946
|
-
* @returns {[HTMLTableSectionElement, () => void]}
|
|
5023
|
+
* @returns {HTMLTableSectionElement}
|
|
4947
5024
|
*/
|
|
4948
5025
|
function Line(store, fieldRenderer, layout, {
|
|
4949
|
-
columns,
|
|
4950
|
-
remove, dragenter, dragstart, dragend,
|
|
5026
|
+
columns, deletable,
|
|
5027
|
+
remove, dragenter, dragstart, dragend,
|
|
4951
5028
|
}, options) {
|
|
4952
5029
|
const root = document.createElement('tbody');
|
|
4953
5030
|
root.addEventListener('dragenter', () => {
|
|
@@ -4960,38 +5037,34 @@ function Line(store, fieldRenderer, layout, {
|
|
|
4960
5037
|
root.addEventListener('dragend', dragend);
|
|
4961
5038
|
const head = root.appendChild(document.createElement('tr'));
|
|
4962
5039
|
|
|
4963
|
-
/** @type {(() => void)[]} */
|
|
4964
|
-
const destroyList = [];
|
|
4965
5040
|
|
|
4966
5041
|
|
|
4967
5042
|
let trigger = () => { };
|
|
4968
5043
|
/** @type {HTMLButtonElement[]} */
|
|
4969
5044
|
const triggerList = [];
|
|
4970
5045
|
if (columns.find(v => v.actions?.includes('trigger'))) {
|
|
4971
|
-
const
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
ext.classList.add('NeeloongForm-table-line-open');
|
|
5046
|
+
const form = Form(store, fieldRenderer, layout, options);
|
|
5047
|
+
if (form) {
|
|
5048
|
+
const body = root.appendChild(document.createElement('tr'));
|
|
5049
|
+
const main = body.appendChild(document.createElement('td'));
|
|
5050
|
+
main.colSpan = columns.length;
|
|
5051
|
+
body.hidden = true;
|
|
5052
|
+
trigger = () => {
|
|
5053
|
+
if (body.hidden) {
|
|
5054
|
+
body.hidden = false;
|
|
5055
|
+
for (const ext of triggerList) {
|
|
5056
|
+
ext.classList.remove('NeeloongForm-table-line-open');
|
|
5057
|
+
ext.classList.add('NeeloongForm-table-line-close');
|
|
5058
|
+
}
|
|
5059
|
+
} else {
|
|
5060
|
+
body.hidden = true;
|
|
5061
|
+
for (const ext of triggerList) {
|
|
5062
|
+
ext.classList.remove('NeeloongForm-table-line-close');
|
|
5063
|
+
ext.classList.add('NeeloongForm-table-line-open');
|
|
5064
|
+
}
|
|
4991
5065
|
}
|
|
4992
|
-
}
|
|
4993
|
-
}
|
|
4994
|
-
|
|
5066
|
+
};
|
|
5067
|
+
}
|
|
4995
5068
|
}
|
|
4996
5069
|
|
|
4997
5070
|
/**
|
|
@@ -5013,15 +5086,14 @@ function Line(store, fieldRenderer, layout, {
|
|
|
5013
5086
|
|
|
5014
5087
|
}
|
|
5015
5088
|
|
|
5016
|
-
for (const
|
|
5017
|
-
const { actions, field, pattern } =
|
|
5089
|
+
for (const column of columns) {
|
|
5090
|
+
const { actions, field, pattern } = column;
|
|
5018
5091
|
if (!actions?.length) {
|
|
5019
5092
|
const td = head.appendChild(document.createElement('td'));
|
|
5020
5093
|
const child = field && store.child(field);
|
|
5021
5094
|
if (child) {
|
|
5022
|
-
const
|
|
5023
|
-
|
|
5024
|
-
td.appendChild(el);
|
|
5095
|
+
const el = FormFieldInline(child, fieldRenderer, column, options);
|
|
5096
|
+
if (el) { td.appendChild(el); }
|
|
5025
5097
|
}
|
|
5026
5098
|
continue;
|
|
5027
5099
|
}
|
|
@@ -5041,9 +5113,9 @@ function Line(store, fieldRenderer, layout, {
|
|
|
5041
5113
|
const move = handle.appendChild(document.createElement('button'));
|
|
5042
5114
|
move.classList.add('NeeloongForm-table-move');
|
|
5043
5115
|
move.addEventListener('pointerdown', pointerdown);
|
|
5044
|
-
|
|
5116
|
+
watch(() => store.readonly || store.disabled, disabled => {
|
|
5045
5117
|
move.disabled = disabled;
|
|
5046
|
-
}, true)
|
|
5118
|
+
}, true, options.signal);
|
|
5047
5119
|
continue;
|
|
5048
5120
|
}
|
|
5049
5121
|
case 'remove': {
|
|
@@ -5051,9 +5123,9 @@ function Line(store, fieldRenderer, layout, {
|
|
|
5051
5123
|
const del = handle.appendChild(document.createElement('button'));
|
|
5052
5124
|
del.classList.add('NeeloongForm-table-remove');
|
|
5053
5125
|
del.addEventListener('click', remove);
|
|
5054
|
-
|
|
5126
|
+
watch(() => !deletable.get(), disabled => {
|
|
5055
5127
|
del.disabled = disabled;
|
|
5056
|
-
}, true)
|
|
5128
|
+
}, true, options.signal);
|
|
5057
5129
|
continue;
|
|
5058
5130
|
}
|
|
5059
5131
|
case 'serial': {
|
|
@@ -5065,28 +5137,25 @@ function Line(store, fieldRenderer, layout, {
|
|
|
5065
5137
|
}
|
|
5066
5138
|
}
|
|
5067
5139
|
|
|
5068
|
-
return
|
|
5069
|
-
for (const destroy of destroyList) {
|
|
5070
|
-
destroy();
|
|
5071
|
-
}
|
|
5072
|
-
}];
|
|
5140
|
+
return root;
|
|
5073
5141
|
}
|
|
5074
5142
|
|
|
5075
5143
|
/** @import { Store, ArrayStore } from '../Store/index.mjs' */
|
|
5076
|
-
/** @import { StoreLayout } from '../types.mjs' */
|
|
5144
|
+
/** @import { StoreLayout } from '../StoreLayout.types.mjs' */
|
|
5077
5145
|
|
|
5078
5146
|
/**
|
|
5079
5147
|
*
|
|
5148
|
+
* @template T
|
|
5149
|
+
* @param {AbortSignal | null | undefined} signal
|
|
5080
5150
|
* @param {HTMLElement} parent
|
|
5081
|
-
* @param {StoreLayout.Column[]} columns
|
|
5151
|
+
* @param {StoreLayout.Column<T>[]} columns
|
|
5082
5152
|
* @param {() => any} add
|
|
5083
5153
|
* @param {{get(): boolean}} addable
|
|
5084
5154
|
* @param {boolean?} [editable]
|
|
5155
|
+
* @returns {void}
|
|
5085
5156
|
*/
|
|
5086
|
-
function renderHead(parent, columns, add, addable, editable) {
|
|
5157
|
+
function renderHead(signal, parent, columns, add, addable, editable) {
|
|
5087
5158
|
const tr = parent.appendChild(document.createElement('tr'));
|
|
5088
|
-
/** @type {(() => void)[]} */
|
|
5089
|
-
const destroyList = [];
|
|
5090
5159
|
for (const { action, actions, width, label } of columns) {
|
|
5091
5160
|
const th = tr.appendChild(document.createElement('th'));
|
|
5092
5161
|
if (width) { th.setAttribute('width', `${width}`); }
|
|
@@ -5098,33 +5167,30 @@ function renderHead(parent, columns, add, addable, editable) {
|
|
|
5098
5167
|
const button = th.appendChild(document.createElement('button'));
|
|
5099
5168
|
button.addEventListener('click', add);
|
|
5100
5169
|
button.classList.add('NeeloongForm-table-add');
|
|
5101
|
-
|
|
5170
|
+
watch(() => !addable.get(), disabled => { button.disabled = disabled; }, true, signal);
|
|
5102
5171
|
}
|
|
5103
|
-
return () => {
|
|
5104
|
-
for (const destroy of destroyList) {
|
|
5105
|
-
destroy();
|
|
5106
|
-
}
|
|
5107
|
-
};
|
|
5108
5172
|
}
|
|
5109
5173
|
/**
|
|
5110
5174
|
*
|
|
5175
|
+
* @template T
|
|
5111
5176
|
* @param {ArrayStore} store
|
|
5112
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
5113
|
-
* @param {StoreLayout.Field
|
|
5177
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
5178
|
+
* @param {StoreLayout.Field<T>} layout
|
|
5114
5179
|
* @param {StoreLayout.Options?} options
|
|
5115
|
-
* @returns {
|
|
5180
|
+
* @returns {HTMLTableElement?}
|
|
5116
5181
|
*/
|
|
5117
5182
|
function Table(store, fieldRenderer, layout, options) {
|
|
5118
|
-
|
|
5183
|
+
if (options?.signal?.aborted) { return null; }
|
|
5184
|
+
const headerColumns = layout.columns;
|
|
5119
5185
|
const fieldList = Object.entries(store.type || {})
|
|
5120
5186
|
.filter(([k, v]) => typeof v?.type !== 'object')
|
|
5121
5187
|
.map(([field, { width, label }]) => ({ field, width, label }));
|
|
5122
|
-
/** @type {StoreLayout.Column[]} */
|
|
5188
|
+
/** @type {StoreLayout.Column<T>[]} */
|
|
5123
5189
|
let columns = [];
|
|
5124
5190
|
if (Array.isArray(headerColumns)) {
|
|
5125
5191
|
const map = new Map(fieldList.map(v => [v.field, v]));
|
|
5126
5192
|
|
|
5127
|
-
/** @type {(StoreLayout.Column | null)[]} */
|
|
5193
|
+
/** @type {(StoreLayout.Column<T> | null)[]} */
|
|
5128
5194
|
const allColumns = headerColumns.map(v => {
|
|
5129
5195
|
if (!v) { return null; }
|
|
5130
5196
|
if (typeof v === 'number') { return { placeholder: v }; }
|
|
@@ -5154,7 +5220,7 @@ function Table(store, fieldRenderer, layout, options) {
|
|
|
5154
5220
|
// }
|
|
5155
5221
|
return null;
|
|
5156
5222
|
});
|
|
5157
|
-
columns = /** @type {StoreLayout.Column[]} */(allColumns.filter(Boolean));
|
|
5223
|
+
columns = /** @type {StoreLayout.Column<T>[]} */(allColumns.filter(Boolean));
|
|
5158
5224
|
|
|
5159
5225
|
}
|
|
5160
5226
|
if (!columns.length) {
|
|
@@ -5165,11 +5231,10 @@ function Table(store, fieldRenderer, layout, options) {
|
|
|
5165
5231
|
}
|
|
5166
5232
|
|
|
5167
5233
|
const table = document.createElement('table');
|
|
5168
|
-
table.
|
|
5234
|
+
table.classList.add('NeeloongForm-table');
|
|
5169
5235
|
const thead = table.appendChild(document.createElement('thead'));
|
|
5170
5236
|
|
|
5171
|
-
const addable = new Signal.Computed(() => store.addable);
|
|
5172
|
-
const deletable = { get: () => Boolean(options?.editable) };
|
|
5237
|
+
const addable = new Signal.Computed(() => !store.readonly && !store.disabled && store.addable);
|
|
5173
5238
|
function add() {
|
|
5174
5239
|
const data = {};
|
|
5175
5240
|
store.add(data);
|
|
@@ -5206,15 +5271,13 @@ function Table(store, fieldRenderer, layout, options) {
|
|
|
5206
5271
|
dragRow = -1;
|
|
5207
5272
|
|
|
5208
5273
|
}
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
destroyList.push(renderHead(thead, columns, add, addable, Boolean(options?.editable)));
|
|
5212
|
-
switch (layout?.tableFoot) {
|
|
5274
|
+
renderHead(options?.signal, thead, columns, add, addable, Boolean(options?.editable));
|
|
5275
|
+
switch (layout.tableFoot) {
|
|
5213
5276
|
default:
|
|
5214
5277
|
case 'header': {
|
|
5215
5278
|
const tfoot = table.appendChild(document.createElement('tfoot'));
|
|
5216
5279
|
tfoot.addEventListener('dragenter', () => { dragenter(); });
|
|
5217
|
-
|
|
5280
|
+
renderHead(options?.signal, tfoot, columns, add, addable, Boolean(options?.editable));
|
|
5218
5281
|
break;
|
|
5219
5282
|
}
|
|
5220
5283
|
case 'add': {
|
|
@@ -5226,39 +5289,34 @@ function Table(store, fieldRenderer, layout, options) {
|
|
|
5226
5289
|
const button = th.appendChild(document.createElement('button'));
|
|
5227
5290
|
button.addEventListener('click', add);
|
|
5228
5291
|
button.classList.add('NeeloongForm-table-foot-add');
|
|
5229
|
-
|
|
5292
|
+
watch(() => !addable.get(), disabled => { button.disabled = disabled; }, true, options?.signal);
|
|
5230
5293
|
break;
|
|
5231
5294
|
}
|
|
5232
5295
|
case 'none':
|
|
5233
5296
|
}
|
|
5234
|
-
|
|
5235
|
-
/** @type {Map<Store, [HTMLTableSectionElement, () => void]>} */
|
|
5297
|
+
/** @type {Map<Store, [HTMLTableSectionElement, AbortController]>} */
|
|
5236
5298
|
let seMap = new Map();
|
|
5237
|
-
|
|
5238
|
-
function destroyMap(map) {
|
|
5239
|
-
for (const [el, destroy] of map.values()) {
|
|
5240
|
-
destroy();
|
|
5241
|
-
el.remove();
|
|
5242
|
-
}
|
|
5243
|
-
|
|
5244
|
-
}
|
|
5245
|
-
const childrenResult = watch(() => store.children, function render(children) {
|
|
5299
|
+
watch(() => store.children, children => {
|
|
5246
5300
|
let nextNode = thead.nextSibling;
|
|
5247
5301
|
const oldSeMap = seMap;
|
|
5248
5302
|
seMap = new Map();
|
|
5249
5303
|
for (let child of children) {
|
|
5250
5304
|
const old = oldSeMap.get(child);
|
|
5251
5305
|
if (!old) {
|
|
5252
|
-
const
|
|
5306
|
+
const ac = new AbortController();
|
|
5307
|
+
const el = Line(child, fieldRenderer, layout, {
|
|
5253
5308
|
columns,
|
|
5309
|
+
deletable: new Signal.Computed(() => !store.readonly && !store.disabled && child.removable),
|
|
5254
5310
|
remove: remove.bind(null, child),
|
|
5255
5311
|
dragenter: dragenter.bind(null, child),
|
|
5256
5312
|
dragstart: dragstart.bind(null, child),
|
|
5257
5313
|
dragend,
|
|
5258
|
-
|
|
5259
|
-
|
|
5314
|
+
}, {
|
|
5315
|
+
...options,
|
|
5316
|
+
signal: options?.signal ? AbortSignal.any([options?.signal, ac.signal]) : ac.signal,
|
|
5317
|
+
});
|
|
5260
5318
|
table.insertBefore(el, nextNode);
|
|
5261
|
-
seMap.set(child, [el,
|
|
5319
|
+
seMap.set(child, [el, ac]);
|
|
5262
5320
|
continue;
|
|
5263
5321
|
}
|
|
5264
5322
|
oldSeMap.delete(child);
|
|
@@ -5269,29 +5327,25 @@ function Table(store, fieldRenderer, layout, options) {
|
|
|
5269
5327
|
}
|
|
5270
5328
|
table.insertBefore(old[0], nextNode);
|
|
5271
5329
|
}
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
return [table, () => {
|
|
5276
|
-
start.remove();
|
|
5277
|
-
thead.remove();
|
|
5278
|
-
destroyMap(seMap);
|
|
5279
|
-
childrenResult();
|
|
5280
|
-
for (const destroy of destroyList) {
|
|
5281
|
-
destroy();
|
|
5330
|
+
for (const [el, ac] of oldSeMap.values()) {
|
|
5331
|
+
el.remove();
|
|
5332
|
+
ac.abort();
|
|
5282
5333
|
}
|
|
5283
|
-
}
|
|
5334
|
+
}, true, options?.signal);
|
|
5335
|
+
|
|
5336
|
+
return table;
|
|
5284
5337
|
}
|
|
5285
5338
|
|
|
5286
|
-
/** @import { StoreLayout } from '../types.mjs' */
|
|
5339
|
+
/** @import { StoreLayout } from '../StoreLayout.types.mjs' */
|
|
5287
5340
|
|
|
5288
5341
|
/**
|
|
5289
5342
|
*
|
|
5290
5343
|
* @param {HTMLElement} root
|
|
5291
|
-
* @param {StoreLayout.Grid
|
|
5344
|
+
* @param {StoreLayout.Grid} layout
|
|
5345
|
+
* @returns {void}
|
|
5292
5346
|
*/
|
|
5293
5347
|
function bindGrid(root, layout) {
|
|
5294
|
-
const { colStart, colSpan, colEnd, rowStart, rowSpan, rowEnd } = layout
|
|
5348
|
+
const { colStart, colSpan, colEnd, rowStart, rowSpan, rowEnd } = layout;
|
|
5295
5349
|
root.classList.add(`NeeloongForm-item-grid`);
|
|
5296
5350
|
if (colStart && colEnd) {
|
|
5297
5351
|
root.style.gridColumn = `${colStart} / ${colEnd}`;
|
|
@@ -5307,226 +5361,126 @@ function bindGrid(root, layout) {
|
|
|
5307
5361
|
} else if (rowSpan) {
|
|
5308
5362
|
root.style.gridRow = `span ${rowSpan}`;
|
|
5309
5363
|
}
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
5364
|
}
|
|
5315
5365
|
|
|
5316
|
-
/** @import {
|
|
5366
|
+
/** @import { StoreLayout } from '../StoreLayout.types.mjs' */
|
|
5317
5367
|
|
|
5318
5368
|
/**
|
|
5319
|
-
*
|
|
5320
|
-
* @
|
|
5321
|
-
* @
|
|
5322
|
-
* @
|
|
5323
|
-
|
|
5324
|
-
function bindErrored(root, values) {
|
|
5325
|
-
return effect(() => {
|
|
5326
|
-
if (values?.error) {
|
|
5327
|
-
root.classList.add('NeeloongForm-item-errored');
|
|
5328
|
-
} else {
|
|
5329
|
-
root.classList.remove('NeeloongForm-item-errored');
|
|
5330
|
-
}
|
|
5331
|
-
});
|
|
5332
|
-
}
|
|
5333
|
-
|
|
5334
|
-
/**
|
|
5335
|
-
*
|
|
5336
|
-
* @param {HTMLElement} root
|
|
5337
|
-
* @param {{ required?: boolean | null }} [values]
|
|
5338
|
-
* @returns {() => void}
|
|
5369
|
+
* @typedef {object} CellValues
|
|
5370
|
+
* @property {string?} [label]
|
|
5371
|
+
* @property {string?} [description]
|
|
5372
|
+
* @property {string?} [error]
|
|
5373
|
+
* @property {boolean?} [required]
|
|
5339
5374
|
*/
|
|
5340
|
-
function bindRequired(root, values) {
|
|
5341
|
-
return effect(() => {
|
|
5342
|
-
if (values?.required) {
|
|
5343
|
-
root.classList.add('NeeloongForm-item-required');
|
|
5344
|
-
} else {
|
|
5345
|
-
root.classList.remove('NeeloongForm-item-required');
|
|
5346
|
-
}
|
|
5347
|
-
});
|
|
5348
|
-
}
|
|
5349
|
-
|
|
5350
|
-
/** @import { CellValues } from './createCell.mjs' */
|
|
5351
|
-
|
|
5352
5375
|
/**
|
|
5353
5376
|
*
|
|
5377
|
+
* @param {AbortSignal | null | undefined} signal
|
|
5354
5378
|
* @param {CellValues} [values]
|
|
5355
|
-
* @returns {[HTMLDivElement,
|
|
5379
|
+
* @returns {[HTMLDivElement, HTMLDivElement]}
|
|
5356
5380
|
*/
|
|
5357
|
-
function createStdCell(values) {
|
|
5358
|
-
/** @type {(() => void)[]} */
|
|
5359
|
-
const destroyList = [];
|
|
5381
|
+
function createStdCell(signal, values) {
|
|
5360
5382
|
const root = document.createElement('div');
|
|
5361
|
-
root.className = 'NeeloongForm-item';
|
|
5362
|
-
destroyList.push(bindRequired(root, values));
|
|
5363
|
-
|
|
5364
5383
|
const label = root.appendChild(document.createElement('div'));
|
|
5365
|
-
label.
|
|
5366
|
-
|
|
5384
|
+
label.classList.add('NeeloongForm-item-label');
|
|
5385
|
+
effect(() => label.innerText = values?.label || '', signal);
|
|
5367
5386
|
|
|
5368
5387
|
const content = root.appendChild(document.createElement('div'));
|
|
5369
|
-
content.
|
|
5388
|
+
content.classList.add('NeeloongForm-item-content');
|
|
5370
5389
|
|
|
5371
5390
|
const description = root.appendChild(document.createElement('div'));
|
|
5372
|
-
description.
|
|
5373
|
-
|
|
5391
|
+
description.classList.add('NeeloongForm-item-description');
|
|
5392
|
+
effect(() => description.innerText = values?.description || '', signal);
|
|
5374
5393
|
const error = root.appendChild(document.createElement('div'));
|
|
5375
|
-
error.
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
return [root, () => {
|
|
5380
|
-
for (const destroy of destroyList) {
|
|
5381
|
-
destroy();
|
|
5382
|
-
}
|
|
5383
|
-
}, content, destroyList];
|
|
5394
|
+
error.classList.add('NeeloongForm-item-error');
|
|
5395
|
+
effect(() => error.innerText = values?.error || '', signal);
|
|
5396
|
+
return [root, content];
|
|
5384
5397
|
|
|
5385
5398
|
|
|
5386
5399
|
}
|
|
5387
5400
|
|
|
5388
|
-
/** @import { CellValues } from './createCell.mjs' */
|
|
5389
|
-
|
|
5390
|
-
/**
|
|
5391
|
-
*
|
|
5392
|
-
* @param {CellValues} [values]
|
|
5393
|
-
* @returns {[HTMLElement, () => void, HTMLElement, (() => void)[]]}
|
|
5394
|
-
*/
|
|
5395
|
-
function createCollapseCell(values) {
|
|
5396
|
-
/** @type {(() => void)[]} */
|
|
5397
|
-
const destroyList = [];
|
|
5398
|
-
const root = document.createElement('details');
|
|
5399
|
-
root.className = 'NeeloongForm-item';
|
|
5400
|
-
destroyList.push(bindRequired(root, values));
|
|
5401
|
-
|
|
5402
|
-
root.open = true;
|
|
5403
|
-
const summary = root.appendChild(document.createElement('summary'));
|
|
5404
|
-
destroyList.push(effect(() => summary.innerText = values?.label || ''));
|
|
5405
|
-
destroyList.push(bindErrored(root, values));
|
|
5406
|
-
|
|
5407
|
-
return [root, () => {
|
|
5408
|
-
for (const destroy of destroyList) {
|
|
5409
|
-
destroy();
|
|
5410
|
-
}
|
|
5411
|
-
}, root, destroyList];
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
}
|
|
5415
|
-
|
|
5416
|
-
/** @import { CellValues } from './createCell.mjs' */
|
|
5417
|
-
|
|
5418
|
-
/**
|
|
5419
|
-
*
|
|
5420
|
-
* @param {CellValues} [values]
|
|
5421
|
-
* @returns {[HTMLDivElement, () => void, HTMLDivElement, (() => void)[]]}
|
|
5422
|
-
*/
|
|
5423
|
-
function createNullCell(values) {
|
|
5424
|
-
/** @type {(() => void)[]} */
|
|
5425
|
-
const destroyList = [];
|
|
5426
|
-
const root = document.createElement('div');
|
|
5427
|
-
root.className = 'NeeloongForm-item';
|
|
5428
|
-
destroyList.push(bindRequired(root, values));
|
|
5429
|
-
destroyList.push(bindErrored(root, values));
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
return [root, () => {
|
|
5433
|
-
for (const destroy of destroyList) {
|
|
5434
|
-
destroy();
|
|
5435
|
-
}
|
|
5436
|
-
}, root, destroyList];
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
}
|
|
5440
|
-
|
|
5441
|
-
/** @import { CellValues } from './createCell.mjs' */
|
|
5442
|
-
|
|
5443
|
-
/**
|
|
5444
|
-
*
|
|
5445
|
-
* @param {CellValues} [values]
|
|
5446
|
-
* @returns {[HTMLElement, () => void, HTMLElement, (() => void)[]]}
|
|
5447
|
-
*/
|
|
5448
|
-
function createFieldsetCell(values) {
|
|
5449
|
-
/** @type {(() => void)[]} */
|
|
5450
|
-
const destroyList = [];
|
|
5451
|
-
const root = document.createElement('fieldset');
|
|
5452
|
-
root.className = 'NeeloongForm-item';
|
|
5453
|
-
destroyList.push(bindRequired(root, values));
|
|
5454
|
-
|
|
5455
|
-
const legend = root.appendChild(document.createElement('legend'));
|
|
5456
|
-
destroyList.push(effect(() => legend.innerText = values?.label || ''));
|
|
5457
|
-
destroyList.push(bindErrored(root, values));
|
|
5458
|
-
|
|
5459
|
-
return [root, () => {
|
|
5460
|
-
for (const destroy of destroyList) {
|
|
5461
|
-
destroy();
|
|
5462
|
-
}
|
|
5463
|
-
}, root, destroyList];
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
}
|
|
5467
|
-
|
|
5468
|
-
/** @import { StoreLayout } from '../types.mjs' */
|
|
5469
|
-
|
|
5470
|
-
/**
|
|
5471
|
-
* @typedef {object} CellValues
|
|
5472
|
-
* @property {string?} [label]
|
|
5473
|
-
* @property {string?} [description]
|
|
5474
|
-
* @property {string?} [error]
|
|
5475
|
-
* @property {boolean?} [required]
|
|
5476
|
-
*/
|
|
5477
5401
|
/**
|
|
5478
5402
|
*
|
|
5479
|
-
* @param {
|
|
5403
|
+
* @param {AbortSignal | null | undefined} signal
|
|
5404
|
+
* @param {StoreLayout.Grid} layout
|
|
5480
5405
|
* @param {CellValues} [values]
|
|
5481
5406
|
* @param {StoreLayout.Grid['cell']?} [defCell]
|
|
5482
5407
|
* @param {boolean?} [blockOnly]
|
|
5483
|
-
* @returns {[HTMLElement,
|
|
5408
|
+
* @returns {[HTMLElement, HTMLElement]}
|
|
5484
5409
|
*/
|
|
5485
|
-
function createCell(layout, values, defCell, blockOnly) {
|
|
5410
|
+
function createCell(signal, layout, values, defCell, blockOnly) {
|
|
5486
5411
|
/**
|
|
5487
5412
|
*
|
|
5488
5413
|
* @param {string?} [cellType]
|
|
5489
|
-
* @returns {[HTMLElement,
|
|
5414
|
+
* @returns {[HTMLElement, HTMLElement]?}
|
|
5490
5415
|
*/
|
|
5491
5416
|
function create(cellType) {
|
|
5492
5417
|
if (!cellType) { return null; }
|
|
5493
5418
|
if (!blockOnly) {
|
|
5494
5419
|
switch (cellType) {
|
|
5495
5420
|
case 'inline': {
|
|
5496
|
-
const
|
|
5497
|
-
bindGrid(
|
|
5498
|
-
return
|
|
5421
|
+
const [root, content] = createStdCell(signal, values);
|
|
5422
|
+
bindGrid(root, layout);
|
|
5423
|
+
return [root, content];
|
|
5499
5424
|
}
|
|
5500
5425
|
case 'base': {
|
|
5501
|
-
const
|
|
5502
|
-
bindGrid(
|
|
5503
|
-
return
|
|
5426
|
+
const root = document.createElement('div');
|
|
5427
|
+
bindGrid(root, layout);
|
|
5428
|
+
return [root, root];
|
|
5504
5429
|
}
|
|
5505
5430
|
}
|
|
5506
5431
|
}
|
|
5507
5432
|
switch (cellType) {
|
|
5508
|
-
case 'block': return createStdCell(values);
|
|
5509
|
-
case 'fieldset':
|
|
5510
|
-
|
|
5433
|
+
case 'block': return createStdCell(signal, values);
|
|
5434
|
+
case 'fieldset': {
|
|
5435
|
+
const root = document.createElement('fieldset');
|
|
5436
|
+
const legend = root.appendChild(document.createElement('legend'));
|
|
5437
|
+
effect(() => legend.innerText = values?.label || '', signal);
|
|
5438
|
+
return [root, root];
|
|
5439
|
+
}
|
|
5440
|
+
case 'collapse': {
|
|
5441
|
+
const root = document.createElement('details');
|
|
5442
|
+
root.open = true;
|
|
5443
|
+
const summary = root.appendChild(document.createElement('summary'));
|
|
5444
|
+
effect(() => summary.innerText = values?.label || '', signal);
|
|
5445
|
+
return [root, root];
|
|
5446
|
+
}
|
|
5511
5447
|
}
|
|
5512
5448
|
return null;
|
|
5513
5449
|
}
|
|
5514
|
-
|
|
5450
|
+
const [root, content] = create(layout.cell) || create(defCell) || createStdCell(signal, values);
|
|
5451
|
+
root.classList.add('NeeloongForm-item');
|
|
5452
|
+
effect(() => {
|
|
5453
|
+
if (values?.error) {
|
|
5454
|
+
root.classList.add('NeeloongForm-item-errored');
|
|
5455
|
+
} else {
|
|
5456
|
+
root.classList.remove('NeeloongForm-item-errored');
|
|
5457
|
+
}
|
|
5458
|
+
}, signal);
|
|
5459
|
+
effect(() => {
|
|
5460
|
+
if (values?.required) {
|
|
5461
|
+
root.classList.add('NeeloongForm-item-required');
|
|
5462
|
+
} else {
|
|
5463
|
+
root.classList.remove('NeeloongForm-item-required');
|
|
5464
|
+
}
|
|
5465
|
+
}, signal);
|
|
5466
|
+
return [root, content];
|
|
5515
5467
|
}
|
|
5516
5468
|
|
|
5517
5469
|
/** @import { Store } from '../Store/index.mjs' */
|
|
5518
5470
|
/** @import { State } from './Tree.mjs' */
|
|
5519
|
-
/** @import { StoreLayout } from '../types.mjs' */
|
|
5471
|
+
/** @import { StoreLayout } from '../StoreLayout.types.mjs' */
|
|
5520
5472
|
|
|
5521
5473
|
/**
|
|
5522
5474
|
*
|
|
5475
|
+
* @template T
|
|
5523
5476
|
* @param {Store<any, any>} store
|
|
5524
5477
|
* @param {Signal.State<Store<any, any>?>} currentStore
|
|
5525
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
5526
|
-
* @param {StoreLayout.Field
|
|
5527
|
-
* @param {State}
|
|
5478
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
5479
|
+
* @param {StoreLayout.Field<T>} layout
|
|
5480
|
+
* @param {Signal.State<State>} state
|
|
5528
5481
|
* @param {object} option
|
|
5529
|
-
* @param {
|
|
5482
|
+
* @param {{get(): boolean}} option.addable
|
|
5483
|
+
* @param {StoreLayout.Column<T>[]} option.columns
|
|
5530
5484
|
* @param {() => void} option.remove
|
|
5531
5485
|
* @param {(el: HTMLElement) => () => void} option.dragenter
|
|
5532
5486
|
* @param {() => void} option.dragstart
|
|
@@ -5536,15 +5490,13 @@ function createCell(layout, values, defCell, blockOnly) {
|
|
|
5536
5490
|
* @param {() => void} option.addNode
|
|
5537
5491
|
* @param {(store: Store<any, any>) => () => void} option.createDetails
|
|
5538
5492
|
* @param {StoreLayout.Options?} options
|
|
5539
|
-
|
|
5540
|
-
* @returns {[HTMLElement, () => void, (s: State) => void]}
|
|
5493
|
+
* @returns {HTMLElement}
|
|
5541
5494
|
*/
|
|
5542
5495
|
function TreeLine(
|
|
5543
|
-
store, currentStore, fieldRenderer, layout,
|
|
5544
|
-
columns,
|
|
5545
|
-
remove, dragenter, dragstart, dragend,
|
|
5496
|
+
store, currentStore, fieldRenderer, layout, state, {
|
|
5497
|
+
columns, addable, deletable,
|
|
5498
|
+
remove, dragenter, dragstart, dragend, addNode, drop, createDetails,
|
|
5546
5499
|
}, options) {
|
|
5547
|
-
const state = new Signal.State(initState);
|
|
5548
5500
|
const root = document.createElement('div');
|
|
5549
5501
|
root.addEventListener('dragstart', (event) => {
|
|
5550
5502
|
if (event.target !== event.currentTarget) { return; }
|
|
@@ -5552,23 +5504,21 @@ function TreeLine(
|
|
|
5552
5504
|
});
|
|
5553
5505
|
root.addEventListener('dragend', dragend);
|
|
5554
5506
|
|
|
5555
|
-
/** @type {(() => void)[]} */
|
|
5556
|
-
const destroyList = [];
|
|
5557
5507
|
root.classList.add('NeeloongForm-tree-item');
|
|
5558
5508
|
|
|
5559
|
-
|
|
5509
|
+
effect(() => {
|
|
5560
5510
|
if (currentStore.get() === store) {
|
|
5561
5511
|
root.classList.add('NeeloongForm-tree-current');
|
|
5562
5512
|
} else {
|
|
5563
5513
|
root.classList.remove('NeeloongForm-tree-current');
|
|
5564
5514
|
}
|
|
5565
|
-
})
|
|
5566
|
-
|
|
5515
|
+
}, options?.signal);
|
|
5516
|
+
effect(() => {
|
|
5567
5517
|
const level = state.get().level;
|
|
5568
5518
|
root.style.setProperty(`--NeeloongForm-tree-level`, `${level}`);
|
|
5569
|
-
})
|
|
5519
|
+
}, options?.signal);
|
|
5570
5520
|
|
|
5571
|
-
|
|
5521
|
+
effect(() => { root.hidden = state.get().hidden; }, options?.signal);
|
|
5572
5522
|
|
|
5573
5523
|
|
|
5574
5524
|
/** @type {HTMLButtonElement[]} */
|
|
@@ -5606,9 +5556,9 @@ function TreeLine(
|
|
|
5606
5556
|
}
|
|
5607
5557
|
close = createDetails(store);
|
|
5608
5558
|
}
|
|
5609
|
-
const moveStart = layout
|
|
5610
|
-
const click = moveStart ? null : layout
|
|
5611
|
-
: layout
|
|
5559
|
+
const moveStart = layout.mainMethod === 'move' ? pointerdown : null;
|
|
5560
|
+
const click = moveStart ? null : layout.mainMethod === 'collapse' ? switchCollapsed
|
|
5561
|
+
: layout.mainMethod === 'trigger' ? trigger : open;
|
|
5612
5562
|
|
|
5613
5563
|
const line = root.appendChild(document.createElement('div'));
|
|
5614
5564
|
line.classList.add('NeeloongForm-tree-line');
|
|
@@ -5621,9 +5571,9 @@ function TreeLine(
|
|
|
5621
5571
|
dropChildren.addEventListener('dragover', (e) => e.preventDefault());
|
|
5622
5572
|
dropFront.addEventListener('drop', () => drop());
|
|
5623
5573
|
dropChildren.addEventListener('drop', () => drop(true));
|
|
5624
|
-
|
|
5574
|
+
effect(() => {
|
|
5625
5575
|
dropFront.hidden = dropChildren.hidden = !state.get().droppable;
|
|
5626
|
-
})
|
|
5576
|
+
}, options?.signal);
|
|
5627
5577
|
|
|
5628
5578
|
let dragleave = () => { };
|
|
5629
5579
|
dropFront.addEventListener('dragenter', () => dragleave = dragenter(dropFront));
|
|
@@ -5631,7 +5581,8 @@ function TreeLine(
|
|
|
5631
5581
|
dropFront.addEventListener('dragleave', () => dragleave());
|
|
5632
5582
|
dropChildren.addEventListener('dragleave', () => dragleave());
|
|
5633
5583
|
|
|
5634
|
-
for (const
|
|
5584
|
+
for (const column of columns) {
|
|
5585
|
+
const { actions, pattern, placeholder, width, field } = column;
|
|
5635
5586
|
if (!actions?.length) {
|
|
5636
5587
|
const td = line.appendChild(document.createElement('div'));
|
|
5637
5588
|
td.classList.add('NeeloongForm-tree-cell');
|
|
@@ -5640,9 +5591,8 @@ function TreeLine(
|
|
|
5640
5591
|
if (field) {
|
|
5641
5592
|
const child = store.child(field);
|
|
5642
5593
|
if (!child) { continue; }
|
|
5643
|
-
const
|
|
5644
|
-
|
|
5645
|
-
td.appendChild(el);
|
|
5594
|
+
const el = FormFieldInline(child, fieldRenderer, column, { ...options, editable: false });
|
|
5595
|
+
if (el) { td.appendChild(el); }
|
|
5646
5596
|
continue;
|
|
5647
5597
|
}
|
|
5648
5598
|
if (typeof placeholder === 'number') {
|
|
@@ -5680,9 +5630,9 @@ function TreeLine(
|
|
|
5680
5630
|
const move = line.appendChild(document.createElement('button'));
|
|
5681
5631
|
move.classList.add('NeeloongForm-tree-move');
|
|
5682
5632
|
move.addEventListener('pointerdown', pointerdown);
|
|
5683
|
-
|
|
5633
|
+
watch(() => store.readonly || store.disabled, disabled => {
|
|
5684
5634
|
move.disabled = disabled;
|
|
5685
|
-
}, true)
|
|
5635
|
+
}, true, options.signal);
|
|
5686
5636
|
continue;
|
|
5687
5637
|
}
|
|
5688
5638
|
case 'add': {
|
|
@@ -5690,9 +5640,9 @@ function TreeLine(
|
|
|
5690
5640
|
const move = line.appendChild(document.createElement('button'));
|
|
5691
5641
|
move.classList.add('NeeloongForm-tree-add');
|
|
5692
5642
|
move.addEventListener('click', addNode);
|
|
5693
|
-
|
|
5643
|
+
watch(() => !addable.get(), disabled => {
|
|
5694
5644
|
move.disabled = disabled;
|
|
5695
|
-
}, true)
|
|
5645
|
+
}, true, options.signal);
|
|
5696
5646
|
continue;
|
|
5697
5647
|
}
|
|
5698
5648
|
case 'remove': {
|
|
@@ -5700,9 +5650,9 @@ function TreeLine(
|
|
|
5700
5650
|
const del = line.appendChild(document.createElement('button'));
|
|
5701
5651
|
del.classList.add('NeeloongForm-tree-remove');
|
|
5702
5652
|
del.addEventListener('click', remove);
|
|
5703
|
-
|
|
5653
|
+
watch(() => !deletable.get(), disabled => {
|
|
5704
5654
|
del.disabled = disabled;
|
|
5705
|
-
}, true)
|
|
5655
|
+
}, true, options.signal);
|
|
5706
5656
|
continue;
|
|
5707
5657
|
}
|
|
5708
5658
|
case 'serial': {
|
|
@@ -5713,7 +5663,7 @@ function TreeLine(
|
|
|
5713
5663
|
}
|
|
5714
5664
|
}
|
|
5715
5665
|
}
|
|
5716
|
-
|
|
5666
|
+
effect(() => {
|
|
5717
5667
|
const s = state.get();
|
|
5718
5668
|
if (!s.hasChildren) {
|
|
5719
5669
|
for (const btn of collapseList) {
|
|
@@ -5734,17 +5684,13 @@ function TreeLine(
|
|
|
5734
5684
|
btn.disabled = false;
|
|
5735
5685
|
}
|
|
5736
5686
|
}
|
|
5737
|
-
})
|
|
5687
|
+
}, options?.signal);
|
|
5738
5688
|
|
|
5739
|
-
return
|
|
5740
|
-
for (const destroy of destroyList) {
|
|
5741
|
-
destroy();
|
|
5742
|
-
}
|
|
5743
|
-
}, s => state.set(s)];
|
|
5689
|
+
return root;
|
|
5744
5690
|
}
|
|
5745
5691
|
|
|
5746
5692
|
/** @import { Store, ArrayStore } from '../Store/index.mjs' */
|
|
5747
|
-
/** @import { StoreLayout } from '../types.mjs' */
|
|
5693
|
+
/** @import { StoreLayout } from '../StoreLayout.types.mjs' */
|
|
5748
5694
|
|
|
5749
5695
|
const verticalWritingMode = new Set([
|
|
5750
5696
|
'vertical-lr', 'vertical-rl', 'sideways-lr', 'sideways-rl',
|
|
@@ -5850,22 +5796,24 @@ function createState(store, states, drag, levelKey, index) {
|
|
|
5850
5796
|
}
|
|
5851
5797
|
/**
|
|
5852
5798
|
*
|
|
5799
|
+
* @template T
|
|
5853
5800
|
* @param {ArrayStore} store
|
|
5854
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
5855
|
-
* @param {StoreLayout.Field
|
|
5801
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
5802
|
+
* @param {StoreLayout.Field<T>} layout
|
|
5856
5803
|
* @param {StoreLayout.Options?} options
|
|
5857
|
-
* @returns {
|
|
5804
|
+
* @returns {HTMLElement?}
|
|
5858
5805
|
*/
|
|
5859
5806
|
function Tree(store, fieldRenderer, layout, options) {
|
|
5860
|
-
|
|
5807
|
+
if (options?.signal?.aborted) { return null; }
|
|
5808
|
+
const headerColumns = layout.columns;
|
|
5861
5809
|
const fieldList = Object.entries(store.type || {})
|
|
5862
5810
|
.filter(([k, v]) => typeof v?.type !== 'object')
|
|
5863
5811
|
.map(([field, { width, label }]) => ({ field, width, label }));
|
|
5864
|
-
/** @type {StoreLayout.Column[]} */
|
|
5812
|
+
/** @type {StoreLayout.Column<T>[]} */
|
|
5865
5813
|
let columns = [];
|
|
5866
5814
|
if (Array.isArray(headerColumns)) {
|
|
5867
5815
|
const map = new Map(fieldList.map(v => [v.field, v]));
|
|
5868
|
-
/** @type {(StoreLayout.Column | null)[]} */
|
|
5816
|
+
/** @type {(StoreLayout.Column<T> | null)[]} */
|
|
5869
5817
|
const allColumns = headerColumns.map(v => {
|
|
5870
5818
|
if (!v) { return null; }
|
|
5871
5819
|
if (typeof v === 'number') { return { placeholder: v }; }
|
|
@@ -5898,7 +5846,7 @@ function Tree(store, fieldRenderer, layout, options) {
|
|
|
5898
5846
|
}
|
|
5899
5847
|
return null;
|
|
5900
5848
|
});
|
|
5901
|
-
columns = /** @type {StoreLayout.Column[]} */(allColumns.filter(Boolean));
|
|
5849
|
+
columns = /** @type {StoreLayout.Column<T>[]} */(allColumns.filter(Boolean));
|
|
5902
5850
|
}
|
|
5903
5851
|
if (!columns.length) {
|
|
5904
5852
|
columns = [
|
|
@@ -5910,13 +5858,13 @@ function Tree(store, fieldRenderer, layout, options) {
|
|
|
5910
5858
|
|
|
5911
5859
|
|
|
5912
5860
|
const root = document.createElement('div');
|
|
5913
|
-
root.
|
|
5861
|
+
root.classList.add('NeeloongForm-tree');
|
|
5914
5862
|
const main = root.appendChild(document.createElement('div'));
|
|
5915
|
-
main.
|
|
5863
|
+
main.classList.add('NeeloongForm-tree-main');
|
|
5916
5864
|
const splitter = root.appendChild(document.createElement('div'));
|
|
5917
|
-
splitter.
|
|
5865
|
+
splitter.classList.add('NeeloongForm-tree-splitter');
|
|
5918
5866
|
const details = root.appendChild(document.createElement('div'));
|
|
5919
|
-
details.
|
|
5867
|
+
details.classList.add('NeeloongForm-tree-details');
|
|
5920
5868
|
splitter.hidden = true;
|
|
5921
5869
|
details.hidden = true;
|
|
5922
5870
|
/** @type {number?} */
|
|
@@ -5980,9 +5928,8 @@ function Tree(store, fieldRenderer, layout, options) {
|
|
|
5980
5928
|
});
|
|
5981
5929
|
|
|
5982
5930
|
|
|
5983
|
-
/** @type {
|
|
5984
|
-
|
|
5985
|
-
let destroyDetails = () => { };
|
|
5931
|
+
/** @type {AbortController?} */
|
|
5932
|
+
let detailAbortController = null;
|
|
5986
5933
|
const detailsStore = new Signal.State(/** @type{Store<any, any>?}*/(null));
|
|
5987
5934
|
/**
|
|
5988
5935
|
*
|
|
@@ -5990,32 +5937,42 @@ function Tree(store, fieldRenderer, layout, options) {
|
|
|
5990
5937
|
* @returns
|
|
5991
5938
|
*/
|
|
5992
5939
|
function createDetails(store) {
|
|
5993
|
-
if (
|
|
5994
|
-
|
|
5940
|
+
if (options?.signal?.aborted) { return () => { }; }
|
|
5941
|
+
if (detailsStore.get() === store && detailAbortController) {
|
|
5942
|
+
const ac = detailAbortController;
|
|
5943
|
+
return () => { ac.abort(); };
|
|
5944
|
+
}
|
|
5945
|
+
detailAbortController?.abort();
|
|
5995
5946
|
detailsStore.set(store);
|
|
5996
|
-
const
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
5947
|
+
const ac = new AbortController();
|
|
5948
|
+
detailAbortController = ac;
|
|
5949
|
+
const signal = options?.signal ? AbortSignal.any([options?.signal, ac.signal]) : ac.signal;
|
|
5950
|
+
const form = Form(store, fieldRenderer, layout, {
|
|
5951
|
+
...options,
|
|
5952
|
+
signal: options?.signal ? AbortSignal.any([options?.signal, signal]) : signal,
|
|
5953
|
+
});
|
|
5954
|
+
signal.addEventListener('abort', () => {
|
|
6004
5955
|
detailsStore.set(null);
|
|
6005
|
-
form.remove();
|
|
6006
|
-
destroy();
|
|
6007
5956
|
stopMove();
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
|
|
6011
|
-
|
|
5957
|
+
}, { once: true });
|
|
5958
|
+
if (form) {
|
|
5959
|
+
details.appendChild(form);
|
|
5960
|
+
details.hidden = false;
|
|
5961
|
+
splitter.hidden = false;
|
|
5962
|
+
signal.addEventListener('abort', () => {
|
|
5963
|
+
form.remove();
|
|
5964
|
+
splitter.hidden = true;
|
|
5965
|
+
details.hidden = true;
|
|
5966
|
+
}, { once: true });
|
|
5967
|
+
|
|
5968
|
+
}
|
|
5969
|
+
return () => { ac.abort(); };
|
|
6012
5970
|
|
|
6013
5971
|
}
|
|
6014
5972
|
|
|
6015
5973
|
|
|
6016
|
-
const levelKey = layout
|
|
6017
|
-
const addable = new Signal.Computed(() => store.addable);
|
|
6018
|
-
const deletable = { get: () => Boolean(options?.editable) };
|
|
5974
|
+
const levelKey = layout.levelKey || 'level';
|
|
5975
|
+
const addable = new Signal.Computed(() => !store.readonly && !store.disabled && store.addable);
|
|
6019
5976
|
/**
|
|
6020
5977
|
*
|
|
6021
5978
|
* @param {number} parent
|
|
@@ -6144,7 +6101,7 @@ function Tree(store, fieldRenderer, layout, options) {
|
|
|
6144
6101
|
const button = main.appendChild(document.createElement('button'));
|
|
6145
6102
|
button.addEventListener('click', () => addNode(-1));
|
|
6146
6103
|
button.classList.add('NeeloongForm-tree-head-add');
|
|
6147
|
-
|
|
6104
|
+
watch(() => !addable.get(), disabled => { button.disabled = disabled; }, true, options.signal);
|
|
6148
6105
|
}
|
|
6149
6106
|
const start = main.appendChild(document.createComment(''));
|
|
6150
6107
|
if (options?.editable) {
|
|
@@ -6164,21 +6121,13 @@ function Tree(store, fieldRenderer, layout, options) {
|
|
|
6164
6121
|
dropFront.addEventListener('drop', () => drop());
|
|
6165
6122
|
|
|
6166
6123
|
|
|
6167
|
-
|
|
6124
|
+
watch(() => !addable.get(), disabled => { button.disabled = disabled; }, true, options.signal);
|
|
6168
6125
|
}
|
|
6169
|
-
/** @type {Map<Store, [HTMLElement,
|
|
6126
|
+
/** @type {Map<Store, [tbody: HTMLElement, AbortController, (s: State) => void]>} */
|
|
6170
6127
|
let seMap = new Map();
|
|
6171
|
-
/** @param {Map<Store, [tbody: HTMLElement, destroy: () => void, (s: State) => void]>} map */
|
|
6172
|
-
function destroyMap(map) {
|
|
6173
|
-
for (const [el, destroy] of map.values()) {
|
|
6174
|
-
destroy();
|
|
6175
|
-
el.remove();
|
|
6176
|
-
}
|
|
6177
|
-
|
|
6178
|
-
}
|
|
6179
6128
|
/** @type {State[]} */
|
|
6180
6129
|
const states = [];
|
|
6181
|
-
|
|
6130
|
+
watch(() => store.children, children => {
|
|
6182
6131
|
let nextNode = start.nextSibling;
|
|
6183
6132
|
const oldSeMap = seMap;
|
|
6184
6133
|
seMap = new Map();
|
|
@@ -6193,19 +6142,24 @@ function Tree(store, fieldRenderer, layout, options) {
|
|
|
6193
6142
|
const state = states[i];
|
|
6194
6143
|
const old = oldSeMap.get(child);
|
|
6195
6144
|
if (!old) {
|
|
6196
|
-
const
|
|
6197
|
-
|
|
6145
|
+
const elState = new Signal.State(state);
|
|
6146
|
+
const ac = new AbortController();
|
|
6147
|
+
const el = TreeLine(child, detailsStore, fieldRenderer, layout, elState, {
|
|
6148
|
+
columns, addable,
|
|
6149
|
+
deletable: new Signal.Computed(() => !store.readonly && !store.disabled && child.removable),
|
|
6198
6150
|
remove: remove.bind(null, child),
|
|
6199
6151
|
dragenter,
|
|
6200
6152
|
dragstart: dragstart.bind(null, child),
|
|
6201
6153
|
dragend,
|
|
6202
|
-
deletable,
|
|
6203
6154
|
addNode: () => addNode(Number(child.index)),
|
|
6204
6155
|
createDetails,
|
|
6205
6156
|
drop: drop.bind(null, child),
|
|
6206
|
-
},
|
|
6157
|
+
}, {
|
|
6158
|
+
...options,
|
|
6159
|
+
signal: options?.signal ? AbortSignal.any([options?.signal, ac.signal]) : ac.signal,
|
|
6160
|
+
});
|
|
6207
6161
|
main.insertBefore(el, nextNode);
|
|
6208
|
-
seMap.set(child, [el,
|
|
6162
|
+
seMap.set(child, [el, ac, s => elState.set(s)]);
|
|
6209
6163
|
continue;
|
|
6210
6164
|
}
|
|
6211
6165
|
oldSeMap.delete(child);
|
|
@@ -6218,103 +6172,104 @@ function Tree(store, fieldRenderer, layout, options) {
|
|
|
6218
6172
|
main.insertBefore(old[0], nextNode);
|
|
6219
6173
|
}
|
|
6220
6174
|
states.splice(childrenLength);
|
|
6221
|
-
|
|
6222
|
-
|
|
6175
|
+
for (const [el, ac] of oldSeMap.values()) {
|
|
6176
|
+
el.remove();
|
|
6177
|
+
ac.abort();
|
|
6178
|
+
}
|
|
6179
|
+
}, true, options?.signal);
|
|
6223
6180
|
|
|
6224
|
-
return
|
|
6225
|
-
start.remove();
|
|
6226
|
-
destroyMap(seMap);
|
|
6227
|
-
childrenResult();
|
|
6228
|
-
destroyDetails?.();
|
|
6229
|
-
for (const destroy of destroyList) {
|
|
6230
|
-
destroy();
|
|
6231
|
-
}
|
|
6232
|
-
}];
|
|
6181
|
+
return root;
|
|
6233
6182
|
}
|
|
6234
6183
|
|
|
6235
6184
|
/**
|
|
6236
6185
|
*
|
|
6186
|
+
* @template T
|
|
6237
6187
|
* @param {string | ParentNode} html
|
|
6238
6188
|
* @param {Store<any, any>} store
|
|
6239
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
6189
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6240
6190
|
* @param {StoreLayout.Options?} options
|
|
6241
|
-
* @param {StoreLayout.Field
|
|
6242
|
-
* @returns
|
|
6191
|
+
* @param {StoreLayout.Field<T>} layout
|
|
6192
|
+
* @returns {ParentNode}
|
|
6243
6193
|
*/
|
|
6244
6194
|
function Html(html, store, fieldRenderer, options, layout) {
|
|
6245
6195
|
const htmlContent = getHtmlContent(html);
|
|
6246
|
-
|
|
6247
|
-
return
|
|
6196
|
+
renderHtml(store, fieldRenderer, htmlContent, options, layout);
|
|
6197
|
+
return htmlContent;
|
|
6248
6198
|
}
|
|
6249
|
-
|
|
6250
6199
|
/**
|
|
6251
6200
|
*
|
|
6252
|
-
* @
|
|
6201
|
+
* @template T
|
|
6202
|
+
* @param {StoreLayout.Field<T>['arrayStyle']?} arrayStyle
|
|
6203
|
+
* @param {ArrayStore} store
|
|
6204
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6205
|
+
* @param {StoreLayout.Field<T>} layout
|
|
6206
|
+
* @param {StoreLayout.Options?} options
|
|
6207
|
+
* @returns {HTMLElement?}
|
|
6253
6208
|
*/
|
|
6254
|
-
function
|
|
6255
|
-
switch(arrayStyle) {
|
|
6256
|
-
case 'tree': return Tree;
|
|
6257
|
-
default: return Table;
|
|
6209
|
+
function renderArrayCell(arrayStyle, store, fieldRenderer, layout, options) {
|
|
6210
|
+
switch (arrayStyle) {
|
|
6211
|
+
case 'tree': return Tree(store, fieldRenderer, layout, options);
|
|
6212
|
+
default: return Table(store, fieldRenderer, layout, options);
|
|
6258
6213
|
}
|
|
6259
6214
|
|
|
6260
6215
|
}
|
|
6261
6216
|
|
|
6262
6217
|
/**
|
|
6263
6218
|
*
|
|
6219
|
+
* @template T
|
|
6264
6220
|
* @param {Store<any, any>} store
|
|
6265
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
6266
|
-
* @param {StoreLayout.Field
|
|
6221
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6222
|
+
* @param {StoreLayout.Field<T>} layout
|
|
6267
6223
|
* @param {StoreLayout.Options?} options
|
|
6268
|
-
* @returns {
|
|
6224
|
+
* @returns {ParentNode}
|
|
6269
6225
|
*/
|
|
6270
6226
|
function FormField(store, fieldRenderer, layout, options) {
|
|
6271
6227
|
const { type } = store;
|
|
6272
|
-
const isObject = type && typeof type === 'object';
|
|
6273
|
-
const html = layout
|
|
6228
|
+
const isObject = Boolean(type && typeof type === 'object');
|
|
6229
|
+
const html = layout.html;
|
|
6274
6230
|
/** @type {StoreLayout.Grid['cell']} */
|
|
6275
6231
|
const cellType = isObject
|
|
6276
6232
|
? store instanceof ArrayStore ? 'collapse' : 'fieldset'
|
|
6277
6233
|
: html ? 'base' : 'inline';
|
|
6278
|
-
const [root,
|
|
6279
|
-
|
|
6234
|
+
const [root, content] = createCell(options?.signal, layout, store, cellType, isObject);
|
|
6235
|
+
effect(() => root.hidden = store.hidden, options?.signal);
|
|
6280
6236
|
|
|
6237
|
+
/** @type {false | ParentNode | null} */
|
|
6281
6238
|
const r =
|
|
6282
6239
|
html && Html(html, store, fieldRenderer, options, layout)
|
|
6283
|
-
|| fieldRenderer(store, options)
|
|
6284
|
-
|| store instanceof ArrayStore &&
|
|
6240
|
+
|| fieldRenderer(store, layout.renderer, options)
|
|
6241
|
+
|| store instanceof ArrayStore && renderArrayCell(layout.arrayStyle, store, fieldRenderer, layout, options)
|
|
6285
6242
|
|| isObject && Form(store, fieldRenderer, layout, options);
|
|
6286
6243
|
if (r) {
|
|
6287
|
-
|
|
6288
|
-
content.appendChild(el);
|
|
6289
|
-
destroyList.push(destroy);
|
|
6244
|
+
content.appendChild(r);
|
|
6290
6245
|
}
|
|
6291
|
-
return
|
|
6246
|
+
return root;
|
|
6292
6247
|
}
|
|
6293
6248
|
|
|
6294
6249
|
/** @import { Store } from '../Store/index.mjs' */
|
|
6295
|
-
/** @import { StoreLayout } from '../types.mjs' */
|
|
6250
|
+
/** @import { StoreLayout } from '../StoreLayout.types.mjs' */
|
|
6296
6251
|
|
|
6297
6252
|
/**
|
|
6298
6253
|
*
|
|
6299
6254
|
* @param {Store<any, any>} store
|
|
6300
6255
|
* @param {StoreLayout.Button} layout
|
|
6301
6256
|
* @param {StoreLayout.Options?} options
|
|
6302
|
-
* @returns {
|
|
6257
|
+
* @returns {ParentNode}
|
|
6303
6258
|
*/
|
|
6304
6259
|
function FormButton(store, layout, options) {
|
|
6305
|
-
const [root,
|
|
6260
|
+
const [root, content] = createCell(options?.signal, layout, store);
|
|
6306
6261
|
const button = document.createElement('button');
|
|
6307
|
-
|
|
6262
|
+
effect(() => {
|
|
6308
6263
|
const t = layout.text;
|
|
6309
6264
|
const text = typeof t === 'function' ? t(store, options) : t;
|
|
6310
6265
|
button.innerText = text ?? '';
|
|
6311
|
-
});
|
|
6312
|
-
|
|
6266
|
+
}, options?.signal);
|
|
6267
|
+
effect(() => {
|
|
6313
6268
|
const d = layout.disabled;
|
|
6314
6269
|
const disabled = typeof d === 'function' ? d(store, options) : d;
|
|
6315
6270
|
button.disabled = Boolean(disabled);
|
|
6316
|
-
});
|
|
6317
|
-
button.
|
|
6271
|
+
}, options?.signal);
|
|
6272
|
+
button.classList.add('NeeloongForm-item-button');
|
|
6318
6273
|
content.appendChild(button);
|
|
6319
6274
|
const click = layout.click;
|
|
6320
6275
|
if (typeof click === 'function') {
|
|
@@ -6325,40 +6280,42 @@ function FormButton(store, layout, options) {
|
|
|
6325
6280
|
button.addEventListener('click', e => call(click, e, store, options));
|
|
6326
6281
|
}
|
|
6327
6282
|
}
|
|
6328
|
-
return
|
|
6283
|
+
return root;
|
|
6329
6284
|
}
|
|
6330
6285
|
|
|
6331
6286
|
/** @import { Store } from '../Store/index.mjs' */
|
|
6332
|
-
/** @import { StoreLayout } from '../types.mjs' */
|
|
6287
|
+
/** @import { StoreLayout } from '../StoreLayout.types.mjs' */
|
|
6333
6288
|
|
|
6334
6289
|
/**
|
|
6335
6290
|
*
|
|
6291
|
+
* @template T
|
|
6336
6292
|
* @param {Store<any, any>} store
|
|
6337
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
6293
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6338
6294
|
* @param {StoreLayout.Html} layout
|
|
6339
6295
|
* @param {StoreLayout.Options?} options
|
|
6340
|
-
* @returns {
|
|
6296
|
+
* @returns {ParentNode?}
|
|
6341
6297
|
*/
|
|
6342
6298
|
function FormHtml(store, fieldRenderer, layout, options) {
|
|
6343
|
-
const [root, destroy, content, destroyList] = createCell(layout, store);
|
|
6344
6299
|
const html = layout.html;
|
|
6345
|
-
if (!html) { return
|
|
6300
|
+
if (!html) { return null; }
|
|
6301
|
+
const [root, content] = createCell(options?.signal, layout, store);
|
|
6346
6302
|
const htmlContent = getHtmlContent(html);
|
|
6347
|
-
|
|
6303
|
+
renderHtml(store, fieldRenderer, htmlContent, options, layout);
|
|
6348
6304
|
content.appendChild(htmlContent);
|
|
6349
|
-
return
|
|
6305
|
+
return root;
|
|
6350
6306
|
}
|
|
6351
6307
|
|
|
6352
6308
|
/** @import { Store } from '../Store/index.mjs' */
|
|
6353
|
-
/** @import { StoreLayout } from '../types.mjs' */
|
|
6309
|
+
/** @import { StoreLayout } from '../StoreLayout.types.mjs' */
|
|
6354
6310
|
|
|
6355
6311
|
/**
|
|
6356
6312
|
*
|
|
6313
|
+
* @template T
|
|
6357
6314
|
* @param {Store<any, any>} store
|
|
6358
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
6359
|
-
* @param {StoreLayout.Item} item
|
|
6315
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6316
|
+
* @param {StoreLayout.Item<T>} item
|
|
6360
6317
|
* @param {StoreLayout.Options?} options
|
|
6361
|
-
* @returns {
|
|
6318
|
+
* @returns {ParentNode?}
|
|
6362
6319
|
*/
|
|
6363
6320
|
function FormItem(store, fieldRenderer, item, options) {
|
|
6364
6321
|
if (item.type === 'button') {
|
|
@@ -6367,7 +6324,9 @@ function FormItem(store, fieldRenderer, item, options) {
|
|
|
6367
6324
|
if (item.type === 'html') {
|
|
6368
6325
|
return FormHtml(store, fieldRenderer, item, options);
|
|
6369
6326
|
}
|
|
6370
|
-
const
|
|
6327
|
+
const field = item.field;
|
|
6328
|
+
if (!field) { return null; }
|
|
6329
|
+
const fieldStore = store.child(field);
|
|
6371
6330
|
if (fieldStore) {
|
|
6372
6331
|
return FormField(fieldStore, fieldRenderer, item, options);
|
|
6373
6332
|
}
|
|
@@ -6376,64 +6335,62 @@ function FormItem(store, fieldRenderer, item, options) {
|
|
|
6376
6335
|
|
|
6377
6336
|
/**
|
|
6378
6337
|
*
|
|
6338
|
+
* @template T
|
|
6379
6339
|
* @param {Store<any, any>} store
|
|
6380
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
6381
|
-
* @param {StoreLayout
|
|
6340
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6341
|
+
* @param {StoreLayout<T>} layout
|
|
6382
6342
|
* @param {StoreLayout.Options?} options
|
|
6383
6343
|
* @param {HTMLElement} [parent]
|
|
6384
|
-
* @returns {
|
|
6344
|
+
* @returns {HTMLElement?}
|
|
6385
6345
|
*/
|
|
6386
6346
|
function Form(store, fieldRenderer, layout, options, parent) {
|
|
6347
|
+
if (options?.signal?.aborted) { return null; }
|
|
6387
6348
|
const root = parent instanceof HTMLElement ? parent : document.createElement('div');
|
|
6388
|
-
root.
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
const fieldLayouts = layout?.fields;
|
|
6392
|
-
if (fieldLayouts) {
|
|
6349
|
+
root.classList.add('NeeloongForm');
|
|
6350
|
+
const fieldLayouts = layout.fields || store.layout.fields;
|
|
6351
|
+
if (fieldLayouts?.length) {
|
|
6393
6352
|
for (const fieldTemplate of fieldLayouts) {
|
|
6394
|
-
const
|
|
6395
|
-
if (
|
|
6396
|
-
const [el, destroy] = result;
|
|
6397
|
-
root.appendChild(el);
|
|
6398
|
-
destroyList.push(destroy);
|
|
6353
|
+
const el = FormItem(store, fieldRenderer, fieldTemplate, options);
|
|
6354
|
+
if (el) { root.appendChild(el); }
|
|
6399
6355
|
}
|
|
6400
6356
|
} else {
|
|
6401
6357
|
const fields = [...store].map(([, v]) => v);
|
|
6402
6358
|
for (const field of fields) {
|
|
6403
|
-
const
|
|
6404
|
-
root.appendChild(el);
|
|
6405
|
-
destroyList.push(destroy);
|
|
6359
|
+
const el = FormField(field, fieldRenderer, field.layout, options);
|
|
6360
|
+
if (el) { root.appendChild(el); }
|
|
6406
6361
|
}
|
|
6407
6362
|
}
|
|
6408
|
-
return
|
|
6409
|
-
for (const destroy of destroyList) {
|
|
6410
|
-
destroy();
|
|
6411
|
-
}
|
|
6412
|
-
}];
|
|
6363
|
+
return root;
|
|
6413
6364
|
|
|
6414
6365
|
}
|
|
6415
6366
|
|
|
6416
6367
|
/** @import { Store } from '../Store/index.mjs' */
|
|
6417
|
-
/** @import { StoreLayout } from '../types.mjs' */
|
|
6368
|
+
/** @import { StoreLayout } from '../StoreLayout.types.mjs' */
|
|
6418
6369
|
|
|
6419
6370
|
/**
|
|
6420
6371
|
*
|
|
6372
|
+
* @template T
|
|
6421
6373
|
* @param {Store} store
|
|
6422
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
6374
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6423
6375
|
* @param {HTMLElement} root
|
|
6424
|
-
* @param {StoreLayout
|
|
6376
|
+
* @param {StoreLayout<T>} layout
|
|
6425
6377
|
* @param {StoreLayout.Options & {clone?: boolean} | null} [options]
|
|
6378
|
+
* @returns {void}
|
|
6426
6379
|
*/
|
|
6427
6380
|
function renderStore(store, fieldRenderer, root, layout, options) {
|
|
6428
|
-
|
|
6429
|
-
|
|
6430
|
-
|
|
6431
|
-
|
|
6432
|
-
root
|
|
6433
|
-
return
|
|
6381
|
+
if (options?.signal?.aborted) { return; }
|
|
6382
|
+
const storeLayout = layout || store.layout;
|
|
6383
|
+
const html = storeLayout.html;
|
|
6384
|
+
if (!html) {
|
|
6385
|
+
Form(store, fieldRenderer, storeLayout, options || null, root);
|
|
6386
|
+
return;
|
|
6434
6387
|
}
|
|
6435
|
-
const
|
|
6436
|
-
|
|
6388
|
+
const content = getHtmlContent(html);
|
|
6389
|
+
renderHtml(store, fieldRenderer, content, options || null, storeLayout);
|
|
6390
|
+
root.appendChild(content);
|
|
6391
|
+
options?.signal?.addEventListener('abort', () => {
|
|
6392
|
+
root.removeChild(content);
|
|
6393
|
+
}, { once: true });
|
|
6437
6394
|
}
|
|
6438
6395
|
|
|
6439
6396
|
export { ArrayStore, index as Layout, ObjectStore, Store, effect, render, renderStore, watch };
|