@@ -3,6 +3,58 @@ import { BaseInterface } from "./BaseInterface";
33import { FieldInterface , FieldConstructor } from "./FieldInterface" ;
44import { OptionsModel } from "./OptionsModel" ;
55import { ValidatorInterface , ValidationPlugins } from "./ValidatorInterface" ;
6+ /**
7+ * Recursively derives all possible field paths from a form values type `T`.
8+ * Supports nested objects, arrays (with `[]` suffix), and dot-separated paths.
9+ * Excludes built-in non-plain objects like Date, File, Blob, etc.
10+ *
11+ * @example
12+ * // --- Basic usage ---
13+ * type Profile = {
14+ * username: string;
15+ * email: string;
16+ * };
17+ * // PathsOf<Profile> = "username" | "email"
18+ *
19+ * @example
20+ * // --- Nested objects ---
21+ * type NestedClubFields = {
22+ * club: { name: string; city: string };
23+ * members: { firstname: string; lastname: string; hobbies: string[] }[];
24+ * };
25+ * // PathsOf<NestedClubFields> = "club" | "members" | "club.name" | "club.city"
26+ * // | "members[].firstname" | "members[].lastname" | "members[].hobbies"
27+ *
28+ * @example
29+ * // --- Usage with form.$() or form.select() ---
30+ * const form = new Form<{ profile: { name: string; age: number } }>({ });
31+ *
32+ * // Top-level keys get autocomplete directly from keyof F:
33+ * form.$('profile'); // ✓ autocomplete, returns Field<{ name: string; age: number }>
34+ *
35+ * // For nested paths, use PathsOf in a helper function:
36+ * import { PathsOf } from 'mobx-react-form';
37+ *
38+ * function getField(form: Form<{ profile: { name: string; age: number } }>, path: PathsOf<{ profile: { name: string; age: number } }>) {
39+ * return form.$(path).value;
40+ * // ^— path autocompletes to: "profile" | "profile.name" | "profile.age"
41+ * }
42+ * getField(form, 'profile.name'); // ✓ returns string
43+ */
44+ export type PathsOf < T > = T extends ( infer U ) [ ]
45+ ? PathsOf < U >
46+ : T extends Date | File | Blob | RegExp | Map < any , any > | Set < any > | Promise < any >
47+ ? never
48+ : T extends object
49+ ? { [ K in keyof T & string ] :
50+ T [ K ] extends ( infer U ) [ ]
51+ ? K | `${K } [].${PathsOf < U > } `
52+ : T [ K ] extends object
53+ ? K | `${K } .${PathsOf < T [ K ] > } `
54+ : K
55+ } [ keyof T & string ]
56+ : never ;
57+
658export interface FormInterface < F extends Record < string , any > = Record < string , any > > extends BaseInterface < F > {
759 name : string ;
860 extra : Record < string , any > ;
@@ -33,8 +85,79 @@ export interface FormInterface<F extends Record<string, any> = Record<string, an
3385 makeField ( data : FieldConstructor , FieldClass ?: typeof Field ) : FieldInterface ;
3486}
3587
88+ export interface FieldDefinition {
89+ /** Field value */
90+ value ?: any ;
91+ /** Field label */
92+ label ?: string ;
93+ /** Field placeholder */
94+ placeholder ?: string ;
95+ /** Validation rules string (e.g. "required|string|min:3") */
96+ rules ?: string ;
97+ /** Field type (e.g. "text", "checkbox", "password", "file", etc.) */
98+ type ?: string ;
99+ /** Whether the field is disabled */
100+ disabled ?: boolean ;
101+ /** Related field paths */
102+ related ?: string [ ] ;
103+ /** Default value */
104+ default ?: any ;
105+ /** Initial value */
106+ initial ?: any ;
107+ /** Nested sub-fields definition */
108+ fields ?: any ;
109+ /** Binding name for the UI component */
110+ bindings ?: string ;
111+ /** Extra metadata */
112+ extra ?: Record < string , any > ;
113+ /** Field-level options */
114+ options ?: OptionsModel ;
115+ /** Field hooks */
116+ hooks ?: Record < string , any > ;
117+ /** Field handlers */
118+ handlers ?: Record < string , any > ;
119+ /** Custom validation functions */
120+ validators ?: any [ ] ;
121+ /** Which field prop to use for validation output */
122+ validatedWith ?: string ;
123+ /** MobX observers */
124+ observers ?: any [ ] ;
125+ /** MobX interceptors */
126+ interceptors ?: any [ ] ;
127+ /** Ref callback/object */
128+ ref ?: any ;
129+ /** Whether the field is nullable */
130+ nullable ?: boolean ;
131+ /** Auto-focus on mount */
132+ autoFocus ?: boolean ;
133+ /** Input mode for mobile keyboards */
134+ inputMode ?: string ;
135+ /** Autocomplete attribute */
136+ autoComplete ?: string ;
137+ /** Input converter function */
138+ input ?: Function ;
139+ /** Output converter function */
140+ output ?: Function ;
141+ /** Value converter function */
142+ converter ?: Function ;
143+ /** Multiple converters */
144+ converters ?: Function [ ] ;
145+ /** Computed value */
146+ computed ?: any ;
147+ /** Field name (overrides the key) */
148+ name ?: string ;
149+ /** Custom Field class */
150+ class ?: any ;
151+ }
152+
36153export interface FieldsDefinitions {
37154 struct ?: string [ ] ;
155+ /**
156+ * Field definitions.
157+ * - For autocomplete on field props, use `Record<string, FieldDefinition>`
158+ * (e.g. `const fields: Record<string, FieldDefinition> = { ... }`)
159+ * - Or pass an array of field path strings for struct/separated mode.
160+ */
38161 fields ?: any ;
39162 computed ?: any ;
40163 values ?: any ;
0 commit comments