@nwon/react-mui-hook-form 1.2.17 → 1.3.1

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 (28) hide show
  1. package/dist/formFields/HookFormProvider.d.ts +1 -2
  2. package/dist/formFields/InputEmail/InputEmail.d.ts +2 -3
  3. package/dist/formFields/InputPasswordSet/InputPasswordSet.d.ts +1 -1
  4. package/dist/formFields/InputPasswordSet/InputPasswordSetInterfaces.d.ts +3 -0
  5. package/dist/formFields/baseTypes/BaseInputProps.d.ts +33 -0
  6. package/dist/formFields/baseTypes/InputAutocomplete/InputAutocomplete.d.ts +2 -1
  7. package/dist/formFields/baseTypes/InputAutocomplete/InputAutocompleteInterfaces.d.ts +6 -3
  8. package/dist/formFields/baseTypes/InputCheckbox/InputCheckbox.d.ts +2 -3
  9. package/dist/formFields/baseTypes/InputDatePicker/InputDatePicker.d.ts +3 -4
  10. package/dist/formFields/baseTypes/InputDateTimePicker/InputDateTimePicker.d.ts +3 -4
  11. package/dist/formFields/baseTypes/InputNumber/InputNumber.d.ts +2 -3
  12. package/dist/formFields/baseTypes/InputOutlinedInput/InputOutlinedInput.d.ts +2 -3
  13. package/dist/formFields/baseTypes/InputRadio/InputRadio.d.ts +4 -4
  14. package/dist/formFields/baseTypes/InputSelect/InputSelect.d.ts +3 -3
  15. package/dist/formFields/baseTypes/InputSelectFromEnum/InputSelectFromEnum.d.ts +2 -1
  16. package/dist/formFields/baseTypes/InputSlider/InputSlider.d.ts +2 -3
  17. package/dist/formFields/baseTypes/InputSwitch/InputSwitch.d.ts +2 -3
  18. package/dist/formFields/baseTypes/InputTextField/InputTextField.d.ts +3 -4
  19. package/dist/formFields/baseTypes/InputTimePicker/InputTimePicker.d.ts +3 -4
  20. package/dist/formFields/baseTypes/InputToggleButton/InputToggleButton.d.ts +2 -3
  21. package/dist/formFields/baseTypes/InputToggleButtonGroup/InputToggleButtonGroup.d.ts +2 -3
  22. package/dist/formFields/baseTypes/useEffectFieldUnregisterOnUnmount.d.ts +12 -0
  23. package/dist/formFields/formHelper/useHookForm.d.ts +7 -2
  24. package/dist/formFields/index.d.ts +1 -0
  25. package/dist/packageExports.d.ts +1 -1
  26. package/dist/packageExports.js +392 -115
  27. package/dist/packageExports.js.map +1 -1
  28. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  import { CheckBoxOutlineBlank, CheckBox } from '@mui/icons-material';
2
2
  import { FormHelperText, useFormControl, Checkbox, FormControl, Autocomplete, TextField, FormControlLabel, Box, InputLabel, OutlinedInput, FormLabel, RadioGroup, Radio, Select, MenuItem, Stack, Tooltip, ListSubheader, Slider, Switch, ToggleButton, ToggleButtonGroup, Typography } from '@mui/material';
3
3
  import { filterNoUndefinedNoNull, uppercaseFirstLetter, assertTruthy, objectHasKey, rethrow } from '@nvon/baseline';
4
- import { useCallback, useMemo, useState } from 'react';
4
+ import { useCallback, useMemo, useState, useEffect } from 'react';
5
5
  import { useFormContext, useWatch, Controller, useForm, FormProvider } from 'react-hook-form';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
7
  import { identity } from 'lodash-es';
@@ -173,6 +173,38 @@ formFieldDefaults) => {
173
173
  return withPlainStrings;
174
174
  };
175
175
 
176
+ /**
177
+ * An effect that unregisters a field from the form when the component unmounts.
178
+ *
179
+ * @throws Error when FormContext is null.
180
+ */
181
+ const useEffectFieldUnregisterOnUnmount = ({
182
+ name,
183
+ unregisterOptions,
184
+ isUnregisteringOnUnmount
185
+ }) => {
186
+ const form = useHookFormContext();
187
+ /**
188
+ * Default options for unregistering the field.
189
+ *
190
+ * Needed to wrap this in a state in order to prevent infinite rerenders.
191
+ */
192
+ const [options] = useState(unregisterOptions);
193
+ if (!form) {
194
+ throw Error(formContextNull);
195
+ }
196
+ const {
197
+ unregister
198
+ } = form;
199
+ useEffect(() => {
200
+ return () => {
201
+ if (isUnregisteringOnUnmount) {
202
+ unregister(name, options);
203
+ }
204
+ };
205
+ }, [isUnregisteringOnUnmount, name, unregister, options]);
206
+ };
207
+
176
208
  var GroupLabelSorting;
177
209
  (function (GroupLabelSorting) {
178
210
  GroupLabelSorting["Alphabetical"] = "alphabetical";
@@ -234,6 +266,7 @@ const icon = /*#__PURE__*/jsx(CheckBoxOutlineBlank, {
234
266
  const checkedIcon = /*#__PURE__*/jsx(CheckBox, {
235
267
  fontSize: "small"
236
268
  });
269
+ const defaultNonMultiselectValue = "";
237
270
  /**
238
271
  * Renders a MUI autocomplete input that is embedded in a react hook form context.
239
272
  *
@@ -245,7 +278,10 @@ const InputAutocomplete = ({
245
278
  noOptions,
246
279
  autoCompleteProps,
247
280
  checkboxesForMultiselect: renderCheckboxes,
248
- groupSorting
281
+ groupSorting,
282
+ inputTextFieldProps,
283
+ unregisterOptions,
284
+ isUnregisteringOnUnmount
249
285
  }) => {
250
286
  const form = useHookFormContext();
251
287
  if (!form) {
@@ -265,54 +301,84 @@ const InputAutocomplete = ({
265
301
  requiredErrorMessage,
266
302
  validate
267
303
  } = useMergedFormField(formField, formField.t);
268
- const sortedOptions = useSortedOptionsWithGroup$1(selectableOptions, groupSorting);
304
+ useEffectFieldUnregisterOnUnmount({
305
+ name,
306
+ unregisterOptions,
307
+ isUnregisteringOnUnmount
308
+ });
309
+ const multiSelect = !!autoCompleteProps?.multiple;
269
310
  const value = useWatch({
270
311
  name,
271
312
  control
272
313
  });
273
- const multiSelect = !!autoCompleteProps?.multiple;
274
- let valueToUse = value;
275
- if (!value) {
276
- valueToUse = multiSelect ? [] : "";
277
- }
314
+ const {
315
+ value: valueToUse,
316
+ hasValue
317
+ } = useMemo(() => {
318
+ if (value) {
319
+ return {
320
+ value,
321
+ hasValue: true
322
+ };
323
+ }
324
+ return {
325
+ value: multiSelect ? [] : defaultNonMultiselectValue,
326
+ hasValue: false
327
+ };
328
+ }, [multiSelect, value]);
329
+ const adjustedSelectableOptions = useMemo(() => {
330
+ if (hasValue || multiSelect) {
331
+ return selectableOptions;
332
+ }
333
+ return [...selectableOptions, {
334
+ value: defaultNonMultiselectValue,
335
+ label: ""
336
+ }];
337
+ }, [hasValue, multiSelect, selectableOptions]);
338
+ const sortedOptions = useSortedOptionsWithGroup$1(adjustedSelectableOptions, groupSorting);
278
339
  assertTruthy(["string", "number", "object"].includes(typeof valueToUse), `Value (Field: ${name}, value: ${valueToUse?.toString() || "undefined"}) for select input has unexpected type`);
340
+ const isRequired = required || muiFormControl?.required;
341
+ const isDisabled = muiFormControl?.disabled || autoCompleteProps?.disabled;
279
342
  const props = register(name, {
280
- required: required ? requiredErrorMessage : false,
343
+ required: isRequired ? requiredErrorMessage : false,
281
344
  validate,
282
- disabled: muiFormControl?.disabled
345
+ disabled: isDisabled
283
346
  });
284
347
  const currentValue = useMemo(() => {
285
- return multiSelect ? selectableOptions.filter(o => {
348
+ return multiSelect ? adjustedSelectableOptions.filter(o => {
286
349
  if (Array.isArray(valueToUse)) {
287
350
  return valueToUse.includes(o.value);
288
351
  }
289
- return selectableOptions.find(option => option.value === valueToUse);
290
- }) : selectableOptions.find(option => option.value === valueToUse);
291
- }, [multiSelect, selectableOptions, valueToUse]);
352
+ return adjustedSelectableOptions.find(option => option.value === valueToUse);
353
+ }) : adjustedSelectableOptions.find(option => option.value === valueToUse);
354
+ }, [multiSelect, adjustedSelectableOptions, valueToUse]);
292
355
  const renderOption = useMemo(() => {
293
356
  if (autoCompleteProps?.renderOption) {
294
357
  return autoCompleteProps.renderOption;
295
358
  }
296
- return multiSelect && renderCheckboxes ? (liProps, option) => /*#__PURE__*/jsxs("li", {
297
- ...liProps,
298
- children: [/*#__PURE__*/jsx(Checkbox, {
299
- icon: icon,
300
- checkedIcon: checkedIcon,
301
- sx: {
302
- mr: 2
303
- },
304
- checked: Array.isArray(currentValue) ? !!currentValue.find(item => item.value === option.value) : false
305
- }), option.label]
306
- }) : undefined;
359
+ return multiSelect && renderCheckboxes ? (liProps, option) => {
360
+ return /*#__PURE__*/jsxs("li", {
361
+ ...liProps,
362
+ children: [/*#__PURE__*/jsx(Checkbox, {
363
+ icon: icon,
364
+ checkedIcon: checkedIcon,
365
+ sx: {
366
+ mr: 2
367
+ },
368
+ checked: Array.isArray(currentValue) ? !!currentValue.find(item => item.value === option.value) : false
369
+ }), option.label]
370
+ });
371
+ } : undefined;
307
372
  }, [autoCompleteProps?.renderOption, currentValue, multiSelect, renderCheckboxes]);
308
373
  return /*#__PURE__*/jsxs(FormControl, {
309
374
  error: hasError,
310
- required: required,
311
- disabled: muiFormControl?.disabled,
375
+ required: isRequired,
376
+ disabled: isDisabled,
312
377
  children: [/*#__PURE__*/jsx(Autocomplete, {
313
378
  options: sortedOptions,
314
- value: currentValue || "",
379
+ value: currentValue,
315
380
  ...props,
381
+ required: isRequired,
316
382
  label: label,
317
383
  renderOption: renderOption,
318
384
  multiple: multiSelect,
@@ -338,11 +404,20 @@ const InputAutocomplete = ({
338
404
  }
339
405
  },
340
406
  noOptionsText: noOptions,
341
- renderInput: params => /*#__PURE__*/jsx(TextField, {
342
- ...params,
343
- label: label,
344
- variant: "outlined"
345
- }),
407
+ filterOptions: options => {
408
+ return options.filter(o => o.value !== defaultNonMultiselectValue);
409
+ },
410
+ renderInput: params => {
411
+ return /*#__PURE__*/jsx(TextField, {
412
+ ...params,
413
+ label: label,
414
+ variant: "outlined",
415
+ ...inputTextFieldProps,
416
+ required: isRequired,
417
+ disabled: isDisabled,
418
+ error: hasError
419
+ });
420
+ },
346
421
  groupBy: option => option.group || "Choose"
347
422
  // need to parse this as any in order to get no typing errors
348
423
  // for multiselect
@@ -359,7 +434,9 @@ const InputCheckbox = ({
359
434
  formField,
360
435
  jsxLabel,
361
436
  checkboxProps,
362
- formControlLabelProps
437
+ formControlLabelProps,
438
+ unregisterOptions,
439
+ isUnregisteringOnUnmount
363
440
  }) => {
364
441
  const {
365
442
  control,
@@ -374,19 +451,31 @@ const InputCheckbox = ({
374
451
  requiredErrorMessage,
375
452
  validate
376
453
  } = useMergedFormField(formField);
454
+ useEffectFieldUnregisterOnUnmount({
455
+ name,
456
+ unregisterOptions,
457
+ isUnregisteringOnUnmount
458
+ });
377
459
  const id = `hook-form-input-checkbox-${name}`;
460
+ const disabled = muiFormControl?.disabled || checkboxProps?.disabled;
461
+ const isRequired = required || muiFormControl?.required;
378
462
  return /*#__PURE__*/jsxs(FormControl, {
379
463
  error: hasError,
380
- disabled: muiFormControl?.disabled,
464
+ disabled: disabled,
465
+ required: required,
381
466
  children: [/*#__PURE__*/jsx(FormControlLabel, {
382
- required: jsxLabel ? false : required // If jsxLabel is set, we don't want to show the asterisk.
467
+ required: jsxLabel ? false : isRequired // If jsxLabel is set, we don't want to show the asterisk.
383
468
  ,
384
- disabled: muiFormControl?.disabled || checkboxProps?.disabled,
469
+ disabled: disabled,
470
+ label: jsxLabel ?? label,
471
+ sx: {
472
+ color: t => hasError ? t.palette.error.main : undefined
473
+ },
385
474
  control: /*#__PURE__*/jsx(Controller, {
386
475
  name: name,
387
476
  control: control,
388
477
  rules: {
389
- required: required ? requiredErrorMessage : false,
478
+ required: isRequired ? requiredErrorMessage : false,
390
479
  validate
391
480
  },
392
481
  render: ({
@@ -404,11 +493,11 @@ const InputCheckbox = ({
404
493
  shouldTouch: true
405
494
  });
406
495
  },
407
- ...checkboxProps
496
+ ...checkboxProps,
497
+ disabled: disabled
408
498
  });
409
499
  }
410
500
  }),
411
- label: jsxLabel ?? label,
412
501
  ...formControlLabelProps
413
502
  }), /*#__PURE__*/jsx(FormFieldError, {
414
503
  fieldName: formField.name
@@ -418,7 +507,9 @@ const InputCheckbox = ({
418
507
 
419
508
  const InputDatePicker = ({
420
509
  formField,
421
- datePickerProps
510
+ datePickerProps,
511
+ unregisterOptions,
512
+ isUnregisteringOnUnmount
422
513
  }) => {
423
514
  const {
424
515
  control
@@ -428,18 +519,29 @@ const InputDatePicker = ({
428
519
  const {
429
520
  label,
430
521
  name,
431
- required
522
+ required,
523
+ requiredErrorMessage
432
524
  } = useMergedFormField(formField);
525
+ useEffectFieldUnregisterOnUnmount({
526
+ name,
527
+ unregisterOptions,
528
+ isUnregisteringOnUnmount
529
+ });
433
530
  const [date, setDate] = useState(dayjs());
531
+ const isRequired = required || muiFormControl?.required;
532
+ const isDisabled = muiFormControl?.disabled || datePickerProps?.disabled;
434
533
  return /*#__PURE__*/jsx(Box, {
435
534
  children: /*#__PURE__*/jsxs(FormControl, {
436
535
  error: hasError,
437
- required: required,
438
- disabled: muiFormControl?.disabled,
536
+ required: isRequired,
537
+ disabled: isDisabled,
439
538
  children: [/*#__PURE__*/jsx(Controller, {
440
539
  name: name,
441
540
  defaultValue: date,
442
541
  control: control,
542
+ rules: {
543
+ required: isRequired ? requiredErrorMessage : false
544
+ },
443
545
  render: ({
444
546
  field: {
445
547
  onChange,
@@ -453,7 +555,14 @@ const InputDatePicker = ({
453
555
  setDate(event);
454
556
  }
455
557
  },
456
- disabled: muiFormControl?.disabled,
558
+ disabled: isDisabled,
559
+ slotProps: {
560
+ textField: {
561
+ required: isRequired,
562
+ disabled: isDisabled,
563
+ error: hasError
564
+ }
565
+ },
457
566
  ...restField,
458
567
  ...datePickerProps
459
568
  })
@@ -466,7 +575,9 @@ const InputDatePicker = ({
466
575
 
467
576
  const InputDateTimePicker = ({
468
577
  formField,
469
- dateTimePickerProps
578
+ dateTimePickerProps,
579
+ unregisterOptions,
580
+ isUnregisteringOnUnmount
470
581
  }) => {
471
582
  const {
472
583
  control
@@ -476,18 +587,29 @@ const InputDateTimePicker = ({
476
587
  const {
477
588
  label,
478
589
  name,
479
- required
590
+ required,
591
+ requiredErrorMessage
480
592
  } = useMergedFormField(formField);
593
+ useEffectFieldUnregisterOnUnmount({
594
+ name,
595
+ unregisterOptions,
596
+ isUnregisteringOnUnmount
597
+ });
481
598
  const [date, setDate] = useState(dayjs());
599
+ const isRequired = required || muiFormControl?.required;
600
+ const isDisabled = muiFormControl?.disabled || dateTimePickerProps?.disabled;
482
601
  return /*#__PURE__*/jsx(Box, {
483
602
  children: /*#__PURE__*/jsxs(FormControl, {
484
603
  error: hasError,
485
- required: required,
486
- disabled: muiFormControl?.disabled,
604
+ required: isRequired,
605
+ disabled: isDisabled,
487
606
  children: [/*#__PURE__*/jsx(Controller, {
488
607
  name: name,
489
608
  defaultValue: date,
490
609
  control: control,
610
+ rules: {
611
+ required: isRequired ? requiredErrorMessage : false
612
+ },
491
613
  render: ({
492
614
  field: {
493
615
  onChange,
@@ -502,7 +624,15 @@ const InputDateTimePicker = ({
502
624
  setDate(event);
503
625
  }
504
626
  },
505
- disabled: muiFormControl?.disabled,
627
+ disabled: isDisabled,
628
+ required: isRequired,
629
+ slotProps: {
630
+ textField: {
631
+ required: isRequired,
632
+ disabled: isDisabled,
633
+ error: hasError
634
+ }
635
+ },
506
636
  ...restField,
507
637
  ...dateTimePickerProps
508
638
  })
@@ -516,7 +646,9 @@ const InputDateTimePicker = ({
516
646
  const InputNumber = ({
517
647
  formField,
518
648
  textFieldProps,
519
- numericFormatProps
649
+ numericFormatProps,
650
+ unregisterOptions,
651
+ isUnregisteringOnUnmount
520
652
  }) => {
521
653
  const form = useHookFormContext();
522
654
  const {
@@ -530,19 +662,26 @@ const InputNumber = ({
530
662
  requiredErrorMessage,
531
663
  validate
532
664
  } = useMergedFormField(formField, formField.t);
665
+ useEffectFieldUnregisterOnUnmount({
666
+ name,
667
+ unregisterOptions,
668
+ isUnregisteringOnUnmount
669
+ });
533
670
  if (!form) {
534
671
  throw Error(formContextNull);
535
672
  }
536
673
  const hasError = useFormFieldHasError(formField.name);
674
+ const isRequired = required || muiFormControl?.required;
675
+ const isDisabled = muiFormControl?.disabled || textFieldProps?.disabled;
537
676
  return /*#__PURE__*/jsxs(FormControl, {
538
677
  error: hasError,
539
678
  required: required,
540
- disabled: muiFormControl?.disabled,
679
+ disabled: isDisabled,
541
680
  children: [/*#__PURE__*/jsx(Controller, {
542
681
  name: name,
543
682
  control: control,
544
683
  rules: {
545
- required: required ? requiredErrorMessage : false,
684
+ required: isRequired ? requiredErrorMessage : false,
546
685
  validate
547
686
  },
548
687
  render: props => {
@@ -560,12 +699,13 @@ const InputNumber = ({
560
699
  rest.onChange(target.value);
561
700
  },
562
701
  label: label,
563
- required: required,
564
702
  onChange: undefined,
565
703
  onBlur: props.field.onBlur,
566
704
  error: !!props.fieldState.error,
567
705
  ...textFieldProps,
568
- ...numericFormatProps
706
+ ...numericFormatProps,
707
+ disabled: isDisabled,
708
+ required: isRequired
569
709
  })
570
710
  );
571
711
  }
@@ -577,7 +717,9 @@ const InputNumber = ({
577
717
 
578
718
  const InputOutlinedInput = ({
579
719
  formField,
580
- outlinedInputProps
720
+ outlinedInputProps,
721
+ unregisterOptions,
722
+ isUnregisteringOnUnmount
581
723
  }) => {
582
724
  const form = useHookFormContext();
583
725
  const muiFormControl = useFormControl();
@@ -588,6 +730,11 @@ const InputOutlinedInput = ({
588
730
  requiredErrorMessage,
589
731
  validate
590
732
  } = useMergedFormField(formField, formField.t);
733
+ useEffectFieldUnregisterOnUnmount({
734
+ name,
735
+ unregisterOptions,
736
+ isUnregisteringOnUnmount
737
+ });
591
738
  if (!form) {
592
739
  throw Error(formContextNull);
593
740
  }
@@ -595,18 +742,21 @@ const InputOutlinedInput = ({
595
742
  control
596
743
  } = form;
597
744
  const hasError = useFormFieldHasError(formField.name);
745
+ const isRequired = required || muiFormControl?.required;
746
+ const isDisabled = muiFormControl?.disabled || outlinedInputProps?.disabled;
598
747
  return /*#__PURE__*/jsxs(FormControl, {
599
748
  error: hasError,
600
749
  required: required,
601
750
  disabled: muiFormControl?.disabled,
602
751
  children: [/*#__PURE__*/jsx(InputLabel, {
603
- required: required,
752
+ required: isRequired,
753
+ disabled: isDisabled,
604
754
  children: label
605
755
  }), /*#__PURE__*/jsx(Controller, {
606
756
  name: name,
607
757
  control: control,
608
758
  rules: {
609
- required: required ? requiredErrorMessage : false,
759
+ required: isRequired ? requiredErrorMessage : false,
610
760
  validate
611
761
  },
612
762
  render: ({
@@ -620,10 +770,10 @@ const InputOutlinedInput = ({
620
770
  value: value,
621
771
  onChange: onChange,
622
772
  onBlur: onBlur,
623
- disabled: muiFormControl?.disabled,
624
- required: required,
625
773
  label: label,
626
- ...outlinedInputProps
774
+ ...outlinedInputProps,
775
+ required: isRequired,
776
+ disabled: isDisabled
627
777
  });
628
778
  }
629
779
  }), /*#__PURE__*/jsx(FormFieldError, {
@@ -636,7 +786,9 @@ const InputRadio = ({
636
786
  formField,
637
787
  selectableOptions,
638
788
  formControlLabelProps,
639
- radioGroupProps
789
+ radioGroupProps,
790
+ unregisterOptions,
791
+ isUnregisteringOnUnmount
640
792
  }) => {
641
793
  const {
642
794
  control
@@ -650,20 +802,31 @@ const InputRadio = ({
650
802
  requiredErrorMessage,
651
803
  validate
652
804
  } = useMergedFormField(formField);
805
+ useEffectFieldUnregisterOnUnmount({
806
+ name,
807
+ unregisterOptions,
808
+ isUnregisteringOnUnmount
809
+ });
653
810
  const id = `hook-form-input-radio-${name}`;
811
+ const isRequired = required || muiFormControl?.required;
812
+ const isDisabled = muiFormControl?.disabled || formControlLabelProps?.disabled;
654
813
  return /*#__PURE__*/jsxs(FormControl, {
655
814
  error: hasError,
656
815
  disabled: muiFormControl?.disabled,
657
816
  children: [/*#__PURE__*/jsx(FormLabel, {
658
817
  id: id,
659
- required: required,
818
+ required: isRequired,
819
+ disabled: isDisabled,
820
+ error: hasError,
821
+ sx: {
822
+ color: t => hasError ? t.palette.error.main : undefined
823
+ },
660
824
  children: label
661
825
  }), /*#__PURE__*/jsx(Controller, {
662
826
  name: name,
663
827
  control: control,
664
- defaultValue: 0,
665
828
  rules: {
666
- required: required ? requiredErrorMessage : false,
829
+ required: isRequired ? requiredErrorMessage : false,
667
830
  validate
668
831
  },
669
832
  render: ({
@@ -684,7 +847,8 @@ const InputRadio = ({
684
847
  value: option.value,
685
848
  control: /*#__PURE__*/jsx(Radio, {}),
686
849
  label: option.label,
687
- ...formControlLabelProps
850
+ ...formControlLabelProps,
851
+ disabled: isDisabled
688
852
  }, option.value);
689
853
  })
690
854
  });
@@ -718,7 +882,9 @@ const InputSelect = ({
718
882
  selectableOptions,
719
883
  optionsTitle,
720
884
  selectComponentProps,
721
- tooltipHolder
885
+ tooltipHolder,
886
+ unregisterOptions,
887
+ isUnregisteringOnUnmount
722
888
  }) => {
723
889
  const form = useHookFormContext();
724
890
  if (!form) {
@@ -735,7 +901,12 @@ const InputSelect = ({
735
901
  requiredErrorMessage,
736
902
  validate
737
903
  } = useMergedFormField(formField, formField.t);
738
- const defaultValue = selectComponentProps?.multiple ? [] : "";
904
+ useEffectFieldUnregisterOnUnmount({
905
+ name,
906
+ unregisterOptions,
907
+ isUnregisteringOnUnmount
908
+ });
909
+ const defaultValue = useMemo(() => selectComponentProps?.multiple ? [] : "", [selectComponentProps?.multiple]);
739
910
  const valueFromForm = useWatch({
740
911
  name,
741
912
  control,
@@ -747,21 +918,29 @@ const InputSelect = ({
747
918
  assertTruthy(["string", "number"].includes(typeof valueFromForm), `Value (Field: ${name}, value: ${valueFromForm?.toString() || "undefined"}) for select input has unexpected type`);
748
919
  }
749
920
  const id = `input-select-${name}`;
750
- const sortedOptions = useSortedOptionsWithGroup(selectableOptions);
921
+ const adjustedOptions = useMemo(() => selectComponentProps?.multiple || Array.isArray(defaultValue) ? selectableOptions : [...selectableOptions, {
922
+ value: defaultValue,
923
+ label: ""
924
+ }], [defaultValue, selectComponentProps?.multiple, selectableOptions]);
925
+ const sortedOptions = useSortedOptionsWithGroup(adjustedOptions);
751
926
  const hasErrors = useFormFieldHasError(formField.name);
927
+ const isRequired = required || muiFormControl?.required;
928
+ const isDisabled = muiFormControl?.disabled || selectComponentProps?.disabled;
752
929
  return /*#__PURE__*/jsxs(FormControl, {
753
930
  error: hasErrors,
754
- required: required,
755
- disabled: muiFormControl?.disabled,
931
+ required: isRequired,
932
+ disabled: isDisabled,
756
933
  children: [/*#__PURE__*/jsx(InputLabel, {
757
934
  id: id,
758
- required: required,
935
+ required: isRequired,
936
+ disabled: isDisabled,
937
+ error: hasErrors,
759
938
  children: label
760
939
  }), /*#__PURE__*/jsx(Controller, {
761
940
  name: name,
762
941
  control: control,
763
942
  rules: {
764
- required: required ? requiredErrorMessage : false,
943
+ required: isRequired ? requiredErrorMessage : false,
765
944
  validate
766
945
  },
767
946
  render: ({
@@ -783,20 +962,22 @@ const InputSelect = ({
783
962
  error: !!error,
784
963
  onChange: onChange,
785
964
  onBlur: onBlur,
965
+ disabled: isDisabled,
966
+ required: isRequired,
786
967
  children: [optionsTitle && /*#__PURE__*/jsx(MenuItem, {
787
968
  value: defaultValue,
788
969
  disabled: true,
789
970
  children: /*#__PURE__*/jsx("em", {
790
971
  children: optionsTitle
791
972
  })
792
- }), sortedOptions?.map((option, index) => {
973
+ }), sortedOptions?.filter(o => o.value !== "").map((option, index) => {
793
974
  const optionBefore = sortedOptions[index - 1];
794
975
  const showGroup = (optionBefore || index == 0) && option.group && optionBefore?.group !== option.group;
795
976
  const disabledText = typeof option.disabled === "string" ? option.disabled : undefined;
796
- const isDisabled = !!disabledText || !!option.disabled;
977
+ const isDisabledToUse = !!disabledText || !!option.disabled || isDisabled;
797
978
  const menuItem = /*#__PURE__*/jsx(MenuItem, {
798
979
  value: option.value,
799
- disabled: isDisabled,
980
+ disabled: isDisabledToUse,
800
981
  title: typeof option.disabled === "string" ? option.disabled : undefined,
801
982
  selected: value === option.value,
802
983
  children: option.label
@@ -865,7 +1046,9 @@ const InputSelectFromEnum = props => {
865
1046
 
866
1047
  const InputSlider = ({
867
1048
  formField,
868
- sliderProps
1049
+ sliderProps,
1050
+ unregisterOptions,
1051
+ isUnregisteringOnUnmount
869
1052
  }) => {
870
1053
  const form = useHookFormContext();
871
1054
  const muiFormControl = useFormControl();
@@ -876,6 +1059,11 @@ const InputSlider = ({
876
1059
  requiredErrorMessage,
877
1060
  validate
878
1061
  } = useMergedFormField(formField, formField.t);
1062
+ useEffectFieldUnregisterOnUnmount({
1063
+ name,
1064
+ unregisterOptions,
1065
+ isUnregisteringOnUnmount
1066
+ });
879
1067
  if (!form) {
880
1068
  throw Error(formContextNull);
881
1069
  }
@@ -883,16 +1071,18 @@ const InputSlider = ({
883
1071
  control
884
1072
  } = form;
885
1073
  const hasError = useFormFieldHasError(formField.name);
1074
+ const isRequired = required || muiFormControl?.required;
1075
+ const isDisabled = muiFormControl?.disabled || sliderProps?.disabled;
886
1076
  return /*#__PURE__*/jsxs(FormControl, {
887
1077
  error: hasError,
888
- required: required,
889
- disabled: muiFormControl?.disabled,
1078
+ required: isRequired,
1079
+ disabled: isDisabled,
890
1080
  children: [/*#__PURE__*/jsx(Controller, {
891
1081
  name: name,
892
1082
  control: control,
893
1083
  defaultValue: 0,
894
1084
  rules: {
895
- required: required ? requiredErrorMessage : false,
1085
+ required: isRequired ? requiredErrorMessage : false,
896
1086
  validate
897
1087
  },
898
1088
  render: ({
@@ -906,12 +1096,13 @@ const InputSlider = ({
906
1096
  value: value || 0,
907
1097
  onChange: onChange,
908
1098
  onBlur: onBlur,
909
- required: required,
1099
+ required: isRequired,
910
1100
  label: label,
911
1101
  component: sliderProps?.component || "span",
912
1102
  max: typeof sliderProps?.max === "number" ? sliderProps.max : undefined,
913
1103
  min: typeof sliderProps?.min === "number" ? sliderProps.min : undefined,
914
- ...sliderProps
1104
+ ...sliderProps,
1105
+ disabled: isDisabled
915
1106
  });
916
1107
  }
917
1108
  }), /*#__PURE__*/jsx(FormFieldError, {
@@ -923,7 +1114,9 @@ const InputSlider = ({
923
1114
  const InputSwitch = ({
924
1115
  formField,
925
1116
  switchProps,
926
- formControlLabelProps
1117
+ formControlLabelProps,
1118
+ unregisterOptions,
1119
+ isUnregisteringOnUnmount
927
1120
  }) => {
928
1121
  const {
929
1122
  control,
@@ -937,17 +1130,29 @@ const InputSwitch = ({
937
1130
  requiredErrorMessage,
938
1131
  validate
939
1132
  } = useMergedFormField(formField);
1133
+ useEffectFieldUnregisterOnUnmount({
1134
+ name,
1135
+ unregisterOptions,
1136
+ isUnregisteringOnUnmount
1137
+ });
1138
+ const isRequired = required || muiFormControl?.required;
1139
+ const isDisabled = muiFormControl?.disabled || switchProps?.disabled;
940
1140
  return /*#__PURE__*/jsxs(FormControl, {
941
1141
  error: hasError,
942
- disabled: muiFormControl?.disabled,
1142
+ disabled: isDisabled,
1143
+ required: isRequired,
943
1144
  children: [/*#__PURE__*/jsx(FormControlLabel, {
944
1145
  label: formField.label,
945
- disabled: muiFormControl?.disabled || switchProps?.disabled,
1146
+ disabled: isDisabled,
1147
+ required: isRequired,
1148
+ sx: {
1149
+ color: t => hasError ? t.palette.error.main : undefined
1150
+ },
946
1151
  control: /*#__PURE__*/jsx(Controller, {
947
1152
  name: name,
948
1153
  control: control,
949
1154
  rules: {
950
- required: required ? requiredErrorMessage : false,
1155
+ required: isRequired ? requiredErrorMessage : false,
951
1156
  validate
952
1157
  },
953
1158
  render: ({
@@ -977,7 +1182,9 @@ const InputSwitch = ({
977
1182
 
978
1183
  const InputTextField = ({
979
1184
  formField,
980
- textFieldProps
1185
+ textFieldProps,
1186
+ unregisterOptions,
1187
+ isUnregisteringOnUnmount
981
1188
  }) => {
982
1189
  const form = useHookFormContext();
983
1190
  const {
@@ -991,19 +1198,26 @@ const InputTextField = ({
991
1198
  requiredErrorMessage,
992
1199
  validate
993
1200
  } = useMergedFormField(formField, formField.t);
1201
+ useEffectFieldUnregisterOnUnmount({
1202
+ name,
1203
+ unregisterOptions,
1204
+ isUnregisteringOnUnmount
1205
+ });
994
1206
  if (!form) {
995
1207
  throw Error(formContextNull);
996
1208
  }
997
1209
  const hasError = useFormFieldHasError(formField.name);
1210
+ const isRequired = required || muiFormControl?.required;
1211
+ const isDisabled = muiFormControl?.disabled || textFieldProps?.disabled;
998
1212
  return /*#__PURE__*/jsxs(FormControl, {
999
1213
  error: hasError,
1000
- required: required,
1001
- disabled: muiFormControl?.disabled,
1214
+ required: isRequired,
1215
+ disabled: isDisabled,
1002
1216
  children: [/*#__PURE__*/jsx(Controller, {
1003
1217
  name: name,
1004
1218
  control: control,
1005
1219
  rules: {
1006
- required: required ? requiredErrorMessage : false,
1220
+ required: isRequired ? requiredErrorMessage : false,
1007
1221
  validate
1008
1222
  },
1009
1223
  render: ({
@@ -1019,10 +1233,10 @@ const InputTextField = ({
1019
1233
  error: !!error,
1020
1234
  onChange: onChange,
1021
1235
  value: value,
1022
- disabled: muiFormControl?.disabled,
1023
1236
  label: label,
1024
- required: required,
1025
- ...textFieldProps
1237
+ ...textFieldProps,
1238
+ required: isRequired,
1239
+ disabled: isDisabled
1026
1240
  });
1027
1241
  }
1028
1242
  }), /*#__PURE__*/jsx(FormFieldError, {
@@ -1034,7 +1248,9 @@ const InputTextField = ({
1034
1248
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
1035
1249
  const InputTimePicker = ({
1036
1250
  formField,
1037
- timePickerProps
1251
+ timePickerProps,
1252
+ unregisterOptions,
1253
+ isUnregisteringOnUnmount
1038
1254
  }) => {
1039
1255
  const {
1040
1256
  control
@@ -1044,18 +1260,29 @@ const InputTimePicker = ({
1044
1260
  const {
1045
1261
  label,
1046
1262
  name,
1047
- required
1263
+ required,
1264
+ requiredErrorMessage
1048
1265
  } = useMergedFormField(formField);
1266
+ useEffectFieldUnregisterOnUnmount({
1267
+ name,
1268
+ unregisterOptions,
1269
+ isUnregisteringOnUnmount
1270
+ });
1049
1271
  const [date, setDate] = useState(dayjs());
1272
+ const isRequired = required || muiFormControl?.required;
1273
+ const isDisabled = muiFormControl?.disabled || timePickerProps?.disabled;
1050
1274
  return /*#__PURE__*/jsx(Box, {
1051
1275
  children: /*#__PURE__*/jsxs(FormControl, {
1052
1276
  error: hasError,
1053
- required: required,
1054
- disabled: muiFormControl?.disabled,
1277
+ required: isRequired,
1278
+ disabled: isDisabled,
1055
1279
  children: [/*#__PURE__*/jsx(Controller, {
1056
1280
  name: name,
1057
1281
  defaultValue: date,
1058
1282
  control: control,
1283
+ rules: {
1284
+ required: isRequired ? requiredErrorMessage : false
1285
+ },
1059
1286
  render: ({
1060
1287
  field: {
1061
1288
  onChange,
@@ -1069,7 +1296,15 @@ const InputTimePicker = ({
1069
1296
  setDate(event);
1070
1297
  }
1071
1298
  },
1072
- disabled: muiFormControl?.disabled,
1299
+ disabled: isDisabled,
1300
+ required: isRequired,
1301
+ slotProps: {
1302
+ textField: {
1303
+ required: isRequired,
1304
+ disabled: isDisabled,
1305
+ error: hasError
1306
+ }
1307
+ },
1073
1308
  ...restField,
1074
1309
  ...timePickerProps
1075
1310
  })
@@ -1084,7 +1319,9 @@ const InputToggleButton = ({
1084
1319
  formField,
1085
1320
  toggleButtonProps,
1086
1321
  formControlLabelProps,
1087
- children
1322
+ children,
1323
+ unregisterOptions,
1324
+ isUnregisteringOnUnmount
1088
1325
  }) => {
1089
1326
  const {
1090
1327
  register,
@@ -1099,6 +1336,11 @@ const InputToggleButton = ({
1099
1336
  requiredErrorMessage,
1100
1337
  validate
1101
1338
  } = useMergedFormField(formField);
1339
+ useEffectFieldUnregisterOnUnmount({
1340
+ name,
1341
+ unregisterOptions,
1342
+ isUnregisteringOnUnmount
1343
+ });
1102
1344
  const id = `hook-form-input-toggle-button-${name}`;
1103
1345
  const valueToUse = !!useWatch({
1104
1346
  name: name,
@@ -1114,19 +1356,22 @@ const InputToggleButton = ({
1114
1356
  shouldTouch: true
1115
1357
  });
1116
1358
  }, [name, setValue, valueToUse]);
1359
+ const isRequired = required || muiFormControl?.required;
1360
+ const isDisabled = muiFormControl?.disabled || toggleButtonProps?.disabled;
1117
1361
  const registered = register(name, {
1118
- required: required ? requiredErrorMessage : false,
1362
+ required: isRequired ? requiredErrorMessage : false,
1119
1363
  validate,
1120
1364
  disabled: muiFormControl?.disabled
1121
1365
  });
1122
1366
  return /*#__PURE__*/jsxs(FormControl, {
1123
1367
  error: hasError,
1124
- disabled: muiFormControl?.disabled,
1368
+ disabled: isDisabled,
1369
+ required: isRequired,
1125
1370
  children: [/*#__PURE__*/jsx(FormControlLabel, {
1126
- required: required,
1371
+ required: isRequired,
1127
1372
  label: formField.label,
1128
1373
  labelPlacement: "top",
1129
- disabled: muiFormControl?.disabled || toggleButtonProps?.disabled,
1374
+ disabled: isDisabled,
1130
1375
  control: /*#__PURE__*/jsx(ToggleButton, {
1131
1376
  value: valueToUse,
1132
1377
  selected: valueToUse,
@@ -1139,6 +1384,7 @@ const InputToggleButton = ({
1139
1384
  sx: {
1140
1385
  alignItems: "flex-start",
1141
1386
  ml: 0,
1387
+ color: t => hasError ? t.palette.error.main : undefined,
1142
1388
  ...formControlLabelProps?.sx
1143
1389
  },
1144
1390
  ...formControlLabelProps
@@ -1154,7 +1400,9 @@ const InputToggleButtonGroup = ({
1154
1400
  stackProps,
1155
1401
  typographyProps,
1156
1402
  buttons,
1157
- enforceValueSelected = false
1403
+ enforceValueSelected = false,
1404
+ unregisterOptions,
1405
+ isUnregisteringOnUnmount
1158
1406
  }) => {
1159
1407
  const {
1160
1408
  register,
@@ -1169,6 +1417,11 @@ const InputToggleButtonGroup = ({
1169
1417
  requiredErrorMessage,
1170
1418
  validate
1171
1419
  } = useMergedFormField(formField);
1420
+ useEffectFieldUnregisterOnUnmount({
1421
+ name,
1422
+ unregisterOptions,
1423
+ isUnregisteringOnUnmount
1424
+ });
1172
1425
  const changeEv = useCallback((_, value) => {
1173
1426
  const onSetValue = () => setValue(name, value, {
1174
1427
  shouldValidate: true,
@@ -1196,6 +1449,8 @@ const InputToggleButtonGroup = ({
1196
1449
  name: name,
1197
1450
  control: control
1198
1451
  });
1452
+ const isRequired = required || muiFormControl?.required;
1453
+ const isDisabled = muiFormControl?.disabled || toggleButtonGroupProps?.disabled;
1199
1454
  const toggleButtonGroup = /*#__PURE__*/jsx(ToggleButtonGroup, {
1200
1455
  ...registered,
1201
1456
  ...toggleButtonGroupProps,
@@ -1209,20 +1464,30 @@ const InputToggleButtonGroup = ({
1209
1464
  value: button.value,
1210
1465
  "aria-labelledby": id,
1211
1466
  ...button.toggleButtonProps,
1467
+ disabled: isDisabled,
1212
1468
  children: button.icon
1213
1469
  }, `${button.value.toString()}-${i}`))
1214
1470
  });
1215
1471
  const label = /*#__PURE__*/jsx(Typography, {
1216
1472
  component: "span",
1217
1473
  ...typographyProps,
1474
+ sx: {
1475
+ color: t => {
1476
+ if (hasError) {
1477
+ return t.palette.error.main;
1478
+ }
1479
+ return isDisabled ? t.palette.text.disabled : undefined;
1480
+ }
1481
+ },
1218
1482
  children: formField.label
1219
1483
  });
1220
1484
  return /*#__PURE__*/jsxs(FormControl, {
1221
1485
  error: hasError,
1222
- disabled: muiFormControl?.disabled,
1486
+ disabled: isDisabled,
1487
+ required: isRequired,
1223
1488
  children: [formField.label ? /*#__PURE__*/jsxs(Stack, {
1224
1489
  ...stackProps,
1225
- children: [required ? /*#__PURE__*/jsxs(Stack, {
1490
+ children: [isRequired ? /*#__PURE__*/jsxs(Stack, {
1226
1491
  id: id,
1227
1492
  component: "label",
1228
1493
  sx: {
@@ -1283,19 +1548,27 @@ const HookFormProvider = FormProvider;
1283
1548
 
1284
1549
  const InputEmail = props => {
1285
1550
  const merged = useMergedFormField(props.formField, props.formField.t, formDefaults);
1286
- return /*#__PURE__*/jsx(InputTextField, {
1551
+ const commonProps = useMemo(() => ({
1287
1552
  textFieldProps: {
1288
1553
  type: "email",
1289
1554
  autoComplete: "email",
1290
1555
  ...props.textFieldProps
1291
1556
  },
1292
1557
  formField: merged
1558
+ }), [merged, props.textFieldProps]);
1559
+ return props.isUnregisteringOnUnmount ? /*#__PURE__*/jsx(InputTextField, {
1560
+ ...commonProps,
1561
+ isUnregisteringOnUnmount: props.isUnregisteringOnUnmount,
1562
+ unregisterOptions: props.unregisterOptions
1563
+ }) : /*#__PURE__*/jsx(InputTextField, {
1564
+ ...commonProps,
1565
+ isUnregisteringOnUnmount: props.isUnregisteringOnUnmount
1293
1566
  });
1294
1567
  };
1295
1568
  const formDefaults = {
1296
1569
  required: true,
1297
1570
  validate: emailInput => {
1298
- if (emailInput.match(/.@./)) {
1571
+ if (emailInput && emailInput.match(/.@./)) {
1299
1572
  return true;
1300
1573
  }
1301
1574
  return "E-Mail address invalid";
@@ -1305,7 +1578,9 @@ const formDefaults = {
1305
1578
  const InputPasswordSet = ({
1306
1579
  passwordField,
1307
1580
  passwordValidationField,
1308
- doNotMatchError
1581
+ doNotMatchError,
1582
+ passwordValidationTextFieldProps,
1583
+ passwordTextFieldProps
1309
1584
  }) => {
1310
1585
  const {
1311
1586
  watch
@@ -1321,21 +1596,23 @@ const InputPasswordSet = ({
1321
1596
  return value === passwordValue || doNotMatchError;
1322
1597
  }, [doNotMatchError, passwordFieldMerged.name, watch]);
1323
1598
  return /*#__PURE__*/jsxs(Fragment, {
1324
- children: [/*#__PURE__*/jsx(InputOutlinedInput, {
1599
+ children: [/*#__PURE__*/jsx(InputTextField, {
1325
1600
  formField: passwordFieldMerged,
1326
- outlinedInputProps: {
1601
+ textFieldProps: {
1327
1602
  type: "password",
1328
- autoComplete: "new-password"
1603
+ autoComplete: "new-password",
1604
+ ...passwordTextFieldProps
1329
1605
  }
1330
- }), /*#__PURE__*/jsx(InputOutlinedInput, {
1606
+ }), /*#__PURE__*/jsx(InputTextField, {
1331
1607
  formField: {
1332
1608
  ...validationFieldMerged,
1333
1609
  validate: validatePasswordMatch,
1334
1610
  t: passwordValidationField.t
1335
1611
  },
1336
- outlinedInputProps: {
1612
+ textFieldProps: {
1337
1613
  type: "password",
1338
- autoComplete: "new-password"
1614
+ autoComplete: "new-password",
1615
+ ...passwordValidationTextFieldProps
1339
1616
  }
1340
1617
  })]
1341
1618
  });