@codeleap/form 6.3.0 → 6.8.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/dist/fields/bool.d.ts +17 -0
- package/dist/fields/bool.d.ts.map +1 -0
- package/dist/fields/date.d.ts +22 -0
- package/dist/fields/date.d.ts.map +1 -0
- package/dist/fields/file.d.ts +17 -0
- package/dist/fields/file.d.ts.map +1 -0
- package/dist/fields/group.d.ts +17 -0
- package/dist/fields/group.d.ts.map +1 -0
- package/dist/fields/index.d.ts +87 -0
- package/dist/fields/index.d.ts.map +1 -0
- package/dist/fields/list.d.ts +34 -0
- package/dist/fields/list.d.ts.map +1 -0
- package/dist/fields/number.d.ts +23 -0
- package/dist/fields/number.d.ts.map +1 -0
- package/dist/fields/selectable.d.ts +25 -0
- package/dist/fields/selectable.d.ts.map +1 -0
- package/dist/fields/text.d.ts +21 -0
- package/dist/fields/text.d.ts.map +1 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/useField.d.ts +16 -0
- package/dist/hooks/useField.d.ts.map +1 -0
- package/dist/hooks/useValidate.d.ts +23 -0
- package/dist/hooks/useValidate.d.ts.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/lib/Field.d.ts +193 -0
- package/dist/lib/Field.d.ts.map +1 -0
- package/dist/lib/Form.d.ts +88 -0
- package/dist/lib/Form.d.ts.map +1 -0
- package/dist/lib/factories.d.ts +14 -0
- package/dist/lib/factories.d.ts.map +1 -0
- package/dist/lib/index.d.ts +3 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/useFieldBinding.d.ts +14 -0
- package/dist/lib/useFieldBinding.d.ts.map +1 -0
- package/dist/types/field.d.ts +22 -0
- package/dist/types/field.d.ts.map +1 -0
- package/dist/types/form.d.ts +26 -0
- package/dist/types/form.d.ts.map +1 -0
- package/dist/types/globals.d.ts +15 -0
- package/dist/types/globals.d.ts.map +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/validation.d.ts +9 -0
- package/dist/types/validation.d.ts.map +1 -0
- package/dist/validators/index.d.ts +2 -0
- package/dist/validators/index.d.ts.map +1 -0
- package/dist/validators/zod.d.ts +22 -0
- package/dist/validators/zod.d.ts.map +1 -0
- package/package.json +26 -10
- package/src/fields/bool.ts +6 -0
- package/src/fields/date.ts +9 -0
- package/src/fields/file.ts +7 -0
- package/src/fields/group.ts +6 -0
- package/src/fields/index.ts +17 -2
- package/src/fields/list.ts +66 -17
- package/src/fields/number.ts +9 -0
- package/src/fields/selectable.ts +9 -0
- package/src/fields/text.ts +8 -1
- package/src/hooks/useField.ts +13 -0
- package/src/hooks/useValidate.ts +16 -0
- package/src/lib/Field.ts +166 -22
- package/src/lib/Form.ts +98 -13
- package/src/lib/factories.tsx +8 -0
- package/src/lib/useFieldBinding.ts +13 -2
- package/src/types/globals.ts +6 -2
- package/src/validators/zod.ts +16 -1
- package/package.json.bak +0 -30
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { GlobalState } from "@codeleap/store";
|
|
2
|
+
import { FieldPaths, FieldTuples, FormDef, FormValues, PropertyForKeys, ValidationResult } from "../types";
|
|
3
|
+
type FormSelector<T extends FormDef, S> = (form: Form<T>) => S;
|
|
4
|
+
/**
|
|
5
|
+
* Container that owns the shared nanostores `GlobalState` atom for a group of
|
|
6
|
+
* fields and wires each field's individual atom to a slice of that shared
|
|
7
|
+
* state. This ensures a single source of truth: reading `form.values` always
|
|
8
|
+
* reflects the live atom values of every field.
|
|
9
|
+
*
|
|
10
|
+
* **Initialization order**
|
|
11
|
+
* The constructor calls `attachState()` synchronously, which replaces each
|
|
12
|
+
* field's own atom with a derived slice and sets the field's `name` from its
|
|
13
|
+
* object key in the shape. Fields must therefore be fully constructed before
|
|
14
|
+
* being passed to `Form`.
|
|
15
|
+
*
|
|
16
|
+
* **React usage**
|
|
17
|
+
* - `use(selector)` — mounts the form in a component, subscribes to state
|
|
18
|
+
* changes via `selector`, and resets all field values on unmount. Prefer
|
|
19
|
+
* this for full-page forms.
|
|
20
|
+
* - `useShared(selector)` — subscribes without the unmount-reset side-effect.
|
|
21
|
+
* Use when the form outlives the component (e.g. a global singleton).
|
|
22
|
+
*
|
|
23
|
+
* **Validation**
|
|
24
|
+
* `validate()` runs every field's synchronous validator and returns a map of
|
|
25
|
+
* results keyed by field name. Pass `revealErrors: true` to simultaneously
|
|
26
|
+
* flip `errorRevealed` on every field, triggering error display in the UI.
|
|
27
|
+
*/
|
|
28
|
+
declare class Form<T extends FormDef> {
|
|
29
|
+
id: string;
|
|
30
|
+
fields: T;
|
|
31
|
+
state: GlobalState<FormValues<T>>;
|
|
32
|
+
constructor(id: string, shape: T);
|
|
33
|
+
get values(): FormValues<T> extends infer T_1 ? T_1 extends FormValues<T> ? T_1 extends undefined ? FormValues<T> : T_1 : never : never;
|
|
34
|
+
get isChanged(): boolean;
|
|
35
|
+
changed(): boolean;
|
|
36
|
+
get isValid(): boolean;
|
|
37
|
+
slice<K extends FieldPaths<T>>(field: K): import("nanostores").WritableAtom<unknown>;
|
|
38
|
+
iterFields<V>(cb: (field: FieldTuples<T>, index: number) => V): V[];
|
|
39
|
+
/**
|
|
40
|
+
* Bulk-sets field values from a partial record. Boolean fields require an
|
|
41
|
+
* explicit `boolean` value; all other fields skip `undefined` and falsy
|
|
42
|
+
* values. Use `resetValues()` to restore all fields to their initial values.
|
|
43
|
+
*/
|
|
44
|
+
setValues(values: Partial<FormValues<T>>): void;
|
|
45
|
+
resetValues(): void;
|
|
46
|
+
attachState(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Returns the first field (in definition order) that fails validation, along
|
|
49
|
+
* with its `ValidationResult`. Returns `undefined` when all fields are
|
|
50
|
+
* valid. Useful for scrolling to the first error on submit.
|
|
51
|
+
*/
|
|
52
|
+
firstInvalid(): {
|
|
53
|
+
field: import("./Field").Field<any, any, unknown, unknown>;
|
|
54
|
+
validation: ValidationResult<unknown, unknown>;
|
|
55
|
+
} | undefined;
|
|
56
|
+
validate<Fields extends FieldPaths<T>[] = FieldPaths<T>[]>(options?: {
|
|
57
|
+
fields?: Fields;
|
|
58
|
+
revealErrors?: boolean;
|
|
59
|
+
}): PropertyForKeys<T, Fields[number], '__validationRes'>;
|
|
60
|
+
/**
|
|
61
|
+
* Returns the transformed props for `field` via `Field.props()`. Throws if
|
|
62
|
+
* the field key does not exist in this form's shape, making typos a runtime
|
|
63
|
+
* error rather than a silent no-op.
|
|
64
|
+
*/
|
|
65
|
+
register(field: FieldPaths<T>): import("..").IFieldProps;
|
|
66
|
+
use<Selected>(selector: FormSelector<T, Selected>): Selected;
|
|
67
|
+
useReset(): void;
|
|
68
|
+
useShared<Selected>(selector: FormSelector<T, Selected>): Selected;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Creates a `Form` instance that is stable for the lifetime of the component
|
|
72
|
+
* (memoised on `name`). Use this when the form is local to a single mounted
|
|
73
|
+
* component. For forms that must survive unmounts (e.g. multi-step flows),
|
|
74
|
+
* construct the `Form` outside React via `form()`.
|
|
75
|
+
*
|
|
76
|
+
* Note: `def` is only read on the first render — changing it after mount has
|
|
77
|
+
* no effect.
|
|
78
|
+
*/
|
|
79
|
+
export declare function useForm<T extends FormDef>(name: string, def: T): Form<T>;
|
|
80
|
+
/**
|
|
81
|
+
* Constructs a `Form` outside of React — suitable for module-level singletons,
|
|
82
|
+
* server-side construction, or multi-step flows where the form must outlive
|
|
83
|
+
* any individual component. Values are **not** automatically reset on unmount;
|
|
84
|
+
* call `resetValues()` explicitly when needed.
|
|
85
|
+
*/
|
|
86
|
+
export declare function form<Def extends FormDef>(...args: ConstructorParameters<typeof Form<Def>>): Form<Def>;
|
|
87
|
+
export {};
|
|
88
|
+
//# sourceMappingURL=Form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Form.d.ts","sourceRoot":"","sources":["../../src/lib/Form.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,WAAW,EAAe,MAAM,iBAAiB,CAAA;AAG5E,OAAO,EAAE,UAAU,EAAuB,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAiB/H,KAAK,YAAY,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,KAAM,CAAC,CAAA;AAI/D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,cAAM,IAAI,CAAC,CAAC,SAAS,OAAO;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,CAAC,CAAA;IACT,KAAK,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAA;gBAGrB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAchC,IAAI,MAAM,8HAET;IAED,IAAI,SAAS,YAEZ;IAGD,OAAO;IAQP,IAAI,OAAO,YAIV;IAED,KAAK,CAAC,CAAC,SAAS,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;IAgBvC,UAAU,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,CAAC;IAe7D;;;;OAIG;IACH,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAQxC,WAAW;IAMX,WAAW;IAUX;;;;OAIG;IACH,YAAY;;;;IAWZ,QAAQ,CAAC,MAAM,SAAS,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,eAAe,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC;IA2BxK;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC;IAO7B,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,QAAQ;IAQ5D,QAAQ;IAKR,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,QAAQ;CAiBnE;AAGD;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,WAO9D;AAED;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,GAAG,SAAS,OAAO,EAAE,GAAG,IAAI,EAAE,qBAAqB,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,aAEzF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Validator } from "../types";
|
|
2
|
+
import { Field } from "./Field";
|
|
3
|
+
type FieldBuilder<T, Validate extends Validator<any, any, any>> = typeof Field<T, Validate>;
|
|
4
|
+
/**
|
|
5
|
+
* Wraps a `Field` subclass constructor in a factory function, eliminating the
|
|
6
|
+
* need to call `new` at the call site and improving inference of the
|
|
7
|
+
* `validate` option's generic type. The returned factory accepts the same
|
|
8
|
+
* options as the class constructor and produces a fully typed `Field` instance.
|
|
9
|
+
*
|
|
10
|
+
* All entries in the `fields` namespace are built with this helper.
|
|
11
|
+
*/
|
|
12
|
+
export declare function fieldFactory<T extends FieldBuilder<any, any>, Value = T extends FieldBuilder<infer V, any> ? V : never, Validator = T extends FieldBuilder<infer VL, any> ? VL : never>(cls: T): <A extends ConstructorParameters<T>[0]>(options?: A) => Field<Value, A["validate"]>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=factories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factories.d.ts","sourceRoot":"","sources":["../../src/lib/factories.tsx"],"names":[],"mappings":"AACA,OAAO,EAAW,SAAS,EAAE,MAAM,UAAU,CAAA;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAE/B,KAAK,YAAY,CAAC,CAAC,EAAE,QAAQ,SAAS,SAAS,CAAC,GAAG,EAAC,GAAG,EAAC,GAAG,CAAC,IAAI,OAAO,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAA;AAEzF;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,CAAC,SAAS,YAAY,CAAC,GAAG,EAAC,GAAG,CAAC,EAC/B,KAAK,GAAG,CAAC,SAAS,YAAY,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,EACxD,SAAS,GAAG,CAAC,SAAS,YAAY,CAAC,MAAM,EAAE,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,KAAK,EAC9D,GAAG,EAAE,CAAC,IACE,CAAC,SAAS,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,KAAG,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAKzF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAA;AACtB,OAAO,EAAC,KAAK,EAAC,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { IFieldRef } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Attaches an imperative handle to `ref` via `useImperativeHandle`. Every
|
|
4
|
+
* method in {@link IFieldRef} is given a default implementation that throws
|
|
5
|
+
* `"ref.<method> not implemented"`, so callers get a clear error rather than a
|
|
6
|
+
* silent no-op when a method is missing from `impl`.
|
|
7
|
+
*
|
|
8
|
+
* `impl` is a partial override — only supply the methods your component
|
|
9
|
+
* actually supports. Unimplemented methods remain as throwing stubs.
|
|
10
|
+
* `deps` is forwarded directly to `useImperativeHandle`; include anything
|
|
11
|
+
* `impl` closes over that can change between renders.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useFieldBinding<T>(ref: React.Ref<IFieldRef<T> | null> | undefined, impl: Partial<IFieldRef<T>>, deps?: React.DependencyList): void;
|
|
14
|
+
//# sourceMappingURL=useFieldBinding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFieldBinding.d.ts","sourceRoot":"","sources":["../../src/lib/useFieldBinding.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAEpC;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,GAAE,KAAK,CAAC,cAAmB,QAoC/I"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { WritableStore } from 'nanostores';
|
|
2
|
+
import { Validator } from './validation';
|
|
3
|
+
export type FieldState<T> = WritableStore<T>;
|
|
4
|
+
export interface ExtraFieldOptions {
|
|
5
|
+
}
|
|
6
|
+
export type FieldOptions<T, Validate extends Validator<T, any, any>> = {
|
|
7
|
+
name?: string;
|
|
8
|
+
defaultValue?: T | null;
|
|
9
|
+
state?: FieldState<T>;
|
|
10
|
+
validate?: Validate;
|
|
11
|
+
loader?: (form: any) => Partial<Omit<FieldOptions<T, Validate>, 'loader'>>;
|
|
12
|
+
onValueChange?: (newValue: T) => void;
|
|
13
|
+
} & ExtraFieldOptions;
|
|
14
|
+
export type FieldMeasureResult = {
|
|
15
|
+
x?: number;
|
|
16
|
+
y?: number;
|
|
17
|
+
width?: number;
|
|
18
|
+
height?: number;
|
|
19
|
+
pageX?: number;
|
|
20
|
+
pageY?: number;
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=field.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../src/types/field.ts"],"names":[],"mappings":"AAAA,OAAO,EAAG,aAAa,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAIxC,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,CAAA;AAE5C,MAAM,WAAW,iBAAiB;CAEjC;AAED,MAAM,MAAM,YAAY,CACtB,CAAC,EACD,QAAQ,SAAS,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,IACrC;IACF,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,YAAY,CAAC,EAAE,CAAC,GAAG,IAAI,CAAA;IACvB,KAAK,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAA;IAErB,QAAQ,CAAC,EAAE,QAAQ,CAAA;IAEnB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAC7B,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,QAAQ,CAAE,EAAE,QAAQ,CAAC,CAC3C,CAAA;IAED,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,IAAI,CAAA;CAEtC,GAAG,iBAAiB,CAAA;AAGrB,MAAM,MAAM,kBAAkB,GAAG;IAC/B,CAAC,CAAC,EAAE,MAAM,CAAA;IACV,CAAC,CAAC,EAAE,MAAM,CAAA;IACV,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Field } from "../lib/Field";
|
|
2
|
+
import { ValidationResult } from "./validation";
|
|
3
|
+
export type FormDef = Record<string, Field<any, any>>;
|
|
4
|
+
export type NarrowKeyof<T> = Extract<keyof T, string>;
|
|
5
|
+
export type FormValues<T extends FormDef> = {
|
|
6
|
+
[K in NarrowKeyof<T>]: T[K]['value'];
|
|
7
|
+
};
|
|
8
|
+
export type FormErrors<T extends FormDef> = {
|
|
9
|
+
[K in NarrowKeyof<T>]: ReturnType<T[K]['validate']> extends ValidationResult<any, infer E> ? E : never;
|
|
10
|
+
};
|
|
11
|
+
export type FormResults<T extends FormDef> = {
|
|
12
|
+
[K in NarrowKeyof<T>]: ReturnType<T[K]['validate']> extends ValidationResult<infer R, any> ? R : never;
|
|
13
|
+
};
|
|
14
|
+
export type FieldTuples<T extends FormDef> = {
|
|
15
|
+
[K in NarrowKeyof<T>]: [K, T[K]];
|
|
16
|
+
}[NarrowKeyof<T>];
|
|
17
|
+
export type PropertyForKeys<T extends FormDef, Keys extends FieldPaths<T>, Property extends keyof Field<any, any>> = {
|
|
18
|
+
[K in Keys]: T[K][Property];
|
|
19
|
+
};
|
|
20
|
+
export type FieldPropertyTuples<T extends FormDef, Property extends keyof Field<any, any>> = {
|
|
21
|
+
[K in NarrowKeyof<T>]: [K, T[K][Property]];
|
|
22
|
+
}[NarrowKeyof<T>];
|
|
23
|
+
export type FieldPaths<T extends FormDef> = ({
|
|
24
|
+
[K in NarrowKeyof<T>]: K;
|
|
25
|
+
})[NarrowKeyof<T>];
|
|
26
|
+
//# sourceMappingURL=form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../src/types/form.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAA;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAE/C,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAG,KAAK,CAAC,GAAG,EAAC,GAAG,CAAC,CAAC,CAAA;AAErD,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAA;AAErD,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,OAAO,IAAI;KACzC,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,GAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;CACtC,CAAA;AAED,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,OAAO,IAAI;KACzC,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,GAAI,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,SAAS,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK;CACxG,CAAA;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,OAAO,IAAI;KAC1C,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,GAAI,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,SAAS,gBAAgB,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK;CACxG,CAAA;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,OAAO,IAAI;KAC1C,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;CACjC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;AAEjB,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,OAAO,EAAE,IAAI,SAAS,UAAU,CAAC,CAAC,CAAC,EAAG,QAAQ,SAAS,MAAM,KAAK,CAAC,GAAG,EAAC,GAAG,CAAC,IAAI;KAClH,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;CAC5B,CAAA;AAED,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,OAAO,EAAE,QAAQ,SAAS,MAAM,KAAK,CAAC,GAAG,EAAC,GAAG,CAAC,IAAI;KACzF,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;CAC3C,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;AAIjB,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,OAAO,IAAI,CAAC;KAC1C,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC;CACzB,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AnyRecord } from '@codeleap/types';
|
|
2
|
+
export interface IFieldRef<T> {
|
|
3
|
+
getValue(): T;
|
|
4
|
+
scrollIntoView(): Promise<void>;
|
|
5
|
+
focus(): void;
|
|
6
|
+
blur(): void;
|
|
7
|
+
revealValue(): void;
|
|
8
|
+
toggleValueVisibility(): void;
|
|
9
|
+
hideValue(): void;
|
|
10
|
+
emit(event: string, ...args: any[]): void;
|
|
11
|
+
}
|
|
12
|
+
export interface IFieldProps {
|
|
13
|
+
}
|
|
14
|
+
export type PropTransformer = (props: AnyRecord) => AnyRecord;
|
|
15
|
+
//# sourceMappingURL=globals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"globals.d.ts","sourceRoot":"","sources":["../../src/types/globals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B,QAAQ,IAAI,CAAC,CAAA;IACb,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/B,KAAK,IAAI,IAAI,CAAA;IACb,IAAI,IAAI,IAAI,CAAA;IACZ,WAAW,IAAI,IAAI,CAAA;IACnB,qBAAqB,IAAI,IAAI,CAAA;IAC7B,SAAS,IAAI,IAAI,CAAA;IACjB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;CAC1C;AAGD,MAAM,WAAW,WAAW;CAE3B;AAED,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,SAAS,KAAK,SAAS,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,SAAS,CAAA;AAC5B,mBAAmB,QAAQ,CAAA;AAC3B,mBAAmB,cAAc,CAAA;AACjC,mBAAmB,WAAW,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type ValidationResult<Result, Err> = {
|
|
2
|
+
isValid: boolean;
|
|
3
|
+
result?: Result;
|
|
4
|
+
error?: Err;
|
|
5
|
+
readableError?: string;
|
|
6
|
+
};
|
|
7
|
+
export type ValidatorFunction<Value, Result, Err> = (value: Value, form: any) => ValidationResult<Result, Err>;
|
|
8
|
+
export type Validator<Value, Result, Err> = ValidatorFunction<Value, Result, Err>;
|
|
9
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/types/validation.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,CAAC,MAAM,EAAE,GAAG,IAAI;IAC1C,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,GAAG,CAAA;IACX,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,KAAK,gBAAgB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;AAE9G,MAAM,MAAM,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/validators/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ValidationResult } from '../types';
|
|
3
|
+
type ZodValidationResult<T extends z.ZodType> = ValidationResult<z.infer<T>, z.ZodError['issues']>;
|
|
4
|
+
/**
|
|
5
|
+
* Adapts a Zod schema into the `Validator` contract expected by `Field` and
|
|
6
|
+
* `useValidate`. Uses `safeParse` internally so Zod errors are captured as
|
|
7
|
+
* `{ isValid: false, error: ZodIssue[] }` rather than thrown exceptions.
|
|
8
|
+
*
|
|
9
|
+
* The returned function is synchronous — async Zod schemas (`z.promise`,
|
|
10
|
+
* `.parseAsync`) are not supported.
|
|
11
|
+
*/
|
|
12
|
+
export declare function zodValidator<T extends z.ZodType>(model: T): (value: unknown) => ZodValidationResult<T>;
|
|
13
|
+
/**
|
|
14
|
+
* Type guard that narrows a `ValidationResult`-shaped value to one produced by
|
|
15
|
+
* `zodValidator`. A valid result must have `result` present; an invalid result
|
|
16
|
+
* must have `error` as an array of `ZodIssue` objects. Use this to
|
|
17
|
+
* distinguish Zod results from results produced by custom validators when
|
|
18
|
+
* handling errors generically.
|
|
19
|
+
*/
|
|
20
|
+
export declare function isZodValidationResult(val: any): val is ZodValidationResult<any>;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=zod.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod.d.ts","sourceRoot":"","sources":["../../src/validators/zod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAY,MAAM,KAAK,CAAA;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAG3C,KAAK,mBAAmB,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,IAAI,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAA;AAElG;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,IAChD,OAAO,OAAO,KAAG,mBAAmB,CAAC,CAAC,CAAC,CAShD;AAOD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,mBAAmB,CAAC,GAAG,CAAC,CAa/E"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codeleap/form",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.8.0",
|
|
4
4
|
"main": "src/index.ts",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"source": "./src/index.ts",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"src"
|
|
17
|
+
],
|
|
5
18
|
"license": "UNLICENSED",
|
|
6
19
|
"repository": {
|
|
7
20
|
"url": "https://github.com/codeleap-uk/internal-libs-monorepo.git",
|
|
@@ -9,22 +22,25 @@
|
|
|
9
22
|
"directory": "packages/form"
|
|
10
23
|
},
|
|
11
24
|
"devDependencies": {
|
|
12
|
-
"@codeleap/config": "6.
|
|
13
|
-
"@codeleap/types": "6.
|
|
14
|
-
"@codeleap/store": "6.
|
|
15
|
-
"
|
|
25
|
+
"@codeleap/config": "6.8.0",
|
|
26
|
+
"@codeleap/types": "6.8.0",
|
|
27
|
+
"@codeleap/store": "6.8.0",
|
|
28
|
+
"@codeleap/hooks": "6.8.0",
|
|
29
|
+
"zod": "4.4.3",
|
|
16
30
|
"ts-node-dev": "1.1.8"
|
|
17
31
|
},
|
|
18
32
|
"scripts": {
|
|
19
|
-
"build": "
|
|
33
|
+
"build": "tsc --build tsconfig.build.json",
|
|
34
|
+
"typecheck": "bun tsc --noEmit -p ./tsconfig.json",
|
|
20
35
|
"playground": "bun src/test.ts"
|
|
21
36
|
},
|
|
22
37
|
"peerDependencies": {
|
|
23
|
-
"@codeleap/types": "6.
|
|
24
|
-
"@codeleap/store": "6.
|
|
25
|
-
"@codeleap/logger": "6.
|
|
38
|
+
"@codeleap/types": "6.8.0",
|
|
39
|
+
"@codeleap/store": "6.8.0",
|
|
40
|
+
"@codeleap/logger": "6.8.0",
|
|
41
|
+
"@codeleap/hooks": "6.8.0",
|
|
26
42
|
"zod": "*",
|
|
27
43
|
"react": "19.1.0",
|
|
28
44
|
"typescript": "5.5.2"
|
|
29
45
|
}
|
|
30
|
-
}
|
|
46
|
+
}
|
package/src/fields/bool.ts
CHANGED
|
@@ -5,10 +5,16 @@ import { zodValidator } from "../validators"
|
|
|
5
5
|
|
|
6
6
|
type VALUE = boolean
|
|
7
7
|
|
|
8
|
+
/** Validator signature for boolean-valued fields. */
|
|
8
9
|
export type BooleanValidator<R = any, Err = any> = Validator<VALUE, R, Err>
|
|
9
10
|
|
|
10
11
|
type BooleanFieldOptions<Validate extends BooleanValidator> = FieldOptions<VALUE, Validate>
|
|
11
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Field for boolean values (checkboxes, toggles). `Form.setValues` treats
|
|
15
|
+
* this field specially: it will only set a value when the incoming value is
|
|
16
|
+
* strictly `boolean`, because falsy coercion would prevent setting `false`.
|
|
17
|
+
*/
|
|
12
18
|
export class BooleanField<Validate extends BooleanValidator> extends Field<boolean, Validate> {
|
|
13
19
|
_type = "BOOLEAN"
|
|
14
20
|
|
package/src/fields/date.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { FieldOptions, Validator } from "../types"
|
|
|
4
4
|
import { zodValidator } from "../validators"
|
|
5
5
|
import dayjs from 'dayjs'
|
|
6
6
|
|
|
7
|
+
/** Validator signature for `Date`-valued fields. */
|
|
7
8
|
export type DateValidator<R = any, Err = any> = Validator<Date, R, Err>
|
|
8
9
|
|
|
9
10
|
type DateFieldOptions<Validate extends DateValidator> = FieldOptions<Date, Validate> & {
|
|
@@ -24,6 +25,14 @@ function normalizeToDate(val: unknown): Date | undefined {
|
|
|
24
25
|
return undefined
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Field for `Date` values with optional `minimumDate` / `maximumDate` bounds.
|
|
30
|
+
* The built-in validator normalises the raw input via `dayjs` before running
|
|
31
|
+
* boundary checks, so it transparently accepts `Date` objects, dayjs instances,
|
|
32
|
+
* and ISO date strings. Invalid or unparseable values are normalised to
|
|
33
|
+
* `undefined`, which fails the `z.date()` check. Bounds are enforced at the
|
|
34
|
+
* start of the day (`startOf('day')`) for dayjs inputs.
|
|
35
|
+
*/
|
|
27
36
|
export class DateField<Validate extends DateValidator> extends Field<Date, Validate> {
|
|
28
37
|
_type = "DATE"
|
|
29
38
|
|
package/src/fields/file.ts
CHANGED
|
@@ -3,10 +3,17 @@ import { z } from 'zod'
|
|
|
3
3
|
import { FieldOptions, Validator } from "../types"
|
|
4
4
|
import { zodValidator } from "../validators"
|
|
5
5
|
|
|
6
|
+
/** Validator signature for file-valued fields. The value type is intentionally `any` to accommodate platform-specific file objects (web `File`, React Native asset objects, etc.). */
|
|
6
7
|
export type FileValidator<R = any, Err = any> = Validator<any, R, Err>
|
|
7
8
|
|
|
8
9
|
type FileFieldOptions<Validate extends FileValidator> = FieldOptions<any, Validate>
|
|
9
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Field for file uploads. The value type is `any` because the shape of a
|
|
13
|
+
* "file" differs between web (`File` / `FileList`) and React Native (asset
|
|
14
|
+
* descriptor objects). Supply a custom `validate` function to enforce whatever
|
|
15
|
+
* shape your platform produces.
|
|
16
|
+
*/
|
|
10
17
|
export class FileField<Validate extends FileValidator> extends Field<any, Validate> {
|
|
11
18
|
_type = "FILE"
|
|
12
19
|
|
package/src/fields/group.ts
CHANGED
|
@@ -9,6 +9,12 @@ type GroupValidator<R = any, Err = any> = Validator<VALUE, R, Err>
|
|
|
9
9
|
|
|
10
10
|
type GroupFieldOptions<Validate extends GroupValidator> = FieldOptions<VALUE, Validate>
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Field that represents a selected group or category, stored as a string key.
|
|
14
|
+
* Structurally identical to `TextField` but carries the `"group"` type tag so
|
|
15
|
+
* platform renderers can distinguish it and render a group-picker control
|
|
16
|
+
* instead of a free-text input.
|
|
17
|
+
*/
|
|
12
18
|
export class GroupField<Validate extends GroupValidator> extends Field<string, Validate> {
|
|
13
19
|
_type = "group"
|
|
14
20
|
|
package/src/fields/index.ts
CHANGED
|
@@ -1,15 +1,30 @@
|
|
|
1
1
|
import { fieldFactory } from "../lib/factories"
|
|
2
2
|
import { TextField } from "./text"
|
|
3
|
-
import { ListField
|
|
3
|
+
import { ListField, listFieldFactory} from "./list"
|
|
4
4
|
import { NumberField } from "./number"
|
|
5
5
|
import { BooleanField } from "./bool"
|
|
6
6
|
import { SelectableField } from "./selectable"
|
|
7
7
|
import { DateField } from "./date"
|
|
8
8
|
import { FileField } from "./file"
|
|
9
9
|
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Convenience namespace that exposes factory functions for every built-in field
|
|
13
|
+
* type. Prefer these over calling constructors directly — they provide better
|
|
14
|
+
* generic inference for the `validate` option.
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* const emailField = fields.text({ validate: zodValidator(z.string().email()) })
|
|
18
|
+
* const tagsField = fields.list({ item: fields.text(), defaultValue: [] })
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* Note: `fields.list` is the only entry that is not wrapped with
|
|
22
|
+
* `fieldFactory`, because `ListField` requires the `item` option's type to be
|
|
23
|
+
* inferred at the call site.
|
|
24
|
+
*/
|
|
10
25
|
export const fields = {
|
|
11
26
|
text: fieldFactory(TextField),
|
|
12
|
-
list:
|
|
27
|
+
list: listFieldFactory,
|
|
13
28
|
number: fieldFactory(NumberField),
|
|
14
29
|
boolean: fieldFactory(BooleanField),
|
|
15
30
|
selectable: fieldFactory(SelectableField),
|
package/src/fields/list.ts
CHANGED
|
@@ -1,36 +1,85 @@
|
|
|
1
1
|
import { Field } from "../lib/Field"
|
|
2
2
|
import { FieldOptions, Validator } from "../types"
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
/** Validator signature for array-valued fields. `R` and `Err` are the result and error types for the whole list, not individual items. */
|
|
5
|
+
export type ListValidator<Val, R = any, Err = any> = Validator<Val[], R, Err>
|
|
5
6
|
|
|
6
|
-
type
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
type ExtractFieldValue<T> = T extends Field<infer Value, any> ? Value : never
|
|
8
|
+
|
|
9
|
+
type AsListValidator<T> = T extends Field<infer Value, infer Validate> ?
|
|
10
|
+
Validator<
|
|
11
|
+
Value[],
|
|
12
|
+
Validate extends Validator<any, infer R, any> ? R[] : never,
|
|
13
|
+
Validate extends Validator<any, any, infer Err> ? Err[] : never
|
|
14
|
+
>
|
|
15
|
+
: never
|
|
16
|
+
|
|
17
|
+
export type _ListFieldOptions<T> = T extends Field<infer Value, infer Validate> ? FieldOptions<
|
|
18
|
+
Value[],
|
|
19
|
+
Validator<
|
|
20
|
+
Value[],
|
|
21
|
+
Validate extends Validator<any, infer R, any> ? R[] : never,
|
|
22
|
+
Validate extends Validator<any, any, infer Err> ? Err[] : never
|
|
23
|
+
>
|
|
24
|
+
> : never
|
|
9
25
|
|
|
10
|
-
export
|
|
26
|
+
export type ListFieldOptions<ItemField extends Field<any, any>> = {
|
|
27
|
+
item: ItemField
|
|
28
|
+
} & _ListFieldOptions<ItemField>
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Field that holds an array of values, each validated by a delegate `item`
|
|
32
|
+
* field. The built-in validator iterates every element through
|
|
33
|
+
* `options.item.validate` and collects all failures into an error array. The
|
|
34
|
+
* list is considered valid only when every element passes. If `item` has no
|
|
35
|
+
* validator, the list is always valid.
|
|
36
|
+
*
|
|
37
|
+
* The `item` field acts as a prototype — it is not mounted independently and
|
|
38
|
+
* does not own its own atom. Do not call `use()` on it directly.
|
|
39
|
+
*/
|
|
40
|
+
export class ListField<T extends Field<any, any>> extends Field<ExtractFieldValue<T>[], AsListValidator<T>> {
|
|
11
41
|
_type = "LIST"
|
|
12
42
|
|
|
13
|
-
constructor(options: ListFieldOptions<T
|
|
43
|
+
constructor(options: ListFieldOptions<T>) {
|
|
14
44
|
super({
|
|
15
|
-
|
|
16
|
-
validate: (v) => {
|
|
17
|
-
if (!options.validate) return {
|
|
45
|
+
...options,
|
|
46
|
+
validate: ((v, form) => {
|
|
47
|
+
if (!options.item?.validate) return {
|
|
18
48
|
isValid: true
|
|
19
49
|
}
|
|
20
50
|
|
|
21
|
-
|
|
22
|
-
|
|
51
|
+
const errors = []
|
|
52
|
+
|
|
53
|
+
for (const value of v) {
|
|
54
|
+
const validation = options.item?.validate?.(value)
|
|
23
55
|
|
|
24
56
|
if (!validation.isValid) {
|
|
25
|
-
|
|
57
|
+
errors.push(validation)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (errors.length) {
|
|
62
|
+
return {
|
|
63
|
+
isValid: false,
|
|
64
|
+
error: errors,
|
|
26
65
|
}
|
|
27
66
|
}
|
|
28
67
|
|
|
29
68
|
return {
|
|
30
|
-
isValid: true
|
|
69
|
+
isValid: true,
|
|
31
70
|
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
})
|
|
71
|
+
}) as AsListValidator<T>,
|
|
72
|
+
} as unknown as FieldOptions<ExtractFieldValue<T>[], AsListValidator<T>>)
|
|
35
73
|
}
|
|
36
|
-
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Convenience factory for `ListField`. Unlike `fieldFactory`-based helpers,
|
|
78
|
+
* `ListField` requires an `item` option whose generic type must be inferred at
|
|
79
|
+
* the call site, so it cannot share the same factory wrapper. This function
|
|
80
|
+
* exists to provide a consistent `fields.list(...)` call signature alongside
|
|
81
|
+
* the other entries in the `fields` namespace.
|
|
82
|
+
*/
|
|
83
|
+
export function listFieldFactory<T extends Field<any,any>>(options: ListFieldOptions<T>): ListField<T> {
|
|
84
|
+
return new ListField(options)
|
|
85
|
+
}
|
package/src/fields/number.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { z } from 'zod'
|
|
|
3
3
|
import { FieldOptions, Validator } from "../types"
|
|
4
4
|
import { zodValidator } from "../validators"
|
|
5
5
|
|
|
6
|
+
/** Validator signature for numeric fields. Accepts either a single number or an array of numbers (for range inputs). */
|
|
6
7
|
export type NumberValidator<R = any, Err = any> = Validator<number | number[], R, Err>
|
|
7
8
|
|
|
8
9
|
type Props = {
|
|
@@ -14,6 +15,14 @@ type NumberFieldOptions<Validate extends NumberValidator> = FieldOptions<number
|
|
|
14
15
|
|
|
15
16
|
const MAX_VALID_DIGITS = 1000000000000000 // maximum number of digits that the input supports to perform operations
|
|
16
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Field for numeric values. Supports both single numbers and arrays of numbers
|
|
20
|
+
* (range / multi-handle sliders) — the mode is inferred from whether
|
|
21
|
+
* `defaultValue` is an array. `min` defaults to `0` and `max` defaults to
|
|
22
|
+
* `1_000_000_000_000_000` (the maximum safe integer range the underlying input
|
|
23
|
+
* supports for arithmetic operations). Values outside the range fail
|
|
24
|
+
* validation.
|
|
25
|
+
*/
|
|
17
26
|
export class NumberField<Validate extends NumberValidator> extends Field<number | number[], Validate> {
|
|
18
27
|
_type = "NUMBER"
|
|
19
28
|
|
package/src/fields/selectable.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { Options } from '@codeleap/types'
|
|
|
6
6
|
|
|
7
7
|
type VALUE = string | number
|
|
8
8
|
|
|
9
|
+
/** Validator signature for selectable fields whose value is a `string` or `number` key. */
|
|
9
10
|
export type SelectableValidator<V extends VALUE, R = any, Err = any> = Validator<V, R, Err>
|
|
10
11
|
|
|
11
12
|
type SelectableFieldOptions<V extends VALUE, Validate extends SelectableValidator<V>> = FieldOptions<V, Validate> & {
|
|
@@ -14,6 +15,14 @@ type SelectableFieldOptions<V extends VALUE, Validate extends SelectableValidato
|
|
|
14
15
|
maxItems?: number
|
|
15
16
|
}
|
|
16
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Field for single or multi-select inputs whose options are a fixed list of
|
|
20
|
+
* string/number keys. `minItems` defaults to `1` (at least one selection
|
|
21
|
+
* required) and `maxItems` defaults to the length of the provided `options`
|
|
22
|
+
* array (all items selectable). The built-in validator accepts either a single
|
|
23
|
+
* value or an array, so the same field type covers both radio-style and
|
|
24
|
+
* checkbox-style UIs.
|
|
25
|
+
*/
|
|
17
26
|
export class SelectableField<V extends VALUE, Validate extends SelectableValidator<V>> extends Field<V, Validate> {
|
|
18
27
|
_type = "SELECTABLE"
|
|
19
28
|
|
package/src/fields/text.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { zodValidator } from "../validators"
|
|
|
5
5
|
|
|
6
6
|
type VALUE = string
|
|
7
7
|
|
|
8
|
+
/** Validator signature for string-valued fields. */
|
|
8
9
|
export type TextValidator<R = any, Err = any> = Validator<VALUE, R, Err>
|
|
9
10
|
|
|
10
11
|
type TextFieldOptions<Validate extends TextValidator> = FieldOptions<VALUE, Validate> & {
|
|
@@ -12,12 +13,18 @@ type TextFieldOptions<Validate extends TextValidator> = FieldOptions<VALUE, Vali
|
|
|
12
13
|
multiline?: boolean
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Field for plain string values. Ships with a `z.string()` fallback validator
|
|
18
|
+
* so the field is always valid when no custom `validate` option is provided.
|
|
19
|
+
* Accepts `secure` (password masking) and `multiline` hints that are forwarded
|
|
20
|
+
* as props to the underlying input component.
|
|
21
|
+
*/
|
|
15
22
|
export class TextField<Validate extends TextValidator> extends Field<string, Validate> {
|
|
16
23
|
_type = "TEXT"
|
|
17
24
|
|
|
18
25
|
constructor(options: TextFieldOptions<Validate>) {
|
|
19
26
|
super({
|
|
20
|
-
validate: zodValidator(z.string()) as unknown as Validate,
|
|
27
|
+
validate: zodValidator(z.string().optional()) as unknown as Validate,
|
|
21
28
|
...options
|
|
22
29
|
})
|
|
23
30
|
}
|