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

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