@neeloong/form 0.4.0 → 0.4.1
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/README.md +4 -0
- package/index.d.mts +36 -12
- package/index.js +121 -22
- package/index.min.js +7 -7
- package/index.min.mjs +6 -6
- package/index.mjs +121 -22
- package/package.json +1 -1
package/README.md
CHANGED
package/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @neeloong/form v0.4.
|
|
2
|
+
* @neeloong/form v0.4.1
|
|
3
3
|
* (c) 2024-2025 Fierflame
|
|
4
4
|
* @license Apache-2.0
|
|
5
5
|
*/
|
|
@@ -79,7 +79,7 @@ declare namespace index_d {
|
|
|
79
79
|
|
|
80
80
|
type VerifyError = any;
|
|
81
81
|
type Component = {
|
|
82
|
-
tag: string | ((ctx: any) => Element);
|
|
82
|
+
tag: string | ((ctx: any) => Element | [Element, (Element | null)?]);
|
|
83
83
|
is?: string | undefined;
|
|
84
84
|
attrs?: Record<string, Component.Attr> | undefined;
|
|
85
85
|
events?: Record<string, Component.Event> | undefined;
|
|
@@ -156,25 +156,22 @@ declare namespace Schema {
|
|
|
156
156
|
type?: null | undefined;
|
|
157
157
|
props?: Record<string, Schema.Field> | undefined;
|
|
158
158
|
array?: boolean | undefined;
|
|
159
|
-
meta?: any;
|
|
160
159
|
};
|
|
161
160
|
type Type = {
|
|
162
161
|
type: string;
|
|
163
162
|
props?: null | undefined;
|
|
164
163
|
array?: boolean | undefined;
|
|
165
|
-
meta?: any;
|
|
166
164
|
};
|
|
167
165
|
type Event = {
|
|
168
|
-
input
|
|
169
|
-
change
|
|
170
|
-
click
|
|
171
|
-
focus
|
|
172
|
-
blur
|
|
173
|
-
add?: Function | null | undefined;
|
|
174
|
-
remove?: Function | null | undefined;
|
|
175
|
-
move?: Function | null | undefined;
|
|
166
|
+
input: InputEvent;
|
|
167
|
+
change: InputEvent;
|
|
168
|
+
click: Event;
|
|
169
|
+
focus: Event;
|
|
170
|
+
blur: Event;
|
|
176
171
|
};
|
|
177
172
|
type Attr = {
|
|
173
|
+
meta?: any;
|
|
174
|
+
component?: any;
|
|
178
175
|
immutable?: boolean | undefined;
|
|
179
176
|
creatable?: boolean | undefined;
|
|
180
177
|
hidden?: boolean | ((store: Store, root: Store) => boolean) | null | undefined;
|
|
@@ -210,6 +207,13 @@ declare namespace Schema {
|
|
|
210
207
|
* 可选值
|
|
211
208
|
*/
|
|
212
209
|
values?: (Schema.Value.Define | Schema.Value.Group.Define)[] | undefined;
|
|
210
|
+
events?: {
|
|
211
|
+
input?: ((this: Store, value: InputEvent, store: Store) => void | boolean | null) | null | undefined;
|
|
212
|
+
change?: ((this: Store, value: InputEvent, store: Store) => void | boolean | null) | null | undefined;
|
|
213
|
+
click?: ((this: Store, value: Event, store: Store) => void | boolean | null) | null | undefined;
|
|
214
|
+
focus?: ((this: Store, value: Event, store: Store) => void | boolean | null) | null | undefined;
|
|
215
|
+
blur?: ((this: Store, value: Event, store: Store) => void | boolean | null) | null | undefined;
|
|
216
|
+
} | undefined;
|
|
213
217
|
};
|
|
214
218
|
}
|
|
215
219
|
|
|
@@ -280,10 +284,30 @@ declare class Store<T = any> {
|
|
|
280
284
|
onUpdate?: ((value: T | null, index: any) => void) | null | undefined;
|
|
281
285
|
onUpdateState?: ((value: T | null, index: any) => void) | null | undefined;
|
|
282
286
|
});
|
|
287
|
+
/**
|
|
288
|
+
*
|
|
289
|
+
* @template {keyof Schema.Event} K
|
|
290
|
+
* @param {K} event
|
|
291
|
+
* @param {Schema.Event[K]} value
|
|
292
|
+
*/
|
|
293
|
+
emit<K extends keyof Schema.Event>(event: K, value: Schema.Event[K]): boolean;
|
|
294
|
+
/**
|
|
295
|
+
*
|
|
296
|
+
* @template {keyof Schema.Event} K
|
|
297
|
+
* @param {K} event
|
|
298
|
+
* @param {(this: this, p: Schema.Event[K], store: this) => void | boolean | null} listener
|
|
299
|
+
* @returns {() => void}
|
|
300
|
+
*/
|
|
301
|
+
listen<K extends keyof Schema.Event>(event: K, listener: (this: this, p: Schema.Event[K], store: this) => void | boolean | null): () => void;
|
|
283
302
|
get null(): boolean;
|
|
303
|
+
get kind(): string;
|
|
284
304
|
schema: Schema.Field;
|
|
305
|
+
get store(): this;
|
|
285
306
|
get parent(): Store<any> | null;
|
|
286
307
|
get root(): Store<any>;
|
|
308
|
+
get type(): any;
|
|
309
|
+
get meta(): any;
|
|
310
|
+
get component(): any;
|
|
287
311
|
set length(v: number);
|
|
288
312
|
get length(): number;
|
|
289
313
|
set index(v: string | number);
|
package/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @neeloong/form v0.4.
|
|
2
|
+
* @neeloong/form v0.4.1
|
|
3
3
|
* (c) 2024-2025 Fierflame
|
|
4
4
|
* @license Apache-2.0
|
|
5
5
|
*/
|
|
@@ -693,6 +693,43 @@
|
|
|
693
693
|
* @template [T=any]
|
|
694
694
|
*/
|
|
695
695
|
class Store {
|
|
696
|
+
/** @type {Map<string, Set<(value: any, store: any) => void | boolean | null>>} */
|
|
697
|
+
#events = new Map()
|
|
698
|
+
/**
|
|
699
|
+
*
|
|
700
|
+
* @template {keyof Schema.Event} K
|
|
701
|
+
* @param {K} event
|
|
702
|
+
* @param {Schema.Event[K]} value
|
|
703
|
+
*/
|
|
704
|
+
emit(event, value) {
|
|
705
|
+
const key = typeof event === 'number' ? String(event) : event;
|
|
706
|
+
const events = this.#events;
|
|
707
|
+
let canceled = false;
|
|
708
|
+
for (const d of [...events.get(key) || []]) {
|
|
709
|
+
canceled = d(value, this) === false || canceled;
|
|
710
|
+
}
|
|
711
|
+
return !canceled;
|
|
712
|
+
}
|
|
713
|
+
/**
|
|
714
|
+
*
|
|
715
|
+
* @template {keyof Schema.Event} K
|
|
716
|
+
* @param {K} event
|
|
717
|
+
* @param {(this: this, p: Schema.Event[K], store: this) => void | boolean | null} listener
|
|
718
|
+
* @returns {() => void}
|
|
719
|
+
*/
|
|
720
|
+
listen(event, listener) {
|
|
721
|
+
const fn = listener.bind(this);
|
|
722
|
+
const events = this.#events;
|
|
723
|
+
const key = typeof event === 'number' ? String(event) : event;
|
|
724
|
+
let set = events.get(key);
|
|
725
|
+
if (!set) {
|
|
726
|
+
set = new Set();
|
|
727
|
+
events.set(key, set);
|
|
728
|
+
}
|
|
729
|
+
set.add(fn);
|
|
730
|
+
return () => { set?.delete(fn); }
|
|
731
|
+
|
|
732
|
+
}
|
|
696
733
|
/**
|
|
697
734
|
* @param {Schema} schema
|
|
698
735
|
* @param {object} [options]
|
|
@@ -703,6 +740,7 @@
|
|
|
703
740
|
}
|
|
704
741
|
#null = false;
|
|
705
742
|
get null() { return this.#null; }
|
|
743
|
+
get kind() { return ''; }
|
|
706
744
|
/**
|
|
707
745
|
* @param {Schema.Field} schema
|
|
708
746
|
* @param {object} options
|
|
@@ -747,6 +785,9 @@
|
|
|
747
785
|
this.#root = parent.#root;
|
|
748
786
|
// TODO: 事件向上冒泡
|
|
749
787
|
}
|
|
788
|
+
this.#type = schema.type;
|
|
789
|
+
this.#meta = schema.meta;
|
|
790
|
+
this.#component = schema.component;
|
|
750
791
|
|
|
751
792
|
const selfNewState = new exports.Signal.State(Boolean(isNew));
|
|
752
793
|
this.#selfNew = selfNewState;
|
|
@@ -807,6 +848,13 @@
|
|
|
807
848
|
this.#convert = typeof convert === 'function' ? convert : null;
|
|
808
849
|
this.#length.set(length || 0);
|
|
809
850
|
this.#index.set(index ?? '');
|
|
851
|
+
|
|
852
|
+
for (const [k, f] of Object.entries(schema.events || {})) {
|
|
853
|
+
if (typeof f !== 'function') { continue; }
|
|
854
|
+
// @ts-ignore
|
|
855
|
+
this.listen(k, f);
|
|
856
|
+
}
|
|
857
|
+
|
|
810
858
|
|
|
811
859
|
}
|
|
812
860
|
#destroyed = false;
|
|
@@ -824,8 +872,18 @@
|
|
|
824
872
|
#parent = null;
|
|
825
873
|
/** @readonly @type {Store} */
|
|
826
874
|
#root = this;
|
|
875
|
+
/** @readonly @type {any} */
|
|
876
|
+
#type;
|
|
877
|
+
/** @readonly @type {any} */
|
|
878
|
+
#meta;
|
|
879
|
+
/** @readonly @type {any} */
|
|
880
|
+
#component;
|
|
881
|
+
get store() { return this; }
|
|
827
882
|
get parent() { return this.#parent; }
|
|
828
883
|
get root() { return this.#root; }
|
|
884
|
+
get type() { return this.#type; }
|
|
885
|
+
get meta() { return this.#meta; }
|
|
886
|
+
get component() { return this.#component; }
|
|
829
887
|
|
|
830
888
|
#length = new exports.Signal.State(0);
|
|
831
889
|
get length() { return this.#length.get(); }
|
|
@@ -1110,6 +1168,7 @@
|
|
|
1110
1168
|
|
|
1111
1169
|
|
|
1112
1170
|
class ObjectStore extends Store {
|
|
1171
|
+
get kind() { return 'object'; }
|
|
1113
1172
|
/** @type {Record<string, Store>} */
|
|
1114
1173
|
#children
|
|
1115
1174
|
*[Symbol.iterator]() {yield* Object.entries(this.#children);}
|
|
@@ -1200,6 +1259,7 @@
|
|
|
1200
1259
|
}
|
|
1201
1260
|
return children[Number(key)] || null;
|
|
1202
1261
|
}
|
|
1262
|
+
get kind() { return 'array'; }
|
|
1203
1263
|
/**
|
|
1204
1264
|
* @param {Schema.Field} schema
|
|
1205
1265
|
* @param {object} [options]
|
|
@@ -2324,8 +2384,24 @@
|
|
|
2324
2384
|
}
|
|
2325
2385
|
|
|
2326
2386
|
const bindable = {
|
|
2387
|
+
type: true,
|
|
2388
|
+
meta: true,
|
|
2389
|
+
component: true,
|
|
2390
|
+
kind: true,
|
|
2391
|
+
|
|
2392
|
+
value: true,
|
|
2393
|
+
state: true,
|
|
2394
|
+
|
|
2395
|
+
store: true,
|
|
2396
|
+
parent: true,
|
|
2397
|
+
root: true,
|
|
2398
|
+
|
|
2399
|
+
schema: true,
|
|
2400
|
+
|
|
2327
2401
|
new: true,
|
|
2328
2402
|
readonly: true,
|
|
2403
|
+
creatable: true,
|
|
2404
|
+
immutable: true,
|
|
2329
2405
|
|
|
2330
2406
|
required: true,
|
|
2331
2407
|
clearable: true,
|
|
@@ -2339,6 +2415,11 @@
|
|
|
2339
2415
|
max: true,
|
|
2340
2416
|
step: true,
|
|
2341
2417
|
values: true,
|
|
2418
|
+
|
|
2419
|
+
null: true,
|
|
2420
|
+
index: true,
|
|
2421
|
+
no: true,
|
|
2422
|
+
length: true,
|
|
2342
2423
|
};
|
|
2343
2424
|
/** @type {Set<keyof typeof bindable>} */
|
|
2344
2425
|
// @ts-ignore
|
|
@@ -2353,21 +2434,12 @@
|
|
|
2353
2434
|
*/
|
|
2354
2435
|
function *toItem(val, key = '', sign = '$') {
|
|
2355
2436
|
yield [`${key}`, {get: () => val.value, set: v => val.value = v, store: val}];
|
|
2356
|
-
yield [`${key}${sign}value`, {get: () => val.value, set: v => val.value = v}];
|
|
2357
|
-
yield [`${key}${sign}state`, {get: () => val.state, set: v => val.state = v}];
|
|
2358
|
-
yield [`${key}${sign}store`, {get: () => val}];
|
|
2359
|
-
yield [`${key}${sign}schema`, {get: () => val.schema}];
|
|
2360
|
-
yield [`${key}${sign}null`, {get: () => val.null}];
|
|
2361
|
-
yield [`${key}${sign}index`, {get: () => val.index}];
|
|
2362
|
-
yield [`${key}${sign}no`, {get: () => val.no}];
|
|
2363
|
-
yield [`${key}${sign}length`, {get: () => val.length}];
|
|
2364
|
-
yield [`${key}${sign}creatable`, {get: () => val.creatable}];
|
|
2365
|
-
yield [`${key}${sign}immutable`, {get: () => val.immutable}];
|
|
2366
|
-
|
|
2367
2437
|
|
|
2368
2438
|
for (const k of bindableSet) {
|
|
2369
2439
|
yield [`${key}${sign}${k}`, {get: () => val[k]}];
|
|
2370
2440
|
}
|
|
2441
|
+
yield [`${key}${sign}value`, {get: () => val.value, set: v => val.value = v}];
|
|
2442
|
+
yield [`${key}${sign}state`, {get: () => val.state, set: v => val.state = v}];
|
|
2371
2443
|
if (!(val instanceof ArrayStore)) { return; }
|
|
2372
2444
|
yield [`${key}${sign}insert`, {exec: (index, value) => val.insert(index, value)}];
|
|
2373
2445
|
yield [`${key}${sign}add`, {exec: (v) => val.add(v)}];
|
|
@@ -2547,10 +2619,11 @@
|
|
|
2547
2619
|
const item = this.#items[name];
|
|
2548
2620
|
if (!item?.get) { return; }
|
|
2549
2621
|
const { store } = item;
|
|
2550
|
-
if (!store) {
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2622
|
+
if (!store) {
|
|
2623
|
+
switch(type) {
|
|
2624
|
+
case 'value': return watch(() => item.get(), cb);
|
|
2625
|
+
}
|
|
2626
|
+
return;
|
|
2554
2627
|
}
|
|
2555
2628
|
// @ts-ignore
|
|
2556
2629
|
if (bindableSet.has(type)) {
|
|
@@ -2575,8 +2648,6 @@
|
|
|
2575
2648
|
const res = Object.fromEntries([...bindableSet].map(v => [
|
|
2576
2649
|
`$${v}`, cb => watch(() => store[v], cb)
|
|
2577
2650
|
]));
|
|
2578
|
-
res.$value = cb => watch(() => store.value, cb);
|
|
2579
|
-
res.$state = cb => watch(() => store.state, cb);
|
|
2580
2651
|
return res;
|
|
2581
2652
|
}
|
|
2582
2653
|
/**
|
|
@@ -2596,7 +2667,7 @@
|
|
|
2596
2667
|
}
|
|
2597
2668
|
/**
|
|
2598
2669
|
* @param {string} name
|
|
2599
|
-
* @returns {Record<string, (
|
|
2670
|
+
* @returns {Record<string, (value: any) => void> | void}
|
|
2600
2671
|
*/
|
|
2601
2672
|
bindStateAllSet(name) {
|
|
2602
2673
|
const item = this.#items[name];
|
|
@@ -2612,6 +2683,27 @@
|
|
|
2612
2683
|
'$state': v => {store.state = v; },
|
|
2613
2684
|
}
|
|
2614
2685
|
}
|
|
2686
|
+
/**
|
|
2687
|
+
* @param {string} name
|
|
2688
|
+
* @returns {Record<string, (value: any) => void> | void}
|
|
2689
|
+
*/
|
|
2690
|
+
bindEvents(name) {
|
|
2691
|
+
const item = this.#items[name];
|
|
2692
|
+
if (!item?.get) { return; }
|
|
2693
|
+
const { store } = item;
|
|
2694
|
+
if (!store) {
|
|
2695
|
+
const set = item.set;
|
|
2696
|
+
if (typeof set !== 'function') { return; }
|
|
2697
|
+
return { '$value': set }
|
|
2698
|
+
}
|
|
2699
|
+
return {
|
|
2700
|
+
'$input': v => {store.emit('input', v); },
|
|
2701
|
+
'$change': v => {store.emit('change', v); },
|
|
2702
|
+
'$click': v => {store.emit('click', v); },
|
|
2703
|
+
'$focus': v => {store.emit('focus', v); },
|
|
2704
|
+
'$blur': v => {store.emit('blur', v); },
|
|
2705
|
+
}
|
|
2706
|
+
}
|
|
2615
2707
|
|
|
2616
2708
|
/**
|
|
2617
2709
|
* @param {string | Layout.EventListener} event
|
|
@@ -4058,12 +4150,13 @@
|
|
|
4058
4150
|
*/
|
|
4059
4151
|
function renderItem(layout, parent, next, env, templates, componentPath, getComponent) {
|
|
4060
4152
|
env = env.set(layout.aliases, layout.vars);
|
|
4153
|
+
const bind = layout.directives.bind;
|
|
4061
4154
|
const fragment = layout.directives.fragment;
|
|
4062
4155
|
if (fragment && typeof fragment === 'string') {
|
|
4063
4156
|
const template = templates[fragment];
|
|
4064
4157
|
if (!template) { return () => {}; }
|
|
4065
4158
|
const [templateLayout, templateEnv] = template;
|
|
4066
|
-
const newEnv = templateEnv.params(templateLayout, layout, env,
|
|
4159
|
+
const newEnv = templateEnv.params(templateLayout, layout, env, bind);
|
|
4067
4160
|
return render(templateLayout, parent, next, newEnv, templates, componentPath, getComponent);
|
|
4068
4161
|
}
|
|
4069
4162
|
if (!layout.name || layout.directives.fragment) {
|
|
@@ -4080,14 +4173,20 @@
|
|
|
4080
4173
|
|
|
4081
4174
|
const componentAttrs = component?.attrs;
|
|
4082
4175
|
const attrs = componentAttrs
|
|
4083
|
-
? bindAttrs(handler, env, layout.attrs, componentAttrs,
|
|
4084
|
-
: bindBaseAttrs(handler, env, layout.attrs,
|
|
4176
|
+
? bindAttrs(handler, env, layout.attrs, componentAttrs, bind)
|
|
4177
|
+
: bindBaseAttrs(handler, env, layout.attrs, bind);
|
|
4085
4178
|
|
|
4086
4179
|
for (const [name, event] of Object.entries(layout.events)) {
|
|
4087
4180
|
const fn = env.getEvent(event);
|
|
4088
4181
|
if (fn) { handler.addEvent(name, fn); }
|
|
4089
4182
|
}
|
|
4090
4183
|
|
|
4184
|
+
if (bind && typeof bind !== 'boolean') {
|
|
4185
|
+
for (const [key, event] of Object.entries(env.bindEvents(bind) || {})) {
|
|
4186
|
+
handler.addEvent(key, event);
|
|
4187
|
+
}
|
|
4188
|
+
}
|
|
4189
|
+
|
|
4091
4190
|
const r = component ?
|
|
4092
4191
|
typeof component.tag === 'function'
|
|
4093
4192
|
? component.tag(context)
|