@nwon/react-mui-hook-form 1.0.3 → 1.0.4

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 (33) hide show
  1. package/README.md +1 -1
  2. package/dist/LoadingButton/LoadingButton.d.ts +6 -0
  3. package/dist/LoadingButton/LoadingButtonInterfaces.d.ts +33 -0
  4. package/dist/LoadingButton/getLoadingButtonState.d.ts +20 -0
  5. package/dist/LoadingButton/index.d.ts +4 -0
  6. package/dist/formFields/HookFormProvider.d.ts +7 -0
  7. package/dist/formFields/InputEmail/InputEmail.d.ts +11 -0
  8. package/dist/formFields/InputPasswordSet/InputPasswordSet.d.ts +8 -0
  9. package/dist/formFields/InputPasswordSet/InputPasswordSetInterfaces.d.ts +15 -0
  10. package/dist/formFields/TranslatedString.d.ts +13 -0
  11. package/dist/formFields/baseTypes/InputAutocomplete/InputAutocomplete.d.ts +8 -0
  12. package/dist/formFields/baseTypes/InputAutocomplete/InputAutocompleteInterfaces.d.ts +22 -0
  13. package/dist/formFields/baseTypes/InputCheckbox/InputCheckbox.d.ts +19 -0
  14. package/dist/formFields/baseTypes/InputDateTimePicker/InputDateTimePicker.d.ts +12 -0
  15. package/dist/formFields/baseTypes/InputRadio/InputRadio.d.ts +13 -0
  16. package/dist/formFields/baseTypes/InputSelect/InputSelect.d.ts +23 -0
  17. package/dist/formFields/baseTypes/InputSelectFromEnum/InputSelectFromEnum.d.ts +6 -0
  18. package/dist/formFields/baseTypes/InputSelectFromEnum/InputSelectFromEnumInterfaces.d.ts +10 -0
  19. package/dist/formFields/baseTypes/InputText/InputText.d.ts +14 -0
  20. package/dist/formFields/errorMessages.d.ts +1 -0
  21. package/dist/formFields/formHelper/getFormError.d.ts +11 -0
  22. package/dist/formFields/formHelper/syncSubmit.d.ts +15 -0
  23. package/dist/formFields/formHelper/useHookForm.d.ts +50 -0
  24. package/dist/formFields/formHelper/useHookFormContext.d.ts +9 -0
  25. package/dist/formFields/formHelper/useMergedFormField.d.ts +6 -0
  26. package/dist/formFields/formHelper/useSortedOptionsWithGroup.d.ts +5 -0
  27. package/dist/formFields/formHelper/useTranslateString.d.ts +8 -0
  28. package/dist/formFields/index.d.ts +28 -0
  29. package/dist/formFields/inputTypes.d.ts +76 -0
  30. package/dist/packageExports.d.ts +7 -0
  31. package/dist/packageExports.js +741 -0
  32. package/dist/packageExports.js.map +1 -0
  33. package/package.json +1 -1
@@ -0,0 +1,741 @@
1
+ function ___$insertStyle(css) {
2
+ if (!css || typeof window === 'undefined') {
3
+ return;
4
+ }
5
+ const style = document.createElement('style');
6
+ style.setAttribute('type', 'text/css');
7
+ style.innerHTML = css;
8
+ document.head.appendChild(style);
9
+ return css;
10
+ }
11
+
12
+ import { LoadingButton as LoadingButton$1 } from '@mui/lab';
13
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
14
+ import { useFormContext, FormProvider, useFormState, Controller, useForm } from 'react-hook-form';
15
+ import { useFormControl, FormControl, InputLabel, OutlinedInput, FormHelperText, Autocomplete, TextField, FormControlLabel, Checkbox, Box, FormLabel, RadioGroup, Radio, Select, MenuItem, Stack, Tooltip, ListSubheader } from '@mui/material';
16
+ import { uppercaseFirstLetter, assertTruthy, objectHasKey, rethrow } from '@nvon/baseline';
17
+ import { useCallback, useMemo, useState, createElement } from 'react';
18
+ import { t } from 'i18next';
19
+ import { DateTimePicker } from '@mui/x-date-pickers';
20
+ import { identity } from 'lodash-es';
21
+
22
+ var LoadingButtonState;
23
+ (function (LoadingButtonState) {
24
+ LoadingButtonState["Idle"] = "idle";
25
+ LoadingButtonState["Loading"] = "loading";
26
+ LoadingButtonState["Success"] = "success";
27
+ })(LoadingButtonState || (LoadingButtonState = {}));
28
+
29
+ const LoadingButton = ({
30
+ buttonText,
31
+ buttonTextSuccess,
32
+ loadingButtonProps,
33
+ loadingButtonPropsPropsSuccess,
34
+ buttonState,
35
+ successIcon
36
+ }) => {
37
+ const isSuccess = buttonState === LoadingButtonState.Success;
38
+ const propsToSpread = isSuccess ? loadingButtonPropsPropsSuccess : loadingButtonProps;
39
+ return /*#__PURE__*/jsx(LoadingButton$1, {
40
+ loading: buttonState === LoadingButtonState.Loading,
41
+ disabled: buttonState !== LoadingButtonState.Idle,
42
+ ...propsToSpread,
43
+ children: buttonState === LoadingButtonState.Success ? /*#__PURE__*/jsxs(Fragment, {
44
+ children: [successIcon ? successIcon : null, buttonTextSuccess ? buttonTextSuccess : buttonText]
45
+ }) : buttonText
46
+ });
47
+ };
48
+
49
+ /**
50
+ * Get loading button state from react-query mutation status.
51
+ */
52
+ const loadingButtonStateFromReactQueryMutationStatus = mutationStatus => {
53
+ const mapStatus = {
54
+ idle: LoadingButtonState.Idle,
55
+ error: LoadingButtonState.Idle,
56
+ success: LoadingButtonState.Success,
57
+ loading: LoadingButtonState.Loading
58
+ };
59
+ return mapStatus[mutationStatus];
60
+ };
61
+ /**
62
+ * Get loading button state from a react-hook-form context.
63
+ */
64
+ const useLoadingButtonStateFromFormContext = () => {
65
+ const formContext = useFormContext();
66
+ return loadingButtonStateFromFormState(formContext.formState);
67
+ };
68
+ /**
69
+ * Get loading button state from a react-hook-form state.
70
+ */
71
+ const loadingButtonStateFromFormState = (
72
+ // we are not interested in the value types FormState holds
73
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
74
+ formState) => {
75
+ if (formState.isSubmitting) {
76
+ return LoadingButtonState.Loading;
77
+ }
78
+ if (formState.isDirty) {
79
+ return LoadingButtonState.Idle;
80
+ }
81
+ if (formState.isSubmitSuccessful) {
82
+ return LoadingButtonState.Success;
83
+ }
84
+ return LoadingButtonState.Idle;
85
+ };
86
+
87
+ /**
88
+ * Reexport of FormProvider.
89
+ *
90
+ * 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.
91
+ */
92
+ const HookFormProvider = FormProvider;
93
+
94
+ 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";
95
+
96
+ /**
97
+ * Get the field errors for a (possibly nested) field name.
98
+ *
99
+ * Checking `formState.errors[fieldName]` only works if fieldName is not a path
100
+ * (e.g. Does not include dots).
101
+ *
102
+ * Did not find a built-in way to do this … there might be one though.
103
+ */
104
+ const getFormError = (errors, fieldName) => {
105
+ const nestedKeys = fieldName.split(".");
106
+ //
107
+ // To my best knowledge, this works as expected.
108
+ //
109
+ // It recursively walks the error object by the given keys
110
+ // until the lowest level is reached, or undefined returned.
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 nestedKeys.reduce(
118
+ // @ts-expect-error
119
+ (errorObj, pathKey) => errorObj?.[pathKey], errors);
120
+ /* eslint-enable */
121
+ };
122
+
123
+ /**
124
+ * Return a function which turns our TranslatedString into a plain string.
125
+ *
126
+ * @throws Error if no t was provided but a translated string.
127
+ */
128
+ const useTranslateString = () => {
129
+ if (!t) {
130
+ throw Error("If you pass in a translated validate function you need to provide a t");
131
+ }
132
+ return useCallback(input => {
133
+ return typeof input === "string" ? input : input(t);
134
+ }, []);
135
+ };
136
+
137
+ /**
138
+ * Merge a form field with defaults.
139
+ */
140
+ const useMergedFormField = (
141
+ /**
142
+ * Form fields, typically those passed into a component.
143
+ *
144
+ */
145
+ formField, t,
146
+ /**
147
+ * Additional defaults. Duplicate values will be overridden by the formField.
148
+ */
149
+ formFieldDefaults) => {
150
+ const translate = useTranslateString();
151
+ const merged = useMemo(() => {
152
+ const builtInDefaults = {
153
+ label: uppercaseFirstLetter(formField.name),
154
+ required: false,
155
+ requiredErrorMessage: "Please fill in required information",
156
+ validate: undefined
157
+ };
158
+ return {
159
+ ...builtInDefaults,
160
+ ...formFieldDefaults,
161
+ ...formField
162
+ };
163
+ }, [formField, formFieldDefaults]);
164
+ const withPlainStrings = useMemo(() => {
165
+ // Translating the validate function is a bit tricky,
166
+ // since it can be an object in both cases.
167
+ const validate = (() => {
168
+ if (typeof merged.validate === "object" && typeof merged.validate.translated === "function") {
169
+ if (!t) {
170
+ throw Error("If you pass in a translated validate function you need to provide a t");
171
+ }
172
+ return merged.validate.translated(t);
173
+ }
174
+ return merged.validate;
175
+ })(); // This should be fine. Not sure why TS is complaining.
176
+ return {
177
+ ...merged,
178
+ label: translate(merged.label, t),
179
+ requiredErrorMessage: translate(merged.requiredErrorMessage, t),
180
+ validate
181
+ };
182
+ }, [merged, t, translate]);
183
+ return withPlainStrings;
184
+ };
185
+
186
+ const InputText = ({
187
+ formField,
188
+ textFieldProps
189
+ }) => {
190
+ const form = useFormContext();
191
+ const muiFormControl = useFormControl();
192
+ const {
193
+ label,
194
+ name,
195
+ required,
196
+ requiredErrorMessage,
197
+ validate
198
+ } = useMergedFormField(formField, formField.t);
199
+ if (!form) {
200
+ throw Error(formContextNull);
201
+ }
202
+ const {
203
+ register,
204
+ formState
205
+ } = form;
206
+ const error = getFormError(formState.errors, formField.name);
207
+ return /*#__PURE__*/jsxs(FormControl, {
208
+ error: !!error,
209
+ required: required,
210
+ disabled: muiFormControl?.disabled,
211
+ children: [/*#__PURE__*/jsx(InputLabel, {
212
+ required: required,
213
+ children: label
214
+ }), /*#__PURE__*/jsx(OutlinedInput, {
215
+ ...register(name, {
216
+ required: required ? requiredErrorMessage : false,
217
+ validate,
218
+ disabled: muiFormControl?.disabled
219
+ }),
220
+ required: required,
221
+ label: label,
222
+ ...textFieldProps
223
+ }), error?.message && /*#__PURE__*/jsx(FormHelperText, {
224
+ children: error?.message
225
+ })]
226
+ });
227
+ };
228
+
229
+ const InputEmail = props => {
230
+ const merged = useMergedFormField(props.formField, props.formField.t, formDefaults);
231
+ return /*#__PURE__*/jsx(InputText, {
232
+ textFieldProps: {
233
+ type: "email",
234
+ ...props.textFieldProps
235
+ },
236
+ formField: merged
237
+ });
238
+ };
239
+ const formDefaults = {
240
+ required: true,
241
+ validate: emailInput => {
242
+ if (emailInput.match(/.@./)) {
243
+ return true;
244
+ }
245
+ return "E-Mail address invalid";
246
+ }
247
+ };
248
+
249
+ const InputPasswordSet = ({
250
+ passwordField,
251
+ passwordValidationField,
252
+ doNotMatchError
253
+ }) => {
254
+ const {
255
+ watch
256
+ } = useFormContext();
257
+ const passwordFieldMerged = useMergedFormField(passwordField, passwordField.t, {
258
+ required: true
259
+ });
260
+ const validationFieldMerged = useMergedFormField(passwordValidationField, passwordValidationField.t, {
261
+ required: true
262
+ });
263
+ const validatePasswordMatch = useCallback(value => {
264
+ const passwordValue = watch(passwordFieldMerged.name);
265
+ return value === passwordValue || doNotMatchError;
266
+ }, [doNotMatchError, passwordFieldMerged.name, watch]);
267
+ return /*#__PURE__*/jsxs(Fragment, {
268
+ children: [/*#__PURE__*/jsx(InputText, {
269
+ formField: passwordFieldMerged,
270
+ textFieldProps: {
271
+ type: "password"
272
+ }
273
+ }), /*#__PURE__*/jsx(InputText, {
274
+ formField: {
275
+ ...validationFieldMerged,
276
+ validate: validatePasswordMatch,
277
+ t: passwordValidationField.t
278
+ },
279
+ textFieldProps: {
280
+ type: "password"
281
+ }
282
+ })]
283
+ });
284
+ };
285
+
286
+ const InputAutocomplete = ({
287
+ formField,
288
+ selectableOptions,
289
+ multiSelect,
290
+ noOptions,
291
+ autoCompleteProps
292
+ }) => {
293
+ const form = useFormContext();
294
+ if (!form) {
295
+ throw Error(formContextNull);
296
+ }
297
+ const {
298
+ register,
299
+ watch,
300
+ formState,
301
+ setValue
302
+ } = form;
303
+ const error = getFormError(formState.errors, formField.name);
304
+ const muiFormControl = useFormControl();
305
+ const {
306
+ label,
307
+ name,
308
+ required,
309
+ requiredErrorMessage,
310
+ validate
311
+ } = useMergedFormField(formField, formField.t);
312
+ const value = watch(name);
313
+ let valueToUse = value;
314
+ if (!value) {
315
+ valueToUse = multiSelect ? [] : "";
316
+ }
317
+ assertTruthy(["string", "number", "object"].includes(typeof valueToUse), "Value for select input has unexpected type");
318
+ const props = register(name, {
319
+ required: required ? requiredErrorMessage : false,
320
+ validate,
321
+ disabled: muiFormControl?.disabled
322
+ });
323
+ const currentValue = useMemo(() => multiSelect ? selectableOptions.filter(o => {
324
+ if (Array.isArray(valueToUse)) {
325
+ return valueToUse.includes(o.value);
326
+ }
327
+ return valueToUse;
328
+ }) : valueToUse, [multiSelect, selectableOptions, valueToUse]);
329
+ return /*#__PURE__*/jsxs(FormControl, {
330
+ error: !!error,
331
+ required: required,
332
+ disabled: muiFormControl?.disabled,
333
+ children: [/*#__PURE__*/jsx(Autocomplete, {
334
+ options: selectableOptions,
335
+ multiple: multiSelect,
336
+ value: currentValue,
337
+ label: label,
338
+ ...props,
339
+ getOptionLabel: o => {
340
+ if (objectHasKey(o, "label")) {
341
+ return o.label;
342
+ }
343
+ return "";
344
+ },
345
+ onChange: (e, selectedOption) => {
346
+ if (Array.isArray(selectedOption)) {
347
+ setValue(name, selectedOption.map(o => o.value));
348
+ } else {
349
+ setValue(name, selectedOption.value);
350
+ }
351
+ },
352
+ noOptionsText: noOptions,
353
+ renderInput: params => /*#__PURE__*/jsx(TextField, {
354
+ ...params,
355
+ label: label,
356
+ variant: "outlined"
357
+ })
358
+ // need to parse this as any in order to get no typing errors
359
+ // for multiselect
360
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
361
+ ,
362
+ ...autoCompleteProps
363
+ }), error?.message && /*#__PURE__*/jsx(FormHelperText, {
364
+ children: error?.message
365
+ })]
366
+ });
367
+ };
368
+
369
+ const InputCheckbox = ({
370
+ formField,
371
+ jsxLabel,
372
+ checkboxProps,
373
+ formControlLabelProps
374
+ }) => {
375
+ const {
376
+ register,
377
+ watch,
378
+ setValue
379
+ } = useFormContext();
380
+ const {
381
+ errors
382
+ } = useFormState();
383
+ const error = getFormError(errors, formField.name);
384
+ const muiFormControl = useFormControl();
385
+ const {
386
+ label,
387
+ name,
388
+ required,
389
+ requiredErrorMessage,
390
+ validate
391
+ } = useMergedFormField(formField);
392
+ const changeEv = useCallback(e => {
393
+ setValue(name, e.target.checked, {
394
+ shouldValidate: true,
395
+ shouldDirty: true,
396
+ shouldTouch: true
397
+ });
398
+ }, [name, setValue]);
399
+ const id = `rvo-input-checkbox-${name}`;
400
+ const registered = register(name, {
401
+ required: required ? requiredErrorMessage : false,
402
+ onChange: changeEv,
403
+ validate,
404
+ disabled: muiFormControl?.disabled
405
+ });
406
+ const value = watch(name, false) ?? false;
407
+ return /*#__PURE__*/jsxs(FormControl, {
408
+ error: !!error,
409
+ disabled: muiFormControl?.disabled,
410
+ children: [/*#__PURE__*/jsx(FormControlLabel, {
411
+ required: jsxLabel ? false : required // If jsxLabel is set, we don't want to show the asterisk.
412
+ ,
413
+ control: /*#__PURE__*/jsx(Checkbox, {
414
+ checked: value,
415
+ "aria-labelledby": id,
416
+ ...registered,
417
+ ...checkboxProps
418
+ }),
419
+ label: jsxLabel ?? label,
420
+ ...formControlLabelProps
421
+ }), error?.message && /*#__PURE__*/jsx(FormHelperText, {
422
+ children: error?.message
423
+ })]
424
+ });
425
+ };
426
+
427
+ const InputDateTimePicker = ({
428
+ formField,
429
+ dateTimePickerProps
430
+ }) => {
431
+ const {
432
+ formState,
433
+ control
434
+ } = useFormContext();
435
+ const error = getFormError(formState.errors, formField.name);
436
+ const muiFormControl = useFormControl();
437
+ const {
438
+ label,
439
+ name,
440
+ required
441
+ } = useMergedFormField(formField);
442
+ const [date, setDate] = useState(new Date());
443
+ return /*#__PURE__*/jsx(Box, {
444
+ children: /*#__PURE__*/jsxs(FormControl, {
445
+ error: !!error,
446
+ required: required,
447
+ disabled: muiFormControl?.disabled,
448
+ children: [/*#__PURE__*/jsx(Controller, {
449
+ name: name,
450
+ defaultValue: date,
451
+ control: control,
452
+ render: ({
453
+ field: {
454
+ onChange,
455
+ ...restField
456
+ }
457
+ }) => /*#__PURE__*/jsx(DateTimePicker, {
458
+ label: label,
459
+ ampm: dateTimePickerProps?.ampm ? dateTimePickerProps.ampm : false,
460
+ onChange: event => {
461
+ onChange(event);
462
+ if (event) {
463
+ setDate(event);
464
+ }
465
+ },
466
+ disabled: muiFormControl?.disabled,
467
+ renderInput: params => /*#__PURE__*/jsx(TextField, {
468
+ required: required,
469
+ ...params
470
+ }),
471
+ ...restField,
472
+ ...dateTimePickerProps
473
+ })
474
+ }), error?.message && /*#__PURE__*/jsx(FormHelperText, {
475
+ children: error?.message
476
+ })]
477
+ })
478
+ });
479
+ };
480
+
481
+ const InputRadio = ({
482
+ formField,
483
+ selectableOptions,
484
+ formControlLabelProps,
485
+ radioGroupProps
486
+ }) => {
487
+ const {
488
+ register,
489
+ watch,
490
+ setValue
491
+ } = useFormContext();
492
+ const {
493
+ errors
494
+ } = useFormState();
495
+ const error = getFormError(errors, formField.name);
496
+ const muiFormControl = useFormControl();
497
+ const {
498
+ label,
499
+ name,
500
+ required,
501
+ requiredErrorMessage,
502
+ validate
503
+ } = useMergedFormField(formField);
504
+ const changeEv = useCallback(e => {
505
+ setValue(name, e.target.value, {
506
+ shouldValidate: true,
507
+ shouldDirty: true,
508
+ shouldTouch: true
509
+ });
510
+ }, [name, setValue]);
511
+ const value = watch(name) ?? "";
512
+ assertTruthy(["string", "number"].includes(typeof value), "Value for select input has unexpected type");
513
+ const id = `rvo-input-radio-${name}`;
514
+ const registered = register(name, {
515
+ required: required ? requiredErrorMessage : false,
516
+ onChange: changeEv,
517
+ validate,
518
+ disabled: muiFormControl?.disabled
519
+ });
520
+ return /*#__PURE__*/jsxs(FormControl, {
521
+ error: !!error,
522
+ disabled: muiFormControl?.disabled,
523
+ children: [/*#__PURE__*/jsx(FormLabel, {
524
+ id: id,
525
+ required: required,
526
+ children: label
527
+ }), /*#__PURE__*/jsx(RadioGroup, {
528
+ value: value,
529
+ "aria-labelledby": id,
530
+ ...radioGroupProps,
531
+ children: selectableOptions?.map(option => {
532
+ return /*#__PURE__*/createElement(FormControlLabel, {
533
+ ...registered,
534
+ key: option.value,
535
+ value: option.value,
536
+ control: /*#__PURE__*/jsx(Radio, {}),
537
+ label: option.label,
538
+ ...formControlLabelProps
539
+ });
540
+ })
541
+ }), error?.message && /*#__PURE__*/jsx(FormHelperText, {
542
+ children: error?.message
543
+ })]
544
+ });
545
+ };
546
+
547
+ /**
548
+ * Sorts the options by group and value.
549
+ */
550
+ const useSortedOptionsWithGroup = selectableOptions => {
551
+ return useMemo(() => selectableOptions.sort((a, b) => {
552
+ if (a.group == undefined && !!b.group) {
553
+ return -1;
554
+ }
555
+ if (a.group && b.group && a.group < b.group) {
556
+ return -1;
557
+ }
558
+ if (a.group == b.group && b.value > a.value) {
559
+ return 1;
560
+ }
561
+ return 0;
562
+ }), [selectableOptions]);
563
+ };
564
+
565
+ const InputSelect = ({
566
+ formField,
567
+ selectableOptions,
568
+ placeholderText,
569
+ selectComponentProps,
570
+ tooltipHolder
571
+ }) => {
572
+ const form = useFormContext();
573
+ if (!form) {
574
+ throw Error(formContextNull);
575
+ }
576
+ const {
577
+ register,
578
+ watch,
579
+ formState
580
+ } = form;
581
+ const error = getFormError(formState.errors, formField.name);
582
+ const muiFormControl = useFormControl();
583
+ const {
584
+ label,
585
+ name,
586
+ required,
587
+ requiredErrorMessage,
588
+ validate
589
+ } = useMergedFormField(formField, formField.t);
590
+ const defaultValue = selectComponentProps?.multiple ? [] : "";
591
+ const value = watch(name) ?? defaultValue;
592
+ if (selectComponentProps?.multiple && value) {
593
+ assertTruthy(Array.isArray(value), "Value for multiple select need to be an array or undefined");
594
+ } else if (value) {
595
+ assertTruthy(["string", "number"].includes(typeof value), "Value for select input has unexpected type");
596
+ }
597
+ const id = `input-select-${name}`;
598
+ const sortedOptions = useSortedOptionsWithGroup(selectableOptions);
599
+ return /*#__PURE__*/jsxs(FormControl, {
600
+ error: !!error,
601
+ required: required,
602
+ disabled: muiFormControl?.disabled,
603
+ children: [/*#__PURE__*/jsx(InputLabel, {
604
+ id: id,
605
+ required: required,
606
+ children: label
607
+ }), /*#__PURE__*/jsxs(Select, {
608
+ labelId: id,
609
+ ...selectComponentProps,
610
+ error: !!formState.errors[name],
611
+ label: label,
612
+ value: value,
613
+ ...register(name, {
614
+ required: required ? requiredErrorMessage : false,
615
+ validate,
616
+ disabled: muiFormControl?.disabled
617
+ }),
618
+ children: [/*#__PURE__*/jsx(MenuItem, {
619
+ value: "",
620
+ children: /*#__PURE__*/jsx("em", {
621
+ children: placeholderText
622
+ })
623
+ }), sortedOptions?.map((option, index) => {
624
+ const optionBefore = sortedOptions[index - 1];
625
+ const showGroup = (optionBefore || index == 0) && option.group && optionBefore?.group !== option.group;
626
+ const disabledText = typeof option.disabled === "string" ? option.disabled : undefined;
627
+ const isDisabled = !!disabledText || !!option.disabled;
628
+ const menuItem = /*#__PURE__*/jsx(MenuItem, {
629
+ value: option.value,
630
+ disabled: isDisabled,
631
+ title: typeof option.disabled === "string" ? option.disabled : undefined,
632
+ selected: value === option.value,
633
+ children: option.label
634
+ }, option.label);
635
+ const wrappedMenuItem = disabledText ? /*#__PURE__*/jsxs(Box, {
636
+ sx: {
637
+ position: "relative"
638
+ },
639
+ children: [menuItem, /*#__PURE__*/jsx(Stack, {
640
+ direction: "column",
641
+ justifyContent: "center",
642
+ spacing: 1,
643
+ sx: {
644
+ position: "absolute",
645
+ right: th => th.spacing(0.5),
646
+ top: 0,
647
+ bottom: 0
648
+ },
649
+ children: tooltipHolder ? /*#__PURE__*/jsx(Tooltip, {
650
+ title: disabledText,
651
+ children: tooltipHolder
652
+ }) : null
653
+ })]
654
+ }) : menuItem;
655
+ return showGroup ? [/*#__PURE__*/jsx(ListSubheader, {
656
+ children: option.group
657
+ }, option.group), wrappedMenuItem] : wrappedMenuItem;
658
+ })]
659
+ }), error?.message && /*#__PURE__*/jsx(FormHelperText, {
660
+ children: error?.message
661
+ })]
662
+ });
663
+ };
664
+
665
+ const InputSelectFromEnum = props => {
666
+ const {
667
+ enumData,
668
+ formField
669
+ } = props;
670
+ const translateFunction = formField.t;
671
+ const options = useMemo(() => {
672
+ return Object.entries(enumData.enumToUse).map(([, value]) => {
673
+ const label = enumData.labelsForEnum[value];
674
+ assertTruthy(label, "Could not find a label for value" + value);
675
+ if (typeof label === "string") {
676
+ return {
677
+ label,
678
+ value
679
+ };
680
+ }
681
+ assertTruthy(translateFunction, "If you want to use translated labels you need to provide a translate function in the HookFormProvider.");
682
+ return {
683
+ label: label(translateFunction),
684
+ value
685
+ };
686
+ });
687
+ }, [enumData.enumToUse, enumData.labelsForEnum, translateFunction]);
688
+ return /*#__PURE__*/jsx(InputSelect, {
689
+ ...props,
690
+ selectableOptions: options,
691
+ formField: formField
692
+ });
693
+ };
694
+
695
+ /**
696
+ * Turn an async submitHandler into a synchronous one.
697
+ *
698
+ * Reasoning:
699
+ * - we're often talking to the API during form submission. The onSubmit handler will be returning a Promise in this case.
700
+ * - the `form` element, per definition, always expects a synchronous function.
701
+ * - creating on inline function in every form is a bit clumsy, and does not look clean.
702
+ *
703
+ * Then/catch cases should be properly handled by the submit handler itself,
704
+ * the catch supplied here is only a last safety net against an "unhandled promise rejection" error.
705
+ */
706
+ const syncSubmit = asyncSubmitHandler => {
707
+ return e => {
708
+ asyncSubmitHandler(e).catch(rethrow);
709
+ };
710
+ };
711
+
712
+ /**
713
+ * Wrapper around react-hook-form's useForm.
714
+ *
715
+ * Should behave like the original function, only exposing a "fieldName"
716
+ * function on top which is used to validate field names.
717
+ */
718
+ const useHookForm = props => {
719
+ const form = useForm(props);
720
+ return {
721
+ ...form,
722
+ fieldName: identity
723
+ };
724
+ };
725
+
726
+ /**
727
+ * Wrapper around react-hook-form's useFormContext.
728
+ *
729
+ * Should behave like the original function, only exposing a "fieldName"
730
+ * function on top which is used to validate field names.
731
+ */
732
+ const useHookFormContext = () => {
733
+ const form = useFormContext();
734
+ return {
735
+ ...form,
736
+ fieldName: identity
737
+ };
738
+ };
739
+
740
+ export { HookFormProvider, InputAutocomplete, InputCheckbox, InputDateTimePicker, InputEmail, InputPasswordSet, InputRadio, InputSelect, InputSelectFromEnum, InputText, LoadingButton, LoadingButtonState, getFormError, loadingButtonStateFromFormState, loadingButtonStateFromReactQueryMutationStatus, syncSubmit, useHookForm, useHookFormContext, useLoadingButtonStateFromFormContext, useMergedFormField, useSortedOptionsWithGroup, useTranslateString };
741
+ //# sourceMappingURL=packageExports.js.map