@nwon/react-mui-hook-form 3.1.1 → 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/LoadingButton/LoadingButton.d.ts +6 -0
  2. package/dist/LoadingButton/LoadingButtonInterfaces.d.ts +33 -0
  3. package/dist/LoadingButton/getLoadingButtonState.d.ts +20 -0
  4. package/dist/LoadingButton/index.d.ts +4 -0
  5. package/dist/formFields/HookFormProvider.d.ts +7 -0
  6. package/dist/formFields/InputEmail/InputEmail.d.ts +10 -0
  7. package/dist/formFields/InputPasswordSet/InputPasswordSet.d.ts +8 -0
  8. package/dist/formFields/InputPasswordSet/InputPasswordSetInterfaces.d.ts +18 -0
  9. package/dist/formFields/TranslatedString.d.ts +13 -0
  10. package/dist/formFields/baseTypes/BaseInputProps.d.ts +33 -0
  11. package/dist/formFields/baseTypes/InputAutocomplete/InputAutocomplete.d.ts +9 -0
  12. package/dist/formFields/baseTypes/InputAutocomplete/InputAutocompleteInterfaces.d.ts +24 -0
  13. package/dist/formFields/baseTypes/InputAutocomplete/useSortedOptionsWithGroup.d.ts +9 -0
  14. package/dist/formFields/baseTypes/InputCheckbox/InputCheckbox.d.ts +18 -0
  15. package/dist/formFields/baseTypes/InputDatePicker/InputDatePicker.d.ts +16 -0
  16. package/dist/formFields/baseTypes/InputDateTimePicker/InputDateTimePicker.d.ts +16 -0
  17. package/dist/formFields/baseTypes/InputNumber/InputNumber.d.ts +15 -0
  18. package/dist/formFields/baseTypes/InputOutlinedInput/InputOutlinedInput.d.ts +13 -0
  19. package/dist/formFields/baseTypes/InputRadio/InputRadio.d.ts +13 -0
  20. package/dist/formFields/baseTypes/InputSelect/InputSelect.d.ts +26 -0
  21. package/dist/formFields/baseTypes/InputSelectFromEnum/InputSelectFromEnum.d.ts +15 -0
  22. package/dist/formFields/baseTypes/InputSelectFromEnum/InputSelectFromEnumInterfaces.d.ts +10 -0
  23. package/dist/formFields/baseTypes/InputSlider/InputSlider.d.ts +13 -0
  24. package/dist/formFields/baseTypes/InputSwitch/InputSwitch.d.ts +11 -0
  25. package/dist/formFields/baseTypes/InputTextField/InputTextField.d.ts +13 -0
  26. package/dist/formFields/baseTypes/InputTimePicker/InputTimePicker.d.ts +16 -0
  27. package/dist/formFields/baseTypes/InputToggleButton/InputToggleButton.d.ts +12 -0
  28. package/dist/formFields/baseTypes/InputToggleButtonGroup/InputToggleButtonGroup.d.ts +34 -0
  29. package/dist/formFields/baseTypes/useEffectFieldUnregisterOnUnmount.d.ts +12 -0
  30. package/dist/formFields/errorMessages.d.ts +1 -0
  31. package/dist/formFields/errors/FormFieldError.d.ts +11 -0
  32. package/dist/formFields/errors/FormFieldErrorDisplay.d.ts +11 -0
  33. package/dist/formFields/errors/getFormErrorForNestedKeys.d.ts +14 -0
  34. package/dist/formFields/errors/useFormFieldError.d.ts +7 -0
  35. package/dist/formFields/errors/useFormFieldHasError.d.ts +6 -0
  36. package/dist/formFields/formHelper/syncSubmit.d.ts +15 -0
  37. package/dist/formFields/formHelper/useHookForm.d.ts +58 -0
  38. package/dist/formFields/formHelper/useHookFormContext.d.ts +9 -0
  39. package/dist/formFields/formHelper/useMergedFormField.d.ts +6 -0
  40. package/dist/formFields/formHelper/useSortedOptionsWithGroup.d.ts +5 -0
  41. package/dist/formFields/formHelper/useTranslateString.d.ts +8 -0
  42. package/dist/formFields/index.d.ts +49 -0
  43. package/dist/formFields/inputTypes.d.ts +76 -0
  44. package/dist/packageExports.d.ts +9 -0
  45. package/dist/packageExports.js +1766 -0
  46. package/dist/packageExports.js.map +1 -0
  47. package/package.json +1 -1
@@ -0,0 +1,1766 @@
1
+ import { CheckBoxOutlineBlank, CheckBox } from '@mui/icons-material';
2
+ import { FormHelperText, Checkbox, FormControl, Autocomplete, TextField, FormControlLabel, Box, InputLabel, OutlinedInput, FormLabel, RadioGroup, Radio, Select, MenuItem, Typography, Stack, Tooltip, ListSubheader, Slider, Switch, ToggleButton, ToggleButtonGroup } from '@mui/material';
3
+ import { useFormControl } from '@mui/material/FormControl';
4
+ import { filterNoUndefinedNoNull, uppercaseFirstLetter, assertTruthy, objectHasKey, rethrow } from '@nvon/baseline';
5
+ import { useCallback, useMemo, useState, useEffect } from 'react';
6
+ import { useFormContext, useWatch, Controller, useForm, useFieldArray, FormProvider } from 'react-hook-form';
7
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
+ import { identity } from 'lodash-es';
9
+ import { t } from 'i18next';
10
+ import { DatePicker, DateTimePicker, TimePicker } from '@mui/x-date-pickers';
11
+ import dayjs from 'dayjs';
12
+ import { NumericFormat } from 'react-number-format';
13
+ import { LoadingButton as LoadingButton$1 } from '@mui/lab';
14
+
15
+ const formContextNull = "FormContext is null. This should not happen. You may need to use the HookFormProvider instead of the FormProvider exported by react-hook-form";
16
+
17
+ const FormFieldErrorDisplay = ({
18
+ error,
19
+ formHelperTextProps
20
+ }) => {
21
+ if (Array.isArray(error)) {
22
+ return /*#__PURE__*/jsx(FormHelperText, {
23
+ ...formHelperTextProps,
24
+ error: true,
25
+ children: error.map(e => e.message).filter(filterNoUndefinedNoNull).join(", ")
26
+ });
27
+ }
28
+ if (error?.message) {
29
+ return /*#__PURE__*/jsx(FormHelperText, {
30
+ ...formHelperTextProps,
31
+ error: true,
32
+ children: error?.message
33
+ });
34
+ }
35
+ return null;
36
+ };
37
+
38
+ /**
39
+ * Wrapper around react-hook-form's useFormContext.
40
+ *
41
+ * Should behave like the original function, only exposing a "fieldName"
42
+ * function on top which is used to validate field names.
43
+ */
44
+ const useHookFormContext = () => {
45
+ const form = useFormContext();
46
+ return {
47
+ ...form,
48
+ fieldName: identity
49
+ };
50
+ };
51
+
52
+ /**
53
+ * Get the field errors for a (possibly nested) field name.
54
+ *
55
+ * Checking `formState.errors[fieldName]` only works if fieldName is not a path
56
+ * (e.g. Does not include dots).
57
+ *
58
+ * Did not find a built-in way to do this … there might be one though.
59
+ *
60
+ * Supports both dot notation (e.g., "response.receipts.0.field") and
61
+ * bracket notation (e.g., "response.receipts[0].field") for array fields.
62
+ */
63
+ const getFormErrorForNestedKeys = (errors, fieldName) => {
64
+ // Parse the field name to handle both dot notation and bracket notation
65
+ // e.g., "response.receipts.0.field" or "response.receipts[0].field"
66
+ const keys = [];
67
+ let currentKey = "";
68
+ let i = 0;
69
+ while (i < fieldName.length) {
70
+ const char = fieldName[i];
71
+ if (char === "[") {
72
+ // Save the current key if any
73
+ if (currentKey) {
74
+ keys.push(currentKey);
75
+ currentKey = "";
76
+ }
77
+ // Find the closing bracket
78
+ i++; // Skip the opening bracket
79
+ let bracketContent = "";
80
+ while (i < fieldName.length && fieldName[i] !== "]") {
81
+ bracketContent += fieldName[i];
82
+ i++;
83
+ }
84
+ // Parse the bracket content as a number if possible, otherwise as string
85
+ const numIndex = Number(bracketContent);
86
+ keys.push(isNaN(numIndex) ? bracketContent : numIndex);
87
+ i++; // Skip the closing bracket
88
+ } else if (char === ".") {
89
+ // Save the current key if any
90
+ if (currentKey) {
91
+ keys.push(currentKey);
92
+ currentKey = "";
93
+ }
94
+ i++; // Skip the dot
95
+ } else {
96
+ currentKey += char;
97
+ i++;
98
+ }
99
+ }
100
+ // Don't forget the last key
101
+ if (currentKey) {
102
+ keys.push(currentKey);
103
+ }
104
+ //
105
+ // To my best knowledge, this works as expected.
106
+ //
107
+ // It recursively walks the error object by the given keys
108
+ // until the lowest level is reached, or undefined returned.
109
+ //
110
+ // Handles both object properties and array indices.
111
+ //
112
+ // Typescript is just not very happy with the dynamic nature of this,
113
+ // hence the errors.
114
+ //
115
+ /* eslint-disable @typescript-eslint/ban-ts-comment,@typescript-eslint/no-unsafe-return */
116
+ // @ts-expect-error
117
+ return keys.reduce((errorObj, pathKey) => {
118
+ if (errorObj === undefined || errorObj === null) {
119
+ return undefined;
120
+ }
121
+ // Handle array access
122
+ if (typeof pathKey === "number") {
123
+ return Array.isArray(errorObj) ? errorObj[pathKey] :
124
+ // @ts-expect-error
125
+ errorObj?.[pathKey];
126
+ }
127
+ // Handle object property access
128
+ // @ts-expect-error
129
+ return errorObj?.[pathKey];
130
+ }, errors);
131
+ /* eslint-enable */
132
+ };
133
+
134
+ /**
135
+ * Returns the error for a given field name.
136
+ *
137
+ * @throws Error when FormContext is null.
138
+ */
139
+ const useFormFieldError = fieldName => {
140
+ const form = useHookFormContext();
141
+ if (!form) {
142
+ throw Error(formContextNull);
143
+ }
144
+ const {
145
+ formState
146
+ } = form;
147
+ const errors = getFormErrorForNestedKeys(formState.errors, fieldName);
148
+ return errors;
149
+ };
150
+
151
+ const FormFieldError = ({
152
+ fieldName,
153
+ formHelperTextProps
154
+ }) => {
155
+ const error = useFormFieldError(fieldName);
156
+ return /*#__PURE__*/jsx(FormFieldErrorDisplay, {
157
+ error: error,
158
+ formHelperTextProps: formHelperTextProps
159
+ });
160
+ };
161
+
162
+ /**
163
+ * Returns whether or not a field has an error.
164
+ *
165
+ * @throws Error when FormContext is null.
166
+ */
167
+ const useFormFieldHasError = fieldName => !!useFormFieldError(fieldName);
168
+
169
+ /**
170
+ * Return a function which turns our TranslatedString into a plain string.
171
+ *
172
+ * @throws Error if no t was provided but a translated string.
173
+ */
174
+ const useTranslateString = () => {
175
+ if (!t) {
176
+ throw Error("If you pass in a translated validate function you need to provide a t");
177
+ }
178
+ return useCallback(input => {
179
+ return typeof input === "string" ? input : input(t);
180
+ }, []);
181
+ };
182
+
183
+ /**
184
+ * Merge a form field with defaults.
185
+ */
186
+ const useMergedFormField = (
187
+ /**
188
+ * Form fields, typically those passed into a component.
189
+ *
190
+ */
191
+ formField, t,
192
+ /**
193
+ * Additional defaults. Duplicate values will be overridden by the formField.
194
+ */
195
+ formFieldDefaults) => {
196
+ const translate = useTranslateString();
197
+ const merged = useMemo(() => {
198
+ const builtInDefaults = {
199
+ label: uppercaseFirstLetter(formField.name),
200
+ required: false,
201
+ requiredErrorMessage: "Please fill in required information",
202
+ validate: undefined
203
+ };
204
+ return {
205
+ ...builtInDefaults,
206
+ ...formFieldDefaults,
207
+ ...formField
208
+ };
209
+ }, [formField, formFieldDefaults]);
210
+ const withPlainStrings = useMemo(() => {
211
+ // Translating the validate function is a bit tricky,
212
+ // since it can be an object in both cases.
213
+ const validate = (() => {
214
+ if (typeof merged.validate === "object" && typeof merged.validate.translated === "function") {
215
+ if (!t) {
216
+ throw Error("If you pass in a translated validate function you need to provide a t");
217
+ }
218
+ return merged.validate.translated(t);
219
+ }
220
+ return merged.validate;
221
+ })(); // This should be fine. Not sure why TS is complaining.
222
+ return {
223
+ ...merged,
224
+ label: translate(merged.label, t),
225
+ requiredErrorMessage: translate(merged.requiredErrorMessage, t),
226
+ validate
227
+ };
228
+ }, [merged, t, translate]);
229
+ return withPlainStrings;
230
+ };
231
+
232
+ /**
233
+ * An effect that unregisters a field from the form when the component unmounts.
234
+ *
235
+ * @throws Error when FormContext is null.
236
+ */
237
+ const useEffectFieldUnregisterOnUnmount = ({
238
+ name,
239
+ unregisterOptions,
240
+ isUnregisteringOnUnmount
241
+ }) => {
242
+ const form = useHookFormContext();
243
+ /**
244
+ * Default options for unregistering the field.
245
+ *
246
+ * Needed to wrap this in a state in order to prevent infinite rerenders.
247
+ */
248
+ const [options] = useState(unregisterOptions);
249
+ if (!form) {
250
+ throw Error(formContextNull);
251
+ }
252
+ const {
253
+ unregister
254
+ } = form;
255
+ useEffect(() => {
256
+ return () => {
257
+ if (isUnregisteringOnUnmount) {
258
+ unregister(name, options);
259
+ }
260
+ };
261
+ }, [isUnregisteringOnUnmount, name, unregister, options]);
262
+ };
263
+
264
+ var GroupLabelSorting;
265
+ (function (GroupLabelSorting) {
266
+ GroupLabelSorting["Alphabetical"] = "alphabetical";
267
+ GroupLabelSorting["GroupMemberCountAsc"] = "groupMemberCountAsc";
268
+ })(GroupLabelSorting || (GroupLabelSorting = {}));
269
+ /**
270
+ * Sorts option in the desired order.
271
+ */
272
+ const useSortedOptionsWithGroup$1 = (selectableOptions, sorting = GroupLabelSorting.Alphabetical) => {
273
+ return useMemo(() => {
274
+ if (sorting === GroupLabelSorting.GroupMemberCountAsc) {
275
+ const groupCounts = selectableOptions.reduce((acc, option) => {
276
+ if (option.group) {
277
+ acc[option.group] = (acc[option.group] || 0) + 1;
278
+ }
279
+ return acc;
280
+ }, {});
281
+ return selectableOptions.sort((a, b) => {
282
+ if (a.group == undefined && !!b.group) {
283
+ return -1;
284
+ }
285
+ if (a.group && b.group) {
286
+ const groupA = groupCounts[a.group];
287
+ const groupB = groupCounts[b.group];
288
+ if (groupA && groupB && groupA < groupB) {
289
+ return -1;
290
+ } else if (groupCounts[a.group] === groupCounts[b.group]) {
291
+ if (b.label > a.label) {
292
+ return -1;
293
+ }
294
+ return 1;
295
+ }
296
+ return 1;
297
+ }
298
+ if (b.label > a.label) {
299
+ return -1;
300
+ }
301
+ return 1;
302
+ });
303
+ }
304
+ return selectableOptions.sort((a, b) => {
305
+ if (a.group == undefined && !!b.group) {
306
+ return -1;
307
+ }
308
+ if (a.group && b.group && a.group < b.group) {
309
+ return -1;
310
+ }
311
+ if (a.group == b.group && b.label > a.label) {
312
+ return 1;
313
+ }
314
+ return 0;
315
+ });
316
+ }, [selectableOptions, sorting]);
317
+ };
318
+
319
+ const icon = /*#__PURE__*/jsx(CheckBoxOutlineBlank, {
320
+ fontSize: "small"
321
+ });
322
+ const checkedIcon = /*#__PURE__*/jsx(CheckBox, {
323
+ fontSize: "small"
324
+ });
325
+ const defaultNonMultiselectValue = "";
326
+ /**
327
+ * Renders a MUI autocomplete input that is embedded in a react hook form context.
328
+ *
329
+ * @throws Error when FormContext is null.
330
+ */
331
+ const InputAutocomplete = ({
332
+ formField,
333
+ selectableOptions,
334
+ noOptions,
335
+ autoCompleteProps,
336
+ checkboxesForMultiselect: renderCheckboxes,
337
+ groupSorting,
338
+ inputTextFieldProps,
339
+ unregisterOptions,
340
+ isUnregisteringOnUnmount
341
+ }) => {
342
+ const form = useHookFormContext();
343
+ if (!form) {
344
+ throw Error(formContextNull);
345
+ }
346
+ const {
347
+ register,
348
+ control,
349
+ setValue
350
+ } = form;
351
+ const hasError = useFormFieldHasError(formField.name);
352
+ const muiFormControl = useFormControl();
353
+ const {
354
+ label,
355
+ name,
356
+ required,
357
+ requiredErrorMessage,
358
+ validate
359
+ } = useMergedFormField(formField, formField.t);
360
+ useEffectFieldUnregisterOnUnmount({
361
+ name,
362
+ unregisterOptions,
363
+ isUnregisteringOnUnmount
364
+ });
365
+ const multiSelect = !!autoCompleteProps?.multiple;
366
+ const value = useWatch({
367
+ name,
368
+ control,
369
+ exact: true
370
+ });
371
+ const {
372
+ value: valueToUse,
373
+ hasValue
374
+ } = useMemo(() => {
375
+ if (value) {
376
+ return {
377
+ value,
378
+ hasValue: true
379
+ };
380
+ }
381
+ return {
382
+ value: multiSelect ? [] : defaultNonMultiselectValue,
383
+ hasValue: false
384
+ };
385
+ }, [multiSelect, value]);
386
+ const adjustedSelectableOptions = useMemo(() => {
387
+ if (hasValue || multiSelect) {
388
+ return selectableOptions;
389
+ }
390
+ return [...selectableOptions, {
391
+ value: defaultNonMultiselectValue,
392
+ label: ""
393
+ }];
394
+ }, [hasValue, multiSelect, selectableOptions]);
395
+ const sortedOptions = useSortedOptionsWithGroup$1(adjustedSelectableOptions, groupSorting);
396
+ assertTruthy(["string", "number", "object"].includes(typeof valueToUse), `Value (Field: ${name}, value: ${valueToUse?.toString() || "undefined"}) for select input has unexpected type`);
397
+ const isRequired = required || muiFormControl?.required;
398
+ const isDisabled = muiFormControl?.disabled || autoCompleteProps?.disabled;
399
+ const props = register(name, {
400
+ required: isRequired ? requiredErrorMessage : false,
401
+ validate,
402
+ disabled: isDisabled
403
+ });
404
+ const currentValue = useMemo(() => {
405
+ return multiSelect ? adjustedSelectableOptions.filter(o => {
406
+ if (Array.isArray(valueToUse)) {
407
+ return valueToUse.includes(o.value);
408
+ }
409
+ return adjustedSelectableOptions.find(option => option.value === valueToUse);
410
+ }) : adjustedSelectableOptions.find(option => option.value === valueToUse);
411
+ }, [multiSelect, adjustedSelectableOptions, valueToUse]);
412
+ const renderOption = useMemo(() => {
413
+ if (autoCompleteProps?.renderOption) {
414
+ return autoCompleteProps.renderOption;
415
+ }
416
+ return multiSelect && renderCheckboxes ? (liProps, option) => {
417
+ return /*#__PURE__*/jsxs("li", {
418
+ ...liProps,
419
+ children: [/*#__PURE__*/jsx(Checkbox, {
420
+ icon: icon,
421
+ checkedIcon: checkedIcon,
422
+ sx: {
423
+ mr: 2
424
+ },
425
+ checked: Array.isArray(currentValue) ? !!currentValue.find(item => item.value === option.value) : false
426
+ }), option.label]
427
+ });
428
+ } : undefined;
429
+ }, [autoCompleteProps?.renderOption, currentValue, multiSelect, renderCheckboxes]);
430
+ return /*#__PURE__*/jsxs(FormControl, {
431
+ error: hasError,
432
+ required: isRequired,
433
+ disabled: isDisabled,
434
+ children: [/*#__PURE__*/jsx(Autocomplete, {
435
+ options: sortedOptions,
436
+ value: currentValue,
437
+ ...props,
438
+ required: isRequired,
439
+ label: label,
440
+ renderOption: renderOption,
441
+ multiple: multiSelect,
442
+ getOptionLabel: o => {
443
+ if (objectHasKey(o, "label")) {
444
+ return o.label;
445
+ }
446
+ return "";
447
+ },
448
+ onChange: (e, selectedOption) => {
449
+ if (Array.isArray(selectedOption)) {
450
+ setValue(name, selectedOption.map(o => o.value), {
451
+ shouldDirty: true,
452
+ shouldValidate: true,
453
+ shouldTouch: true
454
+ });
455
+ } else if (selectedOption) {
456
+ setValue(name, selectedOption.value, {
457
+ shouldDirty: true,
458
+ shouldValidate: true,
459
+ shouldTouch: true
460
+ });
461
+ }
462
+ },
463
+ noOptionsText: noOptions,
464
+ filterOptions: (options, {
465
+ inputValue
466
+ }) => {
467
+ return options.filter(o => {
468
+ // Filter out the default empty option
469
+ if (o.value === defaultNonMultiselectValue) {
470
+ return false;
471
+ }
472
+ // If no input, show all non-default options
473
+ if (!inputValue) {
474
+ return true;
475
+ }
476
+ // Filter based on input text (case-insensitive)
477
+ return o.label.toLowerCase().includes(inputValue.toLowerCase());
478
+ });
479
+ },
480
+ renderInput: params => {
481
+ return /*#__PURE__*/jsx(TextField, {
482
+ ...params,
483
+ label: label,
484
+ variant: "outlined",
485
+ ...inputTextFieldProps,
486
+ required: isRequired,
487
+ disabled: isDisabled,
488
+ error: hasError
489
+ });
490
+ },
491
+ groupBy: option => option.group || "Choose"
492
+ // need to parse this as any in order to get no typing errors
493
+ // for multiselect
494
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
495
+ ,
496
+ ...autoCompleteProps
497
+ }), /*#__PURE__*/jsx(FormFieldError, {
498
+ fieldName: formField.name
499
+ })]
500
+ });
501
+ };
502
+
503
+ const InputCheckbox = ({
504
+ formField,
505
+ jsxLabel,
506
+ checkboxProps,
507
+ formControlLabelProps,
508
+ unregisterOptions,
509
+ isUnregisteringOnUnmount
510
+ }) => {
511
+ const {
512
+ control,
513
+ setValue
514
+ } = useHookFormContext();
515
+ const hasError = useFormFieldHasError(formField.name);
516
+ const muiFormControl = useFormControl();
517
+ const {
518
+ label,
519
+ name,
520
+ required,
521
+ requiredErrorMessage,
522
+ validate
523
+ } = useMergedFormField(formField);
524
+ useEffectFieldUnregisterOnUnmount({
525
+ name,
526
+ unregisterOptions,
527
+ isUnregisteringOnUnmount
528
+ });
529
+ const id = `hook-form-input-checkbox-${name}`;
530
+ const disabled = muiFormControl?.disabled || checkboxProps?.disabled;
531
+ const isRequired = required || muiFormControl?.required;
532
+ return /*#__PURE__*/jsxs(FormControl, {
533
+ error: hasError,
534
+ disabled: disabled,
535
+ required: required,
536
+ children: [/*#__PURE__*/jsx(FormControlLabel, {
537
+ required: jsxLabel ? false : isRequired // If jsxLabel is set, we don't want to show the asterisk.
538
+ ,
539
+ disabled: disabled,
540
+ label: jsxLabel ?? label,
541
+ sx: {
542
+ color: t => hasError ? t.palette.error.main : undefined
543
+ },
544
+ control: /*#__PURE__*/jsx(Controller, {
545
+ name: name,
546
+ control: control,
547
+ rules: {
548
+ required: isRequired ? requiredErrorMessage : false,
549
+ validate
550
+ },
551
+ render: ({
552
+ field: {
553
+ value
554
+ }
555
+ }) => {
556
+ return /*#__PURE__*/jsx(Checkbox, {
557
+ checked: !!value,
558
+ "aria-labelledby": id,
559
+ onChange: (e, val) => {
560
+ setValue(name, val, {
561
+ shouldValidate: true,
562
+ shouldDirty: true,
563
+ shouldTouch: true
564
+ });
565
+ },
566
+ ...checkboxProps,
567
+ disabled: disabled
568
+ });
569
+ }
570
+ }),
571
+ ...formControlLabelProps
572
+ }), /*#__PURE__*/jsx(FormFieldError, {
573
+ fieldName: formField.name
574
+ })]
575
+ });
576
+ };
577
+
578
+ const InputDatePicker = ({
579
+ formField,
580
+ datePickerProps,
581
+ unregisterOptions,
582
+ isUnregisteringOnUnmount
583
+ }) => {
584
+ const {
585
+ control
586
+ } = useHookFormContext();
587
+ const hasError = useFormFieldHasError(formField.name);
588
+ const muiFormControl = useFormControl();
589
+ const {
590
+ label,
591
+ name,
592
+ required,
593
+ requiredErrorMessage
594
+ } = useMergedFormField(formField);
595
+ useEffectFieldUnregisterOnUnmount({
596
+ name,
597
+ unregisterOptions,
598
+ isUnregisteringOnUnmount
599
+ });
600
+ const [date, setDate] = useState(dayjs());
601
+ const isRequired = required || muiFormControl?.required;
602
+ const isDisabled = muiFormControl?.disabled || datePickerProps?.disabled;
603
+ return /*#__PURE__*/jsx(Box, {
604
+ children: /*#__PURE__*/jsxs(FormControl, {
605
+ error: hasError,
606
+ required: isRequired,
607
+ disabled: isDisabled,
608
+ children: [/*#__PURE__*/jsx(Controller, {
609
+ name: name,
610
+ defaultValue: date,
611
+ control: control,
612
+ rules: {
613
+ required: isRequired ? requiredErrorMessage : false
614
+ },
615
+ render: ({
616
+ field: {
617
+ onChange,
618
+ ...restField
619
+ }
620
+ }) => /*#__PURE__*/jsx(DatePicker, {
621
+ label: label,
622
+ onChange: event => {
623
+ onChange(event);
624
+ if (event) {
625
+ setDate(event);
626
+ }
627
+ },
628
+ disabled: isDisabled,
629
+ slotProps: {
630
+ textField: {
631
+ required: isRequired,
632
+ disabled: isDisabled,
633
+ error: hasError
634
+ }
635
+ },
636
+ ...restField,
637
+ ...datePickerProps
638
+ })
639
+ }), /*#__PURE__*/jsx(FormFieldError, {
640
+ fieldName: formField.name
641
+ })]
642
+ })
643
+ });
644
+ };
645
+
646
+ const InputDateTimePicker = ({
647
+ formField,
648
+ dateTimePickerProps,
649
+ unregisterOptions,
650
+ isUnregisteringOnUnmount
651
+ }) => {
652
+ const {
653
+ control
654
+ } = useHookFormContext();
655
+ const hasError = useFormFieldHasError(formField.name);
656
+ const muiFormControl = useFormControl();
657
+ const {
658
+ label,
659
+ name,
660
+ required,
661
+ requiredErrorMessage
662
+ } = useMergedFormField(formField);
663
+ useEffectFieldUnregisterOnUnmount({
664
+ name,
665
+ unregisterOptions,
666
+ isUnregisteringOnUnmount
667
+ });
668
+ const [date, setDate] = useState(dayjs());
669
+ const isRequired = required || muiFormControl?.required;
670
+ const isDisabled = muiFormControl?.disabled || dateTimePickerProps?.disabled;
671
+ return /*#__PURE__*/jsx(Box, {
672
+ children: /*#__PURE__*/jsxs(FormControl, {
673
+ error: hasError,
674
+ required: isRequired,
675
+ disabled: isDisabled,
676
+ children: [/*#__PURE__*/jsx(Controller, {
677
+ name: name,
678
+ defaultValue: date,
679
+ control: control,
680
+ rules: {
681
+ required: isRequired ? requiredErrorMessage : false
682
+ },
683
+ render: ({
684
+ field: {
685
+ onChange,
686
+ ...restField
687
+ }
688
+ }) => /*#__PURE__*/jsx(DateTimePicker, {
689
+ label: label,
690
+ ampm: dateTimePickerProps?.ampm ? dateTimePickerProps.ampm : false,
691
+ onChange: event => {
692
+ onChange(event);
693
+ if (event) {
694
+ setDate(event);
695
+ }
696
+ },
697
+ disabled: isDisabled,
698
+ required: isRequired,
699
+ slotProps: {
700
+ textField: {
701
+ required: isRequired,
702
+ disabled: isDisabled,
703
+ error: hasError
704
+ }
705
+ },
706
+ ...restField,
707
+ ...dateTimePickerProps
708
+ })
709
+ }), /*#__PURE__*/jsx(FormFieldError, {
710
+ fieldName: formField.name
711
+ })]
712
+ })
713
+ });
714
+ };
715
+
716
+ const InputNumber = ({
717
+ formField,
718
+ textFieldProps,
719
+ numericFormatProps,
720
+ unregisterOptions,
721
+ isUnregisteringOnUnmount
722
+ }) => {
723
+ const form = useHookFormContext();
724
+ const {
725
+ control
726
+ } = form;
727
+ const muiFormControl = useFormControl();
728
+ const {
729
+ label,
730
+ name,
731
+ required,
732
+ requiredErrorMessage,
733
+ validate
734
+ } = useMergedFormField(formField, formField.t);
735
+ useEffectFieldUnregisterOnUnmount({
736
+ name,
737
+ unregisterOptions,
738
+ isUnregisteringOnUnmount
739
+ });
740
+ if (!form) {
741
+ throw Error(formContextNull);
742
+ }
743
+ const hasError = useFormFieldHasError(formField.name);
744
+ const isRequired = required || muiFormControl?.required;
745
+ const isDisabled = muiFormControl?.disabled || textFieldProps?.disabled;
746
+ return /*#__PURE__*/jsxs(FormControl, {
747
+ error: hasError,
748
+ required: required,
749
+ disabled: isDisabled,
750
+ children: [/*#__PURE__*/jsx(Controller, {
751
+ name: name,
752
+ control: control,
753
+ rules: {
754
+ required: isRequired ? requiredErrorMessage : false,
755
+ validate
756
+ },
757
+ render: props => {
758
+ const {
759
+ ref,
760
+ ...rest
761
+ } = props.field;
762
+ return (
763
+ /*#__PURE__*/
764
+ // @ts-expect-error TextFieldProps is not compatible with NumberFormatBaseProps
765
+ jsx(NumericFormat, {
766
+ ...rest,
767
+ customInput: TextField,
768
+ onValueChange: target => {
769
+ rest.onChange(target.value);
770
+ },
771
+ label: label,
772
+ onChange: undefined,
773
+ onBlur: props.field.onBlur,
774
+ error: !!props.fieldState.error,
775
+ ...textFieldProps,
776
+ ...numericFormatProps,
777
+ disabled: isDisabled,
778
+ required: isRequired
779
+ })
780
+ );
781
+ }
782
+ }), /*#__PURE__*/jsx(FormFieldError, {
783
+ fieldName: formField.name
784
+ })]
785
+ });
786
+ };
787
+
788
+ const InputOutlinedInput = ({
789
+ formField,
790
+ outlinedInputProps,
791
+ unregisterOptions,
792
+ isUnregisteringOnUnmount
793
+ }) => {
794
+ const form = useHookFormContext();
795
+ const muiFormControl = useFormControl();
796
+ const {
797
+ label,
798
+ name,
799
+ required,
800
+ requiredErrorMessage,
801
+ validate
802
+ } = useMergedFormField(formField, formField.t);
803
+ useEffectFieldUnregisterOnUnmount({
804
+ name,
805
+ unregisterOptions,
806
+ isUnregisteringOnUnmount
807
+ });
808
+ if (!form) {
809
+ throw Error(formContextNull);
810
+ }
811
+ const {
812
+ control
813
+ } = form;
814
+ const hasError = useFormFieldHasError(formField.name);
815
+ const isRequired = required || muiFormControl?.required;
816
+ const isDisabled = muiFormControl?.disabled || outlinedInputProps?.disabled;
817
+ return /*#__PURE__*/jsxs(FormControl, {
818
+ error: hasError,
819
+ required: required,
820
+ disabled: muiFormControl?.disabled,
821
+ children: [/*#__PURE__*/jsx(InputLabel, {
822
+ required: isRequired,
823
+ disabled: isDisabled,
824
+ children: label
825
+ }), /*#__PURE__*/jsx(Controller, {
826
+ name: name,
827
+ control: control,
828
+ rules: {
829
+ required: isRequired ? requiredErrorMessage : false,
830
+ validate
831
+ },
832
+ render: ({
833
+ field: {
834
+ value,
835
+ onBlur,
836
+ onChange
837
+ }
838
+ }) => {
839
+ return /*#__PURE__*/jsx(OutlinedInput, {
840
+ value: value,
841
+ onChange: onChange,
842
+ onBlur: onBlur,
843
+ label: label,
844
+ ...outlinedInputProps,
845
+ required: isRequired,
846
+ disabled: isDisabled
847
+ });
848
+ }
849
+ }), /*#__PURE__*/jsx(FormFieldError, {
850
+ fieldName: formField.name
851
+ })]
852
+ });
853
+ };
854
+
855
+ const InputRadio = ({
856
+ formField,
857
+ selectableOptions,
858
+ formControlLabelProps,
859
+ radioGroupProps,
860
+ unregisterOptions,
861
+ isUnregisteringOnUnmount
862
+ }) => {
863
+ const {
864
+ control
865
+ } = useHookFormContext();
866
+ const hasError = useFormFieldHasError(formField.name);
867
+ const muiFormControl = useFormControl();
868
+ const {
869
+ label,
870
+ name,
871
+ required,
872
+ requiredErrorMessage,
873
+ validate
874
+ } = useMergedFormField(formField);
875
+ useEffectFieldUnregisterOnUnmount({
876
+ name,
877
+ unregisterOptions,
878
+ isUnregisteringOnUnmount
879
+ });
880
+ const id = `hook-form-input-radio-${name}`;
881
+ const isRequired = required || muiFormControl?.required;
882
+ const isDisabled = muiFormControl?.disabled || formControlLabelProps?.disabled;
883
+ return /*#__PURE__*/jsxs(FormControl, {
884
+ error: hasError,
885
+ disabled: muiFormControl?.disabled,
886
+ children: [/*#__PURE__*/jsx(FormLabel, {
887
+ id: id,
888
+ required: isRequired,
889
+ disabled: isDisabled,
890
+ error: hasError,
891
+ sx: {
892
+ color: t => hasError ? t.palette.error.main : undefined
893
+ },
894
+ children: label
895
+ }), /*#__PURE__*/jsx(Controller, {
896
+ name: name,
897
+ control: control,
898
+ rules: {
899
+ required: isRequired ? requiredErrorMessage : false,
900
+ validate
901
+ },
902
+ render: ({
903
+ field: {
904
+ onChange,
905
+ value,
906
+ onBlur
907
+ }
908
+ }) => {
909
+ return /*#__PURE__*/jsx(RadioGroup, {
910
+ value: value,
911
+ "aria-labelledby": id,
912
+ onChange: onChange,
913
+ onBlur: onBlur,
914
+ ...radioGroupProps,
915
+ children: selectableOptions?.map(option => {
916
+ return /*#__PURE__*/jsx(FormControlLabel, {
917
+ value: option.value,
918
+ control: /*#__PURE__*/jsx(Radio, {}),
919
+ label: option.label,
920
+ ...formControlLabelProps,
921
+ disabled: isDisabled
922
+ }, typeof option.value === "boolean" ? option.value.toString() : option.value);
923
+ })
924
+ });
925
+ }
926
+ }), /*#__PURE__*/jsx(FormFieldError, {
927
+ fieldName: formField.name
928
+ })]
929
+ });
930
+ };
931
+
932
+ /**
933
+ * Sorts the options by group and value.
934
+ */
935
+ const useSortedOptionsWithGroup = selectableOptions => {
936
+ return useMemo(() => selectableOptions.sort((a, b) => {
937
+ if (a.group == undefined && !!b.group) {
938
+ return -1;
939
+ }
940
+ if (a.group && b.group && a.group < b.group) {
941
+ return -1;
942
+ }
943
+ if (a.group == b.group && b.value > a.value) {
944
+ return 1;
945
+ }
946
+ return 0;
947
+ }), [selectableOptions]);
948
+ };
949
+
950
+ const InputSelect = ({
951
+ formField,
952
+ selectableOptions,
953
+ optionsTitle,
954
+ selectComponentProps,
955
+ tooltipHolder,
956
+ unregisterOptions,
957
+ isUnregisteringOnUnmount
958
+ }) => {
959
+ const form = useHookFormContext();
960
+ if (!form) {
961
+ throw Error(formContextNull);
962
+ }
963
+ const {
964
+ control
965
+ } = form;
966
+ const muiFormControl = useFormControl();
967
+ const {
968
+ label,
969
+ name,
970
+ required,
971
+ requiredErrorMessage,
972
+ validate
973
+ } = useMergedFormField(formField, formField.t);
974
+ useEffectFieldUnregisterOnUnmount({
975
+ name,
976
+ unregisterOptions,
977
+ isUnregisteringOnUnmount
978
+ });
979
+ const defaultValue = useMemo(() => selectComponentProps?.multiple ? [] : "", [selectComponentProps?.multiple]);
980
+ const id = `input-select-${name}`;
981
+ const adjustedOptions = useMemo(() => selectComponentProps?.multiple || Array.isArray(defaultValue) ? selectableOptions : [...selectableOptions, {
982
+ value: defaultValue,
983
+ label: ""
984
+ }], [defaultValue, selectComponentProps?.multiple, selectableOptions]);
985
+ const sortedOptions = useSortedOptionsWithGroup(adjustedOptions);
986
+ const hasErrors = useFormFieldHasError(formField.name);
987
+ const isRequired = required || muiFormControl?.required;
988
+ const isDisabled = muiFormControl?.disabled || selectComponentProps?.disabled;
989
+ return /*#__PURE__*/jsxs(FormControl, {
990
+ error: hasErrors,
991
+ required: isRequired,
992
+ disabled: isDisabled,
993
+ children: [/*#__PURE__*/jsx(InputLabel, {
994
+ id: id,
995
+ required: isRequired,
996
+ disabled: isDisabled,
997
+ error: hasErrors,
998
+ children: label
999
+ }), /*#__PURE__*/jsx(Controller, {
1000
+ name: name,
1001
+ control: control,
1002
+ rules: {
1003
+ required: isRequired ? requiredErrorMessage : false,
1004
+ validate
1005
+ },
1006
+ render: ({
1007
+ field: {
1008
+ onChange,
1009
+ onBlur,
1010
+ value
1011
+ },
1012
+ fieldState: {
1013
+ error
1014
+ }
1015
+ }) => {
1016
+ const valueToUse = value || defaultValue;
1017
+ return /*#__PURE__*/jsxs(Select, {
1018
+ labelId: id,
1019
+ ...selectComponentProps,
1020
+ label: label,
1021
+ value: valueToUse,
1022
+ error: !!error,
1023
+ onChange: onChange,
1024
+ onBlur: onBlur,
1025
+ disabled: isDisabled,
1026
+ required: isRequired,
1027
+ children: [optionsTitle && /*#__PURE__*/jsx(MenuItem, {
1028
+ value: defaultValue,
1029
+ disabled: true,
1030
+ children: /*#__PURE__*/jsx("em", {
1031
+ children: optionsTitle
1032
+ })
1033
+ }), sortedOptions?.filter(o => o.value !== "").map((option, index) => {
1034
+ const optionBefore = sortedOptions[index - 1];
1035
+ const showGroup = (optionBefore || index == 0) && option.group && optionBefore?.group !== option.group;
1036
+ const disabledText = typeof option.disabled === "string" ? option.disabled : undefined;
1037
+ const isDisabledToUse = !!disabledText || !!option.disabled || isDisabled;
1038
+ const menuItem = /*#__PURE__*/jsx(MenuItem, {
1039
+ value: typeof option.value === "boolean" ? option.value.toString() : option.value,
1040
+ disabled: isDisabledToUse,
1041
+ title: typeof option.disabled === "string" ? option.disabled : undefined,
1042
+ selected: typeof option.value === "boolean" ? option.value.toString() === value : value === option.value,
1043
+ children: /*#__PURE__*/jsx(Typography, {
1044
+ dangerouslySetInnerHTML: {
1045
+ __html: option.label
1046
+ }
1047
+ })
1048
+ }, option.label);
1049
+ const wrappedMenuItem = disabledText ? /*#__PURE__*/jsxs(Box, {
1050
+ sx: {
1051
+ position: "relative"
1052
+ },
1053
+ children: [menuItem, /*#__PURE__*/jsx(Stack, {
1054
+ direction: "column",
1055
+ justifyContent: "center",
1056
+ spacing: 1,
1057
+ sx: {
1058
+ position: "absolute",
1059
+ right: th => th.spacing(0.5),
1060
+ top: 0,
1061
+ bottom: 0
1062
+ },
1063
+ children: tooltipHolder ? /*#__PURE__*/jsx(Tooltip, {
1064
+ title: disabledText,
1065
+ children: tooltipHolder
1066
+ }) : null
1067
+ })]
1068
+ }) : menuItem;
1069
+ return showGroup ? [/*#__PURE__*/jsx(ListSubheader, {
1070
+ children: option.group
1071
+ }, option.group), wrappedMenuItem] : wrappedMenuItem;
1072
+ })]
1073
+ });
1074
+ }
1075
+ }), /*#__PURE__*/jsx(FormFieldError, {
1076
+ fieldName: formField.name
1077
+ })]
1078
+ });
1079
+ };
1080
+
1081
+ const InputSelectFromEnum = props => {
1082
+ const {
1083
+ enumData,
1084
+ formField
1085
+ } = props;
1086
+ const translateFunction = formField.t;
1087
+ const options = useMemo(() => {
1088
+ return Object.entries(enumData.enumToUse).map(([key, value]) => {
1089
+ const label = enumData.labelsForEnum[key];
1090
+ assertTruthy(label, "Could not find a label for value: " + value + " in Field " + formField.name);
1091
+ if (typeof label === "string") {
1092
+ return {
1093
+ label,
1094
+ value
1095
+ };
1096
+ }
1097
+ assertTruthy(translateFunction, `If you want to use translated labels for field (name: ${formField.name}) you need to provide a translate function in the HookFormProvider.`);
1098
+ return {
1099
+ label: label(translateFunction),
1100
+ value
1101
+ };
1102
+ }).filter(option => {
1103
+ if (props.limitOptions) {
1104
+ return props.limitOptions.includes(option.value);
1105
+ }
1106
+ return true;
1107
+ });
1108
+ }, [enumData.enumToUse, enumData.labelsForEnum, formField.name, translateFunction, props.limitOptions]);
1109
+ return props.autocomplete ? /*#__PURE__*/jsx(InputAutocomplete, {
1110
+ noOptions: props.autocomplete.noOptionText,
1111
+ ...props,
1112
+ selectableOptions: options,
1113
+ formField: formField
1114
+ }) : /*#__PURE__*/jsx(InputSelect, {
1115
+ ...props,
1116
+ selectableOptions: options,
1117
+ formField: formField
1118
+ });
1119
+ };
1120
+
1121
+ const InputSlider = ({
1122
+ formField,
1123
+ sliderProps,
1124
+ unregisterOptions,
1125
+ isUnregisteringOnUnmount
1126
+ }) => {
1127
+ const form = useHookFormContext();
1128
+ const muiFormControl = useFormControl();
1129
+ const {
1130
+ label,
1131
+ name,
1132
+ required,
1133
+ requiredErrorMessage,
1134
+ validate
1135
+ } = useMergedFormField(formField, formField.t);
1136
+ useEffectFieldUnregisterOnUnmount({
1137
+ name,
1138
+ unregisterOptions,
1139
+ isUnregisteringOnUnmount
1140
+ });
1141
+ if (!form) {
1142
+ throw Error(formContextNull);
1143
+ }
1144
+ const {
1145
+ control
1146
+ } = form;
1147
+ const hasError = useFormFieldHasError(formField.name);
1148
+ const isRequired = required || muiFormControl?.required;
1149
+ const isDisabled = muiFormControl?.disabled || sliderProps?.disabled;
1150
+ return /*#__PURE__*/jsxs(FormControl, {
1151
+ error: hasError,
1152
+ required: isRequired,
1153
+ disabled: isDisabled,
1154
+ children: [/*#__PURE__*/jsx(Controller, {
1155
+ name: name,
1156
+ control: control,
1157
+ defaultValue: 0,
1158
+ rules: {
1159
+ required: isRequired ? requiredErrorMessage : false,
1160
+ validate
1161
+ },
1162
+ render: ({
1163
+ field: {
1164
+ onChange,
1165
+ value,
1166
+ onBlur
1167
+ }
1168
+ }) => {
1169
+ return /*#__PURE__*/jsx(Slider, {
1170
+ value: value || 0,
1171
+ onChange: onChange,
1172
+ onBlur: onBlur,
1173
+ required: isRequired,
1174
+ label: label,
1175
+ component: sliderProps?.component || "span",
1176
+ max: typeof sliderProps?.max === "number" ? sliderProps.max : undefined,
1177
+ min: typeof sliderProps?.min === "number" ? sliderProps.min : undefined,
1178
+ ...sliderProps,
1179
+ disabled: isDisabled
1180
+ });
1181
+ }
1182
+ }), /*#__PURE__*/jsx(FormFieldError, {
1183
+ fieldName: name
1184
+ })]
1185
+ });
1186
+ };
1187
+
1188
+ const InputSwitch = ({
1189
+ formField,
1190
+ switchProps,
1191
+ formControlLabelProps,
1192
+ unregisterOptions,
1193
+ isUnregisteringOnUnmount
1194
+ }) => {
1195
+ const {
1196
+ control,
1197
+ setValue
1198
+ } = useHookFormContext();
1199
+ const hasError = useFormFieldHasError(formField.name);
1200
+ const muiFormControl = useFormControl();
1201
+ const {
1202
+ label,
1203
+ name,
1204
+ required,
1205
+ requiredErrorMessage,
1206
+ validate
1207
+ } = useMergedFormField(formField);
1208
+ useEffectFieldUnregisterOnUnmount({
1209
+ name,
1210
+ unregisterOptions,
1211
+ isUnregisteringOnUnmount
1212
+ });
1213
+ const isRequired = required || muiFormControl?.required;
1214
+ const isDisabled = muiFormControl?.disabled || switchProps?.disabled;
1215
+ return /*#__PURE__*/jsxs(FormControl, {
1216
+ error: hasError,
1217
+ disabled: isDisabled,
1218
+ required: isRequired,
1219
+ children: [/*#__PURE__*/jsx(FormControlLabel, {
1220
+ label: label,
1221
+ disabled: isDisabled,
1222
+ required: isRequired,
1223
+ sx: {
1224
+ color: t => hasError ? t.palette.error.main : undefined
1225
+ },
1226
+ control: /*#__PURE__*/jsx(Controller, {
1227
+ name: name,
1228
+ control: control,
1229
+ rules: {
1230
+ required: isRequired ? requiredErrorMessage : false,
1231
+ validate
1232
+ },
1233
+ render: ({
1234
+ field: {
1235
+ value
1236
+ }
1237
+ }) => {
1238
+ return /*#__PURE__*/jsx(Switch, {
1239
+ checked: !!value,
1240
+ onChange: (e, val) => {
1241
+ setValue(name, val, {
1242
+ shouldValidate: true,
1243
+ shouldDirty: true,
1244
+ shouldTouch: true
1245
+ });
1246
+ },
1247
+ ...switchProps
1248
+ });
1249
+ }
1250
+ }),
1251
+ ...formControlLabelProps
1252
+ }), /*#__PURE__*/jsx(FormFieldError, {
1253
+ fieldName: formField.name
1254
+ })]
1255
+ });
1256
+ };
1257
+
1258
+ const InputTextField = ({
1259
+ formField,
1260
+ textFieldProps,
1261
+ unregisterOptions,
1262
+ isUnregisteringOnUnmount
1263
+ }) => {
1264
+ const form = useHookFormContext();
1265
+ const {
1266
+ control
1267
+ } = form;
1268
+ const muiFormControl = useFormControl();
1269
+ const {
1270
+ label,
1271
+ name,
1272
+ required,
1273
+ requiredErrorMessage,
1274
+ validate
1275
+ } = useMergedFormField(formField, formField.t);
1276
+ useEffectFieldUnregisterOnUnmount({
1277
+ name,
1278
+ unregisterOptions,
1279
+ isUnregisteringOnUnmount
1280
+ });
1281
+ if (!form) {
1282
+ throw Error(formContextNull);
1283
+ }
1284
+ const hasError = useFormFieldHasError(formField.name);
1285
+ const isRequired = required || muiFormControl?.required;
1286
+ const isDisabled = muiFormControl?.disabled || textFieldProps?.disabled;
1287
+ return /*#__PURE__*/jsxs(FormControl, {
1288
+ error: hasError,
1289
+ required: isRequired,
1290
+ disabled: isDisabled,
1291
+ children: [/*#__PURE__*/jsx(Controller, {
1292
+ name: name,
1293
+ control: control,
1294
+ rules: {
1295
+ required: isRequired ? requiredErrorMessage : false,
1296
+ validate
1297
+ },
1298
+ render: ({
1299
+ field: {
1300
+ onChange,
1301
+ value
1302
+ },
1303
+ fieldState: {
1304
+ error
1305
+ }
1306
+ }) => {
1307
+ return /*#__PURE__*/jsx(TextField, {
1308
+ error: !!error,
1309
+ onChange: onChange,
1310
+ value: value,
1311
+ label: label,
1312
+ ...textFieldProps,
1313
+ required: isRequired,
1314
+ disabled: isDisabled
1315
+ });
1316
+ }
1317
+ }), /*#__PURE__*/jsx(FormFieldError, {
1318
+ fieldName: formField.name
1319
+ })]
1320
+ });
1321
+ };
1322
+
1323
+ const InputTimePicker = ({
1324
+ formField,
1325
+ timePickerProps,
1326
+ unregisterOptions,
1327
+ isUnregisteringOnUnmount
1328
+ }) => {
1329
+ const {
1330
+ control
1331
+ } = useHookFormContext();
1332
+ const hasError = useFormFieldHasError(formField.name);
1333
+ const muiFormControl = useFormControl();
1334
+ const {
1335
+ label,
1336
+ name,
1337
+ required,
1338
+ requiredErrorMessage
1339
+ } = useMergedFormField(formField);
1340
+ useEffectFieldUnregisterOnUnmount({
1341
+ name,
1342
+ unregisterOptions,
1343
+ isUnregisteringOnUnmount
1344
+ });
1345
+ const [date, setDate] = useState(dayjs());
1346
+ const isRequired = required || muiFormControl?.required;
1347
+ const isDisabled = muiFormControl?.disabled || timePickerProps?.disabled;
1348
+ return /*#__PURE__*/jsx(Box, {
1349
+ children: /*#__PURE__*/jsxs(FormControl, {
1350
+ error: hasError,
1351
+ required: isRequired,
1352
+ disabled: isDisabled,
1353
+ children: [/*#__PURE__*/jsx(Controller, {
1354
+ name: name,
1355
+ defaultValue: date,
1356
+ control: control,
1357
+ rules: {
1358
+ required: isRequired ? requiredErrorMessage : false
1359
+ },
1360
+ render: ({
1361
+ field: {
1362
+ onChange,
1363
+ ...restField
1364
+ }
1365
+ }) => /*#__PURE__*/jsx(TimePicker, {
1366
+ label: label,
1367
+ onChange: event => {
1368
+ onChange(event);
1369
+ if (event) {
1370
+ setDate(event);
1371
+ }
1372
+ },
1373
+ disabled: isDisabled,
1374
+ required: isRequired,
1375
+ slotProps: {
1376
+ textField: {
1377
+ required: isRequired,
1378
+ disabled: isDisabled,
1379
+ error: hasError
1380
+ }
1381
+ },
1382
+ ...restField,
1383
+ ...timePickerProps
1384
+ })
1385
+ }), /*#__PURE__*/jsx(FormFieldError, {
1386
+ fieldName: formField.name
1387
+ })]
1388
+ })
1389
+ });
1390
+ };
1391
+
1392
+ const InputToggleButton = ({
1393
+ formField,
1394
+ toggleButtonProps,
1395
+ formControlLabelProps,
1396
+ children,
1397
+ unregisterOptions,
1398
+ isUnregisteringOnUnmount
1399
+ }) => {
1400
+ const {
1401
+ register,
1402
+ control,
1403
+ setValue
1404
+ } = useHookFormContext();
1405
+ const hasError = useFormFieldHasError(formField.name);
1406
+ const muiFormControl = useFormControl();
1407
+ const {
1408
+ label,
1409
+ name,
1410
+ required,
1411
+ requiredErrorMessage,
1412
+ validate
1413
+ } = useMergedFormField(formField);
1414
+ useEffectFieldUnregisterOnUnmount({
1415
+ name,
1416
+ unregisterOptions,
1417
+ isUnregisteringOnUnmount
1418
+ });
1419
+ const id = `hook-form-input-toggle-button-${name}`;
1420
+ const valueToUse = !!useWatch({
1421
+ name: name,
1422
+ control: control,
1423
+ exact: true
1424
+ });
1425
+ assertTruthy(typeof valueToUse === "boolean", `Value (Field: ${name}, value: ${valueToUse?.toString() || "undefined"}) for a InputToggleButton should be undefined or boolean`);
1426
+ const onClick = useCallback(
1427
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1428
+ e => {
1429
+ setValue(name, !valueToUse, {
1430
+ shouldValidate: true,
1431
+ shouldDirty: true,
1432
+ shouldTouch: true
1433
+ });
1434
+ }, [name, setValue, valueToUse]);
1435
+ const isRequired = required || muiFormControl?.required;
1436
+ const isDisabled = muiFormControl?.disabled || toggleButtonProps?.disabled;
1437
+ const registered = register(name, {
1438
+ required: isRequired ? requiredErrorMessage : false,
1439
+ validate,
1440
+ disabled: muiFormControl?.disabled
1441
+ });
1442
+ return /*#__PURE__*/jsxs(FormControl, {
1443
+ error: hasError,
1444
+ disabled: isDisabled,
1445
+ required: isRequired,
1446
+ children: [/*#__PURE__*/jsx(FormControlLabel, {
1447
+ required: isRequired,
1448
+ label: label,
1449
+ labelPlacement: "top",
1450
+ disabled: isDisabled,
1451
+ control: /*#__PURE__*/jsx(ToggleButton, {
1452
+ value: valueToUse,
1453
+ selected: valueToUse,
1454
+ "aria-labelledby": id,
1455
+ onClick: onClick,
1456
+ ...registered,
1457
+ ...toggleButtonProps,
1458
+ children: children
1459
+ }),
1460
+ sx: {
1461
+ alignItems: "flex-start",
1462
+ ml: 0,
1463
+ color: t => hasError ? t.palette.error.main : undefined,
1464
+ ...formControlLabelProps?.sx
1465
+ },
1466
+ ...formControlLabelProps
1467
+ }), /*#__PURE__*/jsx(FormFieldError, {
1468
+ fieldName: formField.name
1469
+ })]
1470
+ });
1471
+ };
1472
+
1473
+ const InputToggleButtonGroup = ({
1474
+ formField,
1475
+ toggleButtonGroupProps,
1476
+ stackProps,
1477
+ typographyProps,
1478
+ buttons,
1479
+ enforceValueSelected = false,
1480
+ unregisterOptions,
1481
+ isUnregisteringOnUnmount
1482
+ }) => {
1483
+ const {
1484
+ register,
1485
+ setValue,
1486
+ control
1487
+ } = useHookFormContext();
1488
+ const hasError = useFormFieldHasError(formField.name);
1489
+ const muiFormControl = useFormControl();
1490
+ const {
1491
+ label: labelText,
1492
+ name,
1493
+ required,
1494
+ requiredErrorMessage,
1495
+ validate
1496
+ } = useMergedFormField(formField);
1497
+ useEffectFieldUnregisterOnUnmount({
1498
+ name,
1499
+ unregisterOptions,
1500
+ isUnregisteringOnUnmount
1501
+ });
1502
+ const changeEv = useCallback((_, value) => {
1503
+ const onSetValue = () => setValue(name, value, {
1504
+ shouldValidate: true,
1505
+ shouldDirty: true,
1506
+ shouldTouch: true
1507
+ });
1508
+ if (enforceValueSelected) {
1509
+ if (toggleButtonGroupProps?.exclusive === true && value !== null) {
1510
+ onSetValue();
1511
+ } else if (toggleButtonGroupProps?.exclusive === false || toggleButtonGroupProps?.exclusive === undefined && value?.length) {
1512
+ onSetValue();
1513
+ }
1514
+ } else {
1515
+ onSetValue();
1516
+ }
1517
+ }, [enforceValueSelected, name, setValue, toggleButtonGroupProps?.exclusive]);
1518
+ const id = `hook-form-input-toggle-button-group-${name}`;
1519
+ const registered = register(name, {
1520
+ required: required ? requiredErrorMessage : false,
1521
+ validate,
1522
+ disabled: muiFormControl?.disabled
1523
+ });
1524
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
1525
+ const valueFromForm = useWatch({
1526
+ name: name,
1527
+ control: control,
1528
+ exact: true
1529
+ });
1530
+ const isRequired = required || muiFormControl?.required;
1531
+ const isDisabled = muiFormControl?.disabled || toggleButtonGroupProps?.disabled;
1532
+ const toggleButtonGroup = /*#__PURE__*/jsx(ToggleButtonGroup, {
1533
+ ...registered,
1534
+ ...toggleButtonGroupProps,
1535
+ onChange: changeEv
1536
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
1537
+ ,
1538
+ value: valueFromForm,
1539
+ children: buttons.map((button, i) => /*#__PURE__*/jsx(ToggleButton
1540
+ // eslint-disable-next-line react/no-array-index-key
1541
+ , {
1542
+ value: button.value,
1543
+ "aria-labelledby": id,
1544
+ ...button.toggleButtonProps,
1545
+ disabled: isDisabled,
1546
+ children: button.icon
1547
+ }, `${button.value.toString()}-${i}`))
1548
+ });
1549
+ const label = /*#__PURE__*/jsx(Typography, {
1550
+ component: "span",
1551
+ ...typographyProps,
1552
+ sx: {
1553
+ color: t => {
1554
+ if (hasError) {
1555
+ return t.palette.error.main;
1556
+ }
1557
+ return isDisabled ? t.palette.text.disabled : undefined;
1558
+ }
1559
+ },
1560
+ children: labelText
1561
+ });
1562
+ return /*#__PURE__*/jsxs(FormControl, {
1563
+ error: hasError,
1564
+ disabled: isDisabled,
1565
+ required: isRequired,
1566
+ children: [formField.label ? /*#__PURE__*/jsxs(Stack, {
1567
+ ...stackProps,
1568
+ children: [isRequired ? /*#__PURE__*/jsxs(Stack, {
1569
+ id: id,
1570
+ component: "label",
1571
+ sx: {
1572
+ display: "block"
1573
+ },
1574
+ children: [label, /*#__PURE__*/jsxs(Box, {
1575
+ component: "span",
1576
+ "aria-hidden": true,
1577
+ sx: {
1578
+ color: hasError ? t => t.palette.error.main : undefined
1579
+ },
1580
+ children: ["\u2009", "*"]
1581
+ })]
1582
+ }) : label, toggleButtonGroup]
1583
+ }) : toggleButtonGroup, /*#__PURE__*/jsx(FormFieldError, {
1584
+ fieldName: formField.name
1585
+ })]
1586
+ });
1587
+ };
1588
+
1589
+ /**
1590
+ * Turn an async submitHandler into a synchronous one.
1591
+ *
1592
+ * Reasoning:
1593
+ * - we're often talking to the API during form submission. The onSubmit handler will be returning a Promise in this case.
1594
+ * - the `form` element, per definition, always expects a synchronous function.
1595
+ * - creating on inline function in every form is a bit clumsy, and does not look clean.
1596
+ *
1597
+ * Then/catch cases should be properly handled by the submit handler itself,
1598
+ * the catch supplied here is only a last safety net against an "unhandled promise rejection" error.
1599
+ */
1600
+ const syncSubmit = asyncSubmitHandler => {
1601
+ return e => {
1602
+ asyncSubmitHandler(e).catch(rethrow);
1603
+ };
1604
+ };
1605
+
1606
+ /**
1607
+ * Wrapper around react-hook-form's useForm.
1608
+ *
1609
+ * Should behave like the original function, only exposing a "fieldName"
1610
+ * function on top which is used to validate field names.
1611
+ */
1612
+ const useHookForm = props => {
1613
+ const form = useForm(props);
1614
+ return {
1615
+ ...form,
1616
+ fieldName: identity
1617
+ };
1618
+ };
1619
+ const useHookFormFieldArray = useFieldArray;
1620
+
1621
+ /**
1622
+ * Reexport of FormProvider.
1623
+ *
1624
+ * This became necessary as context is not available when the FormProvider is initialized outside of the package. Most likely this is some kind of instance mismatch.
1625
+ */
1626
+ const HookFormProvider = FormProvider;
1627
+
1628
+ const InputEmail = props => {
1629
+ const merged = useMergedFormField(props.formField, props.formField.t, formDefaults);
1630
+ const commonProps = useMemo(() => ({
1631
+ textFieldProps: {
1632
+ type: "email",
1633
+ autoComplete: "email",
1634
+ ...props.textFieldProps
1635
+ },
1636
+ formField: merged
1637
+ }), [merged, props.textFieldProps]);
1638
+ return props.isUnregisteringOnUnmount ? /*#__PURE__*/jsx(InputTextField, {
1639
+ ...commonProps,
1640
+ isUnregisteringOnUnmount: props.isUnregisteringOnUnmount,
1641
+ unregisterOptions: props.unregisterOptions
1642
+ }) : /*#__PURE__*/jsx(InputTextField, {
1643
+ ...commonProps,
1644
+ isUnregisteringOnUnmount: props.isUnregisteringOnUnmount
1645
+ });
1646
+ };
1647
+ const formDefaults = {
1648
+ required: true,
1649
+ validate: emailInput => {
1650
+ if (emailInput && emailInput.match(/.@./)) {
1651
+ return true;
1652
+ }
1653
+ return "E-Mail address invalid";
1654
+ }
1655
+ };
1656
+
1657
+ const InputPasswordSet = ({
1658
+ passwordField,
1659
+ passwordValidationField,
1660
+ doNotMatchError,
1661
+ passwordValidationTextFieldProps,
1662
+ passwordTextFieldProps
1663
+ }) => {
1664
+ const {
1665
+ watch
1666
+ } = useHookFormContext();
1667
+ const passwordFieldMerged = useMergedFormField(passwordField, passwordField.t, {
1668
+ required: true
1669
+ });
1670
+ const validationFieldMerged = useMergedFormField(passwordValidationField, passwordValidationField.t, {
1671
+ required: true
1672
+ });
1673
+ const validatePasswordMatch = useCallback(value => {
1674
+ const passwordValue = watch(passwordFieldMerged.name);
1675
+ return value === passwordValue || doNotMatchError;
1676
+ }, [doNotMatchError, passwordFieldMerged.name, watch]);
1677
+ return /*#__PURE__*/jsxs(Fragment, {
1678
+ children: [/*#__PURE__*/jsx(InputTextField, {
1679
+ formField: passwordFieldMerged,
1680
+ textFieldProps: {
1681
+ type: "password",
1682
+ autoComplete: "new-password",
1683
+ ...passwordTextFieldProps
1684
+ }
1685
+ }), /*#__PURE__*/jsx(InputTextField, {
1686
+ formField: {
1687
+ ...validationFieldMerged,
1688
+ validate: validatePasswordMatch,
1689
+ t: passwordValidationField.t
1690
+ },
1691
+ textFieldProps: {
1692
+ type: "password",
1693
+ autoComplete: "new-password",
1694
+ ...passwordValidationTextFieldProps
1695
+ }
1696
+ })]
1697
+ });
1698
+ };
1699
+
1700
+ var LoadingButtonState;
1701
+ (function (LoadingButtonState) {
1702
+ LoadingButtonState["Idle"] = "idle";
1703
+ LoadingButtonState["Loading"] = "loading";
1704
+ LoadingButtonState["Success"] = "success";
1705
+ })(LoadingButtonState || (LoadingButtonState = {}));
1706
+
1707
+ const LoadingButton = ({
1708
+ buttonText,
1709
+ buttonTextSuccess,
1710
+ loadingButtonProps,
1711
+ loadingButtonPropsPropsSuccess,
1712
+ buttonState,
1713
+ successIcon
1714
+ }) => {
1715
+ const isSuccess = buttonState === LoadingButtonState.Success;
1716
+ const propsToSpread = isSuccess ? loadingButtonPropsPropsSuccess : loadingButtonProps;
1717
+ return /*#__PURE__*/jsx(LoadingButton$1, {
1718
+ loading: buttonState === LoadingButtonState.Loading,
1719
+ disabled: buttonState !== LoadingButtonState.Idle,
1720
+ ...propsToSpread,
1721
+ children: buttonState === LoadingButtonState.Success ? /*#__PURE__*/jsxs(Fragment, {
1722
+ children: [successIcon ? successIcon : null, buttonTextSuccess ? buttonTextSuccess : buttonText]
1723
+ }) : buttonText
1724
+ });
1725
+ };
1726
+
1727
+ /**
1728
+ * Get loading button state from react-query mutation status.
1729
+ */
1730
+ const loadingButtonStateFromReactQueryMutationStatus = mutationStatus => {
1731
+ const mapStatus = {
1732
+ idle: LoadingButtonState.Idle,
1733
+ error: LoadingButtonState.Idle,
1734
+ success: LoadingButtonState.Success,
1735
+ loading: LoadingButtonState.Loading
1736
+ };
1737
+ return mapStatus[mutationStatus];
1738
+ };
1739
+ /**
1740
+ * Get loading button state from a react-hook-form context.
1741
+ */
1742
+ const useLoadingButtonStateFromFormContext = () => {
1743
+ const formContext = useHookFormContext();
1744
+ return loadingButtonStateFromFormState(formContext.formState);
1745
+ };
1746
+ /**
1747
+ * Get loading button state from a react-hook-form state.
1748
+ */
1749
+ const loadingButtonStateFromFormState = (
1750
+ // we are not interested in the value types FormState holds
1751
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1752
+ formState) => {
1753
+ if (formState.isSubmitting) {
1754
+ return LoadingButtonState.Loading;
1755
+ }
1756
+ if (formState.isDirty) {
1757
+ return LoadingButtonState.Idle;
1758
+ }
1759
+ if (formState.isSubmitSuccessful) {
1760
+ return LoadingButtonState.Success;
1761
+ }
1762
+ return LoadingButtonState.Idle;
1763
+ };
1764
+
1765
+ export { FormFieldError, FormFieldErrorDisplay, HookFormProvider, InputAutocomplete, InputCheckbox, InputDatePicker, InputDateTimePicker, InputEmail, InputNumber, InputOutlinedInput, InputPasswordSet, InputRadio, InputSelect, InputSelectFromEnum, InputSlider, InputSwitch, InputOutlinedInput as InputText, InputTextField, InputTimePicker, InputToggleButton, InputToggleButtonGroup, LoadingButton, LoadingButtonState, getFormErrorForNestedKeys, loadingButtonStateFromFormState, loadingButtonStateFromReactQueryMutationStatus, syncSubmit, useFormFieldError, useFormFieldHasError, useHookForm, useHookFormContext, useHookFormFieldArray, useLoadingButtonStateFromFormContext, useMergedFormField, useSortedOptionsWithGroup, useTranslateString };
1766
+ //# sourceMappingURL=packageExports.js.map