@fuf-stack/uniform 1.6.0 → 1.6.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/dist/Checkboxes/index.cjs +12 -6
- package/dist/Checkboxes/index.cjs.map +1 -1
- package/dist/Checkboxes/index.js +11 -5
- package/dist/FieldArray/index.cjs +12 -6
- package/dist/FieldArray/index.cjs.map +1 -1
- package/dist/FieldArray/index.js +11 -5
- package/dist/Form/index.cjs +12 -6
- package/dist/Form/index.cjs.map +1 -1
- package/dist/Form/index.js +11 -5
- package/dist/Input/index.cjs +12 -6
- package/dist/Input/index.cjs.map +1 -1
- package/dist/Input/index.js +11 -5
- package/dist/RadioBoxes/index.cjs +12 -6
- package/dist/RadioBoxes/index.cjs.map +1 -1
- package/dist/RadioBoxes/index.js +11 -5
- package/dist/RadioTabs/index.cjs +12 -6
- package/dist/RadioTabs/index.cjs.map +1 -1
- package/dist/RadioTabs/index.js +11 -5
- package/dist/Radios/index.cjs +12 -6
- package/dist/Radios/index.cjs.map +1 -1
- package/dist/Radios/index.js +11 -5
- package/dist/Select/index.cjs +12 -6
- package/dist/Select/index.cjs.map +1 -1
- package/dist/Select/index.js +11 -5
- package/dist/SubmitButton/index.cjs +12 -6
- package/dist/SubmitButton/index.cjs.map +1 -1
- package/dist/SubmitButton/index.js +11 -5
- package/dist/Switch/index.cjs +12 -6
- package/dist/Switch/index.cjs.map +1 -1
- package/dist/Switch/index.js +11 -5
- package/dist/TextArea/index.cjs +12 -6
- package/dist/TextArea/index.cjs.map +1 -1
- package/dist/TextArea/index.js +11 -5
- package/dist/{chunk-GBPAALJG.cjs → chunk-345LYO4H.cjs} +3 -3
- package/dist/{chunk-GBPAALJG.cjs.map → chunk-345LYO4H.cjs.map} +1 -1
- package/dist/chunk-35V726MB.js +1 -0
- package/dist/chunk-35V726MB.js.map +1 -0
- package/dist/{chunk-SLLZPY7M.js → chunk-6C6YW5TM.js} +2 -2
- package/dist/{chunk-ATRA4SVX.cjs → chunk-A5Z75X7M.cjs} +3 -3
- package/dist/{chunk-ATRA4SVX.cjs.map → chunk-A5Z75X7M.cjs.map} +1 -1
- package/dist/chunk-AACO4OEK.cjs +100 -0
- package/dist/chunk-AACO4OEK.cjs.map +1 -0
- package/dist/chunk-AHJJIANM.js +7 -0
- package/dist/chunk-AHJJIANM.js.map +1 -0
- package/dist/{chunk-5OX4LSPF.js → chunk-BXGILW5C.js} +4 -4
- package/dist/chunk-CK362NWK.js +34 -0
- package/dist/chunk-CK362NWK.js.map +1 -0
- package/dist/chunk-D3NAUOYG.js +122 -0
- package/dist/chunk-D3NAUOYG.js.map +1 -0
- package/dist/chunk-D5UUY4BD.cjs +68 -0
- package/dist/chunk-D5UUY4BD.cjs.map +1 -0
- package/dist/{chunk-MTMVQAN3.cjs → chunk-E4DCVJS5.cjs} +3 -3
- package/dist/{chunk-MTMVQAN3.cjs.map → chunk-E4DCVJS5.cjs.map} +1 -1
- package/dist/{chunk-D5ZZGT4Z.cjs → chunk-F6JQYB53.cjs} +4 -4
- package/dist/{chunk-D5ZZGT4Z.cjs.map → chunk-F6JQYB53.cjs.map} +1 -1
- package/dist/{chunk-HW4B6QID.js → chunk-GUPJNFEX.js} +10 -6
- package/dist/{chunk-HW4B6QID.js.map → chunk-GUPJNFEX.js.map} +1 -1
- package/dist/{chunk-GNBMDY5Q.js → chunk-H24QXVUI.js} +2 -2
- package/dist/{chunk-YJE5OZJ5.js → chunk-HQGTCSHK.js} +2 -2
- package/dist/{chunk-XCYA4ZBY.cjs → chunk-IYULWK4H.cjs} +7 -5
- package/dist/chunk-IYULWK4H.cjs.map +1 -0
- package/dist/{chunk-CVSFT7PV.js → chunk-JKWNYLNS.js} +4 -4
- package/dist/chunk-JMFDNTVC.cjs +34 -0
- package/dist/chunk-JMFDNTVC.cjs.map +1 -0
- package/dist/chunk-L5TXRTPB.js +68 -0
- package/dist/chunk-L5TXRTPB.js.map +1 -0
- package/dist/chunk-LTKRK3OS.cjs +1 -0
- package/dist/chunk-LTKRK3OS.cjs.map +1 -0
- package/dist/{chunk-MVZIOCAW.js → chunk-MXUKW3PZ.js} +2 -2
- package/dist/{chunk-3SZ2UKFA.cjs → chunk-NZBO4N3S.cjs} +4 -280
- package/dist/chunk-NZBO4N3S.cjs.map +1 -0
- package/dist/{chunk-XNAXMUTF.cjs → chunk-NZIAIYPS.cjs} +4 -4
- package/dist/{chunk-XNAXMUTF.cjs.map → chunk-NZIAIYPS.cjs.map} +1 -1
- package/dist/{chunk-JF437QVX.cjs → chunk-OJHD2XHD.cjs} +3 -3
- package/dist/{chunk-JF437QVX.cjs.map → chunk-OJHD2XHD.cjs.map} +1 -1
- package/dist/chunk-PCTYJUY7.cjs +7 -0
- package/dist/chunk-PCTYJUY7.cjs.map +1 -0
- package/dist/{chunk-2K6FWC4H.js → chunk-PO5UQAU6.js} +2 -278
- package/dist/chunk-PO5UQAU6.js.map +1 -0
- package/dist/{chunk-FNRALO75.js → chunk-QRCV7JVB.js} +2 -2
- package/dist/{chunk-3OFR3TO6.cjs → chunk-RMCPVDAC.cjs} +3 -3
- package/dist/{chunk-3OFR3TO6.cjs.map → chunk-RMCPVDAC.cjs.map} +1 -1
- package/dist/{chunk-NAN6QRAS.js → chunk-SJZ7UUEE.js} +5 -3
- package/dist/{chunk-NAN6QRAS.js.map → chunk-SJZ7UUEE.js.map} +1 -1
- package/dist/chunk-TGJJZEHB.cjs +122 -0
- package/dist/chunk-TGJJZEHB.cjs.map +1 -0
- package/dist/{chunk-IRWIEND4.js → chunk-TKFODQWI.js} +2 -2
- package/dist/{chunk-4HTB52DX.cjs → chunk-VPUMTPD3.cjs} +3 -3
- package/dist/{chunk-4HTB52DX.cjs.map → chunk-VPUMTPD3.cjs.map} +1 -1
- package/dist/{chunk-D537ZGNE.cjs → chunk-WFO4XPA3.cjs} +4 -4
- package/dist/{chunk-D537ZGNE.cjs.map → chunk-WFO4XPA3.cjs.map} +1 -1
- package/dist/{chunk-JEXF6TLO.cjs → chunk-XJBGXFVX.cjs} +10 -6
- package/dist/chunk-XJBGXFVX.cjs.map +1 -0
- package/dist/chunk-Z7FVILDT.js +100 -0
- package/dist/chunk-Z7FVILDT.js.map +1 -0
- package/dist/{chunk-MLPLWUXZ.js → chunk-Z7NI5347.js} +2 -2
- package/dist/hooks/index.cjs +18 -7
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.cts +10 -287
- package/dist/hooks/index.d.ts +10 -287
- package/dist/hooks/index.js +24 -13
- package/dist/hooks/useClientValidation/index.cjs +12 -0
- package/dist/hooks/useClientValidation/index.cjs.map +1 -0
- package/dist/hooks/useClientValidation/index.d.cts +147 -0
- package/dist/hooks/useClientValidation/index.d.ts +147 -0
- package/dist/hooks/useClientValidation/index.js +12 -0
- package/dist/hooks/useClientValidation/index.js.map +1 -0
- package/dist/hooks/useController/index.cjs +9 -0
- package/dist/hooks/useController/index.cjs.map +1 -0
- package/dist/hooks/useController/index.d.cts +28 -0
- package/dist/hooks/useController/index.d.ts +28 -0
- package/dist/hooks/useController/index.js +9 -0
- package/dist/hooks/useController/index.js.map +1 -0
- package/dist/hooks/useFormContext/index.cjs +11 -0
- package/dist/hooks/useFormContext/index.cjs.map +1 -0
- package/dist/hooks/useFormContext/index.d.cts +50 -0
- package/dist/hooks/useFormContext/index.d.ts +50 -0
- package/dist/hooks/useFormContext/index.js +11 -0
- package/dist/hooks/useFormContext/index.js.map +1 -0
- package/dist/hooks/useInput/index.cjs +8 -0
- package/dist/hooks/useInput/index.cjs.map +1 -0
- package/dist/hooks/useInput/index.d.cts +1 -0
- package/dist/hooks/useInput/index.d.ts +1 -0
- package/dist/hooks/useInput/index.js +8 -0
- package/dist/hooks/useInput/index.js.map +1 -0
- package/dist/hooks/useUniformField/index.cjs +14 -0
- package/dist/hooks/useUniformField/index.cjs.map +1 -0
- package/dist/hooks/useUniformField/index.d.cts +83 -0
- package/dist/hooks/useUniformField/index.d.ts +83 -0
- package/dist/hooks/useUniformField/index.js +14 -0
- package/dist/hooks/useUniformField/index.js.map +1 -0
- package/dist/hooks/useUniformFieldArray/index.cjs +15 -0
- package/dist/hooks/useUniformFieldArray/index.cjs.map +1 -0
- package/dist/hooks/useUniformFieldArray/index.d.cts +70 -0
- package/dist/hooks/useUniformFieldArray/index.d.ts +70 -0
- package/dist/hooks/useUniformFieldArray/index.js +15 -0
- package/dist/hooks/useUniformFieldArray/index.js.map +1 -0
- package/dist/index.cjs +28 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.js +38 -27
- package/package.json +31 -1
- package/dist/chunk-2K6FWC4H.js.map +0 -1
- package/dist/chunk-3SZ2UKFA.cjs.map +0 -1
- package/dist/chunk-JEXF6TLO.cjs.map +0 -1
- package/dist/chunk-XCYA4ZBY.cjs.map +0 -1
- /package/dist/{chunk-SLLZPY7M.js.map → chunk-6C6YW5TM.js.map} +0 -0
- /package/dist/{chunk-5OX4LSPF.js.map → chunk-BXGILW5C.js.map} +0 -0
- /package/dist/{chunk-GNBMDY5Q.js.map → chunk-H24QXVUI.js.map} +0 -0
- /package/dist/{chunk-YJE5OZJ5.js.map → chunk-HQGTCSHK.js.map} +0 -0
- /package/dist/{chunk-CVSFT7PV.js.map → chunk-JKWNYLNS.js.map} +0 -0
- /package/dist/{chunk-MVZIOCAW.js.map → chunk-MXUKW3PZ.js.map} +0 -0
- /package/dist/{chunk-FNRALO75.js.map → chunk-QRCV7JVB.js.map} +0 -0
- /package/dist/{chunk-IRWIEND4.js.map → chunk-TKFODQWI.js.map} +0 -0
- /package/dist/{chunk-MLPLWUXZ.js.map → chunk-Z7NI5347.js.map} +0 -0
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1,290 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import { UseControllerProps as UseControllerProps$1, ControllerRenderProps, UseFormStateReturn, ControllerFieldState, FieldValues, Path, FieldError, ArrayPath } from 'react-hook-form';
|
|
6
|
-
import * as _heroui_input from '@heroui/input';
|
|
7
|
-
import { useInput } from '@heroui/input';
|
|
1
|
+
export { clientValidationSchemaByName, useClientValidation } from './useClientValidation/index.js';
|
|
2
|
+
export { UseControllerProps, UseControllerReturn, useController } from './useController/index.js';
|
|
3
|
+
export { UseUniformFieldArrayProps, useUniformFieldArray } from './useUniformFieldArray/index.js';
|
|
4
|
+
export { checkFieldIsRequired, useFormContext } from './useFormContext/index.js';
|
|
8
5
|
export { useInput } from '@heroui/input';
|
|
9
|
-
import * as React from 'react';
|
|
10
|
-
import { ReactNode } from 'react';
|
|
11
|
-
import { D as DebugModeSettings } from '../FormContext-LRho0tno.js';
|
|
12
6
|
export { UseInputValueDebounceOptions, UseInputValueDebounceReturn, useInputValueDebounce } from './useInputValueDebounce/index.js';
|
|
13
7
|
export { InputValueTransform, UseInputValueTransformOptions, UseInputValueTransformReturn, useInputValueTransform } from './useInputValueTransform/index.js';
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
*
|
|
21
|
-
* When the client validation schema changes, automatically re-validates all touched
|
|
22
|
-
* fields to ensure they are validated against the new schema.
|
|
23
|
-
*
|
|
24
|
-
* @param data - Data to create validation schema from (or null/undefined to clear validation)
|
|
25
|
-
* @param schemaFactory - Function that creates a validation schema from the data.
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* ```tsx
|
|
29
|
-
* const { data: teamData } = useTeamQuery(teamId);
|
|
30
|
-
*
|
|
31
|
-
* useClientValidation(teamData, (data) =>
|
|
32
|
-
* vt.object({
|
|
33
|
-
* username: vt.string().refine(
|
|
34
|
-
* (value) => !data.existingUsers.includes(value),
|
|
35
|
-
* { message: 'Username already exists' }
|
|
36
|
-
* )
|
|
37
|
-
* })
|
|
38
|
-
* );
|
|
39
|
-
* ```
|
|
40
|
-
*/
|
|
41
|
-
declare const useClientValidation: <TData = unknown>(data: TData | null | undefined, schemaFactory: (data: TData) => VetoTypeAny) => void;
|
|
42
|
-
/**
|
|
43
|
-
* Helper function to create a veto looseObject schema for a single field with nested path support.
|
|
44
|
-
*
|
|
45
|
-
* Parses field paths (dot-notation) and creates properly nested loose object schemas with array support.
|
|
46
|
-
* All intermediate objects and arrays are marked as optional to allow partial data structures.
|
|
47
|
-
* Numeric segments in the path are treated as array indices, and the parent field is wrapped in an array schema.
|
|
48
|
-
*
|
|
49
|
-
* @param name - The dot-separated path to the field (e.g., 'username', 'user.profile.email', 'items.0.name')
|
|
50
|
-
* @param fieldSchema - The veto validation schema for the field
|
|
51
|
-
* @returns A nested loose object schema matching the field path structure with proper type inference
|
|
52
|
-
*
|
|
53
|
-
* @example
|
|
54
|
-
* ```tsx
|
|
55
|
-
* // Simple field
|
|
56
|
-
* clientValidationSchemaByName('username', vt.string())
|
|
57
|
-
* // => objectLoose({ username: vt.string() })
|
|
58
|
-
* ```
|
|
59
|
-
*
|
|
60
|
-
* @example
|
|
61
|
-
* ```tsx
|
|
62
|
-
* // Nested field (with optional intermediate objects)
|
|
63
|
-
* clientValidationSchemaByName('user.profile.email', vt.string().email())
|
|
64
|
-
* // => objectLoose({ user: objectLoose({ profile: objectLoose({ email: vt.string().email() }).optional() }).optional() })
|
|
65
|
-
* ```
|
|
66
|
-
*
|
|
67
|
-
* @example
|
|
68
|
-
* ```tsx
|
|
69
|
-
* // Array field (with optional array)
|
|
70
|
-
* clientValidationSchemaByName('items.0.name', vt.string())
|
|
71
|
-
* // => objectLoose({ items: array(objectLoose({ name: vt.string() })).optional() })
|
|
72
|
-
* ```
|
|
73
|
-
*
|
|
74
|
-
* @example
|
|
75
|
-
* ```tsx
|
|
76
|
-
* // Usage with useClientValidation
|
|
77
|
-
* const { data: userData } = useUserQuery(userId);
|
|
78
|
-
*
|
|
79
|
-
* useClientValidation(userData, (data) =>
|
|
80
|
-
* clientValidationSchemaByName('username', vt.string().refine(
|
|
81
|
-
* (value) => !data.existingUsernames.includes(value),
|
|
82
|
-
* { message: 'Username already taken' }
|
|
83
|
-
* ))
|
|
84
|
-
* );
|
|
85
|
-
* ```
|
|
86
|
-
*/
|
|
87
|
-
declare const clientValidationSchemaByName: <T extends VetoTypeAny>(name: string, fieldSchema: T) => _fuf_stack_veto_dist_types_d_CNPgNK_V.Z;
|
|
88
|
-
|
|
89
|
-
type UseControllerProps<TFieldValues extends object = object> = UseControllerProps$1<TFieldValues>;
|
|
90
|
-
interface UseControllerReturn<TFieldValues extends object = object> {
|
|
91
|
-
field: Omit<ControllerRenderProps<TFieldValues>, 'onChange' | 'value'> & {
|
|
92
|
-
onChange: (...event: any[]) => void;
|
|
93
|
-
value: string;
|
|
94
|
-
};
|
|
95
|
-
formState: UseFormStateReturn<TFieldValues>;
|
|
96
|
-
fieldState: ControllerFieldState;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* A wrapper around react-hook-form's useController that transparently handles nullish string conversions.
|
|
100
|
-
*
|
|
101
|
-
* Key features:
|
|
102
|
-
* 1. Empty strings ('') in the UI are stored as null in form state
|
|
103
|
-
* 2. Null/undefined values in form state are displayed as empty strings in the UI
|
|
104
|
-
* 3. Handles both direct value changes and React synthetic events
|
|
105
|
-
* 4. Maintains the same API as react-hook-form's useController
|
|
106
|
-
*
|
|
107
|
-
* This enables consistent handling of empty/null values while keeping a clean API
|
|
108
|
-
* for form inputs that expect string values.
|
|
109
|
-
*
|
|
110
|
-
* @see https://react-hook-form.com/docs/usecontroller
|
|
111
|
-
*/
|
|
112
|
-
declare const useController: <TFieldValues extends object = object>(props: UseControllerProps<TFieldValues>) => UseControllerReturn<TFieldValues>;
|
|
113
|
-
|
|
114
|
-
/** Schema check whether a field is required or optional */
|
|
115
|
-
declare const checkFieldIsRequired: (validation: VetoInstance, path: string[]) => boolean;
|
|
116
|
-
/**
|
|
117
|
-
* Custom hook that extends react-hook-form's useFormContext to add validation and state management.
|
|
118
|
-
*/
|
|
119
|
-
declare const useFormContext: <TFieldValues extends FieldValues = FieldValues, TContext = any, TTransformedValues = TFieldValues>() => {
|
|
120
|
-
formState: react_hook_form.FormState<TFieldValues>;
|
|
121
|
-
getFieldState: (name: Path<TFieldValues>, testId?: string) => {
|
|
122
|
-
error: FieldError[] | undefined;
|
|
123
|
-
invalid: boolean;
|
|
124
|
-
required: boolean;
|
|
125
|
-
testId: string;
|
|
126
|
-
isDirty: boolean;
|
|
127
|
-
isTouched: boolean;
|
|
128
|
-
isValidating: boolean;
|
|
129
|
-
};
|
|
130
|
-
getValues: react_hook_form.UseFormGetValues<TFieldValues>;
|
|
131
|
-
subscribe: react_hook_form.UseFromSubscribe<TFieldValues>;
|
|
132
|
-
watch: react_hook_form.UseFormWatch<TFieldValues>;
|
|
133
|
-
debugMode: "debug" | "debug-testids" | "off" | "disabled";
|
|
134
|
-
debugModeSettings?: DebugModeSettings;
|
|
135
|
-
preventSubmit: (prevent: boolean) => void;
|
|
136
|
-
setDebugMode: (debugMode: "debug" | "debug-testids" | "off" | "disabled") => void;
|
|
137
|
-
triggerSubmit: (e?: React.BaseSyntheticEvent) => Promise<void> | void;
|
|
138
|
-
validation: {
|
|
139
|
-
instance?: VetoInstance;
|
|
140
|
-
errors?: VetoFormattedError;
|
|
141
|
-
setClientValidationSchema: (key: string, schema: _fuf_stack_veto.VetoTypeAny | null) => void;
|
|
142
|
-
};
|
|
143
|
-
setError: react_hook_form.UseFormSetError<TFieldValues>;
|
|
144
|
-
clearErrors: react_hook_form.UseFormClearErrors<TFieldValues>;
|
|
145
|
-
setValue: react_hook_form.UseFormSetValue<TFieldValues>;
|
|
146
|
-
trigger: react_hook_form.UseFormTrigger<TFieldValues>;
|
|
147
|
-
resetField: react_hook_form.UseFormResetField<TFieldValues>;
|
|
148
|
-
reset: react_hook_form.UseFormReset<TFieldValues>;
|
|
149
|
-
handleSubmit: react_hook_form.UseFormHandleSubmit<TFieldValues, TTransformedValues>;
|
|
150
|
-
unregister: react_hook_form.UseFormUnregister<TFieldValues>;
|
|
151
|
-
control: react_hook_form.Control<TFieldValues, TContext, TTransformedValues>;
|
|
152
|
-
register: react_hook_form.UseFormRegister<TFieldValues>;
|
|
153
|
-
setFocus: react_hook_form.UseFormSetFocus<TFieldValues>;
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
interface UseUniformFieldArrayProps<TFieldValues extends FieldValues = FieldValues> {
|
|
157
|
-
/** Field name for the array */
|
|
158
|
-
name: ArrayPath<TFieldValues>;
|
|
159
|
-
/** Whether this is a flat array (array of primitives) */
|
|
160
|
-
flat?: boolean;
|
|
161
|
-
/** Initial value for new array elements */
|
|
162
|
-
elementInitialValue?: unknown;
|
|
163
|
-
/** Whether the last element cannot be removed (always maintain at least one element) */
|
|
164
|
-
lastElementNotRemovable?: boolean;
|
|
165
|
-
/** Disable the field */
|
|
166
|
-
disabled?: boolean;
|
|
167
|
-
/** Optional explicit test id used to build stable test ids */
|
|
168
|
-
testId?: string;
|
|
169
|
-
/** Optional label content; pass false to suppress label entirely */
|
|
170
|
-
label?: ReactNode | false;
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Enhanced useFieldArray hook with initialization and animation logic.
|
|
174
|
-
* Based on React Hook Form's useFieldArray with additional features:
|
|
175
|
-
* - Automatic initialization when lastElementNotRemovable is set
|
|
176
|
-
* - Animation control (disabled during initialization)
|
|
177
|
-
* - Support for flat arrays (arrays of primitives)
|
|
178
|
-
*
|
|
179
|
-
* Note: Automatic validation triggering on length change is disabled to prevent
|
|
180
|
-
* triggering form-wide validation. Array validation still runs on form submission.
|
|
181
|
-
*
|
|
182
|
-
* @see https://react-hook-form.com/docs/usefieldarray
|
|
183
|
-
*/
|
|
184
|
-
declare const useUniformFieldArray: <TFieldValues extends FieldValues = FieldValues>({ name, flat, elementInitialValue: _elementInitialValue, lastElementNotRemovable, disabled, testId: explicitTestId, label, }: UseUniformFieldArrayProps<TFieldValues>) => {
|
|
185
|
-
control: react_hook_form.Control<TFieldValues, any, TFieldValues>;
|
|
186
|
-
debugMode: ReturnType<typeof useFormContext<TFieldValues_1>>["debugMode"];
|
|
187
|
-
defaultValue: unknown;
|
|
188
|
-
disabled: boolean | undefined;
|
|
189
|
-
error: react_hook_form.FieldError[] | undefined;
|
|
190
|
-
errorMessage: ReactNode | null;
|
|
191
|
-
field: Omit<react_hook_form.ControllerRenderProps<TFieldValues>, "value" | "onChange"> & {
|
|
192
|
-
onChange: (... /** Initial value for new array elements */event: any[]) => void;
|
|
193
|
-
value: string;
|
|
194
|
-
};
|
|
195
|
-
getErrorMessageProps: ReturnType<typeof _heroui_input.useInput>["getErrorMessageProps"];
|
|
196
|
-
getHelperWrapperProps: ReturnType<typeof _heroui_input.useInput>["getHelperWrapperProps"];
|
|
197
|
-
getLabelProps: ReturnType<typeof _heroui_input.useInput>["getLabelProps"];
|
|
198
|
-
getValues: react_hook_form.UseFormGetValues<TFieldValues>;
|
|
199
|
-
invalid: boolean;
|
|
200
|
-
label: ReactNode | null;
|
|
201
|
-
onBlur: ReturnType<typeof useController>["field"]["onBlur"];
|
|
202
|
-
onChange: ReturnType<typeof useController>["field"]["onChange"];
|
|
203
|
-
ref: ReturnType<typeof useController>["field"]["ref"];
|
|
204
|
-
required: boolean;
|
|
205
|
-
resetField: react_hook_form.UseFormResetField<TFieldValues>;
|
|
206
|
-
testId: string;
|
|
207
|
-
fields: react_hook_form.FieldArrayWithId<TFieldValues, ArrayPath<TFieldValues>, "id">[];
|
|
208
|
-
append: react_hook_form.UseFieldArrayAppend<TFieldValues, ArrayPath<TFieldValues>>;
|
|
209
|
-
remove: react_hook_form.UseFieldArrayRemove;
|
|
210
|
-
insert: react_hook_form.UseFieldArrayInsert<TFieldValues, ArrayPath<TFieldValues>>;
|
|
211
|
-
move: react_hook_form.UseFieldArrayMove;
|
|
212
|
-
disableAnimation: boolean;
|
|
213
|
-
elementInitialValue: {};
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
interface UseUniformFieldParams<TFieldValues extends FieldValues = FieldValues> {
|
|
217
|
-
/** Form field name */
|
|
218
|
-
name: Path<TFieldValues> & string;
|
|
219
|
-
/** Disable the field */
|
|
220
|
-
disabled?: boolean;
|
|
221
|
-
/** Optional explicit test id used to build stable test ids */
|
|
222
|
-
testId?: string;
|
|
223
|
-
/** Optional label content; pass false to suppress label entirely */
|
|
224
|
-
label?: ReactNode | false;
|
|
225
|
-
}
|
|
226
|
-
interface UseUniformFieldReturn<TFieldValues extends FieldValues = FieldValues> {
|
|
227
|
-
/** react-hook-form control instance for advanced integrations */
|
|
228
|
-
control: ReturnType<typeof useFormContext<TFieldValues>>['control'];
|
|
229
|
-
/** Debug mode from Uniform provider */
|
|
230
|
-
debugMode: ReturnType<typeof useFormContext<TFieldValues>>['debugMode'];
|
|
231
|
-
/** Current value used to initialize uncontrolled components */
|
|
232
|
-
defaultValue: unknown;
|
|
233
|
-
/** Whether the field is currently disabled (from RHF) */
|
|
234
|
-
disabled: boolean | undefined;
|
|
235
|
-
/** Validation error(s) for the field */
|
|
236
|
-
error: FieldError[] | undefined;
|
|
237
|
-
/** Pre-built errorMessage node to plug into components */
|
|
238
|
-
errorMessage: ReactNode | null;
|
|
239
|
-
/** RHF controller field with nullish conversions applied */
|
|
240
|
-
field: ReturnType<typeof useController<TFieldValues>>['field'];
|
|
241
|
-
/** Helper to spread standardized error message props to underlying components */
|
|
242
|
-
getErrorMessageProps: ReturnType<typeof useInput>['getErrorMessageProps'];
|
|
243
|
-
/** Helper to spread standardized helper wrapper props (for spacing/animation) */
|
|
244
|
-
getHelperWrapperProps: ReturnType<typeof useInput>['getHelperWrapperProps'];
|
|
245
|
-
/** Helper to spread standardized label props to underlying components */
|
|
246
|
-
getLabelProps: ReturnType<typeof useInput>['getLabelProps'];
|
|
247
|
-
/** Access current form values (converted to validation-friendly format) */
|
|
248
|
-
getValues: ReturnType<typeof useFormContext<TFieldValues>>['getValues'];
|
|
249
|
-
/** Whether the field should show invalid state (debounced for smooth animations). True when field is invalid AND (dirty OR touched OR submitted) */
|
|
250
|
-
invalid: boolean;
|
|
251
|
-
/** Computed label node including optional test id copy button */
|
|
252
|
-
label: ReactNode | null;
|
|
253
|
-
/** onBlur handler from controller */
|
|
254
|
-
onBlur: ReturnType<typeof useController<TFieldValues>>['field']['onBlur'];
|
|
255
|
-
/** onChange handler from controller (with nullish handling) */
|
|
256
|
-
onChange: ReturnType<typeof useController<TFieldValues>>['field']['onChange'];
|
|
257
|
-
/** Ref to forward to underlying control */
|
|
258
|
-
ref: ReturnType<typeof useController<TFieldValues>>['field']['ref'];
|
|
259
|
-
/** Whether the field is required according to validation schema */
|
|
260
|
-
required: boolean;
|
|
261
|
-
/** Reset a specific field in the form */
|
|
262
|
-
resetField: ReturnType<typeof useFormContext<TFieldValues>>['resetField'];
|
|
263
|
-
/** Generated HTML data-testid for the field */
|
|
264
|
-
testId: string;
|
|
265
|
-
}
|
|
266
|
-
/**
|
|
267
|
-
* Combines frequently used form field logic into a single hook.
|
|
268
|
-
*
|
|
269
|
-
* Provides:
|
|
270
|
-
* - Enhanced form context (validation-aware state, `testId`, value transforms)
|
|
271
|
-
* - Controller field with nullish conversion handling
|
|
272
|
-
* - Debounced `invalid` state with smart timing:
|
|
273
|
-
* • `true` (field becomes invalid): applies immediately so errors show right away
|
|
274
|
-
* • `false` (field becomes valid): delayed 200ms to allow smooth exit animations
|
|
275
|
-
* • Respects `prefers-reduced-motion` by skipping delays when user prefers reduced motion
|
|
276
|
-
* - Smart `invalid` visibility (via `showInvalid`):
|
|
277
|
-
* • Shows errors when field is dirty OR touched OR form has been submitted
|
|
278
|
-
* • Prevents showing errors on pristine/untouched fields for better UX
|
|
279
|
-
* • Works well for all field types (text inputs, checkboxes, radios, arrays)
|
|
280
|
-
* - Prebuilt `errorMessage` React node using `FieldValidationError`
|
|
281
|
-
* - Computed `label` node which appends a `FieldCopyTestIdButton` in
|
|
282
|
-
* `debug-testids` mode
|
|
283
|
-
* - `defaultValue` for uncontrolled defaults and all usual field handlers
|
|
284
|
-
* - Access to form utilities: `control`, `getValues`, `resetField`
|
|
285
|
-
* - Presentation helpers: `getLabelProps`, `getErrorMessageProps`,
|
|
286
|
-
* `getHelperWrapperProps` for consistent wiring to underlying UI components
|
|
287
|
-
*/
|
|
288
|
-
declare function useUniformField<TFieldValues extends FieldValues = FieldValues>(params: UseUniformFieldParams<TFieldValues>): UseUniformFieldReturn<TFieldValues>;
|
|
289
|
-
|
|
290
|
-
export { type UseControllerProps, type UseControllerReturn, type UseUniformFieldArrayProps, type UseUniformFieldParams, type UseUniformFieldReturn, checkFieldIsRequired, clientValidationSchemaByName, useClientValidation, useController, useFormContext, useUniformField, useUniformFieldArray };
|
|
8
|
+
export { UseUniformFieldParams, UseUniformFieldReturn, useUniformField } from './useUniformField/index.js';
|
|
9
|
+
import '@fuf-stack/veto/dist/types.d-Dzd6j9xO';
|
|
10
|
+
import '@fuf-stack/veto';
|
|
11
|
+
import 'react-hook-form';
|
|
12
|
+
import 'react';
|
|
13
|
+
import '../FormContext-LRho0tno.js';
|
package/dist/hooks/index.js
CHANGED
|
@@ -1,22 +1,33 @@
|
|
|
1
|
-
import
|
|
2
|
-
checkFieldIsRequired,
|
|
3
|
-
clientValidationSchemaByName,
|
|
4
|
-
useClientValidation,
|
|
5
|
-
useController,
|
|
6
|
-
useFormContext,
|
|
7
|
-
useInput,
|
|
8
|
-
useUniformField,
|
|
9
|
-
useUniformFieldArray
|
|
10
|
-
} from "../chunk-2K6FWC4H.js";
|
|
11
|
-
import "../chunk-NTDKZW4E.js";
|
|
12
|
-
import "../chunk-ELYGQTXB.js";
|
|
13
|
-
import "../chunk-76KOVUDN.js";
|
|
1
|
+
import "../chunk-35V726MB.js";
|
|
14
2
|
import {
|
|
15
3
|
useInputValueDebounce
|
|
16
4
|
} from "../chunk-MODD3TFE.js";
|
|
17
5
|
import {
|
|
18
6
|
useInputValueTransform
|
|
19
7
|
} from "../chunk-7KLFK2IT.js";
|
|
8
|
+
import {
|
|
9
|
+
useUniformFieldArray
|
|
10
|
+
} from "../chunk-Z7FVILDT.js";
|
|
11
|
+
import {
|
|
12
|
+
useUniformField
|
|
13
|
+
} from "../chunk-D3NAUOYG.js";
|
|
14
|
+
import "../chunk-ELYGQTXB.js";
|
|
15
|
+
import {
|
|
16
|
+
useController
|
|
17
|
+
} from "../chunk-CK362NWK.js";
|
|
18
|
+
import {
|
|
19
|
+
useInput
|
|
20
|
+
} from "../chunk-AHJJIANM.js";
|
|
21
|
+
import "../chunk-NTDKZW4E.js";
|
|
22
|
+
import {
|
|
23
|
+
clientValidationSchemaByName,
|
|
24
|
+
useClientValidation
|
|
25
|
+
} from "../chunk-L5TXRTPB.js";
|
|
26
|
+
import {
|
|
27
|
+
checkFieldIsRequired,
|
|
28
|
+
useFormContext
|
|
29
|
+
} from "../chunk-PO5UQAU6.js";
|
|
30
|
+
import "../chunk-76KOVUDN.js";
|
|
20
31
|
import "../chunk-K2V4ULA2.js";
|
|
21
32
|
export {
|
|
22
33
|
checkFieldIsRequired,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
var _chunkD5UUY4BDcjs = require('../../chunk-D5UUY4BD.cjs');
|
|
5
|
+
require('../../chunk-NZBO4N3S.cjs');
|
|
6
|
+
require('../../chunk-Z353BLWI.cjs');
|
|
7
|
+
require('../../chunk-555JRYCS.cjs');
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
exports.clientValidationSchemaByName = _chunkD5UUY4BDcjs.clientValidationSchemaByName; exports.useClientValidation = _chunkD5UUY4BDcjs.useClientValidation;
|
|
12
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/pixels/pixels/packages/uniform/dist/hooks/useClientValidation/index.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACF,4DAAiC;AACjC,oCAAiC;AACjC,oCAAiC;AACjC,oCAAiC;AACjC;AACE;AACA;AACF,2JAAC","file":"/home/runner/work/pixels/pixels/packages/uniform/dist/hooks/useClientValidation/index.cjs"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import * as _fuf_stack_veto_dist_types_d_Dzd6j9xO from '@fuf-stack/veto/dist/types.d-Dzd6j9xO';
|
|
2
|
+
import { VetoTypeAny } from '@fuf-stack/veto';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hook for adding dynamic client-side validation to forms.
|
|
6
|
+
*
|
|
7
|
+
* Client validation is used for context-dependent validation rules that require external data
|
|
8
|
+
* (e.g., checking if a username already exists). It complements base validation (passed to Form),
|
|
9
|
+
* which handles static rules like "required", min/max length, format, etc.
|
|
10
|
+
*
|
|
11
|
+
* **Typical pattern:**
|
|
12
|
+
* - Base validation: Static, always-on rules (required, format, length constraints)
|
|
13
|
+
* - Client validation: Dynamic rules based on external data (uniqueness, business logic)
|
|
14
|
+
* - Client schemas should use `.nullish()` to allow empty values (base validation handles "required")
|
|
15
|
+
*
|
|
16
|
+
* Automatically manages validation schema lifecycle: sets schema when data is provided,
|
|
17
|
+
* clears schema when data is null/undefined, and cleans up on unmount. When the client
|
|
18
|
+
* validation schema changes, automatically re-validates all touched fields.
|
|
19
|
+
*
|
|
20
|
+
* @param data - Data to create validation schema from (or null/undefined to clear validation)
|
|
21
|
+
* @param schemaFactory - Function that creates a validation schema from the data. Schemas should typically use `.nullish()`.
|
|
22
|
+
* @param options - Optional configuration object
|
|
23
|
+
* @param options.key - Optional custom key for registration. Useful when multiple instances should share validation (e.g., in field arrays)
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```tsx
|
|
27
|
+
* // Base validation handles "required" and format
|
|
28
|
+
* const baseSchema = veto({ username: vt.string({ min: 3 }) });
|
|
29
|
+
*
|
|
30
|
+
* // Client validation adds dynamic uniqueness check
|
|
31
|
+
* const { data: teamData } = useTeamQuery(teamId);
|
|
32
|
+
* useClientValidation(teamData, (data) =>
|
|
33
|
+
* vt.objectLoose({
|
|
34
|
+
* username: vt.string()
|
|
35
|
+
* .refine(
|
|
36
|
+
* (value) => !data.existingUsers.includes(value),
|
|
37
|
+
* { message: 'Username already exists' }
|
|
38
|
+
* )
|
|
39
|
+
* .nullish() // Allow empty - base validation handles "required"
|
|
40
|
+
* })
|
|
41
|
+
* );
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```tsx
|
|
46
|
+
* // Using custom key in a field array to avoid multiple registrations
|
|
47
|
+
* fields.map((field, index) => (
|
|
48
|
+
* useClientValidation(
|
|
49
|
+
* userData,
|
|
50
|
+
* (data) => clientValidationSchemaByName(
|
|
51
|
+
* `items.${index}.name`,
|
|
52
|
+
* vt.string()
|
|
53
|
+
* .refine((val) => !data.forbidden.includes(val), { message: 'Name not allowed' })
|
|
54
|
+
* .nullish()
|
|
55
|
+
* ),
|
|
56
|
+
* { key: 'items-validation' } // All instances share the same key
|
|
57
|
+
* )
|
|
58
|
+
* ));
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
declare const useClientValidation: <TData = unknown>(data: TData | null | undefined, schemaFactory: (data: TData) => VetoTypeAny, options?: {
|
|
62
|
+
key?: string;
|
|
63
|
+
}) => void;
|
|
64
|
+
/**
|
|
65
|
+
* Helper function to create a veto looseObject schema for a single field with nested path support.
|
|
66
|
+
*
|
|
67
|
+
* Parses field paths (dot-notation) and creates properly nested loose object schemas with array support.
|
|
68
|
+
* All intermediate objects and arrays are marked as optional to allow partial data structures.
|
|
69
|
+
* Numeric segments in the path are treated as array indices, and the parent field is wrapped in an array schema.
|
|
70
|
+
* Supports flat arrays (arrays of primitives) via the special `__FLAT__` key.
|
|
71
|
+
*
|
|
72
|
+
* **Important:** The fieldSchema should typically use `.nullish()` to allow empty values. This is because:
|
|
73
|
+
* - Base validation (passed to Form) handles "required" constraints
|
|
74
|
+
* - Client validation adds dynamic, context-dependent rules (e.g., "username already exists")
|
|
75
|
+
* - Form data processing converts empty strings in flat arrays to `null` (not `undefined`)
|
|
76
|
+
* - `.nullish()` accepts both `null` and `undefined`, while `.optional()` only accepts `undefined`
|
|
77
|
+
*
|
|
78
|
+
* This pattern ensures client validation only validates non-empty values, while base validation
|
|
79
|
+
* enforces required fields and basic constraints (min length, format, etc.).
|
|
80
|
+
*
|
|
81
|
+
* @param name - The dot-separated path to the field (e.g., 'username', 'user.profile.email', 'items.0.name', 'tags.0.__FLAT__')
|
|
82
|
+
* @param fieldSchema - The veto validation schema for the field. Should typically use `.nullish()` to allow empty values.
|
|
83
|
+
* @returns A nested loose object schema matching the field path structure with proper type inference
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```tsx
|
|
87
|
+
* // Typical usage: base validation handles "required", client validation adds dynamic rules
|
|
88
|
+
* // Base validation (in Form component)
|
|
89
|
+
* const baseSchema = veto({ username: vt.string({ min: 3 }) }); // Required + min length
|
|
90
|
+
*
|
|
91
|
+
* // Client validation (dynamic check for existing usernames)
|
|
92
|
+
* const { data: userData } = useUserQuery(userId);
|
|
93
|
+
* useClientValidation(userData, (data) =>
|
|
94
|
+
* clientValidationSchemaByName(
|
|
95
|
+
* 'username',
|
|
96
|
+
* vt.string()
|
|
97
|
+
* .refine(
|
|
98
|
+
* (value) => !data.existingUsernames.includes(value),
|
|
99
|
+
* { message: 'Username already taken' }
|
|
100
|
+
* )
|
|
101
|
+
* .nullish() // Allow empty - base validation handles "required"
|
|
102
|
+
* )
|
|
103
|
+
* );
|
|
104
|
+
* ```
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```tsx
|
|
108
|
+
* // Nested field path with dynamic validation
|
|
109
|
+
* clientValidationSchemaByName(
|
|
110
|
+
* 'user.profile.email',
|
|
111
|
+
* vt.string()
|
|
112
|
+
* .refine(
|
|
113
|
+
* (value) => !reservedEmails.includes(value),
|
|
114
|
+
* { message: 'This email is reserved' }
|
|
115
|
+
* )
|
|
116
|
+
* .nullish()
|
|
117
|
+
* )
|
|
118
|
+
* // => objectLoose({ user: objectLoose({ profile: objectLoose({ email: ... }).optional() }).optional() })
|
|
119
|
+
* ```
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```tsx
|
|
123
|
+
* // Array of objects with dynamic validation
|
|
124
|
+
* clientValidationSchemaByName(
|
|
125
|
+
* 'items.0.tag',
|
|
126
|
+
* vt.string()
|
|
127
|
+
* .refine((value) => !forbiddenTags.includes(value), { message: 'Tag not allowed' })
|
|
128
|
+
* .nullish()
|
|
129
|
+
* )
|
|
130
|
+
* // => objectLoose({ items: array(objectLoose({ tag: ... })).optional() })
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```tsx
|
|
135
|
+
* // Flat array (array of primitives) with dynamic validation
|
|
136
|
+
* clientValidationSchemaByName(
|
|
137
|
+
* 'tags.0.__FLAT__',
|
|
138
|
+
* vt.string()
|
|
139
|
+
* .refine((value) => !forbiddenWords.includes(value), { message: 'Word not allowed' })
|
|
140
|
+
* .nullish()
|
|
141
|
+
* )
|
|
142
|
+
* // => objectLoose({ tags: array(vt.string().refine(...).nullish()).optional() })
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
declare const clientValidationSchemaByName: <T extends VetoTypeAny>(name: string, fieldSchema: T) => _fuf_stack_veto_dist_types_d_Dzd6j9xO.Z;
|
|
146
|
+
|
|
147
|
+
export { clientValidationSchemaByName, useClientValidation };
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import * as _fuf_stack_veto_dist_types_d_Dzd6j9xO from '@fuf-stack/veto/dist/types.d-Dzd6j9xO';
|
|
2
|
+
import { VetoTypeAny } from '@fuf-stack/veto';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hook for adding dynamic client-side validation to forms.
|
|
6
|
+
*
|
|
7
|
+
* Client validation is used for context-dependent validation rules that require external data
|
|
8
|
+
* (e.g., checking if a username already exists). It complements base validation (passed to Form),
|
|
9
|
+
* which handles static rules like "required", min/max length, format, etc.
|
|
10
|
+
*
|
|
11
|
+
* **Typical pattern:**
|
|
12
|
+
* - Base validation: Static, always-on rules (required, format, length constraints)
|
|
13
|
+
* - Client validation: Dynamic rules based on external data (uniqueness, business logic)
|
|
14
|
+
* - Client schemas should use `.nullish()` to allow empty values (base validation handles "required")
|
|
15
|
+
*
|
|
16
|
+
* Automatically manages validation schema lifecycle: sets schema when data is provided,
|
|
17
|
+
* clears schema when data is null/undefined, and cleans up on unmount. When the client
|
|
18
|
+
* validation schema changes, automatically re-validates all touched fields.
|
|
19
|
+
*
|
|
20
|
+
* @param data - Data to create validation schema from (or null/undefined to clear validation)
|
|
21
|
+
* @param schemaFactory - Function that creates a validation schema from the data. Schemas should typically use `.nullish()`.
|
|
22
|
+
* @param options - Optional configuration object
|
|
23
|
+
* @param options.key - Optional custom key for registration. Useful when multiple instances should share validation (e.g., in field arrays)
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```tsx
|
|
27
|
+
* // Base validation handles "required" and format
|
|
28
|
+
* const baseSchema = veto({ username: vt.string({ min: 3 }) });
|
|
29
|
+
*
|
|
30
|
+
* // Client validation adds dynamic uniqueness check
|
|
31
|
+
* const { data: teamData } = useTeamQuery(teamId);
|
|
32
|
+
* useClientValidation(teamData, (data) =>
|
|
33
|
+
* vt.objectLoose({
|
|
34
|
+
* username: vt.string()
|
|
35
|
+
* .refine(
|
|
36
|
+
* (value) => !data.existingUsers.includes(value),
|
|
37
|
+
* { message: 'Username already exists' }
|
|
38
|
+
* )
|
|
39
|
+
* .nullish() // Allow empty - base validation handles "required"
|
|
40
|
+
* })
|
|
41
|
+
* );
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```tsx
|
|
46
|
+
* // Using custom key in a field array to avoid multiple registrations
|
|
47
|
+
* fields.map((field, index) => (
|
|
48
|
+
* useClientValidation(
|
|
49
|
+
* userData,
|
|
50
|
+
* (data) => clientValidationSchemaByName(
|
|
51
|
+
* `items.${index}.name`,
|
|
52
|
+
* vt.string()
|
|
53
|
+
* .refine((val) => !data.forbidden.includes(val), { message: 'Name not allowed' })
|
|
54
|
+
* .nullish()
|
|
55
|
+
* ),
|
|
56
|
+
* { key: 'items-validation' } // All instances share the same key
|
|
57
|
+
* )
|
|
58
|
+
* ));
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
declare const useClientValidation: <TData = unknown>(data: TData | null | undefined, schemaFactory: (data: TData) => VetoTypeAny, options?: {
|
|
62
|
+
key?: string;
|
|
63
|
+
}) => void;
|
|
64
|
+
/**
|
|
65
|
+
* Helper function to create a veto looseObject schema for a single field with nested path support.
|
|
66
|
+
*
|
|
67
|
+
* Parses field paths (dot-notation) and creates properly nested loose object schemas with array support.
|
|
68
|
+
* All intermediate objects and arrays are marked as optional to allow partial data structures.
|
|
69
|
+
* Numeric segments in the path are treated as array indices, and the parent field is wrapped in an array schema.
|
|
70
|
+
* Supports flat arrays (arrays of primitives) via the special `__FLAT__` key.
|
|
71
|
+
*
|
|
72
|
+
* **Important:** The fieldSchema should typically use `.nullish()` to allow empty values. This is because:
|
|
73
|
+
* - Base validation (passed to Form) handles "required" constraints
|
|
74
|
+
* - Client validation adds dynamic, context-dependent rules (e.g., "username already exists")
|
|
75
|
+
* - Form data processing converts empty strings in flat arrays to `null` (not `undefined`)
|
|
76
|
+
* - `.nullish()` accepts both `null` and `undefined`, while `.optional()` only accepts `undefined`
|
|
77
|
+
*
|
|
78
|
+
* This pattern ensures client validation only validates non-empty values, while base validation
|
|
79
|
+
* enforces required fields and basic constraints (min length, format, etc.).
|
|
80
|
+
*
|
|
81
|
+
* @param name - The dot-separated path to the field (e.g., 'username', 'user.profile.email', 'items.0.name', 'tags.0.__FLAT__')
|
|
82
|
+
* @param fieldSchema - The veto validation schema for the field. Should typically use `.nullish()` to allow empty values.
|
|
83
|
+
* @returns A nested loose object schema matching the field path structure with proper type inference
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```tsx
|
|
87
|
+
* // Typical usage: base validation handles "required", client validation adds dynamic rules
|
|
88
|
+
* // Base validation (in Form component)
|
|
89
|
+
* const baseSchema = veto({ username: vt.string({ min: 3 }) }); // Required + min length
|
|
90
|
+
*
|
|
91
|
+
* // Client validation (dynamic check for existing usernames)
|
|
92
|
+
* const { data: userData } = useUserQuery(userId);
|
|
93
|
+
* useClientValidation(userData, (data) =>
|
|
94
|
+
* clientValidationSchemaByName(
|
|
95
|
+
* 'username',
|
|
96
|
+
* vt.string()
|
|
97
|
+
* .refine(
|
|
98
|
+
* (value) => !data.existingUsernames.includes(value),
|
|
99
|
+
* { message: 'Username already taken' }
|
|
100
|
+
* )
|
|
101
|
+
* .nullish() // Allow empty - base validation handles "required"
|
|
102
|
+
* )
|
|
103
|
+
* );
|
|
104
|
+
* ```
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```tsx
|
|
108
|
+
* // Nested field path with dynamic validation
|
|
109
|
+
* clientValidationSchemaByName(
|
|
110
|
+
* 'user.profile.email',
|
|
111
|
+
* vt.string()
|
|
112
|
+
* .refine(
|
|
113
|
+
* (value) => !reservedEmails.includes(value),
|
|
114
|
+
* { message: 'This email is reserved' }
|
|
115
|
+
* )
|
|
116
|
+
* .nullish()
|
|
117
|
+
* )
|
|
118
|
+
* // => objectLoose({ user: objectLoose({ profile: objectLoose({ email: ... }).optional() }).optional() })
|
|
119
|
+
* ```
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```tsx
|
|
123
|
+
* // Array of objects with dynamic validation
|
|
124
|
+
* clientValidationSchemaByName(
|
|
125
|
+
* 'items.0.tag',
|
|
126
|
+
* vt.string()
|
|
127
|
+
* .refine((value) => !forbiddenTags.includes(value), { message: 'Tag not allowed' })
|
|
128
|
+
* .nullish()
|
|
129
|
+
* )
|
|
130
|
+
* // => objectLoose({ items: array(objectLoose({ tag: ... })).optional() })
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```tsx
|
|
135
|
+
* // Flat array (array of primitives) with dynamic validation
|
|
136
|
+
* clientValidationSchemaByName(
|
|
137
|
+
* 'tags.0.__FLAT__',
|
|
138
|
+
* vt.string()
|
|
139
|
+
* .refine((value) => !forbiddenWords.includes(value), { message: 'Word not allowed' })
|
|
140
|
+
* .nullish()
|
|
141
|
+
* )
|
|
142
|
+
* // => objectLoose({ tags: array(vt.string().refine(...).nullish()).optional() })
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
declare const clientValidationSchemaByName: <T extends VetoTypeAny>(name: string, fieldSchema: T) => _fuf_stack_veto_dist_types_d_Dzd6j9xO.Z;
|
|
146
|
+
|
|
147
|
+
export { clientValidationSchemaByName, useClientValidation };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
clientValidationSchemaByName,
|
|
3
|
+
useClientValidation
|
|
4
|
+
} from "../../chunk-L5TXRTPB.js";
|
|
5
|
+
import "../../chunk-PO5UQAU6.js";
|
|
6
|
+
import "../../chunk-76KOVUDN.js";
|
|
7
|
+
import "../../chunk-K2V4ULA2.js";
|
|
8
|
+
export {
|
|
9
|
+
clientValidationSchemaByName,
|
|
10
|
+
useClientValidation
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|