@juantroconisf/lib 6.0.0 → 7.0.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/README.md CHANGED
@@ -27,36 +27,33 @@ pnpm add @juantroconisf/lib
27
27
  import { useForm } from "@juantroconisf/lib";
28
28
 
29
29
  const MyForm = () => {
30
- const { on, state, helpers } = useForm({
31
- name: "Juan",
32
- lines: [
33
- { id: 1, amount: 10 }
34
- ]
35
- }, {
36
- rules: {
37
- name: { required: true }
30
+ const { on, state, helpers } = useForm(
31
+ {
32
+ name: "Juan",
33
+ lines: [{ id: 1, amount: 10 }],
38
34
  },
39
- arrayRules: {
40
- lines: {
41
- amount: (item, index) => ({ min: 1 })
42
- }
43
- }
44
- });
35
+ {
36
+ rules: {
37
+ name: { required: true },
38
+ "lines.amount": (value, state, item) => ({ min: 1 }),
39
+ },
40
+ },
41
+ );
45
42
 
46
43
  return (
47
44
  <form>
48
45
  {/* Scalar/Nested Registration */}
49
- <Input {...on.input("name")} label="Name" />
46
+ <Input {...on.input("name")} label='Name' />
50
47
 
51
- {/* Array Registration (By ID) */}
48
+ {/* Array Registration (By ID + Composite Key) */}
52
49
  {state.lines.map((line) => (
53
- <Input
54
- key={line.id}
55
- {...on.input("lines", line.id, "amount")}
56
- label="Amount"
50
+ <Input
51
+ key={line.id}
52
+ {...on.input("lines.amount", line.id)}
53
+ label='Amount'
57
54
  />
58
55
  ))}
59
-
56
+
60
57
  <Button onClick={() => helpers.removeById("lines", 1)}>
61
58
  Remove First
62
59
  </Button>
@@ -72,26 +69,30 @@ const MyForm = () => {
72
69
  ### `useForm(initialState, options)`
73
70
 
74
71
  #### Options
75
- - **`rules`**: Validation rules for root/nested fields.
76
- - **`messages`**: Custom error messages for root/nested fields.
77
- - **`arrayRules`**: Validation rules for array items. Receives `(item, index)`.
78
- - **`arrayMessages`**: Custom error messages for array items.
79
- - **`arrayIdentifiers`**: Mapping of array keys to their unique ID property (defaults to `"id"`).
72
+
73
+ - **`rules`**: Validation rules map. Keys can be deep paths (e.g. `user.name`, `lines.amount`). Supports functional rules `(value, state, item?, index?)`.
74
+ - **`messages`**: Custom error messages map. Keys match rules.
75
+ - **`arrayIdentifiers`**: Mapping of array keys (supporting dot-notation for nested arrays) to their unique ID property (defaults to `"id"`).
80
76
 
81
77
  ### The `on` Object
82
- Provides methods to register components with the form state. Support both scalar/nested paths and array tracking.
83
78
 
84
- - **`on.input(path)`** / **`on.input(arrayKey, itemId, field)`**
85
- - **`on.select(path)`** / **`on.select(arrayKey, itemId, field)`**
86
- - **`on.autocomplete(path)`** / **`on.autocomplete(arrayKey, itemId, field)`**
79
+ Provides methods to register components with the form state. Support both scalar/nested paths and array tracking via composite keys.
80
+
81
+ - **`on.input(path)`** / **`on.input(compositeKey, itemId)`** / **`on.input(arrayKey, index)`** (for primitive arrays)
82
+ - **`on.select(path)`** / **`on.select(compositeKey, itemId)`** / **`on.select(arrayKey, index)`**
83
+ - **`on.autocomplete(path)`** / **`on.autocomplete(compositeKey, itemId)`** / **`on.autocomplete(arrayKey, index)`**
87
84
 
88
85
  ### Helpers
86
+
89
87
  Utilities for common state manipulations:
88
+
90
89
  - **`addItem(arrayKey, item, index?)`**
91
90
  - **`removeItem(arrayKey, index)`**
92
91
  - **`removeById(arrayKey, itemId)`**
92
+ - **`updateItem(arrayKey, index, value)`**
93
93
  - **`moveItem(arrayKey, from, to)`**
94
94
  - **`moveById(arrayKey, fromId, toId)`**
95
+ - **`getItem(arrayKey, itemId)`**
95
96
 
96
97
  ---
97
98
 
package/dist/index.d.mts CHANGED
@@ -43,43 +43,24 @@ type ValidatorErrorMessage = {
43
43
  * @template O The state type.
44
44
  * @template K The key of the array in the state.
45
45
  */
46
- type ArrayRules<O extends StateType, K extends keyof O = keyof O> = {
47
- [F in FieldPaths<ArrayElement<O[K]>>]?: ValidatorParams | ((item: ArrayElement<O[K]>, index: number) => ValidatorParams);
48
- };
49
- /**
50
- * Custom error messages for individual fields in an array item.
51
- * @template O The state type.
52
- * @template K The key of the array in the state.
53
- */
54
- type ArrayMessages<O extends StateType, K extends keyof O = keyof O> = {
55
- [F in FieldPaths<ArrayElement<O[K]>>]?: ValidatorErrorMessage;
56
- };
46
+ type ValidatorRule<item = any> = ValidatorParams | ((item: item, ...args: any[]) => ValidatorParams);
47
+ type RulePath<T> = T extends object ? {
48
+ [K in keyof T & string]: NonNullable<T[K]> extends (infer E)[] ? K | (E extends object ? `${K}.${RulePath<E>}` : never) : NonNullable<T[K]> extends object ? NonNullable<T[K]> extends Date ? K : K | `${K}.${RulePath<NonNullable<T[K]>>}` : K;
49
+ }[keyof T & string] : never;
57
50
  /**
58
51
  * Options for the useForm hook.
59
52
  * @template O The state type.
60
53
  */
61
54
  interface FormOptions<O extends StateType> {
62
55
  /** Validation rules for top-level fields. */
63
- rules?: {
64
- [key in keyof O]?: ValidatorParams;
65
- };
56
+ rules?: Partial<Record<RulePath<O>, ValidatorRule>>;
66
57
  /** Custom error messages for top-level fields. */
67
- messages?: {
68
- [key in keyof O]?: ValidatorErrorMessage;
69
- };
70
- /** Validation rules for items within arrays. */
71
- arrayRules?: {
72
- [K in ArrayKeys<O>]?: ArrayRules<O, K>;
73
- };
74
- /** Custom error messages for items within arrays. */
75
- arrayMessages?: {
76
- [K in ArrayKeys<O>]?: ArrayMessages<O, K>;
77
- };
58
+ messages?: Partial<Record<RulePath<O>, ValidatorErrorMessage>>;
78
59
  /**
79
60
  * Custom property names used as unique identifiers for items in specific arrays.
80
61
  * Default is "id".
81
62
  */
82
- arrayIdentifiers?: Partial<Record<ArrayKeys<O>, string>>;
63
+ arrayIdentifiers?: Partial<Record<ArrayPaths<O>, string>>;
83
64
  }
84
65
  type TouchedType = Map<string, boolean>;
85
66
  type ErrorsType = Map<string, NextUIError>;
@@ -91,10 +72,6 @@ interface ComponentInputProps<O extends StateType> {
91
72
  isInvalid: boolean;
92
73
  errorMessage: string;
93
74
  }
94
- type UXProps<O extends StateType> = Record<keyof O, {
95
- isInvalid: boolean;
96
- errorMessage: string;
97
- }>;
98
75
  /** Props returned by on.input() */
99
76
  interface ItemInputProps<V = any> extends ComponentInputProps<any> {
100
77
  onValueChange: (value: V) => void;
@@ -117,23 +94,49 @@ interface OnMethods<O extends StateType> {
117
94
  /** Registers a scalar or nested object field. */
118
95
  input<P extends AllPaths<O>>(id: P): ItemInputProps<NestedFieldValue<O, P & string>>;
119
96
  /** Registers an array element — adapts to primitive arrays (by index) or object arrays (by ID + field). */
120
- input<K extends ArrayKeys<O>>(arrayKey: K, ...args: O[K] extends Record<string, any>[] ? [itemId: ItemIdType<O, K>, field: FieldPaths<ArrayElement<O[K]>>] | [itemId: ItemIdType<O, K>, field: string, index: number] : [index: number]): ItemInputProps<any>;
97
+ /** Registers an array element adapts to primitive arrays (by index). */
98
+ input<K extends ArrayKeys<O>>(arrayKey: K, index: number): ItemInputProps<any>;
99
+ /** Registers an object array element's field using composite syntax "array.field". */
100
+ input<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: ItemIdType<O, GetArrayKeyFromPath<O, P>>): ItemInputProps<any>;
121
101
  /** Registers a scalar or nested object field. */
122
102
  select<P extends AllPaths<O>>(id: P): ItemSelectProps;
123
103
  /** Registers an array element — adapts to primitive arrays (by index) or object arrays (by ID + field). */
124
- select<K extends ArrayKeys<O>>(arrayKey: K, ...args: O[K] extends Record<string, any>[] ? [itemId: ItemIdType<O, K>, field: FieldPaths<ArrayElement<O[K]>>] | [itemId: ItemIdType<O, K>, field: string, index: number] : [index: number]): ItemSelectProps;
104
+ /** Registers an array element adapts to primitive arrays (by index). */
105
+ select<K extends ArrayKeys<O>>(arrayKey: K, index: number): ItemSelectProps;
106
+ /** Registers an object array element's field using composite syntax "array.field". */
107
+ select<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: ItemIdType<O, GetArrayKeyFromPath<O, P>>): ItemSelectProps;
125
108
  /** Registers a scalar or nested object field. */
126
109
  autocomplete<P extends AllPaths<O>>(id: P): ItemAutocompleteProps;
127
110
  /** Registers an array element — adapts to primitive arrays (by index) or object arrays (by ID + field). */
128
- autocomplete<K extends ArrayKeys<O>>(arrayKey: K, ...args: O[K] extends Record<string, any>[] ? [itemId: ItemIdType<O, K>, field: FieldPaths<ArrayElement<O[K]>>] | [itemId: ItemIdType<O, K>, field: string, index: number] : [index: number]): ItemAutocompleteProps;
111
+ /** Registers an array element adapts to primitive arrays (by index). */
112
+ autocomplete<K extends ArrayKeys<O>>(arrayKey: K, index: number): ItemAutocompleteProps;
113
+ /** Registers an object array element's field using composite syntax "array.field". */
114
+ autocomplete<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: ItemIdType<O, GetArrayKeyFromPath<O, P>>): ItemAutocompleteProps;
129
115
  }
130
116
  type ArrayKeys<O extends StateType> = {
131
117
  [K in keyof O]: O[K] extends any[] ? K : never;
132
118
  }[keyof O];
119
+ /**
120
+ * Recursive type to find all paths to arrays in the state.
121
+ */
122
+ type ArrayPaths<T> = T extends object ? {
123
+ [K in keyof T & string]: NonNullable<T[K]> extends (infer E)[] ? K | (E extends object ? `${K}.${ArrayPaths<E>}` : never) : NonNullable<T[K]> extends object ? NonNullable<T[K]> extends Date ? never : `${K}.${ArrayPaths<NonNullable<T[K]>>}` : never;
124
+ }[keyof T & string] : never;
133
125
  /** Keys whose values are arrays of objects (not primitives). */
134
126
  type ObjectArrayKeys<O extends StateType> = {
135
127
  [K in keyof O]: O[K] extends Record<string, any>[] ? K : never;
136
128
  }[keyof O];
129
+ /**
130
+ * Helper to get paths for fields within object arrays.
131
+ * Returns paths like "arrayKey.fieldName".
132
+ */
133
+ type ObjectArrayFieldPaths<O extends StateType> = {
134
+ [K in keyof O]: O[K] extends Record<string, any>[] ? `${K & string}.${FieldPaths<ArrayElement<O[K]>>}` : never;
135
+ }[keyof O];
136
+ /**
137
+ * Helper to extract the array key from a path string like "arrayKey.field".
138
+ */
139
+ type GetArrayKeyFromPath<O extends StateType, P extends string> = P extends `${infer K}.${string}` ? K extends keyof O ? O[K] extends any[] ? K : never : never : never;
137
140
  type ArrayElement<T> = T extends (infer E)[] ? E : never;
138
141
  /** Resolves the type of the identifier field for an array element (defaults to "id"). */
139
142
  type ItemIdType<O extends StateType, K extends keyof O> = "id" extends keyof ArrayElement<O[K]> ? ArrayElement<O[K]>["id"] : string | number;
@@ -196,6 +199,6 @@ interface UseFormResponse<O extends StateType> {
196
199
  resetTouched: (preservedKeys?: (keyof O)[]) => void;
197
200
  }
198
201
 
199
- declare function useForm<O extends StateType>(initialState: O, { rules, messages, arrayRules, arrayMessages, arrayIdentifiers, }?: FormOptions<O>): UseFormResponse<O>;
202
+ declare function useForm<O extends StateType>(initialState: O, { rules, messages, arrayIdentifiers }?: FormOptions<O>): UseFormResponse<O>;
200
203
 
201
- export { type ArrayMessages, type ArrayRules, type BlurFunc, type ErrorsType, type FormOptions, type HelpersFunc, type NestedChangeProps, NextUIError, type OnMethods, type StateType, type TouchedType, type UXProps, type UseFormResponse, type Validator, type ValidatorErrorMessage, type ValidatorParams, type ValidatorTypes, type ValueChangeFunc, useForm };
204
+ export { type BlurFunc, type ErrorsType, type FormOptions, type HelpersFunc, type NestedChangeProps, NextUIError, type OnMethods, type StateType, type TouchedType, type UseFormResponse, type Validator, type ValidatorErrorMessage, type ValidatorParams, type ValidatorRule, type ValidatorTypes, type ValueChangeFunc, useForm };
package/dist/index.d.ts CHANGED
@@ -43,43 +43,24 @@ type ValidatorErrorMessage = {
43
43
  * @template O The state type.
44
44
  * @template K The key of the array in the state.
45
45
  */
46
- type ArrayRules<O extends StateType, K extends keyof O = keyof O> = {
47
- [F in FieldPaths<ArrayElement<O[K]>>]?: ValidatorParams | ((item: ArrayElement<O[K]>, index: number) => ValidatorParams);
48
- };
49
- /**
50
- * Custom error messages for individual fields in an array item.
51
- * @template O The state type.
52
- * @template K The key of the array in the state.
53
- */
54
- type ArrayMessages<O extends StateType, K extends keyof O = keyof O> = {
55
- [F in FieldPaths<ArrayElement<O[K]>>]?: ValidatorErrorMessage;
56
- };
46
+ type ValidatorRule<item = any> = ValidatorParams | ((item: item, ...args: any[]) => ValidatorParams);
47
+ type RulePath<T> = T extends object ? {
48
+ [K in keyof T & string]: NonNullable<T[K]> extends (infer E)[] ? K | (E extends object ? `${K}.${RulePath<E>}` : never) : NonNullable<T[K]> extends object ? NonNullable<T[K]> extends Date ? K : K | `${K}.${RulePath<NonNullable<T[K]>>}` : K;
49
+ }[keyof T & string] : never;
57
50
  /**
58
51
  * Options for the useForm hook.
59
52
  * @template O The state type.
60
53
  */
61
54
  interface FormOptions<O extends StateType> {
62
55
  /** Validation rules for top-level fields. */
63
- rules?: {
64
- [key in keyof O]?: ValidatorParams;
65
- };
56
+ rules?: Partial<Record<RulePath<O>, ValidatorRule>>;
66
57
  /** Custom error messages for top-level fields. */
67
- messages?: {
68
- [key in keyof O]?: ValidatorErrorMessage;
69
- };
70
- /** Validation rules for items within arrays. */
71
- arrayRules?: {
72
- [K in ArrayKeys<O>]?: ArrayRules<O, K>;
73
- };
74
- /** Custom error messages for items within arrays. */
75
- arrayMessages?: {
76
- [K in ArrayKeys<O>]?: ArrayMessages<O, K>;
77
- };
58
+ messages?: Partial<Record<RulePath<O>, ValidatorErrorMessage>>;
78
59
  /**
79
60
  * Custom property names used as unique identifiers for items in specific arrays.
80
61
  * Default is "id".
81
62
  */
82
- arrayIdentifiers?: Partial<Record<ArrayKeys<O>, string>>;
63
+ arrayIdentifiers?: Partial<Record<ArrayPaths<O>, string>>;
83
64
  }
84
65
  type TouchedType = Map<string, boolean>;
85
66
  type ErrorsType = Map<string, NextUIError>;
@@ -91,10 +72,6 @@ interface ComponentInputProps<O extends StateType> {
91
72
  isInvalid: boolean;
92
73
  errorMessage: string;
93
74
  }
94
- type UXProps<O extends StateType> = Record<keyof O, {
95
- isInvalid: boolean;
96
- errorMessage: string;
97
- }>;
98
75
  /** Props returned by on.input() */
99
76
  interface ItemInputProps<V = any> extends ComponentInputProps<any> {
100
77
  onValueChange: (value: V) => void;
@@ -117,23 +94,49 @@ interface OnMethods<O extends StateType> {
117
94
  /** Registers a scalar or nested object field. */
118
95
  input<P extends AllPaths<O>>(id: P): ItemInputProps<NestedFieldValue<O, P & string>>;
119
96
  /** Registers an array element — adapts to primitive arrays (by index) or object arrays (by ID + field). */
120
- input<K extends ArrayKeys<O>>(arrayKey: K, ...args: O[K] extends Record<string, any>[] ? [itemId: ItemIdType<O, K>, field: FieldPaths<ArrayElement<O[K]>>] | [itemId: ItemIdType<O, K>, field: string, index: number] : [index: number]): ItemInputProps<any>;
97
+ /** Registers an array element adapts to primitive arrays (by index). */
98
+ input<K extends ArrayKeys<O>>(arrayKey: K, index: number): ItemInputProps<any>;
99
+ /** Registers an object array element's field using composite syntax "array.field". */
100
+ input<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: ItemIdType<O, GetArrayKeyFromPath<O, P>>): ItemInputProps<any>;
121
101
  /** Registers a scalar or nested object field. */
122
102
  select<P extends AllPaths<O>>(id: P): ItemSelectProps;
123
103
  /** Registers an array element — adapts to primitive arrays (by index) or object arrays (by ID + field). */
124
- select<K extends ArrayKeys<O>>(arrayKey: K, ...args: O[K] extends Record<string, any>[] ? [itemId: ItemIdType<O, K>, field: FieldPaths<ArrayElement<O[K]>>] | [itemId: ItemIdType<O, K>, field: string, index: number] : [index: number]): ItemSelectProps;
104
+ /** Registers an array element adapts to primitive arrays (by index). */
105
+ select<K extends ArrayKeys<O>>(arrayKey: K, index: number): ItemSelectProps;
106
+ /** Registers an object array element's field using composite syntax "array.field". */
107
+ select<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: ItemIdType<O, GetArrayKeyFromPath<O, P>>): ItemSelectProps;
125
108
  /** Registers a scalar or nested object field. */
126
109
  autocomplete<P extends AllPaths<O>>(id: P): ItemAutocompleteProps;
127
110
  /** Registers an array element — adapts to primitive arrays (by index) or object arrays (by ID + field). */
128
- autocomplete<K extends ArrayKeys<O>>(arrayKey: K, ...args: O[K] extends Record<string, any>[] ? [itemId: ItemIdType<O, K>, field: FieldPaths<ArrayElement<O[K]>>] | [itemId: ItemIdType<O, K>, field: string, index: number] : [index: number]): ItemAutocompleteProps;
111
+ /** Registers an array element adapts to primitive arrays (by index). */
112
+ autocomplete<K extends ArrayKeys<O>>(arrayKey: K, index: number): ItemAutocompleteProps;
113
+ /** Registers an object array element's field using composite syntax "array.field". */
114
+ autocomplete<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: ItemIdType<O, GetArrayKeyFromPath<O, P>>): ItemAutocompleteProps;
129
115
  }
130
116
  type ArrayKeys<O extends StateType> = {
131
117
  [K in keyof O]: O[K] extends any[] ? K : never;
132
118
  }[keyof O];
119
+ /**
120
+ * Recursive type to find all paths to arrays in the state.
121
+ */
122
+ type ArrayPaths<T> = T extends object ? {
123
+ [K in keyof T & string]: NonNullable<T[K]> extends (infer E)[] ? K | (E extends object ? `${K}.${ArrayPaths<E>}` : never) : NonNullable<T[K]> extends object ? NonNullable<T[K]> extends Date ? never : `${K}.${ArrayPaths<NonNullable<T[K]>>}` : never;
124
+ }[keyof T & string] : never;
133
125
  /** Keys whose values are arrays of objects (not primitives). */
134
126
  type ObjectArrayKeys<O extends StateType> = {
135
127
  [K in keyof O]: O[K] extends Record<string, any>[] ? K : never;
136
128
  }[keyof O];
129
+ /**
130
+ * Helper to get paths for fields within object arrays.
131
+ * Returns paths like "arrayKey.fieldName".
132
+ */
133
+ type ObjectArrayFieldPaths<O extends StateType> = {
134
+ [K in keyof O]: O[K] extends Record<string, any>[] ? `${K & string}.${FieldPaths<ArrayElement<O[K]>>}` : never;
135
+ }[keyof O];
136
+ /**
137
+ * Helper to extract the array key from a path string like "arrayKey.field".
138
+ */
139
+ type GetArrayKeyFromPath<O extends StateType, P extends string> = P extends `${infer K}.${string}` ? K extends keyof O ? O[K] extends any[] ? K : never : never : never;
137
140
  type ArrayElement<T> = T extends (infer E)[] ? E : never;
138
141
  /** Resolves the type of the identifier field for an array element (defaults to "id"). */
139
142
  type ItemIdType<O extends StateType, K extends keyof O> = "id" extends keyof ArrayElement<O[K]> ? ArrayElement<O[K]>["id"] : string | number;
@@ -196,6 +199,6 @@ interface UseFormResponse<O extends StateType> {
196
199
  resetTouched: (preservedKeys?: (keyof O)[]) => void;
197
200
  }
198
201
 
199
- declare function useForm<O extends StateType>(initialState: O, { rules, messages, arrayRules, arrayMessages, arrayIdentifiers, }?: FormOptions<O>): UseFormResponse<O>;
202
+ declare function useForm<O extends StateType>(initialState: O, { rules, messages, arrayIdentifiers }?: FormOptions<O>): UseFormResponse<O>;
200
203
 
201
- export { type ArrayMessages, type ArrayRules, type BlurFunc, type ErrorsType, type FormOptions, type HelpersFunc, type NestedChangeProps, NextUIError, type OnMethods, type StateType, type TouchedType, type UXProps, type UseFormResponse, type Validator, type ValidatorErrorMessage, type ValidatorParams, type ValidatorTypes, type ValueChangeFunc, useForm };
204
+ export { type BlurFunc, type ErrorsType, type FormOptions, type HelpersFunc, type NestedChangeProps, NextUIError, type OnMethods, type StateType, type TouchedType, type UseFormResponse, type Validator, type ValidatorErrorMessage, type ValidatorParams, type ValidatorRule, type ValidatorTypes, type ValueChangeFunc, useForm };