@rachelallyson/hero-hook-form 1.2.0 → 2.1.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/CHANGELOG.md +96 -0
- package/README.md +115 -351
- package/dist/cypress/index.d.ts +141 -0
- package/dist/cypress/index.js +897 -0
- package/dist/index.d.ts +789 -15
- package/dist/index.js +2414 -422
- package/dist/react/index.d.ts +789 -15
- package/dist/react/index.js +2414 -422
- package/package.json +65 -33
package/dist/index.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
1
8
|
// src/components/Form.tsx
|
|
2
|
-
import
|
|
3
|
-
import { Button as
|
|
9
|
+
import React16 from "react";
|
|
10
|
+
import { Button as Button3 } from "@heroui/react";
|
|
4
11
|
|
|
5
12
|
// src/hooks/useFormHelper.ts
|
|
6
13
|
import { useState } from "react";
|
|
@@ -68,8 +75,8 @@ function useFormHelper({
|
|
|
68
75
|
}
|
|
69
76
|
|
|
70
77
|
// src/components/FormField.tsx
|
|
71
|
-
import
|
|
72
|
-
import { useWatch } from "react-hook-form";
|
|
78
|
+
import React15 from "react";
|
|
79
|
+
import { useWatch as useWatch3 } from "react-hook-form";
|
|
73
80
|
|
|
74
81
|
// src/fields/CheckboxField.tsx
|
|
75
82
|
import React2 from "react";
|
|
@@ -191,16 +198,16 @@ function CheckboxField(props) {
|
|
|
191
198
|
{
|
|
192
199
|
control,
|
|
193
200
|
name,
|
|
194
|
-
render: ({ field, fieldState }) => /* @__PURE__ */ React2.createElement("div", { className }, /* @__PURE__ */ React2.createElement(
|
|
201
|
+
render: ({ field: field2, fieldState }) => /* @__PURE__ */ React2.createElement("div", { className }, /* @__PURE__ */ React2.createElement(
|
|
195
202
|
Checkbox,
|
|
196
203
|
{
|
|
197
204
|
...defaults.checkbox,
|
|
198
205
|
...checkboxProps,
|
|
199
206
|
isDisabled,
|
|
200
207
|
isInvalid: Boolean(fieldState.error),
|
|
201
|
-
isSelected: Boolean(
|
|
202
|
-
onBlur:
|
|
203
|
-
onValueChange: (val) =>
|
|
208
|
+
isSelected: Boolean(field2.value),
|
|
209
|
+
onBlur: field2.onBlur,
|
|
210
|
+
onValueChange: (val) => field2.onChange(val)
|
|
204
211
|
},
|
|
205
212
|
label
|
|
206
213
|
), description ? /* @__PURE__ */ React2.createElement("p", { className: "text-small text-default-400" }, description) : null, fieldState.error?.message ? /* @__PURE__ */ React2.createElement("p", { className: "text-tiny text-danger mt-1" }, fieldState.error.message) : null),
|
|
@@ -209,13 +216,43 @@ function CheckboxField(props) {
|
|
|
209
216
|
);
|
|
210
217
|
}
|
|
211
218
|
|
|
212
|
-
// src/fields/
|
|
219
|
+
// src/fields/ConditionalField.tsx
|
|
213
220
|
import React3 from "react";
|
|
221
|
+
import { useWatch, useFormContext } from "react-hook-form";
|
|
222
|
+
function ConditionalField({
|
|
223
|
+
className,
|
|
224
|
+
config,
|
|
225
|
+
control
|
|
226
|
+
}) {
|
|
227
|
+
const { condition, field: field2 } = config;
|
|
228
|
+
const form = useFormContext();
|
|
229
|
+
const formValues = useWatch({ control });
|
|
230
|
+
const shouldShow = condition(formValues);
|
|
231
|
+
if (!shouldShow) {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
return /* @__PURE__ */ React3.createElement("div", { className }, /* @__PURE__ */ React3.createElement(
|
|
235
|
+
FormField,
|
|
236
|
+
{
|
|
237
|
+
config: field2,
|
|
238
|
+
form,
|
|
239
|
+
submissionState: {
|
|
240
|
+
error: void 0,
|
|
241
|
+
isSubmitted: false,
|
|
242
|
+
isSubmitting: false,
|
|
243
|
+
isSuccess: false
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
));
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// src/fields/DateField.tsx
|
|
250
|
+
import React4 from "react";
|
|
214
251
|
import { Controller as Controller2 } from "react-hook-form";
|
|
215
252
|
function CoercedDateInput(props) {
|
|
216
|
-
const { dateProps, description, disabled, errorMessage, field, label } = props;
|
|
253
|
+
const { dateProps, description, disabled, errorMessage, field: field2, label } = props;
|
|
217
254
|
const defaults = useHeroHookFormDefaults();
|
|
218
|
-
return /* @__PURE__ */
|
|
255
|
+
return /* @__PURE__ */ React4.createElement(
|
|
219
256
|
DateInput,
|
|
220
257
|
{
|
|
221
258
|
...defaults.dateInput,
|
|
@@ -225,9 +262,9 @@ function CoercedDateInput(props) {
|
|
|
225
262
|
isDisabled: disabled,
|
|
226
263
|
isInvalid: Boolean(errorMessage),
|
|
227
264
|
label,
|
|
228
|
-
value:
|
|
229
|
-
onBlur:
|
|
230
|
-
onChange:
|
|
265
|
+
value: field2.value ?? null,
|
|
266
|
+
onBlur: field2.onBlur,
|
|
267
|
+
onChange: field2.onChange
|
|
231
268
|
}
|
|
232
269
|
);
|
|
233
270
|
}
|
|
@@ -243,12 +280,12 @@ function DateField(props) {
|
|
|
243
280
|
rules,
|
|
244
281
|
transform
|
|
245
282
|
} = props;
|
|
246
|
-
return /* @__PURE__ */
|
|
283
|
+
return /* @__PURE__ */ React4.createElement(
|
|
247
284
|
Controller2,
|
|
248
285
|
{
|
|
249
286
|
control,
|
|
250
287
|
name,
|
|
251
|
-
render: ({ field, fieldState }) => /* @__PURE__ */
|
|
288
|
+
render: ({ field: field2, fieldState }) => /* @__PURE__ */ React4.createElement("div", { className }, /* @__PURE__ */ React4.createElement(
|
|
252
289
|
CoercedDateInput,
|
|
253
290
|
{
|
|
254
291
|
dateProps,
|
|
@@ -256,8 +293,8 @@ function DateField(props) {
|
|
|
256
293
|
disabled: isDisabled,
|
|
257
294
|
errorMessage: fieldState.error?.message,
|
|
258
295
|
field: {
|
|
259
|
-
...
|
|
260
|
-
onChange: (value) =>
|
|
296
|
+
...field2,
|
|
297
|
+
onChange: (value) => field2.onChange(transform ? transform(value) : value)
|
|
261
298
|
},
|
|
262
299
|
label
|
|
263
300
|
}
|
|
@@ -267,8 +304,144 @@ function DateField(props) {
|
|
|
267
304
|
);
|
|
268
305
|
}
|
|
269
306
|
|
|
307
|
+
// src/fields/DynamicSectionField.tsx
|
|
308
|
+
import React5 from "react";
|
|
309
|
+
import { useWatch as useWatch2, useFormContext as useFormContext2 } from "react-hook-form";
|
|
310
|
+
function DynamicSectionField({
|
|
311
|
+
className,
|
|
312
|
+
config,
|
|
313
|
+
control
|
|
314
|
+
}) {
|
|
315
|
+
const { condition, description, fields, title } = config;
|
|
316
|
+
const form = useFormContext2();
|
|
317
|
+
const formValues = useWatch2({ control });
|
|
318
|
+
const shouldShow = condition(formValues);
|
|
319
|
+
if (!shouldShow) {
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
return /* @__PURE__ */ React5.createElement("div", { className }, (title || description) && /* @__PURE__ */ React5.createElement("div", { className: "mb-6" }, title && /* @__PURE__ */ React5.createElement("h3", { className: "text-lg font-semibold text-gray-900 mb-2" }, title), description && /* @__PURE__ */ React5.createElement("p", { className: "text-sm text-gray-600" }, description)), /* @__PURE__ */ React5.createElement("div", { className: "space-y-4" }, fields.map((fieldConfig, index) => /* @__PURE__ */ React5.createElement(
|
|
323
|
+
FormField,
|
|
324
|
+
{
|
|
325
|
+
key: `${fieldConfig.name}-${index}`,
|
|
326
|
+
config: fieldConfig,
|
|
327
|
+
form,
|
|
328
|
+
submissionState: {
|
|
329
|
+
error: void 0,
|
|
330
|
+
isSubmitted: false,
|
|
331
|
+
isSubmitting: false,
|
|
332
|
+
isSuccess: false
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
))));
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// src/fields/FieldArrayField.tsx
|
|
339
|
+
import React6 from "react";
|
|
340
|
+
import { useFieldArray, useFormContext as useFormContext3 } from "react-hook-form";
|
|
341
|
+
import { Button as Button2 } from "@heroui/react";
|
|
342
|
+
function FieldArrayField({
|
|
343
|
+
className,
|
|
344
|
+
config
|
|
345
|
+
}) {
|
|
346
|
+
const {
|
|
347
|
+
addButtonText = "Add Item",
|
|
348
|
+
fields: fieldConfigs,
|
|
349
|
+
max = 10,
|
|
350
|
+
min = 0,
|
|
351
|
+
name,
|
|
352
|
+
removeButtonText = "Remove"
|
|
353
|
+
} = config;
|
|
354
|
+
const form = useFormContext3();
|
|
355
|
+
if (!form || !form.control) {
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
const { control } = form;
|
|
359
|
+
const { append, fields, remove } = useFieldArray({
|
|
360
|
+
control,
|
|
361
|
+
name
|
|
362
|
+
// FieldArray name
|
|
363
|
+
});
|
|
364
|
+
const canAdd = fields.length < max;
|
|
365
|
+
const canRemove = fields.length > min;
|
|
366
|
+
const handleAdd = () => {
|
|
367
|
+
if (canAdd) {
|
|
368
|
+
const defaultValues = fieldConfigs.reduce((acc, fieldConfig) => {
|
|
369
|
+
const fieldName = fieldConfig.name;
|
|
370
|
+
if (fieldConfig.type === "checkbox" || fieldConfig.type === "switch") {
|
|
371
|
+
acc[fieldName] = false;
|
|
372
|
+
} else if (fieldConfig.type === "slider") {
|
|
373
|
+
acc[fieldName] = 0;
|
|
374
|
+
} else {
|
|
375
|
+
acc[fieldName] = "";
|
|
376
|
+
}
|
|
377
|
+
return acc;
|
|
378
|
+
}, {});
|
|
379
|
+
append(defaultValues);
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
const handleRemove = (index) => {
|
|
383
|
+
if (canRemove) {
|
|
384
|
+
remove(index);
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
return /* @__PURE__ */ React6.createElement("div", { className }, /* @__PURE__ */ React6.createElement("div", { className: "space-y-4" }, fields.map((field2, index) => /* @__PURE__ */ React6.createElement(
|
|
388
|
+
"div",
|
|
389
|
+
{
|
|
390
|
+
key: field2.id,
|
|
391
|
+
className: "border border-gray-200 rounded-lg p-4 space-y-4"
|
|
392
|
+
},
|
|
393
|
+
/* @__PURE__ */ React6.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React6.createElement("h4", { className: "text-sm font-medium text-gray-700" }, config.label, " #", index + 1), canRemove && /* @__PURE__ */ React6.createElement(
|
|
394
|
+
Button2,
|
|
395
|
+
{
|
|
396
|
+
size: "sm",
|
|
397
|
+
variant: "light",
|
|
398
|
+
color: "danger",
|
|
399
|
+
startContent: "\u{1F5D1}\uFE0F",
|
|
400
|
+
onPress: () => handleRemove(index),
|
|
401
|
+
"aria-label": `${removeButtonText} ${config.label} ${index + 1}`
|
|
402
|
+
},
|
|
403
|
+
removeButtonText
|
|
404
|
+
)),
|
|
405
|
+
/* @__PURE__ */ React6.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, fieldConfigs.map((fieldConfig) => /* @__PURE__ */ React6.createElement(
|
|
406
|
+
FormField,
|
|
407
|
+
{
|
|
408
|
+
key: `${fieldConfig.name}-${index}`,
|
|
409
|
+
config: {
|
|
410
|
+
...fieldConfig,
|
|
411
|
+
name: `${name}.${index}.${fieldConfig.name}`
|
|
412
|
+
},
|
|
413
|
+
form,
|
|
414
|
+
submissionState: {
|
|
415
|
+
error: void 0,
|
|
416
|
+
isSubmitted: false,
|
|
417
|
+
isSubmitting: false,
|
|
418
|
+
isSuccess: false
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
)))
|
|
422
|
+
)), canAdd && /* @__PURE__ */ React6.createElement(
|
|
423
|
+
Button2,
|
|
424
|
+
{
|
|
425
|
+
variant: "bordered",
|
|
426
|
+
startContent: "\u2795",
|
|
427
|
+
onPress: handleAdd,
|
|
428
|
+
className: "w-full"
|
|
429
|
+
},
|
|
430
|
+
addButtonText
|
|
431
|
+
), fields.length === 0 && /* @__PURE__ */ React6.createElement("div", { className: "text-center py-8 text-gray-500" }, /* @__PURE__ */ React6.createElement("p", null, "No ", config.label?.toLowerCase(), " added yet."), /* @__PURE__ */ React6.createElement(
|
|
432
|
+
Button2,
|
|
433
|
+
{
|
|
434
|
+
variant: "bordered",
|
|
435
|
+
startContent: "\u2795",
|
|
436
|
+
onPress: handleAdd,
|
|
437
|
+
className: "mt-2"
|
|
438
|
+
},
|
|
439
|
+
addButtonText
|
|
440
|
+
))));
|
|
441
|
+
}
|
|
442
|
+
|
|
270
443
|
// src/fields/FileField.tsx
|
|
271
|
-
import
|
|
444
|
+
import React7 from "react";
|
|
272
445
|
import { Controller as Controller3 } from "react-hook-form";
|
|
273
446
|
function CoercedFileInput(props) {
|
|
274
447
|
const {
|
|
@@ -276,13 +449,13 @@ function CoercedFileInput(props) {
|
|
|
276
449
|
description,
|
|
277
450
|
disabled,
|
|
278
451
|
errorMessage,
|
|
279
|
-
field,
|
|
452
|
+
field: field2,
|
|
280
453
|
fileProps,
|
|
281
454
|
label,
|
|
282
455
|
multiple
|
|
283
456
|
} = props;
|
|
284
457
|
const defaults = useHeroHookFormDefaults();
|
|
285
|
-
return /* @__PURE__ */
|
|
458
|
+
return /* @__PURE__ */ React7.createElement(
|
|
286
459
|
Input,
|
|
287
460
|
{
|
|
288
461
|
...defaults.input,
|
|
@@ -295,11 +468,11 @@ function CoercedFileInput(props) {
|
|
|
295
468
|
label,
|
|
296
469
|
multiple,
|
|
297
470
|
type: "file",
|
|
298
|
-
value:
|
|
299
|
-
onBlur:
|
|
471
|
+
value: field2.value ? "" : "",
|
|
472
|
+
onBlur: field2.onBlur,
|
|
300
473
|
onChange: (e) => {
|
|
301
474
|
const target = e.target;
|
|
302
|
-
|
|
475
|
+
field2.onChange(target.files);
|
|
303
476
|
}
|
|
304
477
|
}
|
|
305
478
|
);
|
|
@@ -318,12 +491,12 @@ function FileField(props) {
|
|
|
318
491
|
rules,
|
|
319
492
|
transform
|
|
320
493
|
} = props;
|
|
321
|
-
return /* @__PURE__ */
|
|
494
|
+
return /* @__PURE__ */ React7.createElement(
|
|
322
495
|
Controller3,
|
|
323
496
|
{
|
|
324
497
|
control,
|
|
325
498
|
name,
|
|
326
|
-
render: ({ field, fieldState }) => /* @__PURE__ */
|
|
499
|
+
render: ({ field: field2, fieldState }) => /* @__PURE__ */ React7.createElement("div", { className }, /* @__PURE__ */ React7.createElement(
|
|
327
500
|
CoercedFileInput,
|
|
328
501
|
{
|
|
329
502
|
accept,
|
|
@@ -331,8 +504,8 @@ function FileField(props) {
|
|
|
331
504
|
disabled: isDisabled,
|
|
332
505
|
errorMessage: fieldState.error?.message,
|
|
333
506
|
field: {
|
|
334
|
-
...
|
|
335
|
-
onChange: (value) =>
|
|
507
|
+
...field2,
|
|
508
|
+
onChange: (value) => field2.onChange(transform ? transform(value) : value)
|
|
336
509
|
},
|
|
337
510
|
fileProps,
|
|
338
511
|
label,
|
|
@@ -345,7 +518,7 @@ function FileField(props) {
|
|
|
345
518
|
}
|
|
346
519
|
|
|
347
520
|
// src/fields/FontPickerField.tsx
|
|
348
|
-
import
|
|
521
|
+
import React8 from "react";
|
|
349
522
|
import { Controller as Controller4 } from "react-hook-form";
|
|
350
523
|
var FontPickerComponent = null;
|
|
351
524
|
var fontPickerLoaded = false;
|
|
@@ -362,17 +535,17 @@ function FontPickerField(props) {
|
|
|
362
535
|
name,
|
|
363
536
|
rules
|
|
364
537
|
} = props;
|
|
365
|
-
const [fontPickerState, setFontPickerState] =
|
|
538
|
+
const [fontPickerState, setFontPickerState] = React8.useState({
|
|
366
539
|
component: FontPickerComponent,
|
|
367
|
-
|
|
368
|
-
|
|
540
|
+
error: null,
|
|
541
|
+
loading: false
|
|
369
542
|
});
|
|
370
|
-
|
|
543
|
+
React8.useEffect(() => {
|
|
371
544
|
if (fontPickerLoaded && FontPickerComponent) {
|
|
372
545
|
setFontPickerState({
|
|
373
546
|
component: FontPickerComponent,
|
|
374
|
-
|
|
375
|
-
|
|
547
|
+
error: null,
|
|
548
|
+
loading: false
|
|
376
549
|
});
|
|
377
550
|
return;
|
|
378
551
|
}
|
|
@@ -382,14 +555,14 @@ function FontPickerField(props) {
|
|
|
382
555
|
if (fontPickerLoaded && FontPickerComponent) {
|
|
383
556
|
setFontPickerState({
|
|
384
557
|
component: FontPickerComponent,
|
|
385
|
-
|
|
386
|
-
|
|
558
|
+
error: null,
|
|
559
|
+
loading: false
|
|
387
560
|
});
|
|
388
561
|
} else {
|
|
389
562
|
setFontPickerState({
|
|
390
563
|
component: null,
|
|
391
|
-
|
|
392
|
-
|
|
564
|
+
error: "Font picker package not found",
|
|
565
|
+
loading: false
|
|
393
566
|
});
|
|
394
567
|
}
|
|
395
568
|
};
|
|
@@ -406,17 +579,17 @@ function FontPickerField(props) {
|
|
|
406
579
|
fontPickerLoading = false;
|
|
407
580
|
setFontPickerState({
|
|
408
581
|
component: FontPickerComponent,
|
|
409
|
-
|
|
410
|
-
|
|
582
|
+
error: null,
|
|
583
|
+
loading: false
|
|
411
584
|
});
|
|
412
585
|
loadingCallbacks.forEach((callback) => callback());
|
|
413
586
|
loadingCallbacks.length = 0;
|
|
414
|
-
} catch
|
|
587
|
+
} catch {
|
|
415
588
|
fontPickerLoading = false;
|
|
416
589
|
setFontPickerState({
|
|
417
590
|
component: null,
|
|
418
|
-
|
|
419
|
-
|
|
591
|
+
error: "Font picker package not found",
|
|
592
|
+
loading: false
|
|
420
593
|
});
|
|
421
594
|
loadingCallbacks.forEach((callback) => callback());
|
|
422
595
|
loadingCallbacks.length = 0;
|
|
@@ -425,23 +598,23 @@ function FontPickerField(props) {
|
|
|
425
598
|
void loadFontPicker();
|
|
426
599
|
}, []);
|
|
427
600
|
if (fontPickerState.loading) {
|
|
428
|
-
return /* @__PURE__ */
|
|
601
|
+
return /* @__PURE__ */ React8.createElement("div", { className }, /* @__PURE__ */ React8.createElement("div", { className: "space-y-2" }, label && /* @__PURE__ */ React8.createElement("label", { className: "block text-sm font-medium text-foreground" }, label), description && /* @__PURE__ */ React8.createElement("p", { className: "text-sm text-muted-foreground" }, description), /* @__PURE__ */ React8.createElement("div", { className: "p-4 border border-default-200 bg-default-50 rounded-medium" }, /* @__PURE__ */ React8.createElement("p", { className: "text-default-600 text-sm" }, "Loading font picker..."))));
|
|
429
602
|
}
|
|
430
603
|
if (!fontPickerState.component) {
|
|
431
|
-
return /* @__PURE__ */
|
|
604
|
+
return /* @__PURE__ */ React8.createElement("div", { className }, /* @__PURE__ */ React8.createElement("div", { className: "space-y-2" }, label && /* @__PURE__ */ React8.createElement("label", { className: "block text-sm font-medium text-foreground" }, label), description && /* @__PURE__ */ React8.createElement("p", { className: "text-sm text-muted-foreground" }, description), /* @__PURE__ */ React8.createElement("div", { className: "p-4 border border-warning-200 bg-warning-50 rounded-medium" }, /* @__PURE__ */ React8.createElement("p", { className: "text-warning-800 text-sm" }, "Font picker requires the @rachelallyson/heroui-font-picker package. Please install it as a peer dependency for advanced font selection features."))));
|
|
432
605
|
}
|
|
433
|
-
return /* @__PURE__ */
|
|
606
|
+
return /* @__PURE__ */ React8.createElement(
|
|
434
607
|
Controller4,
|
|
435
608
|
{
|
|
436
609
|
control,
|
|
437
610
|
name,
|
|
438
|
-
render: ({ field, fieldState }) => /* @__PURE__ */
|
|
611
|
+
render: ({ field: field2, fieldState }) => /* @__PURE__ */ React8.createElement(
|
|
439
612
|
fontPickerState.component,
|
|
440
613
|
{
|
|
441
614
|
label,
|
|
442
615
|
description,
|
|
443
|
-
value:
|
|
444
|
-
onSelectionChange: (value) =>
|
|
616
|
+
value: field2.value ?? "",
|
|
617
|
+
onSelectionChange: (value) => field2.onChange(value),
|
|
445
618
|
errorMessage: fieldState.error?.message,
|
|
446
619
|
isDisabled,
|
|
447
620
|
className,
|
|
@@ -454,12 +627,12 @@ function FontPickerField(props) {
|
|
|
454
627
|
}
|
|
455
628
|
|
|
456
629
|
// src/fields/InputField.tsx
|
|
457
|
-
import
|
|
630
|
+
import React9 from "react";
|
|
458
631
|
import { Controller as Controller5 } from "react-hook-form";
|
|
459
632
|
function CoercedInput(props) {
|
|
460
|
-
const { description, disabled, errorMessage, field, inputProps, label } = props;
|
|
633
|
+
const { description, disabled, errorMessage, field: field2, inputProps, label } = props;
|
|
461
634
|
const defaults = useHeroHookFormDefaults();
|
|
462
|
-
return /* @__PURE__ */
|
|
635
|
+
return /* @__PURE__ */ React9.createElement(
|
|
463
636
|
Input,
|
|
464
637
|
{
|
|
465
638
|
...defaults.input,
|
|
@@ -469,59 +642,61 @@ function CoercedInput(props) {
|
|
|
469
642
|
isDisabled: disabled,
|
|
470
643
|
isInvalid: Boolean(errorMessage),
|
|
471
644
|
label,
|
|
472
|
-
value:
|
|
473
|
-
onBlur:
|
|
474
|
-
onValueChange:
|
|
645
|
+
value: field2.value ?? "",
|
|
646
|
+
onBlur: field2.onBlur,
|
|
647
|
+
onValueChange: field2.onChange
|
|
475
648
|
}
|
|
476
649
|
);
|
|
477
650
|
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
description,
|
|
483
|
-
inputProps,
|
|
484
|
-
isDisabled,
|
|
485
|
-
label,
|
|
486
|
-
name,
|
|
487
|
-
rules,
|
|
488
|
-
transform
|
|
489
|
-
} = props;
|
|
490
|
-
return /* @__PURE__ */ React6.createElement(
|
|
491
|
-
Controller5,
|
|
492
|
-
{
|
|
651
|
+
var InputField = React9.memo(
|
|
652
|
+
(props) => {
|
|
653
|
+
const {
|
|
654
|
+
className,
|
|
493
655
|
control,
|
|
656
|
+
description,
|
|
657
|
+
inputProps,
|
|
658
|
+
isDisabled,
|
|
659
|
+
label,
|
|
494
660
|
name,
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
661
|
+
rules,
|
|
662
|
+
transform
|
|
663
|
+
} = props;
|
|
664
|
+
return /* @__PURE__ */ React9.createElement(
|
|
665
|
+
Controller5,
|
|
666
|
+
{
|
|
667
|
+
control,
|
|
668
|
+
name,
|
|
669
|
+
render: ({ field: field2, fieldState }) => /* @__PURE__ */ React9.createElement("div", { className }, /* @__PURE__ */ React9.createElement(
|
|
670
|
+
CoercedInput,
|
|
671
|
+
{
|
|
672
|
+
description,
|
|
673
|
+
disabled: isDisabled,
|
|
674
|
+
errorMessage: fieldState.error?.message,
|
|
675
|
+
field: {
|
|
676
|
+
...field2,
|
|
677
|
+
onChange: (value) => {
|
|
678
|
+
if (inputProps?.type === "number") {
|
|
679
|
+
const numValue = value === "" ? void 0 : Number(value);
|
|
680
|
+
field2.onChange(
|
|
681
|
+
transform ? transform(String(numValue)) : numValue
|
|
682
|
+
);
|
|
683
|
+
} else {
|
|
684
|
+
field2.onChange(transform ? transform(value) : value);
|
|
685
|
+
}
|
|
511
686
|
}
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
687
|
+
},
|
|
688
|
+
inputProps,
|
|
689
|
+
label
|
|
690
|
+
}
|
|
691
|
+
)),
|
|
692
|
+
rules
|
|
693
|
+
}
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
);
|
|
522
697
|
|
|
523
698
|
// src/fields/RadioGroupField.tsx
|
|
524
|
-
import
|
|
699
|
+
import React10 from "react";
|
|
525
700
|
import { Controller as Controller6 } from "react-hook-form";
|
|
526
701
|
function RadioGroupField(props) {
|
|
527
702
|
const {
|
|
@@ -536,12 +711,12 @@ function RadioGroupField(props) {
|
|
|
536
711
|
rules
|
|
537
712
|
} = props;
|
|
538
713
|
const defaults = useHeroHookFormDefaults();
|
|
539
|
-
return /* @__PURE__ */
|
|
714
|
+
return /* @__PURE__ */ React10.createElement(
|
|
540
715
|
Controller6,
|
|
541
716
|
{
|
|
542
717
|
control,
|
|
543
718
|
name,
|
|
544
|
-
render: ({ field, fieldState }) => /* @__PURE__ */
|
|
719
|
+
render: ({ field: field2, fieldState }) => /* @__PURE__ */ React10.createElement("div", { className }, /* @__PURE__ */ React10.createElement(
|
|
545
720
|
RadioGroup,
|
|
546
721
|
{
|
|
547
722
|
...defaults.radioGroup,
|
|
@@ -550,11 +725,11 @@ function RadioGroupField(props) {
|
|
|
550
725
|
isDisabled,
|
|
551
726
|
isInvalid: Boolean(fieldState.error),
|
|
552
727
|
label,
|
|
553
|
-
value: String(
|
|
554
|
-
onBlur:
|
|
555
|
-
onValueChange: (val) =>
|
|
728
|
+
value: String(field2.value ?? ""),
|
|
729
|
+
onBlur: field2.onBlur,
|
|
730
|
+
onValueChange: (val) => field2.onChange(val)
|
|
556
731
|
},
|
|
557
|
-
options.map((opt) => /* @__PURE__ */
|
|
732
|
+
options.map((opt) => /* @__PURE__ */ React10.createElement(
|
|
558
733
|
Radio,
|
|
559
734
|
{
|
|
560
735
|
key: String(opt.value),
|
|
@@ -563,14 +738,14 @@ function RadioGroupField(props) {
|
|
|
563
738
|
},
|
|
564
739
|
opt.label
|
|
565
740
|
))
|
|
566
|
-
), fieldState.error?.message ? /* @__PURE__ */
|
|
741
|
+
), fieldState.error?.message ? /* @__PURE__ */ React10.createElement("p", { className: "text-tiny text-danger mt-1" }, fieldState.error.message) : null),
|
|
567
742
|
rules
|
|
568
743
|
}
|
|
569
744
|
);
|
|
570
745
|
}
|
|
571
746
|
|
|
572
747
|
// src/fields/SelectField.tsx
|
|
573
|
-
import
|
|
748
|
+
import React11 from "react";
|
|
574
749
|
import { Controller as Controller7 } from "react-hook-form";
|
|
575
750
|
function SelectField(props) {
|
|
576
751
|
const {
|
|
@@ -586,14 +761,14 @@ function SelectField(props) {
|
|
|
586
761
|
selectProps
|
|
587
762
|
} = props;
|
|
588
763
|
const defaults = useHeroHookFormDefaults();
|
|
589
|
-
return /* @__PURE__ */
|
|
764
|
+
return /* @__PURE__ */ React11.createElement(
|
|
590
765
|
Controller7,
|
|
591
766
|
{
|
|
592
767
|
control,
|
|
593
768
|
name,
|
|
594
|
-
render: ({ field, fieldState }) => {
|
|
595
|
-
const selectedKey =
|
|
596
|
-
return /* @__PURE__ */
|
|
769
|
+
render: ({ field: field2, fieldState }) => {
|
|
770
|
+
const selectedKey = field2.value;
|
|
771
|
+
return /* @__PURE__ */ React11.createElement("div", { className }, /* @__PURE__ */ React11.createElement(
|
|
597
772
|
Select,
|
|
598
773
|
{
|
|
599
774
|
...defaults.select,
|
|
@@ -608,10 +783,10 @@ function SelectField(props) {
|
|
|
608
783
|
onSelectionChange: (keys) => {
|
|
609
784
|
const keyArray = Array.from(keys);
|
|
610
785
|
const next = keyArray[0] ?? "";
|
|
611
|
-
|
|
786
|
+
field2.onChange(next);
|
|
612
787
|
}
|
|
613
788
|
},
|
|
614
|
-
options.map((opt) => /* @__PURE__ */
|
|
789
|
+
options.map((opt) => /* @__PURE__ */ React11.createElement(
|
|
615
790
|
SelectItem,
|
|
616
791
|
{
|
|
617
792
|
key: String(opt.value),
|
|
@@ -628,12 +803,12 @@ function SelectField(props) {
|
|
|
628
803
|
}
|
|
629
804
|
|
|
630
805
|
// src/fields/SliderField.tsx
|
|
631
|
-
import
|
|
806
|
+
import React12 from "react";
|
|
632
807
|
import { Controller as Controller8 } from "react-hook-form";
|
|
633
808
|
function CoercedSlider(props) {
|
|
634
|
-
const { description, disabled, errorMessage, field, label, sliderProps } = props;
|
|
809
|
+
const { description, disabled, errorMessage, field: field2, label, sliderProps } = props;
|
|
635
810
|
const defaults = useHeroHookFormDefaults();
|
|
636
|
-
return /* @__PURE__ */
|
|
811
|
+
return /* @__PURE__ */ React12.createElement(
|
|
637
812
|
Slider,
|
|
638
813
|
{
|
|
639
814
|
...defaults.slider,
|
|
@@ -643,9 +818,9 @@ function CoercedSlider(props) {
|
|
|
643
818
|
isDisabled: disabled,
|
|
644
819
|
isInvalid: Boolean(errorMessage),
|
|
645
820
|
label,
|
|
646
|
-
value:
|
|
647
|
-
onBlur:
|
|
648
|
-
onValueChange:
|
|
821
|
+
value: field2.value ?? 0,
|
|
822
|
+
onBlur: field2.onBlur,
|
|
823
|
+
onValueChange: field2.onChange
|
|
649
824
|
}
|
|
650
825
|
);
|
|
651
826
|
}
|
|
@@ -661,20 +836,20 @@ function SliderField(props) {
|
|
|
661
836
|
sliderProps,
|
|
662
837
|
transform
|
|
663
838
|
} = props;
|
|
664
|
-
return /* @__PURE__ */
|
|
839
|
+
return /* @__PURE__ */ React12.createElement(
|
|
665
840
|
Controller8,
|
|
666
841
|
{
|
|
667
842
|
control,
|
|
668
843
|
name,
|
|
669
|
-
render: ({ field, fieldState }) => /* @__PURE__ */
|
|
844
|
+
render: ({ field: field2, fieldState }) => /* @__PURE__ */ React12.createElement("div", { className }, /* @__PURE__ */ React12.createElement(
|
|
670
845
|
CoercedSlider,
|
|
671
846
|
{
|
|
672
847
|
description,
|
|
673
848
|
disabled: isDisabled,
|
|
674
849
|
errorMessage: fieldState.error?.message,
|
|
675
850
|
field: {
|
|
676
|
-
...
|
|
677
|
-
onChange: (value) =>
|
|
851
|
+
...field2,
|
|
852
|
+
onChange: (value) => field2.onChange(transform ? transform(value) : value)
|
|
678
853
|
},
|
|
679
854
|
label,
|
|
680
855
|
sliderProps
|
|
@@ -686,7 +861,7 @@ function SliderField(props) {
|
|
|
686
861
|
}
|
|
687
862
|
|
|
688
863
|
// src/fields/SwitchField.tsx
|
|
689
|
-
import
|
|
864
|
+
import React13 from "react";
|
|
690
865
|
import { Controller as Controller9 } from "react-hook-form";
|
|
691
866
|
function SwitchField(props) {
|
|
692
867
|
const {
|
|
@@ -700,30 +875,30 @@ function SwitchField(props) {
|
|
|
700
875
|
switchProps
|
|
701
876
|
} = props;
|
|
702
877
|
const defaults = useHeroHookFormDefaults();
|
|
703
|
-
return /* @__PURE__ */
|
|
878
|
+
return /* @__PURE__ */ React13.createElement(
|
|
704
879
|
Controller9,
|
|
705
880
|
{
|
|
706
881
|
control,
|
|
707
882
|
name,
|
|
708
|
-
render: ({ field, fieldState }) => /* @__PURE__ */
|
|
883
|
+
render: ({ field: field2, fieldState }) => /* @__PURE__ */ React13.createElement("div", { className }, /* @__PURE__ */ React13.createElement(
|
|
709
884
|
Switch,
|
|
710
885
|
{
|
|
711
886
|
...defaults.switch,
|
|
712
887
|
...switchProps,
|
|
713
888
|
isDisabled,
|
|
714
|
-
isSelected: Boolean(
|
|
715
|
-
onBlur:
|
|
716
|
-
onValueChange: (val) =>
|
|
889
|
+
isSelected: Boolean(field2.value),
|
|
890
|
+
onBlur: field2.onBlur,
|
|
891
|
+
onValueChange: (val) => field2.onChange(val)
|
|
717
892
|
},
|
|
718
893
|
label
|
|
719
|
-
), description ? /* @__PURE__ */
|
|
894
|
+
), description ? /* @__PURE__ */ React13.createElement("p", { className: "text-small text-default-400" }, description) : null, fieldState.error?.message ? /* @__PURE__ */ React13.createElement("p", { className: "text-tiny text-danger mt-1" }, fieldState.error.message) : null),
|
|
720
895
|
rules
|
|
721
896
|
}
|
|
722
897
|
);
|
|
723
898
|
}
|
|
724
899
|
|
|
725
900
|
// src/fields/TextareaField.tsx
|
|
726
|
-
import
|
|
901
|
+
import React14 from "react";
|
|
727
902
|
import { Controller as Controller10 } from "react-hook-form";
|
|
728
903
|
function TextareaField(props) {
|
|
729
904
|
const {
|
|
@@ -737,12 +912,12 @@ function TextareaField(props) {
|
|
|
737
912
|
textareaProps
|
|
738
913
|
} = props;
|
|
739
914
|
const defaults = useHeroHookFormDefaults();
|
|
740
|
-
return /* @__PURE__ */
|
|
915
|
+
return /* @__PURE__ */ React14.createElement(
|
|
741
916
|
Controller10,
|
|
742
917
|
{
|
|
743
918
|
control,
|
|
744
919
|
name,
|
|
745
|
-
render: ({ field, fieldState }) => /* @__PURE__ */
|
|
920
|
+
render: ({ field: field2, fieldState }) => /* @__PURE__ */ React14.createElement("div", { className }, /* @__PURE__ */ React14.createElement(
|
|
746
921
|
Textarea,
|
|
747
922
|
{
|
|
748
923
|
...defaults.textarea,
|
|
@@ -752,9 +927,9 @@ function TextareaField(props) {
|
|
|
752
927
|
isDisabled,
|
|
753
928
|
isInvalid: Boolean(fieldState.error),
|
|
754
929
|
label,
|
|
755
|
-
value:
|
|
756
|
-
onBlur:
|
|
757
|
-
onValueChange:
|
|
930
|
+
value: field2.value ?? "",
|
|
931
|
+
onBlur: field2.onBlur,
|
|
932
|
+
onValueChange: field2.onChange
|
|
758
933
|
}
|
|
759
934
|
)),
|
|
760
935
|
rules
|
|
@@ -763,158 +938,189 @@ function TextareaField(props) {
|
|
|
763
938
|
}
|
|
764
939
|
|
|
765
940
|
// src/components/FormField.tsx
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
if (config.condition && !config.condition(watchedValues)) {
|
|
774
|
-
return null;
|
|
775
|
-
}
|
|
776
|
-
if (config.dependsOn) {
|
|
777
|
-
const dependentValue = watchedValues[config.dependsOn];
|
|
778
|
-
if (config.dependsOnValue !== void 0 && dependentValue !== config.dependsOnValue) {
|
|
941
|
+
var FormField = React15.memo(
|
|
942
|
+
({
|
|
943
|
+
config,
|
|
944
|
+
form,
|
|
945
|
+
submissionState
|
|
946
|
+
}) => {
|
|
947
|
+
if (!form || !form.control) {
|
|
779
948
|
return null;
|
|
780
949
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
ariaLabel: config.ariaLabel,
|
|
785
|
-
className: config.className,
|
|
786
|
-
description: config.description,
|
|
787
|
-
isDisabled: config.isDisabled ?? submissionState.isSubmitting,
|
|
788
|
-
label: config.label,
|
|
789
|
-
name: config.name,
|
|
790
|
-
rules: config.rules
|
|
791
|
-
};
|
|
792
|
-
switch (config.type) {
|
|
793
|
-
case "input":
|
|
794
|
-
return /* @__PURE__ */ React12.createElement(
|
|
795
|
-
InputField,
|
|
796
|
-
{
|
|
797
|
-
...baseProps,
|
|
798
|
-
control,
|
|
799
|
-
defaultValue: config.defaultValue,
|
|
800
|
-
inputProps: config.inputProps
|
|
801
|
-
}
|
|
802
|
-
);
|
|
803
|
-
case "textarea":
|
|
804
|
-
return /* @__PURE__ */ React12.createElement(
|
|
805
|
-
TextareaField,
|
|
806
|
-
{
|
|
807
|
-
...baseProps,
|
|
808
|
-
control,
|
|
809
|
-
defaultValue: config.defaultValue,
|
|
810
|
-
textareaProps: config.textareaProps
|
|
811
|
-
}
|
|
812
|
-
);
|
|
813
|
-
case "select":
|
|
814
|
-
return /* @__PURE__ */ React12.createElement(
|
|
815
|
-
SelectField,
|
|
816
|
-
{
|
|
817
|
-
...baseProps,
|
|
818
|
-
control,
|
|
819
|
-
defaultValue: config.defaultValue,
|
|
820
|
-
options: (config.options ?? []).map((opt) => ({
|
|
821
|
-
label: opt.label,
|
|
822
|
-
value: String(opt.value)
|
|
823
|
-
})),
|
|
824
|
-
selectProps: config.selectProps
|
|
825
|
-
}
|
|
826
|
-
);
|
|
827
|
-
case "checkbox":
|
|
828
|
-
return /* @__PURE__ */ React12.createElement(
|
|
829
|
-
CheckboxField,
|
|
830
|
-
{
|
|
831
|
-
...baseProps,
|
|
832
|
-
checkboxProps: config.checkboxProps,
|
|
833
|
-
control,
|
|
834
|
-
defaultValue: config.defaultValue
|
|
835
|
-
}
|
|
836
|
-
);
|
|
837
|
-
case "radio":
|
|
838
|
-
return /* @__PURE__ */ React12.createElement(
|
|
839
|
-
RadioGroupField,
|
|
840
|
-
{
|
|
841
|
-
...baseProps,
|
|
842
|
-
control,
|
|
843
|
-
defaultValue: config.defaultValue,
|
|
844
|
-
options: (config.radioOptions ?? []).map((opt) => ({
|
|
845
|
-
label: opt.label,
|
|
846
|
-
value: String(opt.value)
|
|
847
|
-
})),
|
|
848
|
-
radioGroupProps: config.radioProps
|
|
849
|
-
}
|
|
850
|
-
);
|
|
851
|
-
case "switch":
|
|
852
|
-
return /* @__PURE__ */ React12.createElement(
|
|
853
|
-
SwitchField,
|
|
854
|
-
{
|
|
855
|
-
...baseProps,
|
|
856
|
-
control,
|
|
857
|
-
defaultValue: config.defaultValue,
|
|
858
|
-
switchProps: config.switchProps
|
|
859
|
-
}
|
|
860
|
-
);
|
|
861
|
-
case "slider":
|
|
862
|
-
return /* @__PURE__ */ React12.createElement(
|
|
863
|
-
SliderField,
|
|
864
|
-
{
|
|
865
|
-
...baseProps,
|
|
866
|
-
control,
|
|
867
|
-
defaultValue: config.defaultValue,
|
|
868
|
-
sliderProps: config.sliderProps
|
|
869
|
-
}
|
|
870
|
-
);
|
|
871
|
-
case "date":
|
|
872
|
-
return /* @__PURE__ */ React12.createElement(
|
|
873
|
-
DateField,
|
|
874
|
-
{
|
|
875
|
-
...baseProps,
|
|
876
|
-
control,
|
|
877
|
-
dateProps: config.dateProps,
|
|
878
|
-
defaultValue: config.defaultValue
|
|
879
|
-
}
|
|
880
|
-
);
|
|
881
|
-
case "file":
|
|
882
|
-
return /* @__PURE__ */ React12.createElement(
|
|
883
|
-
FileField,
|
|
884
|
-
{
|
|
885
|
-
...baseProps,
|
|
886
|
-
accept: config.accept,
|
|
887
|
-
control,
|
|
888
|
-
defaultValue: config.defaultValue,
|
|
889
|
-
fileProps: config.fileProps,
|
|
890
|
-
multiple: config.multiple
|
|
891
|
-
}
|
|
892
|
-
);
|
|
893
|
-
case "fontPicker":
|
|
894
|
-
return /* @__PURE__ */ React12.createElement(
|
|
895
|
-
FontPickerField,
|
|
896
|
-
{
|
|
897
|
-
...baseProps,
|
|
898
|
-
control,
|
|
899
|
-
defaultValue: config.defaultValue,
|
|
900
|
-
fontPickerProps: config.fontPickerProps
|
|
901
|
-
}
|
|
902
|
-
);
|
|
903
|
-
case "custom":
|
|
904
|
-
return config.render({
|
|
905
|
-
control,
|
|
906
|
-
errors: form.formState.errors,
|
|
907
|
-
form,
|
|
908
|
-
isSubmitting: submissionState.isSubmitting,
|
|
909
|
-
name: config.name
|
|
910
|
-
});
|
|
911
|
-
default: {
|
|
912
|
-
const fieldType = config.type;
|
|
913
|
-
console.warn(`Unknown field type: ${fieldType}`);
|
|
950
|
+
const { control } = form;
|
|
951
|
+
const watchedValues = useWatch3({ control });
|
|
952
|
+
if (config.condition && !config.condition(watchedValues)) {
|
|
914
953
|
return null;
|
|
915
954
|
}
|
|
955
|
+
if (config.dependsOn) {
|
|
956
|
+
const dependentValue = watchedValues[config.dependsOn];
|
|
957
|
+
if (config.dependsOnValue !== void 0 && dependentValue !== config.dependsOnValue) {
|
|
958
|
+
return null;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
const baseProps = {
|
|
962
|
+
ariaDescribedBy: config.ariaDescribedBy,
|
|
963
|
+
ariaLabel: config.ariaLabel,
|
|
964
|
+
className: config.className,
|
|
965
|
+
description: config.description,
|
|
966
|
+
isDisabled: config.isDisabled ?? submissionState.isSubmitting,
|
|
967
|
+
label: config.label,
|
|
968
|
+
name: config.name,
|
|
969
|
+
rules: config.rules
|
|
970
|
+
};
|
|
971
|
+
switch (config.type) {
|
|
972
|
+
case "input":
|
|
973
|
+
return /* @__PURE__ */ React15.createElement(
|
|
974
|
+
InputField,
|
|
975
|
+
{
|
|
976
|
+
...baseProps,
|
|
977
|
+
control,
|
|
978
|
+
defaultValue: config.defaultValue,
|
|
979
|
+
inputProps: config.inputProps
|
|
980
|
+
}
|
|
981
|
+
);
|
|
982
|
+
case "textarea":
|
|
983
|
+
return /* @__PURE__ */ React15.createElement(
|
|
984
|
+
TextareaField,
|
|
985
|
+
{
|
|
986
|
+
...baseProps,
|
|
987
|
+
control,
|
|
988
|
+
defaultValue: config.defaultValue,
|
|
989
|
+
textareaProps: config.textareaProps
|
|
990
|
+
}
|
|
991
|
+
);
|
|
992
|
+
case "select":
|
|
993
|
+
return /* @__PURE__ */ React15.createElement(
|
|
994
|
+
SelectField,
|
|
995
|
+
{
|
|
996
|
+
...baseProps,
|
|
997
|
+
control,
|
|
998
|
+
defaultValue: config.defaultValue,
|
|
999
|
+
options: (config.options ?? []).map((opt) => ({
|
|
1000
|
+
label: opt.label,
|
|
1001
|
+
value: String(opt.value)
|
|
1002
|
+
})),
|
|
1003
|
+
selectProps: config.selectProps
|
|
1004
|
+
}
|
|
1005
|
+
);
|
|
1006
|
+
case "checkbox":
|
|
1007
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1008
|
+
CheckboxField,
|
|
1009
|
+
{
|
|
1010
|
+
...baseProps,
|
|
1011
|
+
checkboxProps: config.checkboxProps,
|
|
1012
|
+
control,
|
|
1013
|
+
defaultValue: config.defaultValue
|
|
1014
|
+
}
|
|
1015
|
+
);
|
|
1016
|
+
case "radio":
|
|
1017
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1018
|
+
RadioGroupField,
|
|
1019
|
+
{
|
|
1020
|
+
...baseProps,
|
|
1021
|
+
control,
|
|
1022
|
+
defaultValue: config.defaultValue,
|
|
1023
|
+
options: (config.radioOptions ?? []).map((opt) => ({
|
|
1024
|
+
label: opt.label,
|
|
1025
|
+
value: String(opt.value)
|
|
1026
|
+
})),
|
|
1027
|
+
radioGroupProps: config.radioProps
|
|
1028
|
+
}
|
|
1029
|
+
);
|
|
1030
|
+
case "switch":
|
|
1031
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1032
|
+
SwitchField,
|
|
1033
|
+
{
|
|
1034
|
+
...baseProps,
|
|
1035
|
+
control,
|
|
1036
|
+
defaultValue: config.defaultValue,
|
|
1037
|
+
switchProps: config.switchProps
|
|
1038
|
+
}
|
|
1039
|
+
);
|
|
1040
|
+
case "slider":
|
|
1041
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1042
|
+
SliderField,
|
|
1043
|
+
{
|
|
1044
|
+
...baseProps,
|
|
1045
|
+
control,
|
|
1046
|
+
defaultValue: config.defaultValue,
|
|
1047
|
+
sliderProps: config.sliderProps
|
|
1048
|
+
}
|
|
1049
|
+
);
|
|
1050
|
+
case "date":
|
|
1051
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1052
|
+
DateField,
|
|
1053
|
+
{
|
|
1054
|
+
...baseProps,
|
|
1055
|
+
control,
|
|
1056
|
+
dateProps: config.dateProps,
|
|
1057
|
+
defaultValue: config.defaultValue
|
|
1058
|
+
}
|
|
1059
|
+
);
|
|
1060
|
+
case "file":
|
|
1061
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1062
|
+
FileField,
|
|
1063
|
+
{
|
|
1064
|
+
...baseProps,
|
|
1065
|
+
accept: config.accept,
|
|
1066
|
+
control,
|
|
1067
|
+
defaultValue: config.defaultValue,
|
|
1068
|
+
fileProps: config.fileProps,
|
|
1069
|
+
multiple: config.multiple
|
|
1070
|
+
}
|
|
1071
|
+
);
|
|
1072
|
+
case "fontPicker":
|
|
1073
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1074
|
+
FontPickerField,
|
|
1075
|
+
{
|
|
1076
|
+
...baseProps,
|
|
1077
|
+
control,
|
|
1078
|
+
defaultValue: config.defaultValue,
|
|
1079
|
+
fontPickerProps: config.fontPickerProps
|
|
1080
|
+
}
|
|
1081
|
+
);
|
|
1082
|
+
case "custom":
|
|
1083
|
+
return config.render({
|
|
1084
|
+
control,
|
|
1085
|
+
errors: form.formState.errors,
|
|
1086
|
+
form,
|
|
1087
|
+
isSubmitting: submissionState.isSubmitting,
|
|
1088
|
+
name: config.name
|
|
1089
|
+
});
|
|
1090
|
+
case "conditional":
|
|
1091
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1092
|
+
ConditionalField,
|
|
1093
|
+
{
|
|
1094
|
+
config,
|
|
1095
|
+
control,
|
|
1096
|
+
className: config.className
|
|
1097
|
+
}
|
|
1098
|
+
);
|
|
1099
|
+
case "fieldArray":
|
|
1100
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1101
|
+
FieldArrayField,
|
|
1102
|
+
{
|
|
1103
|
+
config,
|
|
1104
|
+
className: config.className
|
|
1105
|
+
}
|
|
1106
|
+
);
|
|
1107
|
+
case "dynamicSection":
|
|
1108
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1109
|
+
DynamicSectionField,
|
|
1110
|
+
{
|
|
1111
|
+
config,
|
|
1112
|
+
control,
|
|
1113
|
+
className: config.className
|
|
1114
|
+
}
|
|
1115
|
+
);
|
|
1116
|
+
default: {
|
|
1117
|
+
const fieldType = config.type;
|
|
1118
|
+
console.warn(`Unknown field type: ${fieldType}`);
|
|
1119
|
+
return null;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
916
1122
|
}
|
|
917
|
-
|
|
1123
|
+
);
|
|
918
1124
|
|
|
919
1125
|
// src/components/Form.tsx
|
|
920
1126
|
function ConfigurableForm({
|
|
@@ -951,16 +1157,16 @@ function ConfigurableForm({
|
|
|
951
1157
|
});
|
|
952
1158
|
const renderFields = () => {
|
|
953
1159
|
if (layout === "grid") {
|
|
954
|
-
return /* @__PURE__ */
|
|
1160
|
+
return /* @__PURE__ */ React16.createElement(
|
|
955
1161
|
"div",
|
|
956
1162
|
{
|
|
957
1163
|
className: `grid gap-${spacing} ${columns === 1 ? "grid-cols-1" : columns === 2 ? "grid-cols-1 md:grid-cols-2" : "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"}`
|
|
958
1164
|
},
|
|
959
|
-
fields.map((
|
|
1165
|
+
fields.map((field2) => /* @__PURE__ */ React16.createElement(
|
|
960
1166
|
FormField,
|
|
961
1167
|
{
|
|
962
|
-
key:
|
|
963
|
-
config:
|
|
1168
|
+
key: field2.name,
|
|
1169
|
+
config: field2,
|
|
964
1170
|
form,
|
|
965
1171
|
submissionState
|
|
966
1172
|
}
|
|
@@ -968,21 +1174,21 @@ function ConfigurableForm({
|
|
|
968
1174
|
);
|
|
969
1175
|
}
|
|
970
1176
|
if (layout === "horizontal") {
|
|
971
|
-
return /* @__PURE__ */
|
|
1177
|
+
return /* @__PURE__ */ React16.createElement("div", { className: `grid gap-${spacing} grid-cols-1 md:grid-cols-2` }, fields.map((field2) => /* @__PURE__ */ React16.createElement(
|
|
972
1178
|
FormField,
|
|
973
1179
|
{
|
|
974
|
-
key:
|
|
975
|
-
config:
|
|
1180
|
+
key: field2.name,
|
|
1181
|
+
config: field2,
|
|
976
1182
|
form,
|
|
977
1183
|
submissionState
|
|
978
1184
|
}
|
|
979
1185
|
)));
|
|
980
1186
|
}
|
|
981
|
-
return /* @__PURE__ */
|
|
1187
|
+
return /* @__PURE__ */ React16.createElement("div", { className: `space-y-${spacing}` }, fields.map((field2) => /* @__PURE__ */ React16.createElement(
|
|
982
1188
|
FormField,
|
|
983
1189
|
{
|
|
984
|
-
key:
|
|
985
|
-
config:
|
|
1190
|
+
key: field2.name,
|
|
1191
|
+
config: field2,
|
|
986
1192
|
form,
|
|
987
1193
|
submissionState
|
|
988
1194
|
}
|
|
@@ -992,24 +1198,24 @@ function ConfigurableForm({
|
|
|
992
1198
|
e.preventDefault();
|
|
993
1199
|
void handleSubmit();
|
|
994
1200
|
};
|
|
995
|
-
return /* @__PURE__ */
|
|
1201
|
+
return /* @__PURE__ */ React16.createElement("form", { className, role: "form", onSubmit: handleFormSubmit }, title && /* @__PURE__ */ React16.createElement("div", { className: "mb-6" }, /* @__PURE__ */ React16.createElement("h2", { className: "text-xl font-semibold text-foreground mb-2" }, title), subtitle && /* @__PURE__ */ React16.createElement("p", { className: "text-sm text-muted-foreground" }, subtitle)), isSubmitted && isSuccess && /* @__PURE__ */ React16.createElement(
|
|
996
1202
|
"div",
|
|
997
1203
|
{
|
|
998
1204
|
className: "mb-6 p-4 bg-success-50 border border-success-200 rounded-lg",
|
|
999
1205
|
"data-testid": "success-message"
|
|
1000
1206
|
},
|
|
1001
|
-
/* @__PURE__ */
|
|
1002
|
-
/* @__PURE__ */
|
|
1003
|
-
), error && /* @__PURE__ */
|
|
1207
|
+
/* @__PURE__ */ React16.createElement("p", { className: "text-success-800 font-medium" }, "Success!"),
|
|
1208
|
+
/* @__PURE__ */ React16.createElement("p", { className: "text-success-700 text-sm mt-1" }, "Your request has been processed successfully.")
|
|
1209
|
+
), error && /* @__PURE__ */ React16.createElement(
|
|
1004
1210
|
"div",
|
|
1005
1211
|
{
|
|
1006
1212
|
className: "mb-6 p-4 bg-danger-50 border border-danger-200 rounded-lg",
|
|
1007
1213
|
"data-testid": "error-message"
|
|
1008
1214
|
},
|
|
1009
|
-
/* @__PURE__ */
|
|
1010
|
-
/* @__PURE__ */
|
|
1011
|
-
), renderFields(), /* @__PURE__ */
|
|
1012
|
-
|
|
1215
|
+
/* @__PURE__ */ React16.createElement("p", { className: "text-danger-800 font-medium" }, "Error"),
|
|
1216
|
+
/* @__PURE__ */ React16.createElement("p", { className: "text-danger-700 text-sm mt-1" }, error)
|
|
1217
|
+
), renderFields(), /* @__PURE__ */ React16.createElement("div", { className: "mt-6 flex gap-3 justify-end" }, /* @__PURE__ */ React16.createElement(
|
|
1218
|
+
Button3,
|
|
1013
1219
|
{
|
|
1014
1220
|
color: "primary",
|
|
1015
1221
|
isDisabled: isSubmitting,
|
|
@@ -1018,8 +1224,8 @@ function ConfigurableForm({
|
|
|
1018
1224
|
...submitButtonProps
|
|
1019
1225
|
},
|
|
1020
1226
|
submitButtonText
|
|
1021
|
-
), showResetButton && /* @__PURE__ */
|
|
1022
|
-
|
|
1227
|
+
), showResetButton && /* @__PURE__ */ React16.createElement(
|
|
1228
|
+
Button3,
|
|
1023
1229
|
{
|
|
1024
1230
|
isDisabled: isSubmitting,
|
|
1025
1231
|
type: "button",
|
|
@@ -1030,10 +1236,338 @@ function ConfigurableForm({
|
|
|
1030
1236
|
)));
|
|
1031
1237
|
}
|
|
1032
1238
|
|
|
1239
|
+
// src/components/ServerActionForm.tsx
|
|
1240
|
+
import React17 from "react";
|
|
1241
|
+
import {
|
|
1242
|
+
Button as Button4,
|
|
1243
|
+
Checkbox as Checkbox2,
|
|
1244
|
+
Input as Input2,
|
|
1245
|
+
Select as Select2,
|
|
1246
|
+
SelectItem as SelectItem2,
|
|
1247
|
+
Textarea as Textarea2
|
|
1248
|
+
} from "@heroui/react";
|
|
1249
|
+
import { useActionState } from "react";
|
|
1250
|
+
function ServerActionForm({
|
|
1251
|
+
action,
|
|
1252
|
+
className,
|
|
1253
|
+
clientValidationSchema,
|
|
1254
|
+
columns = 1,
|
|
1255
|
+
defaultValues,
|
|
1256
|
+
fields,
|
|
1257
|
+
initialState,
|
|
1258
|
+
layout = "vertical",
|
|
1259
|
+
onError,
|
|
1260
|
+
onSuccess,
|
|
1261
|
+
resetButtonText = "Reset",
|
|
1262
|
+
showResetButton = false,
|
|
1263
|
+
spacing = "4",
|
|
1264
|
+
submitButtonProps = {},
|
|
1265
|
+
submitButtonText = "Submit",
|
|
1266
|
+
subtitle,
|
|
1267
|
+
title
|
|
1268
|
+
}) {
|
|
1269
|
+
const [state, formAction, pending] = useActionState(
|
|
1270
|
+
action,
|
|
1271
|
+
initialState ?? { errors: void 0, message: void 0, success: false }
|
|
1272
|
+
);
|
|
1273
|
+
const formRef = React17.useRef(null);
|
|
1274
|
+
const [clientErrors, setClientErrors] = React17.useState({});
|
|
1275
|
+
const lastSubmittedFormData = React17.useRef(null);
|
|
1276
|
+
React17.useEffect(() => {
|
|
1277
|
+
if (state && (state.errors || state.message && !state.success)) {
|
|
1278
|
+
onError?.({
|
|
1279
|
+
errors: state.errors,
|
|
1280
|
+
message: state.message
|
|
1281
|
+
});
|
|
1282
|
+
}
|
|
1283
|
+
}, [state, onError]);
|
|
1284
|
+
React17.useEffect(() => {
|
|
1285
|
+
if (state?.success && lastSubmittedFormData.current) {
|
|
1286
|
+
onSuccess?.(lastSubmittedFormData.current);
|
|
1287
|
+
}
|
|
1288
|
+
}, [state?.success, onSuccess]);
|
|
1289
|
+
const handleReset = () => {
|
|
1290
|
+
formRef.current?.reset();
|
|
1291
|
+
setClientErrors({});
|
|
1292
|
+
};
|
|
1293
|
+
const handleSubmit = async (e) => {
|
|
1294
|
+
e.preventDefault();
|
|
1295
|
+
if (clientValidationSchema) {
|
|
1296
|
+
const formData2 = new FormData(e.currentTarget);
|
|
1297
|
+
const values = {};
|
|
1298
|
+
formData2.forEach((val, key) => {
|
|
1299
|
+
if (val === "on") {
|
|
1300
|
+
values[key] = true;
|
|
1301
|
+
} else if (val === "") {
|
|
1302
|
+
if (!values[key]) {
|
|
1303
|
+
values[key] = false;
|
|
1304
|
+
}
|
|
1305
|
+
} else {
|
|
1306
|
+
values[key] = val;
|
|
1307
|
+
}
|
|
1308
|
+
});
|
|
1309
|
+
const result = clientValidationSchema.safeParse(values);
|
|
1310
|
+
if (!result.success) {
|
|
1311
|
+
const errors = {};
|
|
1312
|
+
result.error.issues.forEach((issue) => {
|
|
1313
|
+
const path = issue.path.join(".");
|
|
1314
|
+
errors[path] = issue.message;
|
|
1315
|
+
});
|
|
1316
|
+
setClientErrors((prev) => ({ ...prev, ...errors }));
|
|
1317
|
+
return;
|
|
1318
|
+
}
|
|
1319
|
+
setClientErrors({});
|
|
1320
|
+
}
|
|
1321
|
+
const formData = new FormData(e.currentTarget);
|
|
1322
|
+
lastSubmittedFormData.current = formData;
|
|
1323
|
+
formAction(formData);
|
|
1324
|
+
};
|
|
1325
|
+
const renderFields = () => {
|
|
1326
|
+
if (layout === "grid") {
|
|
1327
|
+
return /* @__PURE__ */ React17.createElement(
|
|
1328
|
+
"div",
|
|
1329
|
+
{
|
|
1330
|
+
className: `grid gap-${spacing} ${columns === 1 ? "grid-cols-1" : columns === 2 ? "grid-cols-1 md:grid-cols-2" : "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"}`
|
|
1331
|
+
},
|
|
1332
|
+
fields.map((field2) => /* @__PURE__ */ React17.createElement(
|
|
1333
|
+
ServerActionField,
|
|
1334
|
+
{
|
|
1335
|
+
key: field2.name,
|
|
1336
|
+
clientErrors,
|
|
1337
|
+
defaultValues,
|
|
1338
|
+
errors: state?.errors,
|
|
1339
|
+
field: field2
|
|
1340
|
+
}
|
|
1341
|
+
))
|
|
1342
|
+
);
|
|
1343
|
+
}
|
|
1344
|
+
if (layout === "horizontal") {
|
|
1345
|
+
return /* @__PURE__ */ React17.createElement("div", { className: `grid gap-${spacing} grid-cols-1 md:grid-cols-2` }, fields.map((field2) => /* @__PURE__ */ React17.createElement(
|
|
1346
|
+
ServerActionField,
|
|
1347
|
+
{
|
|
1348
|
+
key: field2.name,
|
|
1349
|
+
clientErrors,
|
|
1350
|
+
defaultValues,
|
|
1351
|
+
errors: state?.errors,
|
|
1352
|
+
field: field2
|
|
1353
|
+
}
|
|
1354
|
+
)));
|
|
1355
|
+
}
|
|
1356
|
+
return /* @__PURE__ */ React17.createElement("div", { className: `space-y-${spacing}` }, fields.map((field2) => /* @__PURE__ */ React17.createElement(
|
|
1357
|
+
ServerActionField,
|
|
1358
|
+
{
|
|
1359
|
+
key: field2.name,
|
|
1360
|
+
clientErrors,
|
|
1361
|
+
defaultValues,
|
|
1362
|
+
errors: state?.errors,
|
|
1363
|
+
field: field2
|
|
1364
|
+
}
|
|
1365
|
+
)));
|
|
1366
|
+
};
|
|
1367
|
+
return /* @__PURE__ */ React17.createElement(
|
|
1368
|
+
"form",
|
|
1369
|
+
{
|
|
1370
|
+
ref: formRef,
|
|
1371
|
+
className,
|
|
1372
|
+
role: "form",
|
|
1373
|
+
onSubmit: handleSubmit
|
|
1374
|
+
},
|
|
1375
|
+
title && /* @__PURE__ */ React17.createElement("div", { className: "mb-6" }, /* @__PURE__ */ React17.createElement("h2", { className: "text-xl font-semibold text-foreground mb-2" }, title), subtitle && /* @__PURE__ */ React17.createElement("p", { className: "text-sm text-muted-foreground" }, subtitle)),
|
|
1376
|
+
state?.success && !pending && /* @__PURE__ */ React17.createElement(
|
|
1377
|
+
"div",
|
|
1378
|
+
{
|
|
1379
|
+
className: "mb-6 p-4 bg-success-50 border border-success-200 rounded-lg",
|
|
1380
|
+
"data-testid": "success-message"
|
|
1381
|
+
},
|
|
1382
|
+
/* @__PURE__ */ React17.createElement("p", { className: "text-success-800 font-medium" }, "Success!"),
|
|
1383
|
+
state.message && /* @__PURE__ */ React17.createElement("p", { className: "text-success-700 text-sm mt-1" }, state.message)
|
|
1384
|
+
),
|
|
1385
|
+
state?.message && !state.success && /* @__PURE__ */ React17.createElement(
|
|
1386
|
+
"div",
|
|
1387
|
+
{
|
|
1388
|
+
className: "mb-6 p-4 bg-danger-50 border border-danger-200 rounded-lg",
|
|
1389
|
+
"data-testid": "error-message"
|
|
1390
|
+
},
|
|
1391
|
+
/* @__PURE__ */ React17.createElement("p", { className: "text-danger-800 font-medium" }, "Error"),
|
|
1392
|
+
/* @__PURE__ */ React17.createElement("p", { className: "text-danger-700 text-sm mt-1" }, state.message)
|
|
1393
|
+
),
|
|
1394
|
+
renderFields(),
|
|
1395
|
+
/* @__PURE__ */ React17.createElement("div", { className: "mt-6 flex gap-3 justify-end" }, /* @__PURE__ */ React17.createElement(
|
|
1396
|
+
Button4,
|
|
1397
|
+
{
|
|
1398
|
+
color: "primary",
|
|
1399
|
+
isDisabled: pending,
|
|
1400
|
+
isLoading: pending,
|
|
1401
|
+
type: "submit",
|
|
1402
|
+
...submitButtonProps
|
|
1403
|
+
},
|
|
1404
|
+
submitButtonText
|
|
1405
|
+
), showResetButton && /* @__PURE__ */ React17.createElement(
|
|
1406
|
+
Button4,
|
|
1407
|
+
{
|
|
1408
|
+
isDisabled: pending,
|
|
1409
|
+
type: "button",
|
|
1410
|
+
variant: "bordered",
|
|
1411
|
+
onPress: handleReset
|
|
1412
|
+
},
|
|
1413
|
+
resetButtonText
|
|
1414
|
+
))
|
|
1415
|
+
);
|
|
1416
|
+
}
|
|
1417
|
+
function ServerActionField({
|
|
1418
|
+
clientErrors,
|
|
1419
|
+
defaultValues,
|
|
1420
|
+
errors,
|
|
1421
|
+
field: field2
|
|
1422
|
+
}) {
|
|
1423
|
+
const fieldName = field2.name;
|
|
1424
|
+
const fieldErrors = errors?.[fieldName];
|
|
1425
|
+
const clientError = clientErrors?.[fieldName];
|
|
1426
|
+
const errorMessage = clientError || (fieldErrors && fieldErrors.length > 0 ? fieldErrors[0] : void 0);
|
|
1427
|
+
const getDefaultValue = () => {
|
|
1428
|
+
const fromProps = defaultValues?.[fieldName];
|
|
1429
|
+
const fromField = field2.defaultValue;
|
|
1430
|
+
if (fromProps !== void 0 && fromProps !== null) {
|
|
1431
|
+
return typeof fromProps === "string" ? fromProps : String(fromProps);
|
|
1432
|
+
}
|
|
1433
|
+
if (fromField !== void 0 && fromField !== null) {
|
|
1434
|
+
return typeof fromField === "string" ? fromField : String(fromField);
|
|
1435
|
+
}
|
|
1436
|
+
return "";
|
|
1437
|
+
};
|
|
1438
|
+
const getDefaultChecked = () => {
|
|
1439
|
+
const fromProps = defaultValues?.[fieldName];
|
|
1440
|
+
const fromField = field2.defaultValue;
|
|
1441
|
+
if (fromProps !== void 0 && fromProps !== null) {
|
|
1442
|
+
return typeof fromProps === "boolean" ? fromProps : false;
|
|
1443
|
+
}
|
|
1444
|
+
if (fromField !== void 0 && fromField !== null) {
|
|
1445
|
+
return typeof fromField === "boolean" ? fromField : false;
|
|
1446
|
+
}
|
|
1447
|
+
return false;
|
|
1448
|
+
};
|
|
1449
|
+
const [value, setValue] = React17.useState(getDefaultValue);
|
|
1450
|
+
const [checked, setChecked] = React17.useState(getDefaultChecked);
|
|
1451
|
+
React17.useEffect(() => {
|
|
1452
|
+
const newDefaultValue = defaultValues?.[fieldName];
|
|
1453
|
+
if (newDefaultValue !== void 0 && newDefaultValue !== null) {
|
|
1454
|
+
if (field2.type === "checkbox") {
|
|
1455
|
+
setChecked(
|
|
1456
|
+
typeof newDefaultValue === "boolean" ? newDefaultValue : false
|
|
1457
|
+
);
|
|
1458
|
+
} else {
|
|
1459
|
+
setValue(
|
|
1460
|
+
typeof newDefaultValue === "string" ? newDefaultValue : String(newDefaultValue)
|
|
1461
|
+
);
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
}, [defaultValues, fieldName, field2.type]);
|
|
1465
|
+
React17.useEffect(() => {
|
|
1466
|
+
const hiddenInput = document.querySelector(
|
|
1467
|
+
`input[type="hidden"][name="${fieldName}"]`
|
|
1468
|
+
);
|
|
1469
|
+
if (hiddenInput) {
|
|
1470
|
+
if (field2.type === "checkbox") {
|
|
1471
|
+
hiddenInput.value = checked ? "on" : "";
|
|
1472
|
+
} else {
|
|
1473
|
+
hiddenInput.value = value;
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
}, [value, checked, fieldName, field2.type]);
|
|
1477
|
+
switch (field2.type) {
|
|
1478
|
+
case "input": {
|
|
1479
|
+
const inputType = field2.inputProps?.type || "text";
|
|
1480
|
+
return /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("input", { type: "hidden", name: fieldName, value }), /* @__PURE__ */ React17.createElement(
|
|
1481
|
+
Input2,
|
|
1482
|
+
{
|
|
1483
|
+
...field2.inputProps,
|
|
1484
|
+
"data-field-name": fieldName,
|
|
1485
|
+
type: inputType,
|
|
1486
|
+
label: field2.label,
|
|
1487
|
+
description: field2.description,
|
|
1488
|
+
isDisabled: field2.isDisabled,
|
|
1489
|
+
isInvalid: Boolean(errorMessage),
|
|
1490
|
+
errorMessage,
|
|
1491
|
+
value,
|
|
1492
|
+
onValueChange: setValue
|
|
1493
|
+
}
|
|
1494
|
+
));
|
|
1495
|
+
}
|
|
1496
|
+
case "textarea": {
|
|
1497
|
+
return /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("input", { type: "hidden", name: fieldName, value }), /* @__PURE__ */ React17.createElement(
|
|
1498
|
+
Textarea2,
|
|
1499
|
+
{
|
|
1500
|
+
...field2.textareaProps,
|
|
1501
|
+
"data-field-name": fieldName,
|
|
1502
|
+
label: field2.label,
|
|
1503
|
+
description: field2.description,
|
|
1504
|
+
isDisabled: field2.isDisabled,
|
|
1505
|
+
isInvalid: Boolean(errorMessage),
|
|
1506
|
+
errorMessage,
|
|
1507
|
+
value,
|
|
1508
|
+
onValueChange: setValue
|
|
1509
|
+
}
|
|
1510
|
+
));
|
|
1511
|
+
}
|
|
1512
|
+
case "checkbox": {
|
|
1513
|
+
return /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("input", { type: "hidden", name: fieldName, value: checked ? "on" : "" }), /* @__PURE__ */ React17.createElement(
|
|
1514
|
+
Checkbox2,
|
|
1515
|
+
{
|
|
1516
|
+
...field2.checkboxProps,
|
|
1517
|
+
"data-field-name": fieldName,
|
|
1518
|
+
isDisabled: field2.isDisabled,
|
|
1519
|
+
isSelected: checked,
|
|
1520
|
+
onValueChange: setChecked,
|
|
1521
|
+
isInvalid: Boolean(errorMessage),
|
|
1522
|
+
errorMessage
|
|
1523
|
+
},
|
|
1524
|
+
field2.label
|
|
1525
|
+
));
|
|
1526
|
+
}
|
|
1527
|
+
case "select": {
|
|
1528
|
+
const options = field2.options || [];
|
|
1529
|
+
return /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("input", { type: "hidden", name: fieldName, value }), /* @__PURE__ */ React17.createElement(
|
|
1530
|
+
Select2,
|
|
1531
|
+
{
|
|
1532
|
+
...field2.selectProps,
|
|
1533
|
+
"data-field-name": fieldName,
|
|
1534
|
+
label: field2.label,
|
|
1535
|
+
description: field2.description,
|
|
1536
|
+
isDisabled: field2.isDisabled,
|
|
1537
|
+
isInvalid: Boolean(errorMessage),
|
|
1538
|
+
errorMessage,
|
|
1539
|
+
selectedKeys: value ? [value] : [],
|
|
1540
|
+
onSelectionChange: (keys) => {
|
|
1541
|
+
const selectedValue = Array.from(keys)[0];
|
|
1542
|
+
setValue(selectedValue || "");
|
|
1543
|
+
}
|
|
1544
|
+
},
|
|
1545
|
+
options.map(
|
|
1546
|
+
(option) => /* @__PURE__ */ React17.createElement(SelectItem2, { key: String(option.value) }, option.label)
|
|
1547
|
+
)
|
|
1548
|
+
));
|
|
1549
|
+
}
|
|
1550
|
+
default:
|
|
1551
|
+
return /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("input", { type: "hidden", name: fieldName, value }), /* @__PURE__ */ React17.createElement(
|
|
1552
|
+
Input2,
|
|
1553
|
+
{
|
|
1554
|
+
"data-field-name": fieldName,
|
|
1555
|
+
label: field2.label,
|
|
1556
|
+
description: field2.description,
|
|
1557
|
+
isDisabled: field2.isDisabled,
|
|
1558
|
+
isInvalid: Boolean(errorMessage),
|
|
1559
|
+
errorMessage,
|
|
1560
|
+
value,
|
|
1561
|
+
onValueChange: setValue
|
|
1562
|
+
}
|
|
1563
|
+
));
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1033
1567
|
// src/hooks/useHeroForm.ts
|
|
1034
|
-
import { useFormContext } from "react-hook-form";
|
|
1568
|
+
import { useFormContext as useFormContext4 } from "react-hook-form";
|
|
1035
1569
|
function useHeroForm() {
|
|
1036
|
-
const form =
|
|
1570
|
+
const form = useFormContext4();
|
|
1037
1571
|
const defaults = useHeroHookFormDefaults();
|
|
1038
1572
|
return {
|
|
1039
1573
|
// All React Hook Form methods and state
|
|
@@ -1044,10 +1578,10 @@ function useHeroForm() {
|
|
|
1044
1578
|
}
|
|
1045
1579
|
|
|
1046
1580
|
// src/providers/FormProvider.tsx
|
|
1047
|
-
import
|
|
1581
|
+
import React18 from "react";
|
|
1048
1582
|
import { FormProvider as RHFProvider } from "react-hook-form";
|
|
1049
1583
|
function FormProvider(props) {
|
|
1050
|
-
return /* @__PURE__ */
|
|
1584
|
+
return /* @__PURE__ */ React18.createElement(RHFProvider, { ...props.methods }, /* @__PURE__ */ React18.createElement(
|
|
1051
1585
|
"form",
|
|
1052
1586
|
{
|
|
1053
1587
|
className: props.className,
|
|
@@ -1060,22 +1594,42 @@ function FormProvider(props) {
|
|
|
1060
1594
|
}
|
|
1061
1595
|
|
|
1062
1596
|
// src/submit/SubmitButton.tsx
|
|
1063
|
-
import
|
|
1597
|
+
import React19 from "react";
|
|
1064
1598
|
function SubmitButton(props) {
|
|
1065
|
-
const ctx =
|
|
1599
|
+
const ctx = useFormContext5();
|
|
1066
1600
|
const loading = props.isLoading ?? ctx.formState.isSubmitting;
|
|
1601
|
+
const enhancedState = props.enhancedState;
|
|
1067
1602
|
const isDisabledFromProps = props.buttonProps?.isDisabled ?? false;
|
|
1068
1603
|
const isDisabled = Boolean(isDisabledFromProps) || Boolean(loading);
|
|
1069
1604
|
const defaults = useHeroHookFormDefaults();
|
|
1070
|
-
|
|
1605
|
+
const getButtonContent = () => {
|
|
1606
|
+
if (enhancedState?.isSuccess) {
|
|
1607
|
+
return /* @__PURE__ */ React19.createElement("span", { className: "inline-flex items-center gap-2" }, "\u2705", props.successText || "Success!");
|
|
1608
|
+
}
|
|
1609
|
+
if (loading) {
|
|
1610
|
+
return /* @__PURE__ */ React19.createElement("span", { className: "inline-flex items-center gap-2" }, "\u23F3", props.loadingText || "Submitting...");
|
|
1611
|
+
}
|
|
1612
|
+
return props.children;
|
|
1613
|
+
};
|
|
1614
|
+
const getButtonColor = () => {
|
|
1615
|
+
if (enhancedState?.isSuccess) {
|
|
1616
|
+
return "success";
|
|
1617
|
+
}
|
|
1618
|
+
if (enhancedState?.isError) {
|
|
1619
|
+
return "danger";
|
|
1620
|
+
}
|
|
1621
|
+
return props.buttonProps?.color || defaults.submitButton.color;
|
|
1622
|
+
};
|
|
1623
|
+
return /* @__PURE__ */ React19.createElement(
|
|
1071
1624
|
Button,
|
|
1072
1625
|
{
|
|
1073
1626
|
type: "submit",
|
|
1074
1627
|
...defaults.submitButton,
|
|
1075
1628
|
...props.buttonProps,
|
|
1076
|
-
isDisabled
|
|
1629
|
+
isDisabled,
|
|
1630
|
+
color: getButtonColor()
|
|
1077
1631
|
},
|
|
1078
|
-
|
|
1632
|
+
getButtonContent()
|
|
1079
1633
|
);
|
|
1080
1634
|
}
|
|
1081
1635
|
|
|
@@ -1215,14 +1769,6 @@ var createPasswordSchema = (minLength = 8) => z.string().min(minLength, `Passwor
|
|
|
1215
1769
|
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/,
|
|
1216
1770
|
"Password must contain at least one uppercase letter, one lowercase letter, and one number"
|
|
1217
1771
|
);
|
|
1218
|
-
var createConfirmPasswordSchema = (passwordField) => z.string().refine(
|
|
1219
|
-
(val) => {
|
|
1220
|
-
return true;
|
|
1221
|
-
},
|
|
1222
|
-
{
|
|
1223
|
-
message: "Passwords do not match"
|
|
1224
|
-
}
|
|
1225
|
-
);
|
|
1226
1772
|
var createNumberRangeSchema = (min, max, fieldName) => z.number().min(min, `${fieldName} must be at least ${min}`).max(max, `${fieldName} must be no more than ${max}`);
|
|
1227
1773
|
var createDateSchema = (fieldName) => z.date({ message: `${fieldName} is required` });
|
|
1228
1774
|
var createFutureDateSchema = (fieldName) => z.date({ message: `${fieldName} is required` }).refine((date) => date > /* @__PURE__ */ new Date(), {
|
|
@@ -1241,17 +1787,61 @@ var createFileSchema = (maxSizeInMB = 5, allowedTypes = ["image/jpeg", "image/pn
|
|
|
1241
1787
|
var createRequiredCheckboxSchema = (fieldName) => z.boolean().refine((val) => val === true, {
|
|
1242
1788
|
message: `You must agree to ${fieldName}`
|
|
1243
1789
|
});
|
|
1244
|
-
var
|
|
1245
|
-
|
|
1246
|
-
|
|
1790
|
+
var crossFieldValidation = {
|
|
1791
|
+
/**
|
|
1792
|
+
* Conditional required field validation
|
|
1793
|
+
*/
|
|
1794
|
+
conditionalRequired: (field2, conditionField, conditionValue) => {
|
|
1795
|
+
return z.object({
|
|
1796
|
+
[conditionField]: z.any(),
|
|
1797
|
+
[field2]: z.string()
|
|
1798
|
+
}).refine(
|
|
1799
|
+
(data) => {
|
|
1800
|
+
if (data[conditionField] === conditionValue) {
|
|
1801
|
+
return data[field2] && data[field2].trim().length > 0;
|
|
1802
|
+
}
|
|
1803
|
+
return true;
|
|
1804
|
+
},
|
|
1805
|
+
{
|
|
1806
|
+
message: "This field is required",
|
|
1807
|
+
path: [field2]
|
|
1808
|
+
}
|
|
1809
|
+
);
|
|
1810
|
+
},
|
|
1811
|
+
/**
|
|
1812
|
+
* Date range validation
|
|
1813
|
+
*/
|
|
1814
|
+
dateRange: (startField, endField) => {
|
|
1815
|
+
return z.object({
|
|
1816
|
+
[endField]: z.string(),
|
|
1817
|
+
[startField]: z.string()
|
|
1818
|
+
}).refine(
|
|
1819
|
+
(data) => {
|
|
1820
|
+
const startDate = new Date(data[startField]);
|
|
1821
|
+
const endDate = new Date(data[endField]);
|
|
1822
|
+
return startDate < endDate;
|
|
1823
|
+
},
|
|
1824
|
+
{
|
|
1825
|
+
message: "End date must be after start date",
|
|
1826
|
+
path: [endField]
|
|
1827
|
+
}
|
|
1828
|
+
);
|
|
1247
1829
|
},
|
|
1248
|
-
|
|
1249
|
-
|
|
1830
|
+
/**
|
|
1831
|
+
* Password confirmation validation
|
|
1832
|
+
*/
|
|
1833
|
+
passwordConfirmation: (passwordField, confirmField) => {
|
|
1834
|
+
return z.object({
|
|
1835
|
+
[confirmField]: z.string(),
|
|
1836
|
+
[passwordField]: z.string()
|
|
1837
|
+
}).refine((data) => data[passwordField] === data[confirmField], {
|
|
1838
|
+
message: "Passwords do not match",
|
|
1839
|
+
path: [confirmField]
|
|
1840
|
+
});
|
|
1250
1841
|
}
|
|
1251
|
-
|
|
1842
|
+
};
|
|
1252
1843
|
var commonValidations = {
|
|
1253
|
-
|
|
1254
|
-
confirmPassword: (passwordField) => createConfirmPasswordSchema(passwordField),
|
|
1844
|
+
confirmPassword: (passwordField, confirmField) => crossFieldValidation.passwordConfirmation(passwordField, confirmField),
|
|
1255
1845
|
date: (fieldName) => createDateSchema(fieldName),
|
|
1256
1846
|
email: createEmailSchema(),
|
|
1257
1847
|
file: (maxSizeInMB, allowedTypes) => createFileSchema(maxSizeInMB, allowedTypes),
|
|
@@ -1268,17 +1858,17 @@ var commonValidations = {
|
|
|
1268
1858
|
};
|
|
1269
1859
|
|
|
1270
1860
|
// src/index.ts
|
|
1271
|
-
import { useFormContext as
|
|
1861
|
+
import { useFormContext as useFormContext5 } from "react-hook-form";
|
|
1272
1862
|
|
|
1273
1863
|
// src/components/ZodForm.tsx
|
|
1274
|
-
import
|
|
1275
|
-
import { Button as
|
|
1864
|
+
import React21 from "react";
|
|
1865
|
+
import { Button as Button6 } from "@heroui/react";
|
|
1276
1866
|
|
|
1277
1867
|
// src/zod-integration.ts
|
|
1278
1868
|
import { useForm as useForm2 } from "react-hook-form";
|
|
1279
1869
|
import { z as z2 } from "zod";
|
|
1280
1870
|
function createZodResolver(schema) {
|
|
1281
|
-
return async (values
|
|
1871
|
+
return async (values) => {
|
|
1282
1872
|
try {
|
|
1283
1873
|
const result = await schema.parseAsync(values);
|
|
1284
1874
|
return {
|
|
@@ -1309,18 +1899,192 @@ function useZodForm(config) {
|
|
|
1309
1899
|
}
|
|
1310
1900
|
function createZodFormConfig(schema, fields, defaultValues) {
|
|
1311
1901
|
return {
|
|
1312
|
-
schema,
|
|
1313
1902
|
fields,
|
|
1314
|
-
|
|
1903
|
+
schema,
|
|
1904
|
+
...defaultValues && {
|
|
1905
|
+
defaultValues
|
|
1906
|
+
}
|
|
1315
1907
|
};
|
|
1316
1908
|
}
|
|
1317
1909
|
|
|
1910
|
+
// src/hooks/useEnhancedFormState.ts
|
|
1911
|
+
import { useCallback, useEffect, useState as useState2 } from "react";
|
|
1912
|
+
function useEnhancedFormState(form, options = {}) {
|
|
1913
|
+
const {
|
|
1914
|
+
autoReset = true,
|
|
1915
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1916
|
+
errorMessage: _errorMessage = "An error occurred. Please try again.",
|
|
1917
|
+
onError,
|
|
1918
|
+
onSuccess,
|
|
1919
|
+
resetDelay = 3e3,
|
|
1920
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1921
|
+
successMessage: _successMessage = "Form submitted successfully!"
|
|
1922
|
+
} = options;
|
|
1923
|
+
const [status, setStatus] = useState2("idle");
|
|
1924
|
+
const [error, setError] = useState2(void 0);
|
|
1925
|
+
const [submittedData, setSubmittedData] = useState2(void 0);
|
|
1926
|
+
const { formState, getValues: _getValues } = form;
|
|
1927
|
+
const { dirtyFields, errors, isSubmitting, touchedFields } = formState;
|
|
1928
|
+
useEffect(() => {
|
|
1929
|
+
if (isSubmitting) {
|
|
1930
|
+
setStatus("submitting");
|
|
1931
|
+
}
|
|
1932
|
+
}, [isSubmitting]);
|
|
1933
|
+
useEffect(() => {
|
|
1934
|
+
if (status === "success" && autoReset) {
|
|
1935
|
+
const timer = setTimeout(() => {
|
|
1936
|
+
setStatus("idle");
|
|
1937
|
+
setSubmittedData(void 0);
|
|
1938
|
+
setError(void 0);
|
|
1939
|
+
}, resetDelay);
|
|
1940
|
+
return () => clearTimeout(timer);
|
|
1941
|
+
}
|
|
1942
|
+
}, [status, autoReset, resetDelay]);
|
|
1943
|
+
const handleSuccess = useCallback(
|
|
1944
|
+
(data) => {
|
|
1945
|
+
setStatus("success");
|
|
1946
|
+
setSubmittedData(data);
|
|
1947
|
+
setError(void 0);
|
|
1948
|
+
onSuccess?.(data);
|
|
1949
|
+
},
|
|
1950
|
+
[onSuccess]
|
|
1951
|
+
);
|
|
1952
|
+
const handleError = useCallback(
|
|
1953
|
+
(errorMessage) => {
|
|
1954
|
+
setStatus("error");
|
|
1955
|
+
setError(errorMessage);
|
|
1956
|
+
setSubmittedData(void 0);
|
|
1957
|
+
onError?.(errorMessage);
|
|
1958
|
+
},
|
|
1959
|
+
[onError]
|
|
1960
|
+
);
|
|
1961
|
+
const reset = useCallback(() => {
|
|
1962
|
+
setStatus("idle");
|
|
1963
|
+
setError(void 0);
|
|
1964
|
+
setSubmittedData(void 0);
|
|
1965
|
+
}, []);
|
|
1966
|
+
return {
|
|
1967
|
+
dirtyFields: new Set(Object.keys(dirtyFields)),
|
|
1968
|
+
error,
|
|
1969
|
+
errorCount: Object.keys(errors).length,
|
|
1970
|
+
handleError,
|
|
1971
|
+
handleSuccess,
|
|
1972
|
+
hasErrors: Object.keys(errors).length > 0,
|
|
1973
|
+
isError: status === "error",
|
|
1974
|
+
isSubmitting,
|
|
1975
|
+
isSuccess: status === "success",
|
|
1976
|
+
reset,
|
|
1977
|
+
status,
|
|
1978
|
+
submittedData,
|
|
1979
|
+
touchedFields: new Set(Object.keys(touchedFields))
|
|
1980
|
+
};
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
// src/components/FormStatus.tsx
|
|
1984
|
+
import React20 from "react";
|
|
1985
|
+
import { Button as Button5 } from "@heroui/react";
|
|
1986
|
+
function FormStatus({
|
|
1987
|
+
className = "",
|
|
1988
|
+
onDismiss,
|
|
1989
|
+
showDetails = false,
|
|
1990
|
+
state
|
|
1991
|
+
}) {
|
|
1992
|
+
const { error, isError, isSubmitting, isSuccess, status, submittedData } = state;
|
|
1993
|
+
if (status === "idle") {
|
|
1994
|
+
return null;
|
|
1995
|
+
}
|
|
1996
|
+
if (isSubmitting) {
|
|
1997
|
+
return /* @__PURE__ */ React20.createElement(
|
|
1998
|
+
"div",
|
|
1999
|
+
{
|
|
2000
|
+
className: `flex items-center gap-3 p-4 bg-blue-50 border border-blue-200 rounded-lg ${className}`
|
|
2001
|
+
},
|
|
2002
|
+
/* @__PURE__ */ React20.createElement("span", { className: "text-blue-600" }, "\u23F3"),
|
|
2003
|
+
/* @__PURE__ */ React20.createElement("div", null, /* @__PURE__ */ React20.createElement("p", { className: "text-sm font-medium text-blue-900" }, "Submitting form..."), showDetails && /* @__PURE__ */ React20.createElement("p", { className: "text-xs text-blue-700" }, "Please wait while we process your request."))
|
|
2004
|
+
);
|
|
2005
|
+
}
|
|
2006
|
+
if (isSuccess) {
|
|
2007
|
+
return /* @__PURE__ */ React20.createElement(
|
|
2008
|
+
"div",
|
|
2009
|
+
{
|
|
2010
|
+
className: `flex items-center gap-3 p-4 bg-green-50 border border-green-200 rounded-lg ${className}`,
|
|
2011
|
+
"data-testid": "success-message"
|
|
2012
|
+
},
|
|
2013
|
+
/* @__PURE__ */ React20.createElement("span", { className: "text-green-600" }, "\u2705"),
|
|
2014
|
+
/* @__PURE__ */ React20.createElement("div", { className: "flex-1" }, /* @__PURE__ */ React20.createElement("p", { className: "text-sm font-medium text-green-900" }, "Form submitted successfully!"), showDetails && submittedData && /* @__PURE__ */ React20.createElement("p", { className: "text-xs text-green-700" }, "Your data has been saved. Thank you for your submission.")),
|
|
2015
|
+
onDismiss && /* @__PURE__ */ React20.createElement(
|
|
2016
|
+
Button5,
|
|
2017
|
+
{
|
|
2018
|
+
size: "sm",
|
|
2019
|
+
variant: "light",
|
|
2020
|
+
isIconOnly: true,
|
|
2021
|
+
onPress: onDismiss,
|
|
2022
|
+
"aria-label": "Dismiss success message"
|
|
2023
|
+
},
|
|
2024
|
+
"\u2715"
|
|
2025
|
+
)
|
|
2026
|
+
);
|
|
2027
|
+
}
|
|
2028
|
+
if (isError && error) {
|
|
2029
|
+
return /* @__PURE__ */ React20.createElement(
|
|
2030
|
+
"div",
|
|
2031
|
+
{
|
|
2032
|
+
className: `flex items-center gap-3 p-4 bg-red-50 border border-red-200 rounded-lg ${className}`,
|
|
2033
|
+
"data-testid": "error-message"
|
|
2034
|
+
},
|
|
2035
|
+
/* @__PURE__ */ React20.createElement("span", { className: "text-red-600" }, "\u26A0\uFE0F"),
|
|
2036
|
+
/* @__PURE__ */ React20.createElement("div", { className: "flex-1" }, /* @__PURE__ */ React20.createElement("p", { className: "text-sm font-medium text-red-900" }, "Error submitting form"), /* @__PURE__ */ React20.createElement("p", { className: "text-xs text-red-700" }, error)),
|
|
2037
|
+
onDismiss && /* @__PURE__ */ React20.createElement(
|
|
2038
|
+
Button5,
|
|
2039
|
+
{
|
|
2040
|
+
size: "sm",
|
|
2041
|
+
variant: "light",
|
|
2042
|
+
isIconOnly: true,
|
|
2043
|
+
onPress: onDismiss,
|
|
2044
|
+
"aria-label": "Dismiss error message"
|
|
2045
|
+
},
|
|
2046
|
+
"\u2715"
|
|
2047
|
+
)
|
|
2048
|
+
);
|
|
2049
|
+
}
|
|
2050
|
+
return null;
|
|
2051
|
+
}
|
|
2052
|
+
function FormToast({
|
|
2053
|
+
duration = 5e3,
|
|
2054
|
+
onDismiss,
|
|
2055
|
+
position = "top-right",
|
|
2056
|
+
state
|
|
2057
|
+
}) {
|
|
2058
|
+
const [isVisible, setIsVisible] = React20.useState(false);
|
|
2059
|
+
React20.useEffect(() => {
|
|
2060
|
+
if (state.isSuccess || state.isError) {
|
|
2061
|
+
setIsVisible(true);
|
|
2062
|
+
if (duration > 0) {
|
|
2063
|
+
const timer = setTimeout(() => {
|
|
2064
|
+
setIsVisible(false);
|
|
2065
|
+
onDismiss?.();
|
|
2066
|
+
}, duration);
|
|
2067
|
+
return () => clearTimeout(timer);
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
}, [state.isSuccess, state.isError, duration, onDismiss]);
|
|
2071
|
+
if (!isVisible) {
|
|
2072
|
+
return null;
|
|
2073
|
+
}
|
|
2074
|
+
const positionClasses = {
|
|
2075
|
+
"bottom-left": "bottom-4 left-4",
|
|
2076
|
+
"bottom-right": "bottom-4 right-4",
|
|
2077
|
+
"top-left": "top-4 left-4",
|
|
2078
|
+
"top-right": "top-4 right-4"
|
|
2079
|
+
};
|
|
2080
|
+
return /* @__PURE__ */ React20.createElement("div", { className: `fixed z-50 ${positionClasses[position]}` }, /* @__PURE__ */ React20.createElement(FormStatus, { state, onDismiss }));
|
|
2081
|
+
}
|
|
2082
|
+
|
|
1318
2083
|
// src/components/ZodForm.tsx
|
|
1319
2084
|
function ZodForm({
|
|
1320
2085
|
className,
|
|
1321
2086
|
columns = 1,
|
|
1322
2087
|
config,
|
|
1323
|
-
errorDisplay = "inline",
|
|
1324
2088
|
layout = "vertical",
|
|
1325
2089
|
onError,
|
|
1326
2090
|
onSubmit,
|
|
@@ -1335,97 +2099,84 @@ function ZodForm({
|
|
|
1335
2099
|
title
|
|
1336
2100
|
}) {
|
|
1337
2101
|
const form = useZodForm(config);
|
|
1338
|
-
const
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
2102
|
+
const enhancedState = useEnhancedFormState(form, {
|
|
2103
|
+
autoReset: true,
|
|
2104
|
+
onError: (error) => onError?.({ field: "form", message: error }),
|
|
2105
|
+
onSuccess,
|
|
2106
|
+
resetDelay: 3e3
|
|
1343
2107
|
});
|
|
1344
2108
|
const handleSubmit = async () => {
|
|
1345
|
-
setSubmissionState((prev) => ({
|
|
1346
|
-
...prev,
|
|
1347
|
-
error: void 0,
|
|
1348
|
-
isSubmitting: true
|
|
1349
|
-
}));
|
|
1350
|
-
const isValid = await form.trigger();
|
|
1351
|
-
if (!isValid) {
|
|
1352
|
-
setSubmissionState({
|
|
1353
|
-
error: "Please fix the validation errors above",
|
|
1354
|
-
isSubmitted: true,
|
|
1355
|
-
isSubmitting: false,
|
|
1356
|
-
isSuccess: false
|
|
1357
|
-
});
|
|
1358
|
-
return;
|
|
1359
|
-
}
|
|
1360
2109
|
try {
|
|
1361
|
-
await form.handleSubmit(
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
2110
|
+
await form.handleSubmit(
|
|
2111
|
+
async (formData) => {
|
|
2112
|
+
await onSubmit(formData);
|
|
2113
|
+
enhancedState.handleSuccess(formData);
|
|
2114
|
+
},
|
|
2115
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2116
|
+
(_errors) => {
|
|
2117
|
+
enhancedState.handleError("Please fix the validation errors above");
|
|
2118
|
+
}
|
|
2119
|
+
)();
|
|
1371
2120
|
} catch (error) {
|
|
1372
2121
|
const errorMessage = error instanceof Error ? error.message : "An error occurred";
|
|
1373
|
-
|
|
1374
|
-
error: errorMessage,
|
|
1375
|
-
isSubmitted: true,
|
|
1376
|
-
isSubmitting: false,
|
|
1377
|
-
isSuccess: false
|
|
1378
|
-
});
|
|
1379
|
-
onError?.({
|
|
1380
|
-
message: errorMessage
|
|
1381
|
-
});
|
|
2122
|
+
enhancedState.handleError(errorMessage);
|
|
1382
2123
|
}
|
|
1383
2124
|
};
|
|
1384
2125
|
const resetForm = () => {
|
|
1385
2126
|
form.reset();
|
|
1386
|
-
|
|
1387
|
-
error: void 0,
|
|
1388
|
-
isSubmitted: false,
|
|
1389
|
-
isSubmitting: false,
|
|
1390
|
-
isSuccess: false
|
|
1391
|
-
});
|
|
2127
|
+
enhancedState.reset();
|
|
1392
2128
|
};
|
|
1393
2129
|
const renderFields = () => {
|
|
1394
2130
|
if (layout === "grid") {
|
|
1395
|
-
return /* @__PURE__ */
|
|
2131
|
+
return /* @__PURE__ */ React21.createElement(
|
|
1396
2132
|
"div",
|
|
1397
2133
|
{
|
|
1398
2134
|
className: `grid gap-${spacing} ${columns === 1 ? "grid-cols-1" : columns === 2 ? "grid-cols-1 md:grid-cols-2" : "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"}`
|
|
1399
2135
|
},
|
|
1400
|
-
config.fields.map((
|
|
2136
|
+
config.fields.map((field2) => /* @__PURE__ */ React21.createElement(
|
|
1401
2137
|
FormField,
|
|
1402
2138
|
{
|
|
1403
|
-
key:
|
|
1404
|
-
config:
|
|
2139
|
+
key: field2.name,
|
|
2140
|
+
config: field2,
|
|
1405
2141
|
form,
|
|
1406
|
-
submissionState
|
|
2142
|
+
submissionState: {
|
|
2143
|
+
error: enhancedState.error,
|
|
2144
|
+
isSubmitted: enhancedState.status !== "idle",
|
|
2145
|
+
isSubmitting: enhancedState.isSubmitting,
|
|
2146
|
+
isSuccess: enhancedState.isSuccess
|
|
2147
|
+
}
|
|
1407
2148
|
}
|
|
1408
2149
|
))
|
|
1409
2150
|
);
|
|
1410
2151
|
}
|
|
1411
2152
|
if (layout === "horizontal") {
|
|
1412
|
-
return /* @__PURE__ */
|
|
2153
|
+
return /* @__PURE__ */ React21.createElement("div", { className: `grid gap-${spacing} grid-cols-1 md:grid-cols-2` }, config.fields.map((field2) => /* @__PURE__ */ React21.createElement(
|
|
1413
2154
|
FormField,
|
|
1414
2155
|
{
|
|
1415
|
-
key:
|
|
1416
|
-
config:
|
|
2156
|
+
key: field2.name,
|
|
2157
|
+
config: field2,
|
|
1417
2158
|
form,
|
|
1418
|
-
submissionState
|
|
2159
|
+
submissionState: {
|
|
2160
|
+
error: enhancedState.error,
|
|
2161
|
+
isSubmitted: enhancedState.status !== "idle",
|
|
2162
|
+
isSubmitting: enhancedState.isSubmitting,
|
|
2163
|
+
isSuccess: enhancedState.isSuccess
|
|
2164
|
+
}
|
|
1419
2165
|
}
|
|
1420
2166
|
)));
|
|
1421
2167
|
}
|
|
1422
|
-
return /* @__PURE__ */
|
|
2168
|
+
return /* @__PURE__ */ React21.createElement("div", { className: `space-y-${spacing}` }, config.fields.map((field2) => /* @__PURE__ */ React21.createElement(
|
|
1423
2169
|
FormField,
|
|
1424
2170
|
{
|
|
1425
|
-
key:
|
|
1426
|
-
config:
|
|
2171
|
+
key: field2.name,
|
|
2172
|
+
config: field2,
|
|
1427
2173
|
form,
|
|
1428
|
-
submissionState
|
|
2174
|
+
submissionState: {
|
|
2175
|
+
error: enhancedState.error,
|
|
2176
|
+
isSubmitted: enhancedState.status !== "idle",
|
|
2177
|
+
isSubmitting: enhancedState.isSubmitting,
|
|
2178
|
+
isSuccess: enhancedState.isSuccess
|
|
2179
|
+
}
|
|
1429
2180
|
}
|
|
1430
2181
|
)));
|
|
1431
2182
|
};
|
|
@@ -1433,7 +2184,7 @@ function ZodForm({
|
|
|
1433
2184
|
e.preventDefault();
|
|
1434
2185
|
void handleSubmit();
|
|
1435
2186
|
};
|
|
1436
|
-
|
|
2187
|
+
React21.useEffect(() => {
|
|
1437
2188
|
if (config.onError && Object.keys(form.formState.errors).length > 0) {
|
|
1438
2189
|
config.onError(form.formState.errors);
|
|
1439
2190
|
}
|
|
@@ -1442,42 +2193,33 @@ function ZodForm({
|
|
|
1442
2193
|
return render({
|
|
1443
2194
|
errors: form.formState.errors,
|
|
1444
2195
|
form,
|
|
1445
|
-
isSubmitted:
|
|
1446
|
-
isSubmitting:
|
|
1447
|
-
isSuccess:
|
|
2196
|
+
isSubmitted: enhancedState.status !== "idle",
|
|
2197
|
+
isSubmitting: enhancedState.isSubmitting,
|
|
2198
|
+
isSuccess: enhancedState.isSuccess,
|
|
1448
2199
|
values: form.getValues()
|
|
1449
2200
|
});
|
|
1450
2201
|
}
|
|
1451
|
-
return /* @__PURE__ */
|
|
1452
|
-
|
|
1453
|
-
{
|
|
1454
|
-
className: "mb-6 p-4 bg-success-50 border border-success-200 rounded-lg",
|
|
1455
|
-
"data-testid": "success-message"
|
|
1456
|
-
},
|
|
1457
|
-
/* @__PURE__ */ React16.createElement("p", { className: "text-success-800 font-medium" }, "Success!"),
|
|
1458
|
-
/* @__PURE__ */ React16.createElement("p", { className: "text-success-700 text-sm mt-1" }, "Your request has been processed successfully.")
|
|
1459
|
-
), submissionState.error && errorDisplay !== "none" && /* @__PURE__ */ React16.createElement(
|
|
1460
|
-
"div",
|
|
2202
|
+
return /* @__PURE__ */ React21.createElement("form", { className, role: "form", onSubmit: handleFormSubmit }, title && /* @__PURE__ */ React21.createElement("div", { className: "mb-6" }, /* @__PURE__ */ React21.createElement("h2", { className: "text-xl font-semibold text-foreground mb-2" }, title), subtitle && /* @__PURE__ */ React21.createElement("p", { className: "text-sm text-muted-foreground" }, subtitle)), /* @__PURE__ */ React21.createElement(
|
|
2203
|
+
FormStatus,
|
|
1461
2204
|
{
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
Button3,
|
|
2205
|
+
state: enhancedState,
|
|
2206
|
+
onDismiss: () => enhancedState.reset(),
|
|
2207
|
+
showDetails: true
|
|
2208
|
+
}
|
|
2209
|
+
), renderFields(), /* @__PURE__ */ React21.createElement("div", { className: "mt-6 flex gap-3 justify-end" }, /* @__PURE__ */ React21.createElement(
|
|
2210
|
+
Button6,
|
|
1469
2211
|
{
|
|
1470
2212
|
color: "primary",
|
|
1471
|
-
isDisabled:
|
|
1472
|
-
isLoading:
|
|
2213
|
+
isDisabled: enhancedState.isSubmitting,
|
|
2214
|
+
isLoading: enhancedState.isSubmitting,
|
|
1473
2215
|
type: "submit",
|
|
1474
2216
|
...submitButtonProps
|
|
1475
2217
|
},
|
|
1476
|
-
submitButtonText
|
|
1477
|
-
), showResetButton && /* @__PURE__ */
|
|
1478
|
-
|
|
2218
|
+
enhancedState.isSuccess ? "Success!" : submitButtonText
|
|
2219
|
+
), showResetButton && /* @__PURE__ */ React21.createElement(
|
|
2220
|
+
Button6,
|
|
1479
2221
|
{
|
|
1480
|
-
isDisabled:
|
|
2222
|
+
isDisabled: enhancedState.isSubmitting,
|
|
1481
2223
|
type: "button",
|
|
1482
2224
|
variant: "bordered",
|
|
1483
2225
|
onPress: resetForm
|
|
@@ -1485,29 +2227,1257 @@ function ZodForm({
|
|
|
1485
2227
|
resetButtonText
|
|
1486
2228
|
)));
|
|
1487
2229
|
}
|
|
2230
|
+
|
|
2231
|
+
// src/builders/BasicFormBuilder.ts
|
|
2232
|
+
var BasicFormBuilder = class {
|
|
2233
|
+
constructor() {
|
|
2234
|
+
this.fields = [];
|
|
2235
|
+
}
|
|
2236
|
+
/**
|
|
2237
|
+
* Add an input field
|
|
2238
|
+
*/
|
|
2239
|
+
input(name, label, type = "text") {
|
|
2240
|
+
this.fields.push({
|
|
2241
|
+
inputProps: { type },
|
|
2242
|
+
label,
|
|
2243
|
+
name,
|
|
2244
|
+
type: "input"
|
|
2245
|
+
});
|
|
2246
|
+
return this;
|
|
2247
|
+
}
|
|
2248
|
+
/**
|
|
2249
|
+
* Add a textarea field
|
|
2250
|
+
*/
|
|
2251
|
+
textarea(name, label, placeholder) {
|
|
2252
|
+
this.fields.push({
|
|
2253
|
+
label,
|
|
2254
|
+
name,
|
|
2255
|
+
textareaProps: { placeholder },
|
|
2256
|
+
type: "textarea"
|
|
2257
|
+
});
|
|
2258
|
+
return this;
|
|
2259
|
+
}
|
|
2260
|
+
/**
|
|
2261
|
+
* Add a select field
|
|
2262
|
+
*/
|
|
2263
|
+
select(name, label, options) {
|
|
2264
|
+
this.fields.push({
|
|
2265
|
+
label,
|
|
2266
|
+
name,
|
|
2267
|
+
options,
|
|
2268
|
+
type: "select"
|
|
2269
|
+
});
|
|
2270
|
+
return this;
|
|
2271
|
+
}
|
|
2272
|
+
/**
|
|
2273
|
+
* Add a checkbox field
|
|
2274
|
+
*/
|
|
2275
|
+
checkbox(name, label) {
|
|
2276
|
+
this.fields.push({
|
|
2277
|
+
label,
|
|
2278
|
+
name,
|
|
2279
|
+
type: "checkbox"
|
|
2280
|
+
});
|
|
2281
|
+
return this;
|
|
2282
|
+
}
|
|
2283
|
+
/**
|
|
2284
|
+
* Add a switch field
|
|
2285
|
+
*/
|
|
2286
|
+
switch(name, label) {
|
|
2287
|
+
this.fields.push({
|
|
2288
|
+
label,
|
|
2289
|
+
name,
|
|
2290
|
+
type: "switch"
|
|
2291
|
+
});
|
|
2292
|
+
return this;
|
|
2293
|
+
}
|
|
2294
|
+
/**
|
|
2295
|
+
* Build the final field configuration array
|
|
2296
|
+
*/
|
|
2297
|
+
build() {
|
|
2298
|
+
return this.fields;
|
|
2299
|
+
}
|
|
2300
|
+
};
|
|
2301
|
+
function createBasicFormBuilder() {
|
|
2302
|
+
return new BasicFormBuilder();
|
|
2303
|
+
}
|
|
2304
|
+
var FormFieldHelpers = {
|
|
2305
|
+
/**
|
|
2306
|
+
* Create a checkbox field
|
|
2307
|
+
*/
|
|
2308
|
+
checkbox: (name, label) => ({
|
|
2309
|
+
label,
|
|
2310
|
+
name,
|
|
2311
|
+
type: "checkbox"
|
|
2312
|
+
}),
|
|
2313
|
+
/**
|
|
2314
|
+
* Create an input field
|
|
2315
|
+
*/
|
|
2316
|
+
input: (name, label, type = "text") => ({
|
|
2317
|
+
inputProps: { type },
|
|
2318
|
+
label,
|
|
2319
|
+
name,
|
|
2320
|
+
type: "input"
|
|
2321
|
+
}),
|
|
2322
|
+
/**
|
|
2323
|
+
* Create a select field
|
|
2324
|
+
*/
|
|
2325
|
+
select: (name, label, options) => ({
|
|
2326
|
+
label,
|
|
2327
|
+
name,
|
|
2328
|
+
options,
|
|
2329
|
+
type: "select"
|
|
2330
|
+
}),
|
|
2331
|
+
/**
|
|
2332
|
+
* Create a switch field
|
|
2333
|
+
*/
|
|
2334
|
+
switch: (name, label) => ({
|
|
2335
|
+
label,
|
|
2336
|
+
name,
|
|
2337
|
+
type: "switch"
|
|
2338
|
+
}),
|
|
2339
|
+
/**
|
|
2340
|
+
* Create a textarea field
|
|
2341
|
+
*/
|
|
2342
|
+
textarea: (name, label, placeholder) => ({
|
|
2343
|
+
label,
|
|
2344
|
+
name,
|
|
2345
|
+
textareaProps: { placeholder },
|
|
2346
|
+
type: "textarea"
|
|
2347
|
+
})
|
|
2348
|
+
};
|
|
2349
|
+
var CommonFields = {
|
|
2350
|
+
/**
|
|
2351
|
+
* Address fields
|
|
2352
|
+
*/
|
|
2353
|
+
address: () => [
|
|
2354
|
+
FormFieldHelpers.input("street", "Street Address"),
|
|
2355
|
+
FormFieldHelpers.input("city", "City"),
|
|
2356
|
+
FormFieldHelpers.input("state", "State/Province"),
|
|
2357
|
+
FormFieldHelpers.input("zipCode", "ZIP/Postal Code"),
|
|
2358
|
+
FormFieldHelpers.select("country", "Country", [
|
|
2359
|
+
{ label: "Select a country", value: "" },
|
|
2360
|
+
{ label: "United States", value: "us" },
|
|
2361
|
+
{ label: "Canada", value: "ca" },
|
|
2362
|
+
{ label: "United Kingdom", value: "uk" },
|
|
2363
|
+
{ label: "Australia", value: "au" },
|
|
2364
|
+
{ label: "Germany", value: "de" },
|
|
2365
|
+
{ label: "France", value: "fr" }
|
|
2366
|
+
])
|
|
2367
|
+
],
|
|
2368
|
+
/**
|
|
2369
|
+
* Personal information fields
|
|
2370
|
+
*/
|
|
2371
|
+
personal: () => [
|
|
2372
|
+
FormFieldHelpers.input("firstName", "First Name"),
|
|
2373
|
+
FormFieldHelpers.input("lastName", "Last Name"),
|
|
2374
|
+
FormFieldHelpers.input("email", "Email", "email"),
|
|
2375
|
+
FormFieldHelpers.input("phone", "Phone", "tel")
|
|
2376
|
+
],
|
|
2377
|
+
/**
|
|
2378
|
+
* Terms and conditions fields
|
|
2379
|
+
*/
|
|
2380
|
+
terms: () => [
|
|
2381
|
+
FormFieldHelpers.checkbox(
|
|
2382
|
+
"terms",
|
|
2383
|
+
"I agree to the terms and conditions"
|
|
2384
|
+
),
|
|
2385
|
+
FormFieldHelpers.checkbox(
|
|
2386
|
+
"privacy",
|
|
2387
|
+
"I agree to the privacy policy"
|
|
2388
|
+
),
|
|
2389
|
+
FormFieldHelpers.checkbox(
|
|
2390
|
+
"newsletter",
|
|
2391
|
+
"Subscribe to newsletter"
|
|
2392
|
+
)
|
|
2393
|
+
]
|
|
2394
|
+
};
|
|
2395
|
+
|
|
2396
|
+
// src/builders/AdvancedFormBuilder.ts
|
|
2397
|
+
function inputField(name, label, props) {
|
|
2398
|
+
return {
|
|
2399
|
+
label,
|
|
2400
|
+
name,
|
|
2401
|
+
type: "input",
|
|
2402
|
+
...props && {
|
|
2403
|
+
inputProps: {
|
|
2404
|
+
className: props.className,
|
|
2405
|
+
description: props.description,
|
|
2406
|
+
disabled: props.isDisabled,
|
|
2407
|
+
placeholder: props.placeholder,
|
|
2408
|
+
type: props.type || "text"
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
};
|
|
2412
|
+
}
|
|
2413
|
+
function textareaField(name, label, props) {
|
|
2414
|
+
return {
|
|
2415
|
+
label,
|
|
2416
|
+
name,
|
|
2417
|
+
type: "textarea",
|
|
2418
|
+
...props && {
|
|
2419
|
+
textareaProps: {
|
|
2420
|
+
className: props.className,
|
|
2421
|
+
description: props.description,
|
|
2422
|
+
disabled: props.isDisabled,
|
|
2423
|
+
placeholder: props.placeholder,
|
|
2424
|
+
rows: props.rows
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2427
|
+
};
|
|
2428
|
+
}
|
|
2429
|
+
function selectField(name, label, options) {
|
|
2430
|
+
return {
|
|
2431
|
+
label,
|
|
2432
|
+
name,
|
|
2433
|
+
options,
|
|
2434
|
+
type: "select"
|
|
2435
|
+
};
|
|
2436
|
+
}
|
|
2437
|
+
function checkboxField(name, label, props) {
|
|
2438
|
+
return {
|
|
2439
|
+
label,
|
|
2440
|
+
name,
|
|
2441
|
+
type: "checkbox",
|
|
2442
|
+
...props && {
|
|
2443
|
+
checkboxProps: {
|
|
2444
|
+
className: props.className,
|
|
2445
|
+
disabled: props.isDisabled
|
|
2446
|
+
}
|
|
2447
|
+
}
|
|
2448
|
+
};
|
|
2449
|
+
}
|
|
2450
|
+
function switchField(name, label, props) {
|
|
2451
|
+
return {
|
|
2452
|
+
label,
|
|
2453
|
+
name,
|
|
2454
|
+
type: "switch",
|
|
2455
|
+
...props && {
|
|
2456
|
+
switchProps: {
|
|
2457
|
+
className: props.className,
|
|
2458
|
+
disabled: props.isDisabled
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
};
|
|
2462
|
+
}
|
|
2463
|
+
function radioField(name, label, options, props) {
|
|
2464
|
+
return {
|
|
2465
|
+
label,
|
|
2466
|
+
name,
|
|
2467
|
+
radioOptions: options,
|
|
2468
|
+
type: "radio",
|
|
2469
|
+
...props && {
|
|
2470
|
+
radioProps: {
|
|
2471
|
+
className: props.className,
|
|
2472
|
+
isDisabled: props.isDisabled,
|
|
2473
|
+
orientation: props.orientation
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
};
|
|
2477
|
+
}
|
|
2478
|
+
function sliderField(name, label, props) {
|
|
2479
|
+
return {
|
|
2480
|
+
label,
|
|
2481
|
+
name,
|
|
2482
|
+
type: "slider",
|
|
2483
|
+
...props && {
|
|
2484
|
+
sliderProps: {
|
|
2485
|
+
className: props.className || "",
|
|
2486
|
+
disabled: props.isDisabled || false,
|
|
2487
|
+
max: props.max || 100,
|
|
2488
|
+
min: props.min || 0,
|
|
2489
|
+
step: props.step || 1
|
|
2490
|
+
}
|
|
2491
|
+
}
|
|
2492
|
+
};
|
|
2493
|
+
}
|
|
2494
|
+
function dateField(name, label, props) {
|
|
2495
|
+
return {
|
|
2496
|
+
label,
|
|
2497
|
+
name,
|
|
2498
|
+
type: "date",
|
|
2499
|
+
...props && {
|
|
2500
|
+
dateProps: {
|
|
2501
|
+
className: props.className || "",
|
|
2502
|
+
disabled: props.isDisabled || false,
|
|
2503
|
+
placeholder: props.placeholder || ""
|
|
2504
|
+
}
|
|
2505
|
+
}
|
|
2506
|
+
};
|
|
2507
|
+
}
|
|
2508
|
+
function fileField(name, label, props) {
|
|
2509
|
+
return {
|
|
2510
|
+
label,
|
|
2511
|
+
name,
|
|
2512
|
+
type: "file",
|
|
2513
|
+
...props && {
|
|
2514
|
+
fileProps: {
|
|
2515
|
+
accept: props.accept || "",
|
|
2516
|
+
className: props.className || "",
|
|
2517
|
+
disabled: props.isDisabled || false,
|
|
2518
|
+
multiple: props.multiple || false
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
};
|
|
2522
|
+
}
|
|
2523
|
+
function fontPickerField(name, label, props) {
|
|
2524
|
+
return {
|
|
2525
|
+
label,
|
|
2526
|
+
name,
|
|
2527
|
+
type: "fontPicker",
|
|
2528
|
+
...props && {
|
|
2529
|
+
fontPickerProps: {
|
|
2530
|
+
className: props.className || "",
|
|
2531
|
+
disabled: props.isDisabled || false
|
|
2532
|
+
}
|
|
2533
|
+
}
|
|
2534
|
+
};
|
|
2535
|
+
}
|
|
2536
|
+
function createField(type, name, label, optionsOrProps, props) {
|
|
2537
|
+
switch (type) {
|
|
2538
|
+
case "input":
|
|
2539
|
+
return inputField(name, label, optionsOrProps);
|
|
2540
|
+
case "textarea":
|
|
2541
|
+
return textareaField(name, label, optionsOrProps);
|
|
2542
|
+
case "select":
|
|
2543
|
+
return selectField(name, label, optionsOrProps);
|
|
2544
|
+
case "checkbox":
|
|
2545
|
+
return checkboxField(name, label, optionsOrProps);
|
|
2546
|
+
case "switch":
|
|
2547
|
+
return switchField(name, label, optionsOrProps);
|
|
2548
|
+
case "radio":
|
|
2549
|
+
return radioField(name, label, optionsOrProps, props);
|
|
2550
|
+
case "slider":
|
|
2551
|
+
return sliderField(name, label, optionsOrProps);
|
|
2552
|
+
case "date":
|
|
2553
|
+
return dateField(name, label, optionsOrProps);
|
|
2554
|
+
case "file":
|
|
2555
|
+
return fileField(name, label, optionsOrProps);
|
|
2556
|
+
case "fontPicker":
|
|
2557
|
+
return fontPickerField(name, label, optionsOrProps);
|
|
2558
|
+
default:
|
|
2559
|
+
throw new Error(`Unknown field type: ${type}`);
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
var AdvancedFieldBuilder = class {
|
|
2563
|
+
constructor() {
|
|
2564
|
+
this.fields = [];
|
|
2565
|
+
}
|
|
2566
|
+
field(type, name, label, optionsOrProps, props) {
|
|
2567
|
+
this.fields.push(createField(type, name, label, optionsOrProps, props));
|
|
2568
|
+
return this;
|
|
2569
|
+
}
|
|
2570
|
+
/**
|
|
2571
|
+
* Add a conditional field that shows/hides based on form data
|
|
2572
|
+
*/
|
|
2573
|
+
conditionalField(name, condition, field2) {
|
|
2574
|
+
this.fields.push({
|
|
2575
|
+
condition,
|
|
2576
|
+
field: field2,
|
|
2577
|
+
name,
|
|
2578
|
+
type: "conditional"
|
|
2579
|
+
});
|
|
2580
|
+
return this;
|
|
2581
|
+
}
|
|
2582
|
+
/**
|
|
2583
|
+
* Add a field array for dynamic repeating field groups
|
|
2584
|
+
*/
|
|
2585
|
+
fieldArray(name, label, fields, options) {
|
|
2586
|
+
this.fields.push({
|
|
2587
|
+
addButtonText: options?.addButtonText,
|
|
2588
|
+
fields,
|
|
2589
|
+
label,
|
|
2590
|
+
max: options?.max,
|
|
2591
|
+
min: options?.min,
|
|
2592
|
+
name,
|
|
2593
|
+
removeButtonText: options?.removeButtonText,
|
|
2594
|
+
type: "fieldArray"
|
|
2595
|
+
});
|
|
2596
|
+
return this;
|
|
2597
|
+
}
|
|
2598
|
+
/**
|
|
2599
|
+
* Add a dynamic section that shows/hides based on form data
|
|
2600
|
+
*/
|
|
2601
|
+
dynamicSection(name, condition, fields, options) {
|
|
2602
|
+
this.fields.push({
|
|
2603
|
+
condition,
|
|
2604
|
+
description: options?.description,
|
|
2605
|
+
fields,
|
|
2606
|
+
name,
|
|
2607
|
+
title: options?.title,
|
|
2608
|
+
type: "dynamicSection"
|
|
2609
|
+
});
|
|
2610
|
+
return this;
|
|
2611
|
+
}
|
|
2612
|
+
/**
|
|
2613
|
+
* Build the final field configuration array
|
|
2614
|
+
*/
|
|
2615
|
+
build() {
|
|
2616
|
+
return this.fields;
|
|
2617
|
+
}
|
|
2618
|
+
};
|
|
2619
|
+
var FieldArrayItemBuilder = class {
|
|
2620
|
+
constructor() {
|
|
2621
|
+
this.fields = [];
|
|
2622
|
+
}
|
|
2623
|
+
field(type, name, label, optionsOrProps, props) {
|
|
2624
|
+
this.fields.push(createField(type, name, label, optionsOrProps, props));
|
|
2625
|
+
return this;
|
|
2626
|
+
}
|
|
2627
|
+
/**
|
|
2628
|
+
* Build the field array item configuration
|
|
2629
|
+
*/
|
|
2630
|
+
build() {
|
|
2631
|
+
return this.fields;
|
|
2632
|
+
}
|
|
2633
|
+
};
|
|
2634
|
+
function createFieldArrayItemBuilder() {
|
|
2635
|
+
return new FieldArrayItemBuilder();
|
|
2636
|
+
}
|
|
2637
|
+
var FieldArrayBuilder = class {
|
|
2638
|
+
constructor(arrayName) {
|
|
2639
|
+
this.arrayName = arrayName;
|
|
2640
|
+
this.fields = [];
|
|
2641
|
+
}
|
|
2642
|
+
field(type, name, label, optionsOrProps, props) {
|
|
2643
|
+
const fullPath = `${this.arrayName}.${name}`;
|
|
2644
|
+
const fieldConfig = createField(
|
|
2645
|
+
type,
|
|
2646
|
+
fullPath,
|
|
2647
|
+
label,
|
|
2648
|
+
optionsOrProps,
|
|
2649
|
+
props
|
|
2650
|
+
);
|
|
2651
|
+
this.fields.push(fieldConfig);
|
|
2652
|
+
return this;
|
|
2653
|
+
}
|
|
2654
|
+
build() {
|
|
2655
|
+
return this.fields;
|
|
2656
|
+
}
|
|
2657
|
+
};
|
|
2658
|
+
function createFieldArrayBuilder(arrayName) {
|
|
2659
|
+
return new FieldArrayBuilder(arrayName);
|
|
2660
|
+
}
|
|
2661
|
+
function createAdvancedBuilder() {
|
|
2662
|
+
return new AdvancedFieldBuilder();
|
|
2663
|
+
}
|
|
2664
|
+
|
|
2665
|
+
// src/builders/TypeInferredBuilder.ts
|
|
2666
|
+
import { z as z3 } from "zod";
|
|
2667
|
+
var TypeInferredBuilder = class {
|
|
2668
|
+
constructor() {
|
|
2669
|
+
this.schemaFields = {};
|
|
2670
|
+
this.formFields = [];
|
|
2671
|
+
}
|
|
2672
|
+
/**
|
|
2673
|
+
* Add a text field
|
|
2674
|
+
*/
|
|
2675
|
+
text(name, label, options) {
|
|
2676
|
+
const { maxLength, minLength, pattern, ...fieldOptions } = options || {};
|
|
2677
|
+
let zodType = z3.string();
|
|
2678
|
+
if (minLength)
|
|
2679
|
+
zodType = zodType.min(
|
|
2680
|
+
minLength,
|
|
2681
|
+
`${label} must be at least ${minLength} characters`
|
|
2682
|
+
);
|
|
2683
|
+
if (maxLength)
|
|
2684
|
+
zodType = zodType.max(
|
|
2685
|
+
maxLength,
|
|
2686
|
+
`${label} must be no more than ${maxLength} characters`
|
|
2687
|
+
);
|
|
2688
|
+
if (pattern)
|
|
2689
|
+
zodType = zodType.regex(
|
|
2690
|
+
new RegExp(pattern),
|
|
2691
|
+
`${label} format is invalid`
|
|
2692
|
+
);
|
|
2693
|
+
this.schemaFields[name] = zodType;
|
|
2694
|
+
this.formFields.push({
|
|
2695
|
+
inputProps: { type: "text", ...fieldOptions },
|
|
2696
|
+
label,
|
|
2697
|
+
name,
|
|
2698
|
+
type: "input"
|
|
2699
|
+
});
|
|
2700
|
+
return this;
|
|
2701
|
+
}
|
|
2702
|
+
/**
|
|
2703
|
+
* Add an email field
|
|
2704
|
+
*/
|
|
2705
|
+
email(name, label, options) {
|
|
2706
|
+
this.schemaFields[name] = z3.string().email(`Please enter a valid email address`);
|
|
2707
|
+
this.formFields.push({
|
|
2708
|
+
inputProps: { type: "email", ...options },
|
|
2709
|
+
label,
|
|
2710
|
+
name,
|
|
2711
|
+
type: "input"
|
|
2712
|
+
});
|
|
2713
|
+
return this;
|
|
2714
|
+
}
|
|
2715
|
+
/**
|
|
2716
|
+
* Add a number field
|
|
2717
|
+
*/
|
|
2718
|
+
number(name, label, options) {
|
|
2719
|
+
const { max, min, step, ...fieldOptions } = options || {};
|
|
2720
|
+
let zodType = z3.number();
|
|
2721
|
+
if (min !== void 0)
|
|
2722
|
+
zodType = zodType.min(min, `${label} must be at least ${min}`);
|
|
2723
|
+
if (max !== void 0)
|
|
2724
|
+
zodType = zodType.max(max, `${label} must be no more than ${max}`);
|
|
2725
|
+
this.schemaFields[name] = zodType;
|
|
2726
|
+
this.formFields.push({
|
|
2727
|
+
inputProps: { max, min, step, type: "number", ...fieldOptions },
|
|
2728
|
+
label,
|
|
2729
|
+
name,
|
|
2730
|
+
type: "input"
|
|
2731
|
+
});
|
|
2732
|
+
return this;
|
|
2733
|
+
}
|
|
2734
|
+
/**
|
|
2735
|
+
* Add a textarea field
|
|
2736
|
+
*/
|
|
2737
|
+
textarea(name, label, options) {
|
|
2738
|
+
const { minLength, ...fieldOptions } = options || {};
|
|
2739
|
+
let zodType = z3.string();
|
|
2740
|
+
if (minLength)
|
|
2741
|
+
zodType = zodType.min(
|
|
2742
|
+
minLength,
|
|
2743
|
+
`${label} must be at least ${minLength} characters`
|
|
2744
|
+
);
|
|
2745
|
+
this.schemaFields[name] = zodType;
|
|
2746
|
+
this.formFields.push({
|
|
2747
|
+
label,
|
|
2748
|
+
name,
|
|
2749
|
+
textareaProps: fieldOptions,
|
|
2750
|
+
type: "textarea"
|
|
2751
|
+
});
|
|
2752
|
+
return this;
|
|
2753
|
+
}
|
|
2754
|
+
/**
|
|
2755
|
+
* Add a select field
|
|
2756
|
+
*/
|
|
2757
|
+
select(name, label, options) {
|
|
2758
|
+
this.schemaFields[name] = z3.string().min(1, `Please select a ${label.toLowerCase()}`);
|
|
2759
|
+
this.formFields.push({
|
|
2760
|
+
label,
|
|
2761
|
+
name,
|
|
2762
|
+
options,
|
|
2763
|
+
type: "select"
|
|
2764
|
+
});
|
|
2765
|
+
return this;
|
|
2766
|
+
}
|
|
2767
|
+
/**
|
|
2768
|
+
* Add a checkbox field
|
|
2769
|
+
*/
|
|
2770
|
+
checkbox(name, label, options) {
|
|
2771
|
+
const { required = false, ...fieldOptions } = options || {};
|
|
2772
|
+
let zodType = z3.boolean();
|
|
2773
|
+
if (required) {
|
|
2774
|
+
zodType = zodType.refine(
|
|
2775
|
+
(val) => val === true,
|
|
2776
|
+
`You must agree to ${label.toLowerCase()}`
|
|
2777
|
+
);
|
|
2778
|
+
}
|
|
2779
|
+
this.schemaFields[name] = zodType;
|
|
2780
|
+
this.formFields.push({
|
|
2781
|
+
checkboxProps: fieldOptions,
|
|
2782
|
+
label,
|
|
2783
|
+
name,
|
|
2784
|
+
type: "checkbox"
|
|
2785
|
+
});
|
|
2786
|
+
return this;
|
|
2787
|
+
}
|
|
2788
|
+
/**
|
|
2789
|
+
* Add a switch field
|
|
2790
|
+
*/
|
|
2791
|
+
switch(name, label, options) {
|
|
2792
|
+
this.schemaFields[name] = z3.boolean().optional();
|
|
2793
|
+
this.formFields.push({
|
|
2794
|
+
label,
|
|
2795
|
+
name,
|
|
2796
|
+
switchProps: options,
|
|
2797
|
+
type: "switch"
|
|
2798
|
+
});
|
|
2799
|
+
return this;
|
|
2800
|
+
}
|
|
2801
|
+
/**
|
|
2802
|
+
* Add a radio field
|
|
2803
|
+
*/
|
|
2804
|
+
radio(name, label, options, fieldOptions) {
|
|
2805
|
+
this.schemaFields[name] = z3.string().min(1, `Please select a ${label.toLowerCase()}`);
|
|
2806
|
+
this.formFields.push({
|
|
2807
|
+
label,
|
|
2808
|
+
name,
|
|
2809
|
+
radioOptions: options,
|
|
2810
|
+
radioProps: fieldOptions,
|
|
2811
|
+
type: "radio"
|
|
2812
|
+
});
|
|
2813
|
+
return this;
|
|
2814
|
+
}
|
|
2815
|
+
/**
|
|
2816
|
+
* Add a slider field
|
|
2817
|
+
*/
|
|
2818
|
+
slider(name, label, options) {
|
|
2819
|
+
const { max = 100, min = 0, step = 1, ...fieldOptions } = options || {};
|
|
2820
|
+
let zodType = z3.number();
|
|
2821
|
+
if (min !== void 0)
|
|
2822
|
+
zodType = zodType.min(min, `${label} must be at least ${min}`);
|
|
2823
|
+
if (max !== void 0)
|
|
2824
|
+
zodType = zodType.max(max, `${label} must be no more than ${max}`);
|
|
2825
|
+
this.schemaFields[name] = zodType;
|
|
2826
|
+
this.formFields.push({
|
|
2827
|
+
label,
|
|
2828
|
+
name,
|
|
2829
|
+
sliderProps: { max, min, step, ...fieldOptions },
|
|
2830
|
+
type: "slider"
|
|
2831
|
+
});
|
|
2832
|
+
return this;
|
|
2833
|
+
}
|
|
2834
|
+
/**
|
|
2835
|
+
* Add a date field
|
|
2836
|
+
*/
|
|
2837
|
+
date(name, label, options) {
|
|
2838
|
+
this.schemaFields[name] = z3.string().min(1, `${label} is required`);
|
|
2839
|
+
this.formFields.push({
|
|
2840
|
+
dateProps: options,
|
|
2841
|
+
label,
|
|
2842
|
+
name,
|
|
2843
|
+
type: "date"
|
|
2844
|
+
});
|
|
2845
|
+
return this;
|
|
2846
|
+
}
|
|
2847
|
+
/**
|
|
2848
|
+
* Add a file field
|
|
2849
|
+
*/
|
|
2850
|
+
file(name, label, options) {
|
|
2851
|
+
this.schemaFields[name] = z3.any().optional();
|
|
2852
|
+
this.formFields.push({
|
|
2853
|
+
fileProps: options,
|
|
2854
|
+
label,
|
|
2855
|
+
name,
|
|
2856
|
+
type: "file"
|
|
2857
|
+
});
|
|
2858
|
+
return this;
|
|
2859
|
+
}
|
|
2860
|
+
/**
|
|
2861
|
+
* Build the final schema and fields
|
|
2862
|
+
*/
|
|
2863
|
+
build() {
|
|
2864
|
+
return {
|
|
2865
|
+
fields: this.formFields,
|
|
2866
|
+
schema: z3.object(this.schemaFields)
|
|
2867
|
+
};
|
|
2868
|
+
}
|
|
2869
|
+
};
|
|
2870
|
+
function createTypeInferredBuilder() {
|
|
2871
|
+
return new TypeInferredBuilder();
|
|
2872
|
+
}
|
|
2873
|
+
function defineInferredForm(fieldDefinitions) {
|
|
2874
|
+
const builder = createTypeInferredBuilder();
|
|
2875
|
+
fieldDefinitions(builder);
|
|
2876
|
+
return builder.build();
|
|
2877
|
+
}
|
|
2878
|
+
var field = {
|
|
2879
|
+
checkbox: (name, label, options) => {
|
|
2880
|
+
const builder = new TypeInferredBuilder();
|
|
2881
|
+
return builder.checkbox(name, label, options);
|
|
2882
|
+
},
|
|
2883
|
+
date: (name, label, options) => {
|
|
2884
|
+
const builder = new TypeInferredBuilder();
|
|
2885
|
+
return builder.date(name, label, options);
|
|
2886
|
+
},
|
|
2887
|
+
email: (name, label, options) => {
|
|
2888
|
+
const builder = new TypeInferredBuilder();
|
|
2889
|
+
return builder.email(name, label, options);
|
|
2890
|
+
},
|
|
2891
|
+
file: (name, label, options) => {
|
|
2892
|
+
const builder = new TypeInferredBuilder();
|
|
2893
|
+
return builder.file(name, label, options);
|
|
2894
|
+
},
|
|
2895
|
+
number: (name, label, options) => {
|
|
2896
|
+
const builder = new TypeInferredBuilder();
|
|
2897
|
+
return builder.number(name, label, options);
|
|
2898
|
+
},
|
|
2899
|
+
radio: (name, label, options, fieldOptions) => {
|
|
2900
|
+
const builder = new TypeInferredBuilder();
|
|
2901
|
+
return builder.radio(name, label, options, fieldOptions);
|
|
2902
|
+
},
|
|
2903
|
+
select: (name, label, options) => {
|
|
2904
|
+
const builder = new TypeInferredBuilder();
|
|
2905
|
+
return builder.select(name, label, options);
|
|
2906
|
+
},
|
|
2907
|
+
slider: (name, label, options) => {
|
|
2908
|
+
const builder = new TypeInferredBuilder();
|
|
2909
|
+
return builder.slider(name, label, options);
|
|
2910
|
+
},
|
|
2911
|
+
switch: (name, label, options) => {
|
|
2912
|
+
const builder = new TypeInferredBuilder();
|
|
2913
|
+
return builder.switch(name, label, options);
|
|
2914
|
+
},
|
|
2915
|
+
text: (name, label, options) => {
|
|
2916
|
+
const builder = new TypeInferredBuilder();
|
|
2917
|
+
return builder.text(name, label, options);
|
|
2918
|
+
},
|
|
2919
|
+
textarea: (name, label, options) => {
|
|
2920
|
+
const builder = new TypeInferredBuilder();
|
|
2921
|
+
return builder.textarea(name, label, options);
|
|
2922
|
+
}
|
|
2923
|
+
};
|
|
2924
|
+
|
|
2925
|
+
// src/builders/NestedPathBuilder.ts
|
|
2926
|
+
var NestedPathBuilder = class {
|
|
2927
|
+
constructor() {
|
|
2928
|
+
this.fields = [];
|
|
2929
|
+
}
|
|
2930
|
+
/**
|
|
2931
|
+
* Create a nested object path builder
|
|
2932
|
+
* Usage: builder.nest("address").field("street", "Street Address")
|
|
2933
|
+
*/
|
|
2934
|
+
nest(path) {
|
|
2935
|
+
return new NestedObjectBuilder(this, path);
|
|
2936
|
+
}
|
|
2937
|
+
/**
|
|
2938
|
+
* Create a section-based path builder
|
|
2939
|
+
* Usage: builder.section("shipping").field("street", "Street Address")
|
|
2940
|
+
*/
|
|
2941
|
+
section(path) {
|
|
2942
|
+
return new SectionBuilder(this, path);
|
|
2943
|
+
}
|
|
2944
|
+
/**
|
|
2945
|
+
* Add a field with single path
|
|
2946
|
+
* Usage: builder.field("firstName", "First Name")
|
|
2947
|
+
*/
|
|
2948
|
+
field(name, label, type = "input", props) {
|
|
2949
|
+
this.fields.push({
|
|
2950
|
+
label,
|
|
2951
|
+
name,
|
|
2952
|
+
type,
|
|
2953
|
+
...props
|
|
2954
|
+
});
|
|
2955
|
+
return this;
|
|
2956
|
+
}
|
|
2957
|
+
/**
|
|
2958
|
+
* Add a field with path segments
|
|
2959
|
+
* Usage: builder.fieldPath(["user", "profile", "name"], "Full Name")
|
|
2960
|
+
*/
|
|
2961
|
+
fieldPath(path, label, type = "input", props) {
|
|
2962
|
+
const name = path.join(".");
|
|
2963
|
+
this.fields.push({
|
|
2964
|
+
label,
|
|
2965
|
+
name,
|
|
2966
|
+
type,
|
|
2967
|
+
...props
|
|
2968
|
+
});
|
|
2969
|
+
return this;
|
|
2970
|
+
}
|
|
2971
|
+
/**
|
|
2972
|
+
* Add a field with template literal path
|
|
2973
|
+
* Usage: builder.field`user.profile.name`("Full Name")
|
|
2974
|
+
*/
|
|
2975
|
+
fieldTemplate(path) {
|
|
2976
|
+
const pathString = path[0];
|
|
2977
|
+
return new FieldTemplateBuilder(this, pathString);
|
|
2978
|
+
}
|
|
2979
|
+
/**
|
|
2980
|
+
* Return to the parent builder (no-op for root builder)
|
|
2981
|
+
*/
|
|
2982
|
+
end() {
|
|
2983
|
+
return this;
|
|
2984
|
+
}
|
|
2985
|
+
build() {
|
|
2986
|
+
return this.fields;
|
|
2987
|
+
}
|
|
2988
|
+
};
|
|
2989
|
+
var NestedObjectBuilder = class _NestedObjectBuilder {
|
|
2990
|
+
constructor(parent, path) {
|
|
2991
|
+
this.parent = parent;
|
|
2992
|
+
this.path = path;
|
|
2993
|
+
}
|
|
2994
|
+
/**
|
|
2995
|
+
* Add a field to the current nested path
|
|
2996
|
+
*/
|
|
2997
|
+
field(fieldName, label, type = "input", props) {
|
|
2998
|
+
const fullPath = `${this.path}.${fieldName}`;
|
|
2999
|
+
this.parent.fields.push({
|
|
3000
|
+
label,
|
|
3001
|
+
name: fullPath,
|
|
3002
|
+
type,
|
|
3003
|
+
...props
|
|
3004
|
+
});
|
|
3005
|
+
return this;
|
|
3006
|
+
}
|
|
3007
|
+
/**
|
|
3008
|
+
* Nest deeper into the object
|
|
3009
|
+
*/
|
|
3010
|
+
nest(subPath) {
|
|
3011
|
+
return new _NestedObjectBuilder(
|
|
3012
|
+
this.parent,
|
|
3013
|
+
`${this.path}.${subPath}`
|
|
3014
|
+
);
|
|
3015
|
+
}
|
|
3016
|
+
/**
|
|
3017
|
+
* Return to the parent builder
|
|
3018
|
+
*/
|
|
3019
|
+
end() {
|
|
3020
|
+
return this.parent;
|
|
3021
|
+
}
|
|
3022
|
+
};
|
|
3023
|
+
var SectionBuilder = class {
|
|
3024
|
+
constructor(parent, path) {
|
|
3025
|
+
this.parent = parent;
|
|
3026
|
+
this.path = path;
|
|
3027
|
+
}
|
|
3028
|
+
/**
|
|
3029
|
+
* Add a field to the current section
|
|
3030
|
+
*/
|
|
3031
|
+
field(fieldName, label, type = "input", props) {
|
|
3032
|
+
const fullPath = `${this.path}.${fieldName}`;
|
|
3033
|
+
this.parent.fields.push({
|
|
3034
|
+
label,
|
|
3035
|
+
name: fullPath,
|
|
3036
|
+
type,
|
|
3037
|
+
...props
|
|
3038
|
+
});
|
|
3039
|
+
return this;
|
|
3040
|
+
}
|
|
3041
|
+
/**
|
|
3042
|
+
* Add multiple fields to the section
|
|
3043
|
+
*/
|
|
3044
|
+
fields(fieldDefinitions) {
|
|
3045
|
+
fieldDefinitions.forEach((field2) => {
|
|
3046
|
+
this.field(field2.name, field2.label, field2.type, field2.props);
|
|
3047
|
+
});
|
|
3048
|
+
return this;
|
|
3049
|
+
}
|
|
3050
|
+
/**
|
|
3051
|
+
* Nest deeper into the section
|
|
3052
|
+
*/
|
|
3053
|
+
nest(subPath) {
|
|
3054
|
+
return new NestedObjectBuilder(
|
|
3055
|
+
this.parent,
|
|
3056
|
+
`${this.path}.${subPath}`
|
|
3057
|
+
);
|
|
3058
|
+
}
|
|
3059
|
+
/**
|
|
3060
|
+
* Return to the parent builder
|
|
3061
|
+
*/
|
|
3062
|
+
end() {
|
|
3063
|
+
return this.parent;
|
|
3064
|
+
}
|
|
3065
|
+
};
|
|
3066
|
+
var FieldTemplateBuilder = class {
|
|
3067
|
+
constructor(parent, path) {
|
|
3068
|
+
this.parent = parent;
|
|
3069
|
+
this.path = path;
|
|
3070
|
+
}
|
|
3071
|
+
/**
|
|
3072
|
+
* Complete the field definition
|
|
3073
|
+
*/
|
|
3074
|
+
complete(label, type = "input", props) {
|
|
3075
|
+
this.parent.fields.push({
|
|
3076
|
+
label,
|
|
3077
|
+
name: this.path,
|
|
3078
|
+
type,
|
|
3079
|
+
...props
|
|
3080
|
+
});
|
|
3081
|
+
return this.parent;
|
|
3082
|
+
}
|
|
3083
|
+
};
|
|
3084
|
+
function createNestedPathBuilder() {
|
|
3085
|
+
return new NestedPathBuilder();
|
|
3086
|
+
}
|
|
3087
|
+
|
|
3088
|
+
// src/hooks/useDebouncedValidation.ts
|
|
3089
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useRef } from "react";
|
|
3090
|
+
function useDebouncedValidation(form, options = {}) {
|
|
3091
|
+
const { delay = 300, enabled = true, fields } = options;
|
|
3092
|
+
const timeoutRef = useRef(
|
|
3093
|
+
void 0
|
|
3094
|
+
);
|
|
3095
|
+
const lastValuesRef = useRef({});
|
|
3096
|
+
const debouncedTrigger = useCallback2(() => {
|
|
3097
|
+
if (!enabled) return;
|
|
3098
|
+
if (timeoutRef.current) {
|
|
3099
|
+
clearTimeout(timeoutRef.current);
|
|
3100
|
+
timeoutRef.current = void 0;
|
|
3101
|
+
}
|
|
3102
|
+
timeoutRef.current = setTimeout(async () => {
|
|
3103
|
+
const currentValues = form.getValues();
|
|
3104
|
+
const lastValues = lastValuesRef.current;
|
|
3105
|
+
const hasChanges = fields ? fields.some((field2) => currentValues[field2] !== lastValues[field2]) : Object.keys(currentValues).some(
|
|
3106
|
+
(key) => currentValues[key] !== lastValues[key]
|
|
3107
|
+
);
|
|
3108
|
+
if (hasChanges) {
|
|
3109
|
+
lastValuesRef.current = { ...currentValues };
|
|
3110
|
+
if (fields && fields.length > 0) {
|
|
3111
|
+
await form.trigger(fields);
|
|
3112
|
+
} else {
|
|
3113
|
+
await form.trigger();
|
|
3114
|
+
}
|
|
3115
|
+
}
|
|
3116
|
+
}, delay);
|
|
3117
|
+
}, [form, delay, fields, enabled]);
|
|
3118
|
+
useEffect2(() => {
|
|
3119
|
+
return () => {
|
|
3120
|
+
if (timeoutRef.current) {
|
|
3121
|
+
clearTimeout(timeoutRef.current);
|
|
3122
|
+
timeoutRef.current = void 0;
|
|
3123
|
+
}
|
|
3124
|
+
};
|
|
3125
|
+
}, []);
|
|
3126
|
+
useEffect2(() => {
|
|
3127
|
+
if (form.formState.isSubmitSuccessful) {
|
|
3128
|
+
lastValuesRef.current = {};
|
|
3129
|
+
}
|
|
3130
|
+
}, [form.formState.isSubmitSuccessful]);
|
|
3131
|
+
return {
|
|
3132
|
+
debouncedTrigger,
|
|
3133
|
+
isDebouncing: !!timeoutRef.current
|
|
3134
|
+
};
|
|
3135
|
+
}
|
|
3136
|
+
function useDebouncedFieldValidation(form, fieldName, options = {}) {
|
|
3137
|
+
const { delay = 300, enabled = true } = options;
|
|
3138
|
+
const timeoutRef = useRef(
|
|
3139
|
+
void 0
|
|
3140
|
+
);
|
|
3141
|
+
const debouncedFieldTrigger = useCallback2(() => {
|
|
3142
|
+
if (!enabled) return;
|
|
3143
|
+
if (timeoutRef.current) {
|
|
3144
|
+
clearTimeout(timeoutRef.current);
|
|
3145
|
+
}
|
|
3146
|
+
timeoutRef.current = setTimeout(async () => {
|
|
3147
|
+
await form.trigger(fieldName);
|
|
3148
|
+
}, delay);
|
|
3149
|
+
}, [form, fieldName, delay, enabled]);
|
|
3150
|
+
useEffect2(() => {
|
|
3151
|
+
return () => {
|
|
3152
|
+
if (timeoutRef.current) {
|
|
3153
|
+
clearTimeout(timeoutRef.current);
|
|
3154
|
+
timeoutRef.current = void 0;
|
|
3155
|
+
}
|
|
3156
|
+
};
|
|
3157
|
+
}, []);
|
|
3158
|
+
return {
|
|
3159
|
+
debouncedFieldTrigger,
|
|
3160
|
+
isDebouncing: !!timeoutRef.current
|
|
3161
|
+
};
|
|
3162
|
+
}
|
|
3163
|
+
|
|
3164
|
+
// src/hooks/useInferredForm.ts
|
|
3165
|
+
import { useForm as useForm3 } from "react-hook-form";
|
|
3166
|
+
var zodResolver;
|
|
3167
|
+
try {
|
|
3168
|
+
zodResolver = __require("@hookform/resolvers/zod").zodResolver;
|
|
3169
|
+
} catch {
|
|
3170
|
+
}
|
|
3171
|
+
function useInferredForm(schema, fields, options = {}) {
|
|
3172
|
+
const {
|
|
3173
|
+
defaultValues,
|
|
3174
|
+
delayError = 0,
|
|
3175
|
+
mode = "onChange",
|
|
3176
|
+
reValidateMode = "onChange",
|
|
3177
|
+
shouldFocusError = true,
|
|
3178
|
+
shouldUnregister = false
|
|
3179
|
+
} = options;
|
|
3180
|
+
return useForm3({
|
|
3181
|
+
defaultValues,
|
|
3182
|
+
delayError,
|
|
3183
|
+
mode,
|
|
3184
|
+
resolver: zodResolver ? zodResolver(schema) : void 0,
|
|
3185
|
+
reValidateMode,
|
|
3186
|
+
shouldFocusError,
|
|
3187
|
+
shouldUnregister
|
|
3188
|
+
});
|
|
3189
|
+
}
|
|
3190
|
+
function useTypeInferredForm(formConfig, options = {}) {
|
|
3191
|
+
return useInferredForm(formConfig.schema, formConfig.fields, options);
|
|
3192
|
+
}
|
|
3193
|
+
|
|
3194
|
+
// src/utils/performance.ts
|
|
3195
|
+
import { useCallback as useCallback3, useMemo as useMemo2, useRef as useRef2 } from "react";
|
|
3196
|
+
function debounce(func, delay) {
|
|
3197
|
+
let timeoutId;
|
|
3198
|
+
return (...args) => {
|
|
3199
|
+
clearTimeout(timeoutId);
|
|
3200
|
+
timeoutId = setTimeout(() => func(...args), delay);
|
|
3201
|
+
};
|
|
3202
|
+
}
|
|
3203
|
+
function throttle(func, limit) {
|
|
3204
|
+
let inThrottle;
|
|
3205
|
+
return (...args) => {
|
|
3206
|
+
if (!inThrottle) {
|
|
3207
|
+
func(...args);
|
|
3208
|
+
inThrottle = true;
|
|
3209
|
+
setTimeout(() => inThrottle = false, limit);
|
|
3210
|
+
}
|
|
3211
|
+
};
|
|
3212
|
+
}
|
|
3213
|
+
function useMemoizedCallback(callback, deps) {
|
|
3214
|
+
const callbackRef = useRef2(callback);
|
|
3215
|
+
callbackRef.current = callback;
|
|
3216
|
+
return useCallback3(
|
|
3217
|
+
((...args) => callbackRef.current(...args)),
|
|
3218
|
+
deps
|
|
3219
|
+
);
|
|
3220
|
+
}
|
|
3221
|
+
function shallowEqual(prevProps, nextProps) {
|
|
3222
|
+
const prevKeys = Object.keys(prevProps);
|
|
3223
|
+
const nextKeys = Object.keys(nextProps);
|
|
3224
|
+
if (prevKeys.length !== nextKeys.length) {
|
|
3225
|
+
return false;
|
|
3226
|
+
}
|
|
3227
|
+
for (const key of prevKeys) {
|
|
3228
|
+
if (prevProps[key] !== nextProps[key]) {
|
|
3229
|
+
return false;
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
return true;
|
|
3233
|
+
}
|
|
3234
|
+
function deepEqual(prevProps, nextProps) {
|
|
3235
|
+
if (prevProps === nextProps) {
|
|
3236
|
+
return true;
|
|
3237
|
+
}
|
|
3238
|
+
if (typeof prevProps !== typeof nextProps) {
|
|
3239
|
+
return false;
|
|
3240
|
+
}
|
|
3241
|
+
if (typeof prevProps !== "object" || prevProps === null || nextProps === null) {
|
|
3242
|
+
return prevProps === nextProps;
|
|
3243
|
+
}
|
|
3244
|
+
const prevKeys = Object.keys(prevProps);
|
|
3245
|
+
const nextKeys = Object.keys(nextProps);
|
|
3246
|
+
if (prevKeys.length !== nextKeys.length) {
|
|
3247
|
+
return false;
|
|
3248
|
+
}
|
|
3249
|
+
for (const key of prevKeys) {
|
|
3250
|
+
if (!nextKeys.includes(key)) {
|
|
3251
|
+
return false;
|
|
3252
|
+
}
|
|
3253
|
+
if (!deepEqual(prevProps[key], nextProps[key])) {
|
|
3254
|
+
return false;
|
|
3255
|
+
}
|
|
3256
|
+
}
|
|
3257
|
+
return true;
|
|
3258
|
+
}
|
|
3259
|
+
function usePerformanceMonitor(componentName, enabled = process.env.NODE_ENV === "development") {
|
|
3260
|
+
const renderCountRef = useRef2(0);
|
|
3261
|
+
const lastRenderTimeRef = useRef2(Date.now());
|
|
3262
|
+
if (enabled) {
|
|
3263
|
+
renderCountRef.current += 1;
|
|
3264
|
+
const now = Date.now();
|
|
3265
|
+
const timeSinceLastRender = now - lastRenderTimeRef.current;
|
|
3266
|
+
console.log(`[Performance] ${componentName}:`, {
|
|
3267
|
+
renderCount: renderCountRef.current,
|
|
3268
|
+
timeSinceLastRender: `${timeSinceLastRender}ms`
|
|
3269
|
+
});
|
|
3270
|
+
lastRenderTimeRef.current = now;
|
|
3271
|
+
}
|
|
3272
|
+
return {
|
|
3273
|
+
renderCount: renderCountRef.current,
|
|
3274
|
+
resetRenderCount: () => {
|
|
3275
|
+
renderCountRef.current = 0;
|
|
3276
|
+
}
|
|
3277
|
+
};
|
|
3278
|
+
}
|
|
3279
|
+
function createOptimizedFieldHandler(onChange, options = {}) {
|
|
3280
|
+
const { debounce: debounceMs, throttle: throttleMs } = options;
|
|
3281
|
+
let handler = onChange;
|
|
3282
|
+
if (throttleMs) {
|
|
3283
|
+
handler = throttle(handler, throttleMs);
|
|
3284
|
+
}
|
|
3285
|
+
if (debounceMs) {
|
|
3286
|
+
handler = debounce(handler, debounceMs);
|
|
3287
|
+
}
|
|
3288
|
+
return handler;
|
|
3289
|
+
}
|
|
3290
|
+
function useMemoizedFieldProps(props, deps) {
|
|
3291
|
+
return useMemo2(() => props, deps);
|
|
3292
|
+
}
|
|
3293
|
+
|
|
3294
|
+
// src/builders/validation-helpers.ts
|
|
3295
|
+
import { z as z4 } from "zod";
|
|
3296
|
+
var validationPatterns = {
|
|
3297
|
+
// Credit card validation
|
|
3298
|
+
creditCard: z4.string().regex(
|
|
3299
|
+
// eslint-disable-next-line no-useless-escape
|
|
3300
|
+
/^[0-9]{4}[\s\-]?[0-9]{4}[\s\-]?[0-9]{4}[\s\-]?[0-9]{4}$/,
|
|
3301
|
+
"Please enter a valid credit card number"
|
|
3302
|
+
),
|
|
3303
|
+
// Date validation (MM/DD/YYYY)
|
|
3304
|
+
date: z4.string().regex(
|
|
3305
|
+
/^(0[1-9]|1[0-2])\/(0[1-9]|[12][0-9]|3[01])\/\d{4}$/,
|
|
3306
|
+
"Please enter a valid date (MM/DD/YYYY)"
|
|
3307
|
+
),
|
|
3308
|
+
// Email validation
|
|
3309
|
+
email: z4.string().email("Please enter a valid email address"),
|
|
3310
|
+
// Password validation
|
|
3311
|
+
password: z4.string().min(8, "Password must be at least 8 characters").regex(/[A-Z]/, "Password must contain at least one uppercase letter").regex(/[a-z]/, "Password must contain at least one lowercase letter").regex(/[0-9]/, "Password must contain at least one number").regex(
|
|
3312
|
+
/[^A-Za-z0-9]/,
|
|
3313
|
+
"Password must contain at least one special character"
|
|
3314
|
+
),
|
|
3315
|
+
// Phone number validation (international)
|
|
3316
|
+
phoneInternational: z4.string().regex(/^\+?[\d\s\-\(\)]+$/, "Please enter a valid phone number"),
|
|
3317
|
+
// Phone number validation (US format)
|
|
3318
|
+
phoneUS: z4.string().regex(
|
|
3319
|
+
/^\(\d{3}\) \d{3}-\d{4}$/,
|
|
3320
|
+
"Please enter a valid phone number (XXX) XXX-XXXX"
|
|
3321
|
+
),
|
|
3322
|
+
// SSN validation
|
|
3323
|
+
ssn: z4.string().regex(/^\d{3}-\d{2}-\d{4}$/, "Please enter a valid SSN (XXX-XX-XXXX)"),
|
|
3324
|
+
// Strong password validation
|
|
3325
|
+
strongPassword: z4.string().min(12, "Password must be at least 12 characters").regex(/[A-Z]/, "Password must contain at least one uppercase letter").regex(/[a-z]/, "Password must contain at least one lowercase letter").regex(/[0-9]/, "Password must contain at least one number").regex(
|
|
3326
|
+
/[^A-Za-z0-9]/,
|
|
3327
|
+
"Password must contain at least one special character"
|
|
3328
|
+
),
|
|
3329
|
+
// Time validation (HH:MM AM/PM)
|
|
3330
|
+
time: z4.string().regex(
|
|
3331
|
+
/^(0[1-9]|1[0-2]):[0-5][0-9] (AM|PM)$/i,
|
|
3332
|
+
"Please enter a valid time (HH:MM AM/PM)"
|
|
3333
|
+
),
|
|
3334
|
+
// URL validation
|
|
3335
|
+
url: z4.string().url("Please enter a valid URL"),
|
|
3336
|
+
// ZIP code validation
|
|
3337
|
+
zipCode: z4.string().regex(/^\d{5}(-\d{4})?$/, "Please enter a valid ZIP code")
|
|
3338
|
+
};
|
|
3339
|
+
var asyncValidation = {
|
|
3340
|
+
/**
|
|
3341
|
+
* Email availability check
|
|
3342
|
+
*/
|
|
3343
|
+
emailAvailability: async (email) => {
|
|
3344
|
+
return new Promise((resolve) => {
|
|
3345
|
+
setTimeout(() => {
|
|
3346
|
+
const takenEmails = ["test@example.com", "admin@example.com"];
|
|
3347
|
+
resolve(!takenEmails.includes(email));
|
|
3348
|
+
}, 1e3);
|
|
3349
|
+
});
|
|
3350
|
+
},
|
|
3351
|
+
/**
|
|
3352
|
+
* Username availability check
|
|
3353
|
+
*/
|
|
3354
|
+
usernameAvailability: async (username) => {
|
|
3355
|
+
return new Promise((resolve) => {
|
|
3356
|
+
setTimeout(() => {
|
|
3357
|
+
const takenUsernames = ["admin", "test", "user"];
|
|
3358
|
+
resolve(!takenUsernames.includes(username.toLowerCase()));
|
|
3359
|
+
}, 1e3);
|
|
3360
|
+
});
|
|
3361
|
+
}
|
|
3362
|
+
};
|
|
3363
|
+
var errorMessages = {
|
|
3364
|
+
date: () => "Please enter a valid date",
|
|
3365
|
+
email: () => "Please enter a valid email address",
|
|
3366
|
+
max: (fieldName, max) => `${fieldName} must be no more than ${max}`,
|
|
3367
|
+
maxLength: (fieldName, max) => `${fieldName} must be no more than ${max} characters`,
|
|
3368
|
+
min: (fieldName, min) => `${fieldName} must be at least ${min}`,
|
|
3369
|
+
minLength: (fieldName, min) => `${fieldName} must be at least ${min} characters`,
|
|
3370
|
+
pattern: (fieldName) => `${fieldName} format is invalid`,
|
|
3371
|
+
phone: () => "Please enter a valid phone number",
|
|
3372
|
+
required: (fieldName) => `${fieldName} is required`,
|
|
3373
|
+
time: () => "Please enter a valid time",
|
|
3374
|
+
url: () => "Please enter a valid URL"
|
|
3375
|
+
};
|
|
3376
|
+
var serverValidation = {
|
|
3377
|
+
/**
|
|
3378
|
+
* Apply server errors to form
|
|
3379
|
+
*/
|
|
3380
|
+
applyServerErrors: (errors, setError) => {
|
|
3381
|
+
Object.entries(errors).forEach(([field2, messages]) => {
|
|
3382
|
+
setError(field2, {
|
|
3383
|
+
message: messages[0],
|
|
3384
|
+
type: "server"
|
|
3385
|
+
// Use first error message
|
|
3386
|
+
});
|
|
3387
|
+
});
|
|
3388
|
+
},
|
|
3389
|
+
/**
|
|
3390
|
+
* Clear server errors
|
|
3391
|
+
*/
|
|
3392
|
+
clearServerErrors: (fields, clearErrors) => {
|
|
3393
|
+
fields.forEach((field2) => {
|
|
3394
|
+
clearErrors(field2, "server");
|
|
3395
|
+
});
|
|
3396
|
+
}
|
|
3397
|
+
};
|
|
3398
|
+
var validationUtils = {
|
|
3399
|
+
/**
|
|
3400
|
+
* Debounced validation
|
|
3401
|
+
*/
|
|
3402
|
+
debounceValidation: (fn, delay = 300) => {
|
|
3403
|
+
let timeoutId;
|
|
3404
|
+
return (...args) => {
|
|
3405
|
+
clearTimeout(timeoutId);
|
|
3406
|
+
timeoutId = setTimeout(() => fn(...args), delay);
|
|
3407
|
+
};
|
|
3408
|
+
},
|
|
3409
|
+
/**
|
|
3410
|
+
* Get field error message
|
|
3411
|
+
*/
|
|
3412
|
+
getFieldError: (errors, field2) => {
|
|
3413
|
+
return errors[field2];
|
|
3414
|
+
},
|
|
3415
|
+
/**
|
|
3416
|
+
* Check if field has error
|
|
3417
|
+
*/
|
|
3418
|
+
hasFieldError: (errors, field2) => {
|
|
3419
|
+
return !!errors[field2];
|
|
3420
|
+
},
|
|
3421
|
+
/**
|
|
3422
|
+
* Validate form data against schema
|
|
3423
|
+
*/
|
|
3424
|
+
validateForm: async (data, schema) => {
|
|
3425
|
+
try {
|
|
3426
|
+
await schema.parseAsync(data);
|
|
3427
|
+
return { errors: {}, success: true };
|
|
3428
|
+
} catch (error) {
|
|
3429
|
+
if (error instanceof z4.ZodError) {
|
|
3430
|
+
const errors = {};
|
|
3431
|
+
error.issues.forEach((err) => {
|
|
3432
|
+
const path = err.path.join(".");
|
|
3433
|
+
errors[path] = err.message;
|
|
3434
|
+
});
|
|
3435
|
+
return { errors, success: false };
|
|
3436
|
+
}
|
|
3437
|
+
throw error;
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
};
|
|
1488
3441
|
export {
|
|
3442
|
+
AdvancedFieldBuilder,
|
|
3443
|
+
BasicFormBuilder,
|
|
1489
3444
|
CheckboxField,
|
|
3445
|
+
CommonFields,
|
|
3446
|
+
ConditionalField,
|
|
1490
3447
|
ConfigurableForm,
|
|
1491
3448
|
DateField,
|
|
3449
|
+
DynamicSectionField,
|
|
3450
|
+
FieldArrayBuilder,
|
|
3451
|
+
FieldArrayField,
|
|
3452
|
+
FieldArrayItemBuilder,
|
|
1492
3453
|
FileField,
|
|
1493
3454
|
FontPickerField,
|
|
1494
3455
|
FormField,
|
|
3456
|
+
FormFieldHelpers,
|
|
1495
3457
|
FormProvider,
|
|
3458
|
+
FormStatus,
|
|
3459
|
+
FormToast,
|
|
1496
3460
|
HeroHookFormProvider,
|
|
1497
3461
|
InputField,
|
|
1498
3462
|
RadioGroupField,
|
|
1499
3463
|
SelectField,
|
|
3464
|
+
ServerActionForm,
|
|
1500
3465
|
SliderField,
|
|
1501
3466
|
SubmitButton,
|
|
1502
3467
|
SwitchField,
|
|
1503
3468
|
TextareaField,
|
|
3469
|
+
TypeInferredBuilder,
|
|
1504
3470
|
ZodForm,
|
|
1505
3471
|
applyServerErrors,
|
|
3472
|
+
asyncValidation,
|
|
1506
3473
|
commonValidations,
|
|
1507
|
-
|
|
1508
|
-
|
|
3474
|
+
createAdvancedBuilder,
|
|
3475
|
+
createBasicFormBuilder,
|
|
1509
3476
|
createDateSchema,
|
|
1510
3477
|
createEmailSchema,
|
|
3478
|
+
createField,
|
|
3479
|
+
createFieldArrayBuilder,
|
|
3480
|
+
createFieldArrayItemBuilder,
|
|
1511
3481
|
createFileSchema,
|
|
1512
3482
|
createFormTestUtils,
|
|
1513
3483
|
createFutureDateSchema,
|
|
@@ -1515,24 +3485,46 @@ export {
|
|
|
1515
3485
|
createMinLengthSchema,
|
|
1516
3486
|
createMockFormData,
|
|
1517
3487
|
createMockFormErrors,
|
|
3488
|
+
createNestedPathBuilder,
|
|
1518
3489
|
createNumberRangeSchema,
|
|
3490
|
+
createOptimizedFieldHandler,
|
|
1519
3491
|
createPasswordSchema,
|
|
1520
3492
|
createPastDateSchema,
|
|
1521
3493
|
createPhoneSchema,
|
|
1522
3494
|
createRequiredCheckboxSchema,
|
|
1523
3495
|
createRequiredSchema,
|
|
3496
|
+
createTypeInferredBuilder,
|
|
1524
3497
|
createUrlSchema,
|
|
1525
3498
|
createZodFormConfig,
|
|
3499
|
+
crossFieldValidation,
|
|
3500
|
+
debounce,
|
|
3501
|
+
deepEqual,
|
|
3502
|
+
defineInferredForm,
|
|
3503
|
+
errorMessages,
|
|
3504
|
+
field,
|
|
1526
3505
|
getFieldError,
|
|
1527
3506
|
getFormErrors,
|
|
1528
3507
|
hasFieldError,
|
|
1529
3508
|
hasFormErrors,
|
|
3509
|
+
serverValidation,
|
|
3510
|
+
shallowEqual,
|
|
1530
3511
|
simulateFieldInput,
|
|
1531
3512
|
simulateFormSubmission,
|
|
1532
|
-
|
|
3513
|
+
throttle,
|
|
3514
|
+
useDebouncedFieldValidation,
|
|
3515
|
+
useDebouncedValidation,
|
|
3516
|
+
useEnhancedFormState,
|
|
3517
|
+
useFormContext5 as useFormContext,
|
|
1533
3518
|
useFormHelper,
|
|
1534
3519
|
useHeroForm,
|
|
1535
3520
|
useHeroHookFormDefaults,
|
|
3521
|
+
useInferredForm,
|
|
3522
|
+
useMemoizedCallback,
|
|
3523
|
+
useMemoizedFieldProps,
|
|
3524
|
+
usePerformanceMonitor,
|
|
3525
|
+
useTypeInferredForm,
|
|
1536
3526
|
useZodForm,
|
|
3527
|
+
validationPatterns,
|
|
3528
|
+
validationUtils,
|
|
1537
3529
|
waitForFormState
|
|
1538
3530
|
};
|