@nwon/react-mui-hook-form 3.1.6 → 3.1.11

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