@mehdashti/forms 0.4.1 → 0.6.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/index.d.ts CHANGED
@@ -4,6 +4,7 @@ export { FieldErrors, FieldValues, Path, PathValue } from 'react-hook-form';
4
4
  import { z, ZodTypeAny } from 'zod';
5
5
  export { z } from 'zod';
6
6
  import * as react_jsx_runtime from 'react/jsx-runtime';
7
+ import { InputProps } from '@mehdashti/ui';
7
8
  import * as React$1 from 'react';
8
9
 
9
10
  interface SmartFormOptions<TFieldValues extends FieldValues = FieldValues> {
@@ -40,6 +41,279 @@ declare function useSmartForm<TFieldValues extends FieldValues = FieldValues>(op
40
41
  };
41
42
  type SmartFormReturn<TFieldValues extends FieldValues = FieldValues> = ReturnType<typeof useSmartForm<TFieldValues>>;
42
43
 
44
+ interface FormInputProps<TFieldValues extends FieldValues> extends Omit<InputProps, "name"> {
45
+ /**
46
+ * Field name (registered with react-hook-form)
47
+ */
48
+ name: Path<TFieldValues>;
49
+ /**
50
+ * Field label
51
+ */
52
+ label?: string;
53
+ /**
54
+ * Helper text shown below the input
55
+ */
56
+ helperText?: string;
57
+ /**
58
+ * Whether the field is required
59
+ */
60
+ required?: boolean;
61
+ }
62
+ declare function FormInput<TFieldValues extends FieldValues>({ name, label, helperText, required, ...inputProps }: FormInputProps<TFieldValues>): react_jsx_runtime.JSX.Element;
63
+
64
+ interface FormTextareaProps$1<TFieldValues extends FieldValues> extends Omit<React$1.TextareaHTMLAttributes<HTMLTextAreaElement>, "name"> {
65
+ /**
66
+ * Field name (registered with react-hook-form)
67
+ */
68
+ name: Path<TFieldValues>;
69
+ /**
70
+ * Field label
71
+ */
72
+ label?: string;
73
+ /**
74
+ * Helper text shown below the input
75
+ */
76
+ helperText?: string;
77
+ /**
78
+ * Whether the field is required
79
+ */
80
+ required?: boolean;
81
+ }
82
+ declare function FormTextarea$1<TFieldValues extends FieldValues>({ name, label, helperText, required, className, ...textareaProps }: FormTextareaProps$1<TFieldValues>): react_jsx_runtime.JSX.Element;
83
+
84
+ interface FormSelectOption {
85
+ value: string;
86
+ label: string;
87
+ disabled?: boolean;
88
+ }
89
+ interface FormSelectProps$1<TFieldValues extends FieldValues> {
90
+ /**
91
+ * Field name (registered with react-hook-form)
92
+ */
93
+ name: Path<TFieldValues>;
94
+ /**
95
+ * Field label
96
+ */
97
+ label?: string;
98
+ /**
99
+ * Helper text shown below the select
100
+ */
101
+ helperText?: string;
102
+ /**
103
+ * Whether the field is required
104
+ */
105
+ required?: boolean;
106
+ /**
107
+ * Whether the field is disabled
108
+ */
109
+ disabled?: boolean;
110
+ /**
111
+ * Placeholder text
112
+ */
113
+ placeholder?: string;
114
+ /**
115
+ * Select options
116
+ */
117
+ options: FormSelectOption[];
118
+ /**
119
+ * Custom className
120
+ */
121
+ className?: string;
122
+ /**
123
+ * Callback when value changes
124
+ */
125
+ onChange?: (value: string) => void;
126
+ }
127
+ declare function FormSelect$1<TFieldValues extends FieldValues>({ name, label, helperText, required, disabled, placeholder, options, className, onChange, }: FormSelectProps$1<TFieldValues>): react_jsx_runtime.JSX.Element;
128
+
129
+ interface FormCheckboxProps$1<TFieldValues extends FieldValues> {
130
+ /**
131
+ * Field name (registered with react-hook-form)
132
+ */
133
+ name: Path<TFieldValues>;
134
+ /**
135
+ * Checkbox label
136
+ */
137
+ label?: string;
138
+ /**
139
+ * Description shown below the label
140
+ */
141
+ description?: string;
142
+ /**
143
+ * Helper text shown below the checkbox
144
+ */
145
+ helperText?: string;
146
+ /**
147
+ * Whether the field is required
148
+ */
149
+ required?: boolean;
150
+ /**
151
+ * Whether the field is disabled
152
+ */
153
+ disabled?: boolean;
154
+ /**
155
+ * Custom className
156
+ */
157
+ className?: string;
158
+ /**
159
+ * Callback when value changes
160
+ */
161
+ onChange?: (checked: boolean) => void;
162
+ }
163
+ declare function FormCheckbox$1<TFieldValues extends FieldValues>({ name, label, description, helperText, required, disabled, className, onChange, }: FormCheckboxProps$1<TFieldValues>): react_jsx_runtime.JSX.Element;
164
+
165
+ interface FormSwitchProps<TFieldValues extends FieldValues> {
166
+ /**
167
+ * Field name (registered with react-hook-form)
168
+ */
169
+ name: Path<TFieldValues>;
170
+ /**
171
+ * Switch label
172
+ */
173
+ label?: string;
174
+ /**
175
+ * Description shown below the label
176
+ */
177
+ description?: string;
178
+ /**
179
+ * Help text shown below the switch
180
+ */
181
+ helperText?: string;
182
+ /**
183
+ * Whether the field is required
184
+ */
185
+ required?: boolean;
186
+ /**
187
+ * Whether the field is disabled
188
+ */
189
+ disabled?: boolean;
190
+ /**
191
+ * Custom className
192
+ */
193
+ className?: string;
194
+ /**
195
+ * Callback when value changes
196
+ */
197
+ onChange?: (checked: boolean) => void;
198
+ }
199
+ declare function FormSwitch<TFieldValues extends FieldValues>({ name, label, description, helperText, required, disabled, className, onChange, }: FormSwitchProps<TFieldValues>): react_jsx_runtime.JSX.Element;
200
+
201
+ interface RadioOption {
202
+ value: string;
203
+ label: string;
204
+ description?: string;
205
+ disabled?: boolean;
206
+ }
207
+ interface FormRadioGroupProps<TFieldValues extends FieldValues> {
208
+ /**
209
+ * Field name (registered with react-hook-form)
210
+ */
211
+ name: Path<TFieldValues>;
212
+ /**
213
+ * Radio group label
214
+ */
215
+ label?: string;
216
+ /**
217
+ * Radio options
218
+ */
219
+ options: RadioOption[];
220
+ /**
221
+ * Layout orientation
222
+ */
223
+ orientation?: "vertical" | "horizontal";
224
+ /**
225
+ * Help text shown below the radio group
226
+ */
227
+ helperText?: string;
228
+ /**
229
+ * Whether the field is required
230
+ */
231
+ required?: boolean;
232
+ /**
233
+ * Whether the field is disabled
234
+ */
235
+ disabled?: boolean;
236
+ /**
237
+ * Custom className
238
+ */
239
+ className?: string;
240
+ }
241
+ declare function FormRadioGroup<TFieldValues extends FieldValues>({ name, label, options, orientation, helperText, required, disabled, className, }: FormRadioGroupProps<TFieldValues>): react_jsx_runtime.JSX.Element;
242
+
243
+ interface FormTagInputProps<TFieldValues extends FieldValues> {
244
+ /**
245
+ * Field name (registered with react-hook-form)
246
+ */
247
+ name: Path<TFieldValues>;
248
+ /**
249
+ * Field label
250
+ */
251
+ label?: string;
252
+ /**
253
+ * Placeholder text
254
+ */
255
+ placeholder?: string;
256
+ /**
257
+ * Help text shown below the input
258
+ */
259
+ helperText?: string;
260
+ /**
261
+ * Whether the field is required
262
+ */
263
+ required?: boolean;
264
+ /**
265
+ * Whether the field is disabled
266
+ */
267
+ disabled?: boolean;
268
+ /**
269
+ * Maximum number of tags allowed
270
+ */
271
+ maxTags?: number;
272
+ /**
273
+ * Separator keys (default: Enter, comma)
274
+ */
275
+ separators?: string[];
276
+ /**
277
+ * Validate individual tags before adding
278
+ */
279
+ validateTag?: (tag: string) => boolean | string;
280
+ /**
281
+ * Custom className
282
+ */
283
+ className?: string;
284
+ }
285
+ declare function FormTagInput<TFieldValues extends FieldValues>({ name, label, placeholder, helperText, required, disabled, maxTags, separators, validateTag, className, }: FormTagInputProps<TFieldValues>): react_jsx_runtime.JSX.Element;
286
+
287
+ /**
288
+ * FormErrorSummary Component
289
+ *
290
+ * Displays all form errors in a summary box with links to fields.
291
+ */
292
+ interface FormErrorSummaryProps {
293
+ /**
294
+ * Title for the error summary
295
+ */
296
+ title?: string;
297
+ /**
298
+ * Custom field labels (for better error messages)
299
+ */
300
+ fieldLabels?: Record<string, string>;
301
+ /**
302
+ * Whether to show the error summary
303
+ * Defaults to showing when there are errors
304
+ */
305
+ show?: boolean;
306
+ /**
307
+ * Custom className
308
+ */
309
+ className?: string;
310
+ /**
311
+ * Callback when an error link is clicked
312
+ */
313
+ onErrorClick?: (fieldName: string) => void;
314
+ }
315
+ declare function FormErrorSummary({ title, fieldLabels, show, className, onErrorClick, }: FormErrorSummaryProps): react_jsx_runtime.JSX.Element | null;
316
+
43
317
  /**
44
318
  * Form field component props
45
319
  */
@@ -261,158 +535,6 @@ interface FormMultiSelectProps<TFieldValues extends FieldValues = FieldValues> {
261
535
  */
262
536
  declare function FormMultiSelect<TFieldValues extends FieldValues = FieldValues>({ name, label, options, required, helpText, disabled, className, control, layout, maxSelection, }: FormMultiSelectProps<TFieldValues>): react_jsx_runtime.JSX.Element;
263
537
 
264
- interface RadioOption {
265
- value: string;
266
- label: string;
267
- description?: string;
268
- disabled?: boolean;
269
- }
270
- interface FormRadioGroupProps<TFieldValues extends FieldValues> {
271
- /**
272
- * Field name (registered with react-hook-form)
273
- */
274
- name: Path<TFieldValues>;
275
- /**
276
- * Radio group label
277
- */
278
- label?: string;
279
- /**
280
- * Radio options
281
- */
282
- options: RadioOption[];
283
- /**
284
- * Layout orientation
285
- */
286
- orientation?: "vertical" | "horizontal";
287
- /**
288
- * Help text shown below the radio group
289
- */
290
- helperText?: string;
291
- /**
292
- * Whether the field is required
293
- */
294
- required?: boolean;
295
- /**
296
- * Whether the field is disabled
297
- */
298
- disabled?: boolean;
299
- /**
300
- * Custom className
301
- */
302
- className?: string;
303
- }
304
- declare function FormRadioGroup<TFieldValues extends FieldValues>({ name, label, options, orientation, helperText, required, disabled, className, }: FormRadioGroupProps<TFieldValues>): react_jsx_runtime.JSX.Element;
305
-
306
- interface FormSwitchProps<TFieldValues extends FieldValues> {
307
- /**
308
- * Field name (registered with react-hook-form)
309
- */
310
- name: Path<TFieldValues>;
311
- /**
312
- * Switch label
313
- */
314
- label?: string;
315
- /**
316
- * Description shown below the label
317
- */
318
- description?: string;
319
- /**
320
- * Help text shown below the switch
321
- */
322
- helperText?: string;
323
- /**
324
- * Whether the field is required
325
- */
326
- required?: boolean;
327
- /**
328
- * Whether the field is disabled
329
- */
330
- disabled?: boolean;
331
- /**
332
- * Custom className
333
- */
334
- className?: string;
335
- /**
336
- * Callback when value changes
337
- */
338
- onChange?: (checked: boolean) => void;
339
- }
340
- declare function FormSwitch<TFieldValues extends FieldValues>({ name, label, description, helperText, required, disabled, className, onChange, }: FormSwitchProps<TFieldValues>): react_jsx_runtime.JSX.Element;
341
-
342
- interface FormTagInputProps<TFieldValues extends FieldValues> {
343
- /**
344
- * Field name (registered with react-hook-form)
345
- */
346
- name: Path<TFieldValues>;
347
- /**
348
- * Field label
349
- */
350
- label?: string;
351
- /**
352
- * Placeholder text
353
- */
354
- placeholder?: string;
355
- /**
356
- * Help text shown below the input
357
- */
358
- helperText?: string;
359
- /**
360
- * Whether the field is required
361
- */
362
- required?: boolean;
363
- /**
364
- * Whether the field is disabled
365
- */
366
- disabled?: boolean;
367
- /**
368
- * Maximum number of tags allowed
369
- */
370
- maxTags?: number;
371
- /**
372
- * Separator keys (default: Enter, comma)
373
- */
374
- separators?: string[];
375
- /**
376
- * Validate individual tags before adding
377
- */
378
- validateTag?: (tag: string) => boolean | string;
379
- /**
380
- * Custom className
381
- */
382
- className?: string;
383
- }
384
- declare function FormTagInput<TFieldValues extends FieldValues>({ name, label, placeholder, helperText, required, disabled, maxTags, separators, validateTag, className, }: FormTagInputProps<TFieldValues>): react_jsx_runtime.JSX.Element;
385
-
386
- /**
387
- * FormErrorSummary Component
388
- *
389
- * Displays all form errors in a summary box with links to fields.
390
- */
391
- interface FormErrorSummaryProps {
392
- /**
393
- * Title for the error summary
394
- */
395
- title?: string;
396
- /**
397
- * Custom field labels (for better error messages)
398
- */
399
- fieldLabels?: Record<string, string>;
400
- /**
401
- * Whether to show the error summary
402
- * Defaults to showing when there are errors
403
- */
404
- show?: boolean;
405
- /**
406
- * Custom className
407
- */
408
- className?: string;
409
- /**
410
- * Callback when an error link is clicked
411
- */
412
- onErrorClick?: (fieldName: string) => void;
413
- }
414
- declare function FormErrorSummary({ title, fieldLabels, show, className, onErrorClick, }: FormErrorSummaryProps): react_jsx_runtime.JSX.Element | null;
415
-
416
538
  interface FormLayoutProps extends React$1.HTMLAttributes<HTMLDivElement> {
417
539
  /**
418
540
  * Number of columns for the form layout
@@ -644,8 +766,45 @@ declare function useUnsavedChanges(options?: UseUnsavedChangesOptions): {
644
766
  hasUnsavedChanges: boolean;
645
767
  isDirty: boolean;
646
768
  };
769
+
647
770
  /**
648
- * Hook variant for React Router integration
771
+ * React Router Integration for Unsaved Changes
772
+ *
773
+ * Provides adapters for blocking navigation with unsaved form changes.
774
+ */
775
+ interface BlockerState {
776
+ /**
777
+ * Whether navigation is currently blocked
778
+ */
779
+ state: "unblocked" | "blocked" | "proceeding";
780
+ /**
781
+ * The location that was blocked (if blocked)
782
+ */
783
+ location?: any;
784
+ /**
785
+ * Proceed with the blocked navigation
786
+ */
787
+ proceed: () => void;
788
+ /**
789
+ * Cancel/reset the blocked navigation
790
+ */
791
+ reset: () => void;
792
+ }
793
+ interface UseUnsavedChangesBlockerOptions {
794
+ /**
795
+ * Custom condition for when to block navigation
796
+ * If not provided, blocks when form is dirty and not submitting
797
+ */
798
+ when?: boolean;
799
+ /**
800
+ * Custom message for the blocker
801
+ */
802
+ message?: string;
803
+ }
804
+ /**
805
+ * Base blocker hook for unsaved form changes
806
+ *
807
+ * Returns blocker state that can be used with React Router or custom navigation
649
808
  *
650
809
  * @example
651
810
  * ```tsx
@@ -668,11 +827,64 @@ declare function useUnsavedChanges(options?: UseUnsavedChangesOptions): {
668
827
  * }
669
828
  * ```
670
829
  */
671
- declare function useUnsavedChangesBlocker(): {
830
+ declare function useUnsavedChangesBlocker(_options?: UseUnsavedChangesBlockerOptions): BlockerState & {
672
831
  hasUnsavedChanges: boolean;
673
832
  isDirty: boolean;
674
- shouldBlock: boolean;
675
833
  };
834
+ /**
835
+ * React Router v6 adapter for unsaved changes blocker
836
+ *
837
+ * Uses React Router's useBlocker hook to prevent navigation
838
+ *
839
+ * @example
840
+ * ```tsx
841
+ * import { useUnsavedChangesBlockerReactRouter } from "@mehdashti/forms";
842
+ * import { useBlocker } from "react-router-dom";
843
+ *
844
+ * function MyForm() {
845
+ * const form = useSmartForm({ schema: mySchema });
846
+ * const blocker = useUnsavedChangesBlockerReactRouter(useBlocker);
847
+ *
848
+ * if (blocker.state === "blocked") {
849
+ * return (
850
+ * <ConfirmDialog
851
+ * title="Unsaved changes"
852
+ * message="You have unsaved changes. Are you sure you want to leave?"
853
+ * onConfirm={() => blocker.proceed()}
854
+ * onCancel={() => blocker.reset()}
855
+ * />
856
+ * );
857
+ * }
858
+ *
859
+ * return <FormProvider {...form}>...</FormProvider>;
860
+ * }
861
+ * ```
862
+ */
863
+ declare function useUnsavedChangesBlockerReactRouter(useBlocker: any, // React Router's useBlocker hook
864
+ options?: UseUnsavedChangesBlockerOptions): any;
865
+ /**
866
+ * TanStack Router adapter for unsaved changes blocker
867
+ *
868
+ * Uses TanStack Router's useBlocker hook to prevent navigation
869
+ *
870
+ * @example
871
+ * ```tsx
872
+ * import { useUnsavedChangesBlockerTanStack } from "@mehdashti/forms";
873
+ * import { useBlocker } from "@tanstack/react-router";
874
+ *
875
+ * function MyForm() {
876
+ * const form = useSmartForm({ schema: mySchema });
877
+ * const blocker = useUnsavedChangesBlockerTanStack(useBlocker);
878
+ *
879
+ * // TanStack Router handles the blocking UI automatically
880
+ * // or you can check blocker.status === "blocked"
881
+ *
882
+ * return <FormProvider {...form}>...</FormProvider>;
883
+ * }
884
+ * ```
885
+ */
886
+ declare function useUnsavedChangesBlockerTanStack(useBlocker: any, // TanStack Router's useBlocker hook
887
+ options?: UseUnsavedChangesBlockerOptions): any;
676
888
 
677
889
  /**
678
890
  * Common Validation Schemas
@@ -854,4 +1066,4 @@ declare function validateFileExtension(filename: string, allowedExtensions: stri
854
1066
  */
855
1067
  declare function formatValidationError(error: z.ZodError): Record<string, string>;
856
1068
 
857
- export { type FieldArrayOptions, FormCheckbox, type FormCheckboxProps, FormDatePicker, type FormDatePickerProps, FormErrorSummary, type FormErrorSummaryProps, FormField, type FormFieldProps, FormFileUpload, type FormFileUploadProps, FormGrid, FormGridItem, type FormGridItemProps, type FormGridProps, FormLayout, type FormLayoutProps, FormMultiSelect, type FormMultiSelectProps, FormRadioGroup, type FormRadioGroupProps, FormSection, type FormSectionProps, FormSelect, type FormSelectProps, FormSwitch, type FormSwitchProps, FormTagInput, type FormTagInputProps, FormTextarea, type FormTextareaProps, FormWizard, type FormWizardProps, type FormWizardStep, type MultiSelectOption, type RadioOption, type SelectOption, type SmartFormOptions, type SmartFormReturn, type UseUnsavedChangesOptions, conditionalSchema, createConfirmPasswordSchema, createFileSizeSchema, createFileTypeSchema, dateStringSchema, emailSchema, formatValidationError, futureDateSchema, getAllErrors, getErrorMessage, hasError, imageFileSchema, invalidFormatMessage, lengthMessage, optionalEmailSchema, optionalUrlSchema, passwordSchema, pastDateSchema, percentageSchema, phoneSchema, positiveIntegerSchema, positiveNumberSchema, priceSchema, requiredMessage, sanitizeString, slugSchema, strongPasswordSchema, urlSchema, useSmartFieldArray, useSmartForm, useUnsavedChanges, useUnsavedChangesBlocker, usernameSchema, validateCreditCard, validateFileExtension, validateIBAN, validatePasswordStrength };
1069
+ export { type BlockerState, type FieldArrayOptions, FormCheckbox, type FormCheckboxProps, FormCheckbox$1 as FormCheckboxUI, type FormCheckboxProps$1 as FormCheckboxUIProps, FormDatePicker, type FormDatePickerProps, FormErrorSummary, type FormErrorSummaryProps, FormField, type FormFieldProps, FormFileUpload, type FormFileUploadProps, FormGrid, FormGridItem, type FormGridItemProps, type FormGridProps, FormInput, type FormInputProps, FormLayout, type FormLayoutProps, FormMultiSelect, type FormMultiSelectProps, FormRadioGroup, type FormRadioGroupProps, FormSection, type FormSectionProps, FormSelect, type FormSelectOption, type FormSelectProps, FormSelect$1 as FormSelectUI, type FormSelectProps$1 as FormSelectUIProps, FormSwitch, type FormSwitchProps, FormTagInput, type FormTagInputProps, FormTextarea, type FormTextareaProps, FormTextarea$1 as FormTextareaUI, type FormTextareaProps$1 as FormTextareaUIProps, FormWizard, type FormWizardProps, type FormWizardStep, type MultiSelectOption, type RadioOption, type SelectOption, type SmartFormOptions, type SmartFormReturn, type UseUnsavedChangesBlockerOptions, type UseUnsavedChangesOptions, conditionalSchema, createConfirmPasswordSchema, createFileSizeSchema, createFileTypeSchema, dateStringSchema, emailSchema, formatValidationError, futureDateSchema, getAllErrors, getErrorMessage, hasError, imageFileSchema, invalidFormatMessage, lengthMessage, optionalEmailSchema, optionalUrlSchema, passwordSchema, pastDateSchema, percentageSchema, phoneSchema, positiveIntegerSchema, positiveNumberSchema, priceSchema, requiredMessage, sanitizeString, slugSchema, strongPasswordSchema, urlSchema, useSmartFieldArray, useSmartForm, useUnsavedChanges, useUnsavedChangesBlocker, useUnsavedChangesBlockerReactRouter, useUnsavedChangesBlockerTanStack, usernameSchema, validateCreditCard, validateFileExtension, validateIBAN, validatePasswordStrength };