@neeloong/form 0.4.0 → 0.4.2
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 +134 -36
- package/index.min.js +7 -7
- package/index.min.mjs +5 -5
- package/index.mjs +134 -36
- 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.2
|
|
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.2
|
|
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,9 +2667,9 @@
|
|
|
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
|
+
bindEvents(name) {
|
|
2602
2673
|
const item = this.#items[name];
|
|
2603
2674
|
if (!item?.get) { return; }
|
|
2604
2675
|
const { store } = item;
|
|
@@ -2606,10 +2677,15 @@
|
|
|
2606
2677
|
const set = item.set;
|
|
2607
2678
|
if (typeof set !== 'function') { return; }
|
|
2608
2679
|
return { '$value': set }
|
|
2609
|
-
|
|
2680
|
+
}
|
|
2610
2681
|
return {
|
|
2611
2682
|
'$value': v => {store.value = v; },
|
|
2612
2683
|
'$state': v => {store.state = v; },
|
|
2684
|
+
'$input': v => {store.emit('input', v); },
|
|
2685
|
+
'$change': v => {store.emit('change', v); },
|
|
2686
|
+
'$click': v => {store.emit('click', v); },
|
|
2687
|
+
'$focus': v => {store.emit('focus', v); },
|
|
2688
|
+
'$blur': v => {store.emit('blur', v); },
|
|
2613
2689
|
}
|
|
2614
2690
|
}
|
|
2615
2691
|
|
|
@@ -3011,9 +3087,8 @@
|
|
|
3011
3087
|
* @param {Component.Handler} handler
|
|
3012
3088
|
* @param {Environment} envs
|
|
3013
3089
|
* @param {Record<string, string | {name: string} | Layout.Calc>} attrs
|
|
3014
|
-
* @param {string | boolean | null} [bindValue]
|
|
3015
3090
|
*/
|
|
3016
|
-
function bindBaseAttrs(handler, envs, attrs
|
|
3091
|
+
function bindBaseAttrs(handler, envs, attrs) {
|
|
3017
3092
|
const tag = handler.tag;
|
|
3018
3093
|
let bk = new Set();
|
|
3019
3094
|
for (const [name, attr] of Object.entries(attrs)) {
|
|
@@ -3029,16 +3104,6 @@
|
|
|
3029
3104
|
}
|
|
3030
3105
|
bk.add(envs.watch(attrSchema, val => handler.set(name, val)));
|
|
3031
3106
|
}
|
|
3032
|
-
if (bindValue && typeof bindValue !== 'boolean') {
|
|
3033
|
-
for (const [key, effect] of Object.entries(envs.bindAll(bindValue) || {})) {
|
|
3034
|
-
if (typeof effect !== 'function') { continue; }
|
|
3035
|
-
bk.add(effect(val => handler.set(key, val)));
|
|
3036
|
-
}
|
|
3037
|
-
for (const [key, setter] of Object.entries(envs.bindStateAllSet(bindValue) || {})) {
|
|
3038
|
-
if (typeof setter !== 'function') { continue; }
|
|
3039
|
-
handler.addEvent(key, $event => setter($event));
|
|
3040
|
-
}
|
|
3041
|
-
}
|
|
3042
3107
|
|
|
3043
3108
|
return ()=> {
|
|
3044
3109
|
const list = bk;
|
|
@@ -4045,6 +4110,34 @@
|
|
|
4045
4110
|
};
|
|
4046
4111
|
}
|
|
4047
4112
|
|
|
4113
|
+
/** @import { Component } from '../types.mjs' */
|
|
4114
|
+
|
|
4115
|
+
|
|
4116
|
+
/**
|
|
4117
|
+
* @param {Component.Handler} handler
|
|
4118
|
+
* @param {Environment} env
|
|
4119
|
+
* @param {string | boolean | null} [bind]
|
|
4120
|
+
*/
|
|
4121
|
+
function bindBase(handler, env, bind) {
|
|
4122
|
+
if (!bind || typeof bind === 'boolean') { return () => {}; }
|
|
4123
|
+
let bk = new Set();
|
|
4124
|
+
for (const [key, effect] of Object.entries(env.bindAll(bind) || {})) {
|
|
4125
|
+
if (typeof effect !== 'function') { continue; }
|
|
4126
|
+
bk.add(effect(val => handler.set(key, val)));
|
|
4127
|
+
}
|
|
4128
|
+
for (const [key, setter] of Object.entries(env.bindEvents(bind) || {})) {
|
|
4129
|
+
handler.addEvent(key, $event => setter($event));
|
|
4130
|
+
}
|
|
4131
|
+
|
|
4132
|
+
return ()=> {
|
|
4133
|
+
const list = bk;
|
|
4134
|
+
bk = new Set();
|
|
4135
|
+
for (const s of list) {
|
|
4136
|
+
s();
|
|
4137
|
+
}
|
|
4138
|
+
}
|
|
4139
|
+
}
|
|
4140
|
+
|
|
4048
4141
|
/** @import Store from '../Store/index.mjs' */
|
|
4049
4142
|
|
|
4050
4143
|
/**
|
|
@@ -4058,12 +4151,13 @@
|
|
|
4058
4151
|
*/
|
|
4059
4152
|
function renderItem(layout, parent, next, env, templates, componentPath, getComponent) {
|
|
4060
4153
|
env = env.set(layout.aliases, layout.vars);
|
|
4154
|
+
const bind = layout.directives.bind;
|
|
4061
4155
|
const fragment = layout.directives.fragment;
|
|
4062
4156
|
if (fragment && typeof fragment === 'string') {
|
|
4063
4157
|
const template = templates[fragment];
|
|
4064
4158
|
if (!template) { return () => {}; }
|
|
4065
4159
|
const [templateLayout, templateEnv] = template;
|
|
4066
|
-
const newEnv = templateEnv.params(templateLayout, layout, env,
|
|
4160
|
+
const newEnv = templateEnv.params(templateLayout, layout, env, bind);
|
|
4067
4161
|
return render(templateLayout, parent, next, newEnv, templates, componentPath, getComponent);
|
|
4068
4162
|
}
|
|
4069
4163
|
if (!layout.name || layout.directives.fragment) {
|
|
@@ -4080,14 +4174,17 @@
|
|
|
4080
4174
|
|
|
4081
4175
|
const componentAttrs = component?.attrs;
|
|
4082
4176
|
const attrs = componentAttrs
|
|
4083
|
-
? bindAttrs(handler, env, layout.attrs, componentAttrs,
|
|
4084
|
-
: bindBaseAttrs(handler, env, layout.attrs
|
|
4177
|
+
? bindAttrs(handler, env, layout.attrs, componentAttrs, bind)
|
|
4178
|
+
: bindBaseAttrs(handler, env, layout.attrs);
|
|
4085
4179
|
|
|
4086
4180
|
for (const [name, event] of Object.entries(layout.events)) {
|
|
4087
4181
|
const fn = env.getEvent(event);
|
|
4088
4182
|
if (fn) { handler.addEvent(name, fn); }
|
|
4089
4183
|
}
|
|
4090
4184
|
|
|
4185
|
+
const base = bindBase(handler, env, bind);
|
|
4186
|
+
|
|
4187
|
+
|
|
4091
4188
|
const r = component ?
|
|
4092
4189
|
typeof component.tag === 'function'
|
|
4093
4190
|
? component.tag(context)
|
|
@@ -4113,6 +4210,7 @@
|
|
|
4113
4210
|
handler.destroy();
|
|
4114
4211
|
attrs();
|
|
4115
4212
|
children();
|
|
4213
|
+
base();
|
|
4116
4214
|
};
|
|
4117
4215
|
}
|
|
4118
4216
|
/**
|