@trackunit/react-form-components 0.0.305 → 0.0.309

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.
package/index.esm.js CHANGED
@@ -1,18 +1,18 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { useNamespaceTranslation, registerTranslations } from '@trackunit/i18n-library-translation';
3
+ import { IconButton, Icon, Tooltip, Heading, Text, MenuItem, Tag, Spinner } from '@trackunit/react-components';
3
4
  import * as React from 'react';
4
- import React__default, { forwardRef, useState, useMemo, useRef, useImperativeHandle, useCallback, useEffect, cloneElement } from 'react';
5
+ import React__default, { useMemo, forwardRef, useCallback, cloneElement, useState, useEffect, useRef, useImperativeHandle } from 'react';
6
+ import { useCopyToClipboard } from 'react-use';
5
7
  import { v4 } from 'uuid';
6
- import { Tooltip, Text, MenuItem, Icon, Tag, Spinner, IconButton, Heading } from '@trackunit/react-components';
7
8
  import { cvaMerge } from '@trackunit/css-class-variance-utilities';
9
+ import { format } from 'date-fns';
10
+ import parsePhoneNumberFromString, { isSupportedCountry, getCountries, getCountryCallingCode, isValidPhoneNumber, parsePhoneNumberFromString as parsePhoneNumberFromString$1 } from 'libphonenumber-js';
8
11
  import ReactSelect, { components } from 'react-select';
9
12
  export { default as ValueType } from 'react-select';
10
13
  import ReactAsyncCreatableSelect from 'react-select/async-creatable';
11
14
  import ReactCreatableSelect from 'react-select/creatable';
12
15
  import ReactAsyncSelect from 'react-select/async';
13
- import { useCopyToClipboard } from 'react-use';
14
- import { format } from 'date-fns';
15
- import parsePhoneNumberFromString, { isSupportedCountry, getCountries, getCountryCallingCode, isValidPhoneNumber, parsePhoneNumberFromString as parsePhoneNumberFromString$1 } from 'libphonenumber-js';
16
16
 
17
17
  var defaultTranslations = {
18
18
  "clearIndicator.icon.tooltip.clearAll": "Clear all",
@@ -69,6 +69,65 @@ const setupLibraryTranslations = () => {
69
69
  registerTranslations(translations);
70
70
  };
71
71
 
72
+ const cvaActionButton = cvaMerge(["drop-shadow-none", "rounded-md"], {
73
+ variants: {
74
+ size: {
75
+ small: ["w-6", "h-6"],
76
+ medium: ["w-8", "h-8"],
77
+ },
78
+ },
79
+ defaultVariants: {
80
+ size: "medium",
81
+ },
82
+ });
83
+ const cvaActionContainer = cvaMerge(["flex", "items-center", "m-1"]);
84
+
85
+ /**
86
+ * The ActionButton component is a wrapper over IconButton to perform an action when the onClick event is triggered.
87
+ *
88
+ * @param {ActionButtonProps} props - The props for the ActionButton component
89
+ * @returns {JSX.Element} ActionButton component
90
+ */
91
+ const ActionButton = ({ type, value, dataTestId, iconSize, disabled, key, className }) => {
92
+ const [, copyToClipboard] = useCopyToClipboard();
93
+ const elementKey = useMemo(() => key !== null && key !== void 0 ? key : `ActionButton-${v4()}`, [key]);
94
+ const getIconName = () => {
95
+ switch (type) {
96
+ case "PHONE_NUMBER":
97
+ return "PhoneArrowUpRight";
98
+ case "WEB_ADDRESS":
99
+ return "ArrowTopRightOnSquare";
100
+ case "EMAIL":
101
+ return "Envelope";
102
+ case "COPY":
103
+ default:
104
+ return "ClipboardDocument";
105
+ }
106
+ };
107
+ const ButtonAction = () => {
108
+ var _a, _b;
109
+ switch (type) {
110
+ case "EMAIL":
111
+ return window.open(`mailto:${value}`);
112
+ case "WEB_ADDRESS":
113
+ if (value) {
114
+ return window.open(value, "_blank", "noopener,noreferrer");
115
+ }
116
+ return null;
117
+ case "PHONE_NUMBER":
118
+ return window.open(`tel:${value}`);
119
+ case "COPY":
120
+ return copyToClipboard((_b = (_a = value === null || value === void 0 ? void 0 : value.current) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : "");
121
+ default:
122
+ return null;
123
+ }
124
+ };
125
+ if (ButtonAction === null) {
126
+ return null;
127
+ }
128
+ return (jsx("div", { className: cvaActionContainer({ className }), children: jsx(IconButton, { className: cvaActionButton({ size: iconSize }), dataTestId: dataTestId || "testIconButtonId", disabled: disabled, icon: jsx(Icon, { name: getIconName(), size: "small" }), onClick: ButtonAction, size: "small", variant: "secondary" }) }, elementKey));
129
+ };
130
+
72
131
  /******************************************************************************
73
132
  Copyright (c) Microsoft Corporation.
74
133
 
@@ -106,95 +165,137 @@ function __awaiter(thisArg, _arguments, P, generator) {
106
165
  });
107
166
  }
108
167
 
109
- const cvaLabel = cvaMerge([
110
- "text-base",
111
- "text-slate-700",
112
- "truncate",
113
- "hover:text-slate-800",
114
- "group-hover:text-slate-800",
115
- "active:text-slate-800",
116
- "group-active:text-slate-800",
117
- ], {
168
+ const cvaInputBase = cvaMerge([
169
+ "component-baseInput-shadow",
170
+ "component-baseInput-border",
171
+ "component-baseInput-background",
172
+ "border-slate-300",
173
+ "focus-within:ring-2",
174
+ "focus-within:ring-inset",
175
+ "focus-within:ring-primary-500",
176
+ "focus-within:border-slate-400",
177
+ "hover:border-slate-400",
178
+ "hover:bg-slate-50",
179
+ "transition",
180
+ ]);
181
+ const cvaInputBaseDisabled = cvaMerge(["bg-slate-100", "hover:bg-slate-100", "hover:border-slate-300"]);
182
+ const cvaInputBaseInvalid = cvaMerge(["border-danger-600", "focus-within:ring-danger-600"]);
183
+ const cvaInput = cvaMerge(["relative", "flex", "h-10", cvaInputBase()], {
118
184
  variants: {
185
+ size: {
186
+ small: ["h-8"],
187
+ medium: ["h-10"],
188
+ },
189
+ disabled: {
190
+ true: cvaInputBaseDisabled(),
191
+ false: "",
192
+ },
119
193
  invalid: {
120
- true: "text-red-600 hover:text-red-700 active:text-red-700 group-hover:text-red-700 group-active:text-red-700",
194
+ true: cvaInputBaseInvalid(),
121
195
  false: "",
122
196
  },
197
+ },
198
+ });
199
+ const cvaInputField = cvaMerge([
200
+ "w-full",
201
+ "px-3",
202
+ "border-0",
203
+ "bg-transparent",
204
+ "text-base",
205
+ "text-slate-900",
206
+ "placeholder-slate-400",
207
+ "focus-visible:outline-none",
208
+ ], {
209
+ variants: {
210
+ size: {
211
+ small: ["py-1"],
212
+ medium: ["py-2"],
213
+ },
123
214
  disabled: {
124
- true: "text-slate-400 hover:text-slate-400 group-hover:text-slate-400",
215
+ true: ["text-slate-700"],
125
216
  false: "",
126
217
  },
127
218
  },
128
- defaultVariants: {
129
- invalid: false,
130
- disabled: false,
131
- },
132
219
  });
133
-
134
- /**
135
- * The Label component is used for labels for input fields.
136
- * This component is **not used directly**, but is part of the FormGroup and Field components.
137
- *
138
- * @param {LabelProps} props - The props for the Label component
139
- * @returns {JSX.Element} Label component
140
- */
141
- const Label = ({ id, htmlFor, children, className, dataTestId, disabled, isInvalid, }) => {
142
- return (jsx("label", { className: cvaLabel({ invalid: isInvalid, disabled, className }), "data-testid": dataTestId, htmlFor: htmlFor || "", id: id || "", children: children }));
143
- };
144
-
145
- const cvaFormGroup = cvaMerge(["component-formGroup-gap"], {
220
+ const cvaInputAddon = cvaMerge([
221
+ "flex",
222
+ "justify-center",
223
+ "items-center",
224
+ "px-3",
225
+ "border-slate-300",
226
+ "text-slate-500",
227
+ "bg-slate-50",
228
+ ]);
229
+ const cvaInputAddonBefore = cvaMerge([cvaInputAddon(), "border-r", "rounded-l-lg"]);
230
+ const cvaInputAddonAfter = cvaMerge([cvaInputAddon(), "border-l", "rounded-r-lg"]);
231
+ const cvaInputPrefix = cvaMerge([
232
+ "flex",
233
+ "justify-center",
234
+ "items-center",
235
+ "text-slate-400",
236
+ "hover:component-search-prefix",
237
+ "component-baseInput-prefix",
238
+ "component-search-borderless",
239
+ "px-3",
240
+ ], {
146
241
  variants: {
147
242
  disabled: {
148
- true: "pointer-events-none",
243
+ true: ["text-slate-500"],
149
244
  false: "",
150
245
  },
151
246
  },
152
247
  });
153
- const cvaFormGroupContainerBefore = cvaMerge(["flex", "gap-1", "mb-1"]);
154
- const cvaFormGroupContainerAfter = cvaMerge(["flex", "justify-between", "mt-1", "text-xs", "text-slate-500"], {
248
+ const cvaInputSuffix = cvaMerge(["flex", "justify-center", "items-center", "text-slate-400", "px-3"], {
155
249
  variants: {
156
- invalid: {
157
- true: "text-danger-500",
250
+ disabled: {
251
+ true: ["text-slate-500"],
158
252
  false: "",
159
253
  },
160
254
  },
161
255
  });
162
- const cvaHelpAddon = cvaMerge(["ml-auto"]);
163
256
 
164
257
  /**
165
- * The FormGroup component should be used to wrap any Input element that needs a label.
166
- * Besides a label the component supplies an optional Tooltip, HelpText and HelpAddon support.
258
+ * A base input component that can be used for text inputs, password inputs, etc.
259
+ * A reference to the input element is provided as the `ref` prop.
260
+ * Extends props from [React.InputHTMLAttributes](https://reactjs.org/docs/dom-elements.html#input)
167
261
  *
168
- * @param {FormGroupProps} props - The props for the FormGroup component
169
- * @returns {JSX.Element} FormGroup component
262
+ * For specific input types make sure to use the corresponding input component.
263
+ * This is a base used by our other input components such as TextInput, NumberInput, PasswordInput, etc.
170
264
  */
171
- const FormGroup = ({ isInvalid, helpText, helpAddon, tip, className, dataTestId, label, htmlFor, children, tipIconProps, disabled = false, }) => {
172
- return (jsxs("div", { className: cvaFormGroup({ disabled, className }), "data-testid": dataTestId, children: [jsxs("div", { className: cvaFormGroupContainerBefore(), children: [jsx(Label, { className: "component-formGroup-font", dataTestId: dataTestId && `${dataTestId}-label`, htmlFor: htmlFor, id: htmlFor + "-label", children: label }), tip && (jsx(Tooltip, { dataTestId: dataTestId && `${dataTestId}-tooltip`, iconProps: tipIconProps, label: tip, placement: "bottom" }))] }), children, jsxs("div", { className: cvaFormGroupContainerAfter({ invalid: isInvalid }), children: [helpText && jsx("span", { "data-testid": dataTestId && `${dataTestId}-helpText`, children: helpText }), helpAddon && (jsx("span", { className: cvaHelpAddon(), "data-testid": dataTestId && `${dataTestId}-helpAddon`, children: helpAddon }))] })] }));
173
- };
265
+ const BaseInput = React.forwardRef((_a, ref) => {
266
+ var { className, isInvalid, dataTestId, prefix, suffix, addonBefore, addonAfter, actions, fieldSize = "medium", nonInteractive = false, showDefaultActions = false, type, inputClassName, addonBeforeClassName } = _a, rest = __rest(_a, ["className", "isInvalid", "dataTestId", "prefix", "suffix", "addonBefore", "addonAfter", "actions", "fieldSize", "nonInteractive", "showDefaultActions", "type", "inputClassName", "addonBeforeClassName"]);
267
+ const isReadOnlyWithPlaceholder = useMemo(() => !!rest.readOnly && !!rest.placeholder && !rest.value, [rest.readOnly, rest.placeholder, rest.value]);
268
+ const renderAsDisabled = rest.disabled || rest.readOnly;
269
+ const innerRef = React.useRef(null);
270
+ React.useImperativeHandle(ref, () => innerRef.current, []);
271
+ return (jsxs("div", { className: cvaInput({
272
+ disabled: renderAsDisabled,
273
+ invalid: isInvalid,
274
+ size: fieldSize,
275
+ className,
276
+ }), "data-testid": dataTestId && `${dataTestId}-container`, children: [addonBefore && addonBefore !== undefined ? (jsx("div", { className: cvaInputAddonBefore({ className: addonBeforeClassName }), "data-testid": dataTestId && `${dataTestId}-addonBefore`, children: addonBefore })) : null, prefix && addonBefore !== prefix ? (jsx("div", { className: cvaInputPrefix({
277
+ disabled: renderAsDisabled,
278
+ }), "data-testid": dataTestId && `${dataTestId}-prefix`, children: prefix })) : null, jsx("input", Object.assign({ className: cvaInputField({ size: fieldSize, disabled: renderAsDisabled, className: inputClassName }), "data-testid": dataTestId, ref: innerRef, type: isReadOnlyWithPlaceholder ? "text" : type }, rest, { readOnly: rest.readOnly || nonInteractive })), suffix && addonBefore !== suffix ? (jsx("div", { className: cvaInputSuffix({
279
+ disabled: renderAsDisabled,
280
+ }), "data-testid": dataTestId && `${dataTestId}-suffix`, children: suffix })) : null, rest.readOnly === true && showDefaultActions ? (jsx(ActionButton, { type: "COPY", value: innerRef }, "default-copy-action")) : null, actions && addonBefore !== actions ? actions : null, addonAfter && addonAfter !== undefined && addonBefore !== addonAfter ? (jsx("div", { className: cvaInputAddonAfter(), "data-testid": dataTestId && `${dataTestId}-addonAfter`, children: addonAfter })) : null] }));
281
+ });
174
282
 
175
- const cvaSelect = cvaMerge([
176
- "relative",
177
- "flex",
178
- "shadow-sm",
179
- "rounded-lg",
180
- "border",
181
- "border-slate-300",
182
- "focus-within:ring-2",
183
- "focus-within:ring-inset",
184
- "focus-within:ring-primary-600",
185
- "focus-within:border-slate-400",
186
- "hover:border-slate-400",
187
- "hover:bg-slate-50",
188
- "bg-white",
189
- "transition",
283
+ const cvaLabel = cvaMerge([
284
+ "text-base",
285
+ "text-slate-700",
286
+ "truncate",
287
+ "hover:text-slate-800",
288
+ "group-hover:text-slate-800",
289
+ "active:text-slate-800",
290
+ "group-active:text-slate-800",
190
291
  ], {
191
292
  variants: {
192
293
  invalid: {
193
- true: "border-red-600 text-red-600 focus-within:ring-red-600 hover:border-red-600",
294
+ true: "text-red-600 hover:text-red-700 active:text-red-700 group-hover:text-red-700 group-active:text-red-700",
194
295
  false: "",
195
296
  },
196
297
  disabled: {
197
- true: "!bg-slate-100",
298
+ true: "text-slate-400 hover:text-slate-400 group-hover:text-slate-400",
198
299
  false: "",
199
300
  },
200
301
  },
@@ -203,94 +304,15 @@ const cvaSelect = cvaMerge([
203
304
  disabled: false,
204
305
  },
205
306
  });
206
- const cvaSelectIcon = cvaMerge("mr-2 flex cursor-pointer items-center justify-center text-slate-400 hover:text-slate-500");
207
- const cvaSelectPrefix = cvaMerge(["flex", "justify-center", "items-center", "text-slate-400", "pl-2"]);
208
- const cvaSelectXIcon = cvaMerge([
209
- "mr-2 flex cursor-pointer items-center justify-center text-slate-400 hover:text-slate-500",
210
- "ml-1",
211
- ]);
212
- const cvaSelectMenuList = cvaMerge(["min-w-min", "shadow-md", "rounded-lg", "z-20", "bg-white", "p-1", "border", "border-slate-300", "gap-1", "grid"], {
213
- variants: {
214
- menuIsOpen: {
215
- true: "animate-fade-in-fast",
216
- false: "animate-fade-out-fast",
217
- },
218
- },
219
- });
220
- const cvaSelectDynamicTagContainer = cvaMerge(["h-full", "flex", "gap-1", "items-center"], {
221
- variants: {
222
- visible: { true: "visible", false: "invisible" },
223
- },
224
- });
225
- const cvaSelectCounter = cvaMerge(["overflow-hidden", "whitespace-nowrap"]);
226
- const cvaSelectMenu = cvaMerge(["relative", "p-1", "grid", "gap-1"]);
227
307
 
228
308
  /**
229
- * The SelectContainer component.
309
+ * The CheckIcon component is used by the checkbox to display the checked state.
230
310
  *
231
- * @param {SelectContainerProps} props - The props for the SelectContainer component
232
- * @returns {JSX.Element} SelectContainer component
311
+ * @param {CheckIconProps} props - The props for the CheckIcon component
312
+ * @returns {JSX.Element} CheckIcon component
233
313
  */
234
- const SelectContainer = ({ children, label, hideLabel, id, hasError, error, description, info, dataTestId, isDisabled, }) => {
235
- return (jsxs("label", { className: cvaSelect({ invalid: hasError, disabled: isDisabled }), "data-testid": dataTestId, children: [label && !hideLabel && jsx(Label, { htmlFor: id, children: label }), children, (hasError || info) && jsx(Text, { size: "small", children: hasError ? error : info })] }));
236
- };
237
-
238
- /**
239
- * @param {MultiValue<Option> | SingleValue<Option>} arg option to check type
240
- * @returns {arg is MultiValue<Option> } is Multivalue
241
- */
242
- function isMultiValue(arg) {
243
- return Array.isArray(arg);
244
- }
245
- function isGroupBase(arg) {
246
- return arg.options !== undefined;
247
- }
248
- const isSelectedOption = (option, selected) => {
249
- if (isGroupBase(option)) {
250
- return false;
251
- }
252
- return isMultiValue(selected)
253
- ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
254
- selected.some(v => v.value === option.value)
255
- : // eslint-disable-next-line @typescript-eslint/no-explicit-any
256
- option.value === (selected === null || selected === void 0 ? void 0 : selected.value);
257
- };
258
- const removeSelectedFromGroups = (group, selected) => {
259
- if (isGroupBase(group)) {
260
- return Object.assign(Object.assign({}, group), { options: group.options.filter(option => !isSelectedOption(option, selected)) });
261
- }
262
- return group;
263
- };
264
- /**
265
- * @template IsMulti
266
- * @template Group
267
- * @param {OptionsOrGroups<Option, Group> | undefined} options An array of options to select from
268
- * @param {PropsValue<Option> | undefined} value Selected values
269
- * @returns {OptionsOrGroups<Option, Group>} An array of ordered options with selected on top
270
- */
271
- const getOrderedOptions = (options, value) => {
272
- if (value && options) {
273
- const orderedValues = isMultiValue(value)
274
- ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
275
- [...value].sort((a, b) => a.label.localeCompare(b.label))
276
- : [value];
277
- const selectableOptions = options
278
- .filter(option => !isSelectedOption(option, value))
279
- .map(option => removeSelectedFromGroups(option, value));
280
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
281
- return orderedValues.concat(selectableOptions) || [];
282
- }
283
- return options || [];
284
- };
285
-
286
- /**
287
- * The CheckIcon component is used by the checkbox to display the checked state.
288
- *
289
- * @param {CheckIconProps} props - The props for the CheckIcon component
290
- * @returns {JSX.Element} CheckIcon component
291
- */
292
- const CheckIcon = ({ className, dataTestId }) => {
293
- return (jsx("svg", { className: className, "data-testid": dataTestId, fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 10 10", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "m2 5.5 2 2L8.5 3", strokeLinecap: "round", strokeLinejoin: "round" }) }));
314
+ const CheckIcon = ({ className, dataTestId }) => {
315
+ return (jsx("svg", { className: className, "data-testid": dataTestId, fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 10 10", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "m2 5.5 2 2L8.5 3", strokeLinecap: "round", strokeLinejoin: "round" }) }));
294
316
  };
295
317
 
296
318
  const cvaCheckbox = cvaMerge([
@@ -471,662 +493,117 @@ const Checkbox = React.forwardRef((_a, ref) => {
471
493
  });
472
494
 
473
495
  /**
474
- * A single select menu item is a basic wrapper around Menu item designed to be used as a single value render in Select list
496
+ * A wrapper around BaseInput with a pop-up day picker.
475
497
  *
476
- * @param {SelectMenuItemProps} props - The props for the SingleSelectMenuItem
477
- * @returns {JSX.Element} SingleSelectMenuItem
498
+ * NOTE: If shown with a label, please use the `DateField` component instead.
478
499
  */
479
- const SingleSelectMenuItem = ({ label, icon, onClick, selected, dataTestId, focused, disabled, }) => {
480
- return (jsx(MenuItem, { dataTestId: dataTestId, disabled: disabled, focused: focused, label: label, onClick: onClick, prefix: icon, selected: selected, suffix: selected ? jsx(Icon, { name: "Check", size: "small" }) : undefined }));
481
- };
500
+ const DateInput = forwardRef((_a, ref) => {
501
+ var { min, max, defaultValue, value } = _a, rest = __rest(_a, ["min", "max", "defaultValue", "value"]);
502
+ const formatDateToInputString = (date) => date instanceof Date ? format(date, "yyyy-MM-dd") : date;
503
+ // Chrome and Firefox need their default icon to have datepicker functionality.
504
+ const showIcon = !/Chrome/.test(navigator.userAgent) && !/Firefox/.test(navigator.userAgent);
505
+ return (jsx(BaseInput, Object.assign({ defaultValue: formatDateToInputString(defaultValue), max: formatDateToInputString(max), min: formatDateToInputString(min), ref: ref, suffix: showIcon && jsx(Icon, { dataTestId: "calendar", name: "Calendar", size: "medium", type: "solid" }), type: "date", value: formatDateToInputString(value) }, rest)));
506
+ });
507
+
482
508
  /**
483
- * A multi select menu item is a basic wrapper around Menu item designed to be used as a multi value render in Select list
509
+ * The Label component is used for labels for input fields.
510
+ * This component is **not used directly**, but is part of the FormGroup and Field components.
484
511
  *
485
- * @param {SelectMenuItemProps} props - The props for the MultiSelectMenuItem
486
- * @returns {JSX.Element} multi select menu item
512
+ * @param {LabelProps} props - The props for the Label component
513
+ * @returns {JSX.Element} Label component
487
514
  */
488
- const MultiSelectMenuItem = ({ label, onClick, selected, dataTestId, focused, disabled, }) => {
489
- return (jsx(MenuItem, { dataTestId: dataTestId, disabled: disabled, focused: focused, label: label, onClick: e => {
490
- e.stopPropagation();
491
- onClick && onClick(e);
492
- }, prefix: jsx(Checkbox, { checked: selected, disabled: disabled, onChange: () => null, onClick: e => {
493
- e.stopPropagation();
494
- }, readOnly: false }), selected: selected }));
515
+ const Label = ({ id, htmlFor, children, className, dataTestId, disabled, isInvalid, }) => {
516
+ return (jsx("label", { className: cvaLabel({ invalid: isInvalid, disabled, className }), "data-testid": dataTestId, htmlFor: htmlFor || "", id: id || "", children: children }));
495
517
  };
496
518
 
519
+ const cvaFormGroup = cvaMerge(["component-formGroup-gap"], {
520
+ variants: {
521
+ disabled: {
522
+ true: "pointer-events-none",
523
+ false: "",
524
+ },
525
+ },
526
+ });
527
+ const cvaFormGroupContainerBefore = cvaMerge(["flex", "gap-1", "mb-1"]);
528
+ const cvaFormGroupContainerAfter = cvaMerge(["flex", "justify-between", "mt-1", "text-xs", "text-slate-500"], {
529
+ variants: {
530
+ invalid: {
531
+ true: "text-danger-500",
532
+ false: "",
533
+ },
534
+ },
535
+ });
536
+ const cvaHelpAddon = cvaMerge(["ml-auto"]);
537
+
497
538
  /**
498
- * Extended Tag component with information about its own width.
499
- * Used in the select component.
539
+ * The FormGroup component should be used to wrap any Input element that needs a label.
540
+ * Besides a label the component supplies an optional Tooltip, HelpText and HelpAddon support.
500
541
  *
501
- * @param {TagProps} props - The props for the tag component
502
- * @returns {JSX.Element} TagWithWidth component
542
+ * @param {FormGroupProps} props - The props for the FormGroup component
543
+ * @returns {JSX.Element} FormGroup component
503
544
  */
504
- const TagWithWidth = (_a) => {
505
- var { onWidthKnown, children } = _a, rest = __rest(_a, ["onWidthKnown", "children"]);
506
- const ref = React__default.useRef(null);
507
- React__default.useLayoutEffect(() => {
508
- var _a;
509
- onWidthKnown && onWidthKnown({ width: ((_a = ref.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 0 });
510
- }, [ref, onWidthKnown]);
511
- return (jsx(Tag, Object.assign({ ref: ref }, rest, { children: children })));
545
+ const FormGroup = ({ isInvalid, helpText, helpAddon, tip, className, dataTestId, label, htmlFor, children, tipIconProps, disabled = false, }) => {
546
+ return (jsxs("div", { className: cvaFormGroup({ disabled, className }), "data-testid": dataTestId, children: [jsxs("div", { className: cvaFormGroupContainerBefore(), children: [jsx(Label, { className: "component-formGroup-font", dataTestId: dataTestId && `${dataTestId}-label`, htmlFor: htmlFor, id: htmlFor + "-label", children: label }), tip && (jsx(Tooltip, { dataTestId: dataTestId && `${dataTestId}-tooltip`, iconProps: tipIconProps, label: tip, placement: "bottom" }))] }), children, jsxs("div", { className: cvaFormGroupContainerAfter({ invalid: isInvalid }), children: [helpText && jsx("span", { "data-testid": dataTestId && `${dataTestId}-helpText`, children: helpText }), helpAddon && (jsx("span", { className: cvaHelpAddon(), "data-testid": dataTestId && `${dataTestId}-helpAddon`, children: helpAddon }))] })] }));
512
547
  };
513
548
 
514
549
  /**
515
- * TagsContainer component to display tags in limited space when children can't fit space it displays counter
550
+ * The date field component is used for entering date values.
516
551
  *
517
- * @param {TagsContainerProps} props - The props for the TagContainer
518
- * @returns {JSX.Element} TagsContainer
552
+ * _**Do use**_ the DateField for date input.
553
+ *
554
+ * _**Do not use**_ this fields for non-serialized dates. Use TextField instead.
519
555
  */
520
- const TagsContainer = ({ items, width = "100%", itemsGap = 5, postFix, disabled }) => {
521
- const [isReady, setIsReady] = React__default.useState(false);
522
- const [counterWidth, setCounterWidth] = React__default.useState(0);
523
- const containerRef = React__default.useRef(null);
524
- const availableWidth = React__default.useRef();
525
- const childrenWidth = React__default.useRef([]);
526
- const itemsCount = items.length;
527
- React__default.useLayoutEffect(() => {
528
- var _a;
529
- availableWidth.current = ((_a = containerRef === null || containerRef === void 0 ? void 0 : containerRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 0;
530
- }, [containerRef]);
531
- const onWidthKnownHandler = ({ width: reportedWidth }) => {
532
- childrenWidth.current.push({ width: reportedWidth + itemsGap });
533
- if (childrenWidth.current.length === itemsCount) {
534
- setIsReady(true);
535
- }
536
- };
537
- const requiredSpace = childrenWidth.current.reduce((previous, current) => {
538
- return previous + current.width;
539
- }, 0);
540
- let counter = 0;
541
- const availableSpace = ((availableWidth === null || availableWidth === void 0 ? void 0 : availableWidth.current) || 0) - counterWidth;
542
- const renderedElements = items
543
- .concat({ text: "", onClick: () => null, disabled: false }) // reserved element for a potential counter
544
- .map((item, index) => {
545
- const spaceNeeded = childrenWidth.current.slice(0, index + 1).reduce((previous, current) => {
546
- return previous + current.width;
547
- }, 0);
548
- const isLast = index === items.length;
549
- const counterRequired = requiredSpace > availableSpace && counter !== 0;
550
- if (isLast && counterRequired) {
551
- return (jsx(TagWithWidth, { color: "white", disabled: disabled, onWidthKnown: ({ width: reportedWidth }) => setCounterWidth(reportedWidth), children: jsxs("div", { className: cvaSelectCounter(), "data-testid": "select-counter", children: ["+", counter] }) }, item.text + index));
552
- }
553
- if (isLast) {
554
- return null;
555
- }
556
- const itemCanFit = spaceNeeded <= availableSpace;
557
- if (itemCanFit) {
558
- return (jsx(TagWithWidth, { className: "inline-flex shrink-0", color: item.disabled ? "unknown" : "primary", dataTestId: `${item.text}-tag`, disabled: disabled, onClose: e => {
559
- e.stopPropagation();
560
- item.onClick();
561
- }, onWidthKnown: onWidthKnownHandler, children: item.text }, item.text + index));
562
- }
563
- const fromTheItems = item.text !== "";
564
- if (fromTheItems) {
565
- counter = counter + 1;
566
- }
567
- return null;
568
- })
569
- .filter(element => element !== null);
570
- return (jsxs("div", { className: cvaSelectDynamicTagContainer({ visible: isReady }), ref: containerRef, style: {
571
- width: `${width}`,
572
- }, children: [renderedElements, postFix] }));
573
- };
556
+ const DateField = forwardRef((_a, ref) => {
557
+ var { label, id, tip, helpText, errorMessage, helpAddon, isInvalid, className, defaultValue, dataTestId } = _a, rest = __rest(_a, ["label", "id", "tip", "helpText", "errorMessage", "helpAddon", "isInvalid", "className", "defaultValue", "dataTestId"]);
558
+ const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
559
+ const htmlForId = id ? id : "dateField-" + v4();
560
+ return (jsx(FormGroup, { dataTestId: dataTestId && `${dataTestId}-FormGroup`, disabled: rest.disabled, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, tip: tip, children: jsx(DateInput, Object.assign({ "aria-labelledby": htmlForId + "-label", defaultValue: defaultValue, id: htmlForId, isInvalid: renderAsInvalid, ref: ref }, rest, { className: className, dataTestId: dataTestId })) }));
561
+ });
562
+
563
+ const cvaDropZone = cvaMerge([
564
+ "flex",
565
+ "component-baseInput-background",
566
+ "justify-center",
567
+ "text-slate-500",
568
+ "rounded-sm",
569
+ "border-2",
570
+ "border-gray-200",
571
+ "border-dashed",
572
+ "hover:bg-slate-100",
573
+ "hover:border-solid",
574
+ "hover:border-primary-500",
575
+ ], {
576
+ variants: {
577
+ size: {
578
+ small: ["p-2"],
579
+ medium: ["p-4"],
580
+ large: ["p-8"],
581
+ },
582
+ disabled: { true: ["bg-slate-100", "hover:bg-slate-100"], false: "" },
583
+ dragActive: { true: ["border-gray-200", "bg-slate-100"], false: "" },
584
+ dropComplete: {
585
+ true: ["border-solid", "border-primary-500", "bg-slate-100", "hover:border-solid", "hover:border-gray-200"],
586
+ false: "",
587
+ },
588
+ invalid: { true: ["border-danger-600", "text-danger-500"], false: "" },
589
+ },
590
+ });
591
+ const cvaDropZoneLabel = cvaMerge([
592
+ "h-full",
593
+ "pt-1",
594
+ "pb-1",
595
+ "gap-2",
596
+ "items-center",
597
+ "flex-col",
598
+ "flex",
599
+ "justify-center",
600
+ ]);
574
601
 
575
602
  /**
576
- * A hook to retrieve components override object.
577
- * This complex object includes all the compositional components that are used in react-select. If you wish to overwrite a component, pass in an object with the appropriate namespace.
603
+ * The Drop Zone can be used to drag and drop files
578
604
  *
579
- * @template IsMulti
580
- * @template Group
581
- * @param {Partial<SelectComponents<Option, IsMulti, Group>> | undefined} componentsProps a custom component prop that you can to override defaults
582
- * @param {boolean} disabled decide to override disabled variant
583
- * @param {boolean} menuIsOpen menu is open state
584
- * @param {React.MutableRefObject<boolean>} refMenuIsEnabled a flag to block menu from open
585
- * @param {string} dataTestId a test id
586
- * @param {number} maxSelectedDisplayCount a number of max display count
587
- * @param {JSX.Element} dropdownIcon an custom dropdown icon
588
- * @returns {Partial<SelectComponents<Option, boolean, GroupBase<Option>>> | undefined} components object to override react-select default components
589
- */
590
- const useCustomComponents = (componentsProps, disabled, menuIsOpen, refMenuIsEnabled, dataTestId, maxSelectedDisplayCount, dropdownIcon) => {
591
- const [t] = useTranslation();
592
- // perhaps it should not be wrap in memo (causing some issues with opening and closing on mobiles)
593
- const customComponents = React.useMemo(() => {
594
- return Object.assign({ ValueContainer: props => {
595
- if (props.isMulti && Array.isArray(props.children) && props.children.length > 0) {
596
- const PLACEHOLDER_KEY = "placeholder";
597
- const key = props && props.children && props.children[0] ? props.children[0].key : "";
598
- const values = props && props.children ? props.children[0] : [];
599
- const tags = key === PLACEHOLDER_KEY ? [] : values;
600
- const searchInput = props && props.children && props.children[1];
601
- return (jsx(components.ValueContainer, Object.assign({}, props, { isDisabled: props.selectProps.isDisabled, children: maxSelectedDisplayCount === undefined ? (jsx(TagsContainer, { disabled: disabled, items: tags
602
- ? tags.map(({ props: tagProps }) => {
603
- return {
604
- text: tagProps.children,
605
- onClick: disabled
606
- ? undefined
607
- : (e) => {
608
- var _a, _b;
609
- refMenuIsEnabled.current = false;
610
- ((_a = tagProps === null || tagProps === void 0 ? void 0 : tagProps.removeProps) === null || _a === void 0 ? void 0 : _a.onClick) && ((_b = tagProps === null || tagProps === void 0 ? void 0 : tagProps.removeProps) === null || _b === void 0 ? void 0 : _b.onClick(e));
611
- },
612
- disabled: disabled,
613
- };
614
- })
615
- : [], postFix: searchInput, width: "100%" })) : (jsxs(Fragment, { children: [tags &&
616
- tags.slice(0, maxSelectedDisplayCount).map(({ props: tagProps }) => {
617
- var _a, _b;
618
- return (jsx(Tag, { className: "inline-flex shrink-0", color: disabled ? "unknown" : "primary", dataTestId: tagProps.children ? `${(_a = tagProps.children) === null || _a === void 0 ? void 0 : _a.toString()}-tag` : undefined, onClose: e => {
619
- var _a, _b;
620
- e.stopPropagation();
621
- refMenuIsEnabled.current = false;
622
- ((_a = tagProps === null || tagProps === void 0 ? void 0 : tagProps.removeProps) === null || _a === void 0 ? void 0 : _a.onClick) && ((_b = tagProps === null || tagProps === void 0 ? void 0 : tagProps.removeProps) === null || _b === void 0 ? void 0 : _b.onClick(e));
623
- }, children: tagProps.children }, (_b = tagProps.children) === null || _b === void 0 ? void 0 : _b.toString()));
624
- }), tags && tags.length > maxSelectedDisplayCount && (jsxs(Tag, { color: "neutral", dataTestId: "counter-tag", children: ["+", tags.length - maxSelectedDisplayCount] })), searchInput] })) })));
625
- }
626
- return (jsx(components.ValueContainer, Object.assign({}, props, { isDisabled: props.selectProps.isDisabled, children: props.children })));
627
- }, LoadingIndicator: props => {
628
- return jsx(Spinner, { className: "mt-1.5 mr-1", size: "small" });
629
- }, DropdownIndicator: props => {
630
- const icon = props.selectProps.menuIsOpen ? (jsx(Icon, { name: "ChevronUp", size: "medium" })) : (jsx(Icon, { name: "ChevronDown", size: "medium" }));
631
- return props.selectProps.isLoading ? null : (jsx(components.DropdownIndicator, Object.assign({}, props, { children: jsx("div", { className: cvaSelectIcon(), children: dropdownIcon ? dropdownIcon : icon }) })));
632
- }, IndicatorSeparator: () => null, ClearIndicator: props => {
633
- if (disabled) {
634
- return null;
635
- }
636
- return (jsx(components.ClearIndicator, Object.assign({}, props, { children: jsx("div", { className: cvaSelectXIcon(), "data-testid": dataTestId && `${dataTestId}-XMarkIcon`, onClick: props.clearValue, children: jsx(Icon, { name: "XCircle", size: "medium", title: t("clearIndicator.icon.tooltip.clearAll") }) }) })));
637
- }, Control: props => {
638
- return jsx(components.Control, Object.assign({}, props, { className: props.isDisabled ? "bg-slate-100" : "" }));
639
- }, SingleValue: props => {
640
- return (jsx(components.SingleValue, Object.assign({}, props, { className: props.isDisabled ? "text-slate-700" : "", children: jsx("div", { "data-testid": dataTestId + "-singleValue", children: props.children }) })));
641
- }, Menu: props => {
642
- return (jsx(components.Menu, Object.assign({}, props, { className: cvaSelectMenuList({ menuIsOpen: props.selectProps.menuIsOpen }) })));
643
- }, MenuList: props => {
644
- return (jsx(components.MenuList, Object.assign({}, props, { innerProps: Object.assign(Object.assign({}, props.innerProps), { onScroll: e => {
645
- const listEl = e.currentTarget;
646
- if (listEl.scrollTop + listEl.clientHeight >= listEl.scrollHeight) {
647
- props.selectProps.onMenuScrollToBottom && props.selectProps.onMenuScrollToBottom(new TouchEvent(""));
648
- }
649
- } }), children: props.children })));
650
- }, Option: props => {
651
- const componentProps = {
652
- label: props.label,
653
- focused: props.isFocused,
654
- selected: props.isSelected,
655
- onClick: props.innerProps.onClick,
656
- };
657
- return (jsx(components.Option, Object.assign({}, props, { innerProps: Object.assign(Object.assign({}, props.innerProps), { role: "option", onClick: () => { } }), children: props.isMulti ? (jsx(MultiSelectMenuItem, Object.assign({}, componentProps, { dataTestId: typeof props.label === "string" ? props.label : undefined, disabled: disabled }))) : (jsx(SingleSelectMenuItem, Object.assign({}, componentProps, { dataTestId: typeof props.label === "string" ? props.label : undefined, disabled: disabled || props.isDisabled }))) })));
658
- } }, componentsProps);
659
- // eslint-disable-next-line react-hooks/exhaustive-deps
660
- }, [componentsProps, disabled, maxSelectedDisplayCount]); // do not add dropdownIcon (it will cause issue with opening/closing list for selects with custom icon)
661
- return customComponents;
662
- };
663
-
664
- /**
665
- * @template IsMulti
666
- * @template Group
667
- * @param {React.RefObject<HTMLDivElement>} refContainer react ref to container element
668
- * @param {React.RefObject<HTMLDivElement>} refPrefix react ref to prefix element
669
- * @param {number | undefined} maxSelectedDisplayCount a number of max display count
670
- * @param {StylesConfig<Option, IsMulti, Group> | undefined} styles a optional object to override styles of react-select
671
- * @returns {StylesConfig<Option, boolean>} styles to override in select
672
- */
673
- const useCustomStyles = (refContainer, refPrefix, maxSelectedDisplayCount, styles, disabled) => {
674
- const customStyles = React.useMemo(() => {
675
- return Object.assign({ control: base => {
676
- return Object.assign(Object.assign({}, base), { border: "0", boxShadow: "0", "&:hover": {
677
- border: "0",
678
- }, marginRight: "2px", backgroundColor: "" });
679
- }, singleValue: base => (Object.assign({}, base)), multiValue: base => (Object.assign({}, base)), multiValueLabel: base => (Object.assign({}, base)), indicatorsContainer: base => (Object.assign(Object.assign({}, base), (disabled && { display: "none" }))), indicatorSeparator: () => ({
680
- width: "0px",
681
- }), menu: base => {
682
- return Object.assign(Object.assign({}, base), { width: "100%", marginTop: "4px", marginBottom: "18px", transition: "all 1s ease-in-out" });
683
- }, input: base => (Object.assign(Object.assign({}, base), { marginLeft: "0px" })), placeholder: base => (Object.assign({}, base)), option: () => ({}), menuPortal: base => (Object.assign(Object.assign({}, base), { width: (refContainer === null || refContainer === void 0 ? void 0 : refContainer.current) ? `${refContainer.current.clientWidth}px` : base.width, transform: (refPrefix === null || refPrefix === void 0 ? void 0 : refPrefix.current) ? `translate(-${refPrefix.current.clientWidth + 2}px)` : "translate(-2px)", backgroundColor: "#ffffff", borderRadius: "var(--border-radius-lg)", zIndex: 20, borderColor: "rgb(var(--color-slate-300))", boxShadow: "var(--tw-ring-inset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)" })), menuList: base => {
684
- return Object.assign(Object.assign({}, base), { position: "relative", padding: "var(--spacing-1)", display: "grid", gap: "var(--spacing-1)", width: "100%", borderRadius: "0px", boxShadow: "none", paddingTop: "0px" });
685
- }, valueContainer: base => {
686
- return Object.assign(Object.assign({}, base), { flexWrap: maxSelectedDisplayCount !== undefined ? "wrap" : "nowrap", gap: "0.25rem" });
687
- }, container: base => (Object.assign(Object.assign({}, base), { border: "none", width: "calc(100% - 2px)", paddingLeft: "2px" })), dropdownIndicator: base => (Object.assign(Object.assign({}, base), { padding: "0px" })), clearIndicator: base => {
688
- return Object.assign(Object.assign({}, base), { padding: "0px" });
689
- } }, styles);
690
- // eslint-disable-next-line react-hooks/exhaustive-deps
691
- }, [refContainer, refPrefix]);
692
- return { customStyles };
693
- };
694
-
695
- /**
696
- * A hook used by selects to share the common code
697
- *
698
- * @param {SelectProps} props - The props for the Select component
699
- * @returns {IUseSelect} Select component
700
- */
701
- const useSelect = (_a) => {
702
- var _b;
703
- var { id, className, dataTestId = "select", prefix, async, dropdownIcon, maxMenuHeight = 200, label, hasError, disabled, isMulti, components, value, options, onChange, isLoading, classNamePrefix = "", onMenuOpen, onMenuClose, maxSelectedDisplayCount = undefined, isClearable = false, isSearchable = true, onMenuScrollToBottom, styles, filterOption, onInputChange } = _a, props = __rest(_a, ["id", "className", "dataTestId", "prefix", "async", "dropdownIcon", "maxMenuHeight", "label", "hasError", "disabled", "isMulti", "components", "value", "options", "onChange", "isLoading", "classNamePrefix", "onMenuOpen", "onMenuClose", "maxSelectedDisplayCount", "isClearable", "isSearchable", "onMenuScrollToBottom", "styles", "filterOption", "onInputChange"]);
704
- const refContainer = React__default.useRef(null);
705
- const refPrefix = React__default.useRef(null);
706
- const { customStyles } = useCustomStyles(refContainer, refPrefix, maxSelectedDisplayCount, styles, disabled);
707
- const [menuIsOpen, setMenuIsOpen] = React__default.useState((_b = props.menuIsOpen) !== null && _b !== void 0 ? _b : false);
708
- const refMenuIsEnabled = React__default.useRef(true);
709
- const customComponents = useCustomComponents(components, disabled || false, menuIsOpen, refMenuIsEnabled, dataTestId, maxSelectedDisplayCount, dropdownIcon);
710
- const menuPlacement = "auto";
711
- const openMenuHandler = () => __awaiter(void 0, void 0, void 0, function* () {
712
- onMenuOpen && onMenuOpen();
713
- if (refMenuIsEnabled.current) {
714
- setMenuIsOpen(true);
715
- }
716
- else {
717
- refMenuIsEnabled.current = true;
718
- }
719
- });
720
- const closeMenuHandler = () => {
721
- setMenuIsOpen(false);
722
- onMenuClose && onMenuClose();
723
- };
724
- const orderedOptions = React__default.useMemo(() => {
725
- return disabled
726
- ? getOrderedOptions(options, value).map(option => {
727
- return Object.assign(Object.assign({}, option), { disabled: true });
728
- })
729
- : getOrderedOptions(options, value);
730
- }, [options, value, disabled]);
731
- return {
732
- refContainer,
733
- refPrefix,
734
- customStyles,
735
- menuIsOpen,
736
- customComponents,
737
- menuPlacement,
738
- openMenuHandler,
739
- closeMenuHandler,
740
- orderedOptions,
741
- };
742
- };
743
-
744
- /**
745
- * The CreatableSelect component.
746
- *
747
- * @param {CreateableSelectProps} props - The props for the CreatableSelect component
748
- * @returns {JSX.Element} CreatableSelect component
749
- */
750
- const CreatableSelect = (props) => {
751
- const { id, dataTestId = "select", async, maxMenuHeight = 200, label, error, disabled, isMulti, value, hideLabel, description, info, options, onChange, isLoading, classNamePrefix = "", filterOption, prefix, onInputChange, placeholder, isClearable, } = props;
752
- const hasError = !!error;
753
- const { refPrefix, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler, orderedOptions, } = useSelect(props);
754
- const selectProps = {
755
- value,
756
- menuPlacement,
757
- maxMenuHeight,
758
- onChange,
759
- "aria-label": label,
760
- "data-testid": dataTestId,
761
- components: customComponents,
762
- styles: customStyles,
763
- tabSelectsValue: false,
764
- blurInputOnSelect: !isMulti,
765
- menuPortalTarget: document.body,
766
- isSearchable: disabled ? false : true,
767
- menuShouldBlockScroll: true,
768
- menuShouldScrollIntoView: true,
769
- openMenuOnFocus: disabled ? false : true,
770
- menuIsOpen: disabled ? false : menuIsOpen,
771
- openMenuOnClick: true,
772
- closeMenuOnSelect: false,
773
- isMulti: isMulti,
774
- classNamePrefix,
775
- isLoading,
776
- onInputChange,
777
- placeholder,
778
- isClearable,
779
- id,
780
- };
781
- return (jsx(SelectContainer, { dataTestId: dataTestId, description: description, error: error, hasError: hasError, hideLabel: hideLabel, id: id, info: info, isDisabled: disabled, label: label, children: jsxs(Fragment, { children: [prefix !== undefined && (jsx("div", { className: cvaSelectPrefix(), "data-testid": dataTestId && `${dataTestId}-prefix`, ref: refPrefix, children: prefix })), async ? (jsx(ReactAsyncCreatableSelect, Object.assign({ "aria-label": label, components: customComponents, "data-testid": dataTestId, maxMenuHeight: maxMenuHeight }, props, { onMenuClose: () => {
782
- closeMenuHandler();
783
- }, onMenuOpen: () => {
784
- !disabled && openMenuHandler();
785
- } }))) : (jsx(ReactCreatableSelect, Object.assign({}, selectProps, { isMulti: isMulti, onMenuClose: () => {
786
- closeMenuHandler();
787
- }, onMenuOpen: () => {
788
- !disabled && openMenuHandler();
789
- }, options: filterOption ? orderedOptions : options })))] }) }));
790
- };
791
-
792
- /**
793
- * Selects are input components used to choose a value from a set.
794
- *
795
- * @param {SelectProps} props - The props for the Select component
796
- * @returns {JSX.Element} Select component
797
- */
798
- const Select = (props) => {
799
- const { className } = props, propsNoClassName = __rest(props, ["className"]);
800
- const { id, dataTestId = "select", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, value, options, onChange, isLoading, classNamePrefix = dataTestId ? dataTestId : "select", onMenuScrollToBottom, filterOption, onInputChange, isSearchable, isClearable = false, readOnly, openMenuOnClick = !disabled, openMenuOnFocus = !disabled, } = props;
801
- const { refContainer, refPrefix, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler, orderedOptions, } = useSelect(props);
802
- const selectProps = {
803
- value,
804
- menuPlacement,
805
- maxMenuHeight,
806
- onChange,
807
- "aria-label": label,
808
- "data-testid": dataTestId,
809
- components: customComponents,
810
- styles: customStyles,
811
- tabSelectsValue: false,
812
- blurInputOnSelect: !isMulti,
813
- menuPortalTarget: props.menuPortalTarget || document.body,
814
- isSearchable: disabled || readOnly ? false : isSearchable,
815
- menuShouldBlockScroll: true,
816
- menuShouldScrollIntoView: true,
817
- openMenuOnFocus,
818
- menuIsOpen: !readOnly ? menuIsOpen : false,
819
- openMenuOnClick,
820
- closeMenuOnSelect: false,
821
- isMulti,
822
- classNamePrefix,
823
- isLoading,
824
- isClearable,
825
- id,
826
- onMenuScrollToBottom,
827
- onInputChange,
828
- };
829
- return (jsxs("div", { className: cvaSelect({ invalid: hasError, disabled: disabled || readOnly, className }), "data-testid": dataTestId, ref: refContainer, children: [prefix !== undefined && (jsx("div", { className: cvaSelectPrefix(), "data-testid": dataTestId && `${dataTestId}-prefix`, ref: refPrefix, children: prefix })), async ? (jsx(ReactAsyncSelect, Object.assign({}, propsNoClassName, selectProps, async, { onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler }))) : (jsx(ReactSelect, Object.assign({}, propsNoClassName, selectProps, { hideSelectedOptions: false, isMulti: isMulti, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, options: filterOption ? orderedOptions : options })))] }));
830
- };
831
- Select.displayName = "Select";
832
-
833
- /**
834
- * The SelectField component is a Select component wrapped in the FromGroup component.
835
- *
836
- * This means that it can easily be added to any form alongside other Field components.
837
- *
838
- * This is done to make the field compatible with the React-hook-form library.
839
- *
840
- * @param {SelectFieldProps} props - The props for the SelectField component
841
- * @returns {JSX.Element} SelectField component
842
- */
843
- const SelectField = forwardRef((_a, ref) => {
844
- var { className, dataTestId, helpText, helpAddon, tip, label, disabled, isInvalid, errorMessage, name, onBlur, options, value, defaultValue, id, onChange } = _a; __rest(_a, ["className", "dataTestId", "helpText", "helpAddon", "tip", "label", "disabled", "isInvalid", "errorMessage", "name", "onBlur", "options", "value", "defaultValue", "id", "onChange"]);
845
- const [innerValue, setInnerValue] = useState(value || defaultValue);
846
- const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
847
- const htmlFor = useMemo(() => (id ? id : "selectField-" + v4()), [id]);
848
- const innerRef = useRef(null);
849
- useImperativeHandle(ref, () => innerRef.current, []);
850
- const handleChange = useCallback((newValue) => {
851
- setInnerValue(newValue === null || newValue === void 0 ? void 0 : newValue.value);
852
- }, []);
853
- useEffect(() => {
854
- var _a;
855
- if (!innerValue) {
856
- return;
857
- }
858
- const event = new Event("change");
859
- (_a = innerRef.current) === null || _a === void 0 ? void 0 : _a.dispatchEvent(event);
860
- // The event as unknown as ChangeEvent<HTMLInputElement> assertion is needed because
861
- // the event's type is inferred as Event, which doesn't have a target property, whereas ChangeEvent does.
862
- onChange === null || onChange === void 0 ? void 0 : onChange(event);
863
- }, [onChange, innerValue]);
864
- const selectedOption = useMemo(() => options.find(option => option.value === value), [options, value]);
865
- const defaultSelectedOption = options.find(option => option.value === defaultValue);
866
- return (jsxs(FormGroup, { isInvalid: renderAsInvalid,
867
- htmlFor,
868
- className,
869
- dataTestId,
870
- helpText,
871
- helpAddon,
872
- tip,
873
- label,
874
- disabled, children: [jsx("select", { onChange, ref: innerRef, name, value: innerValue, hidden: true, children: options.map(option => {
875
- return (jsx("option", { value: option.value, children: option.label }, option.value));
876
- }) }), jsx(Select, { id,
877
- isDisabled: disabled,
878
- onBlur,
879
- options,
880
- onChange: handleChange,
881
- value: selectedOption,
882
- defaultValue: defaultSelectedOption })] }));
883
- });
884
-
885
- const cvaActionButton = cvaMerge(["drop-shadow-none", "rounded-md"], {
886
- variants: {
887
- size: {
888
- small: ["w-6", "h-6"],
889
- medium: ["w-8", "h-8"],
890
- },
891
- },
892
- defaultVariants: {
893
- size: "medium",
894
- },
895
- });
896
- const cvaActionContainer = cvaMerge(["flex", "items-center", "m-1"]);
897
-
898
- /**
899
- * The ActionButton component is a wrapper over IconButton to perform an action when the onClick event is triggered.
900
- *
901
- * @param {ActionButtonProps} props - The props for the ActionButton component
902
- * @returns {JSX.Element} ActionButton component
903
- */
904
- const ActionButton = ({ type, value, dataTestId, iconSize, disabled, key, className }) => {
905
- const [, copyToClipboard] = useCopyToClipboard();
906
- const elementKey = useMemo(() => key !== null && key !== void 0 ? key : `ActionButton-${v4()}`, [key]);
907
- const getIconName = () => {
908
- switch (type) {
909
- case "PHONE_NUMBER":
910
- return "PhoneArrowUpRight";
911
- case "WEB_ADDRESS":
912
- return "ArrowTopRightOnSquare";
913
- case "EMAIL":
914
- return "Envelope";
915
- case "COPY":
916
- default:
917
- return "ClipboardDocument";
918
- }
919
- };
920
- const ButtonAction = () => {
921
- var _a, _b;
922
- switch (type) {
923
- case "EMAIL":
924
- return window.open(`mailto:${value}`);
925
- case "WEB_ADDRESS":
926
- if (value) {
927
- return window.open(value, "_blank", "noopener,noreferrer");
928
- }
929
- return null;
930
- case "PHONE_NUMBER":
931
- return window.open(`tel:${value}`);
932
- case "COPY":
933
- return copyToClipboard((_b = (_a = value === null || value === void 0 ? void 0 : value.current) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : "");
934
- default:
935
- return null;
936
- }
937
- };
938
- if (ButtonAction === null) {
939
- return null;
940
- }
941
- return (jsx("div", { className: cvaActionContainer({ className }), children: jsx(IconButton, { className: cvaActionButton({ size: iconSize }), dataTestId: dataTestId || "testIconButtonId", disabled: disabled, icon: jsx(Icon, { name: getIconName(), size: "small" }), onClick: ButtonAction, size: "small", variant: "secondary" }) }, elementKey));
942
- };
943
-
944
- const cvaInputBase = cvaMerge([
945
- "component-baseInput-shadow",
946
- "component-baseInput-border",
947
- "component-baseInput-background",
948
- "border-slate-300",
949
- "focus-within:ring-2",
950
- "focus-within:ring-inset",
951
- "focus-within:ring-primary-500",
952
- "focus-within:border-slate-400",
953
- "hover:border-slate-400",
954
- "hover:bg-slate-50",
955
- "transition",
956
- ]);
957
- const cvaInputBaseDisabled = cvaMerge(["bg-slate-100", "hover:bg-slate-100", "hover:border-slate-300"]);
958
- const cvaInputBaseInvalid = cvaMerge(["border-danger-600", "focus-within:ring-danger-600"]);
959
- const cvaInput = cvaMerge(["relative", "flex", "h-10", cvaInputBase()], {
960
- variants: {
961
- size: {
962
- small: ["h-8"],
963
- medium: ["h-10"],
964
- },
965
- disabled: {
966
- true: cvaInputBaseDisabled(),
967
- false: "",
968
- },
969
- invalid: {
970
- true: cvaInputBaseInvalid(),
971
- false: "",
972
- },
973
- },
974
- });
975
- const cvaInputField = cvaMerge([
976
- "w-full",
977
- "px-3",
978
- "border-0",
979
- "bg-transparent",
980
- "text-base",
981
- "text-slate-900",
982
- "placeholder-slate-400",
983
- "focus-visible:outline-none",
984
- ], {
985
- variants: {
986
- size: {
987
- small: ["py-1"],
988
- medium: ["py-2"],
989
- },
990
- disabled: {
991
- true: ["text-slate-700"],
992
- false: "",
993
- },
994
- },
995
- });
996
- const cvaInputAddon = cvaMerge([
997
- "flex",
998
- "justify-center",
999
- "items-center",
1000
- "px-3",
1001
- "border-slate-300",
1002
- "text-slate-500",
1003
- "bg-slate-50",
1004
- ]);
1005
- const cvaInputAddonBefore = cvaMerge([cvaInputAddon(), "border-r", "rounded-l-lg"]);
1006
- const cvaInputAddonAfter = cvaMerge([cvaInputAddon(), "border-l", "rounded-r-lg"]);
1007
- const cvaInputPrefix = cvaMerge([
1008
- "flex",
1009
- "justify-center",
1010
- "items-center",
1011
- "text-slate-400",
1012
- "hover:component-search-prefix",
1013
- "component-baseInput-prefix",
1014
- "component-search-borderless",
1015
- "px-3",
1016
- ], {
1017
- variants: {
1018
- disabled: {
1019
- true: ["text-slate-500"],
1020
- false: "",
1021
- },
1022
- },
1023
- });
1024
- const cvaInputSuffix = cvaMerge(["flex", "justify-center", "items-center", "text-slate-400", "px-3"], {
1025
- variants: {
1026
- disabled: {
1027
- true: ["text-slate-500"],
1028
- false: "",
1029
- },
1030
- },
1031
- });
1032
-
1033
- /**
1034
- * A base input component that can be used for text inputs, password inputs, etc.
1035
- * A reference to the input element is provided as the `ref` prop.
1036
- * Extends props from [React.InputHTMLAttributes](https://reactjs.org/docs/dom-elements.html#input)
1037
- *
1038
- * For specific input types make sure to use the corresponding input component.
1039
- * This is a base used by our other input components such as TextInput, NumberInput, PasswordInput, etc.
1040
- */
1041
- const BaseInput = React.forwardRef((_a, ref) => {
1042
- var { className, isInvalid, dataTestId, prefix, suffix, addonBefore, addonAfter, actions, fieldSize = "medium", nonInteractive = false, showDefaultActions = false, type, inputClassName, addonBeforeClassName } = _a, rest = __rest(_a, ["className", "isInvalid", "dataTestId", "prefix", "suffix", "addonBefore", "addonAfter", "actions", "fieldSize", "nonInteractive", "showDefaultActions", "type", "inputClassName", "addonBeforeClassName"]);
1043
- const isReadOnlyWithPlaceholder = useMemo(() => !!rest.readOnly && !!rest.placeholder && !rest.value, [rest.readOnly, rest.placeholder, rest.value]);
1044
- const renderAsDisabled = rest.disabled || rest.readOnly;
1045
- const innerRef = React.useRef(null);
1046
- React.useImperativeHandle(ref, () => innerRef.current, []);
1047
- return (jsxs("div", { className: cvaInput({
1048
- disabled: renderAsDisabled,
1049
- invalid: isInvalid,
1050
- size: fieldSize,
1051
- className,
1052
- }), "data-testid": dataTestId && `${dataTestId}-container`, children: [addonBefore && addonBefore !== undefined ? (jsx("div", { className: cvaInputAddonBefore({ className: addonBeforeClassName }), "data-testid": dataTestId && `${dataTestId}-addonBefore`, children: addonBefore })) : null, prefix && addonBefore !== prefix ? (jsx("div", { className: cvaInputPrefix({
1053
- disabled: renderAsDisabled,
1054
- }), "data-testid": dataTestId && `${dataTestId}-prefix`, children: prefix })) : null, jsx("input", Object.assign({ className: cvaInputField({ size: fieldSize, disabled: renderAsDisabled, className: inputClassName }), "data-testid": dataTestId, ref: innerRef, type: isReadOnlyWithPlaceholder ? "text" : type }, rest, { readOnly: rest.readOnly || nonInteractive })), suffix && addonBefore !== suffix ? (jsx("div", { className: cvaInputSuffix({
1055
- disabled: renderAsDisabled,
1056
- }), "data-testid": dataTestId && `${dataTestId}-suffix`, children: suffix })) : null, rest.readOnly === true && showDefaultActions ? (jsx(ActionButton, { type: "COPY", value: innerRef }, "default-copy-action")) : null, actions && addonBefore !== actions ? actions : null, addonAfter && addonAfter !== undefined && addonBefore !== addonAfter ? (jsx("div", { className: cvaInputAddonAfter(), "data-testid": dataTestId && `${dataTestId}-addonAfter`, children: addonAfter })) : null] }));
1057
- });
1058
-
1059
- /**
1060
- * A wrapper around BaseInput with a pop-up day picker.
1061
- *
1062
- * NOTE: If shown with a label, please use the `DateField` component instead.
1063
- */
1064
- const DateInput = forwardRef((_a, ref) => {
1065
- var { min, max, defaultValue, value } = _a, rest = __rest(_a, ["min", "max", "defaultValue", "value"]);
1066
- const formatDateToInputString = (date) => date instanceof Date ? format(date, "yyyy-MM-dd") : date;
1067
- // Chrome and Firefox need their default icon to have datepicker functionality.
1068
- const showIcon = !/Chrome/.test(navigator.userAgent) && !/Firefox/.test(navigator.userAgent);
1069
- return (jsx(BaseInput, Object.assign({ defaultValue: formatDateToInputString(defaultValue), max: formatDateToInputString(max), min: formatDateToInputString(min), ref: ref, suffix: showIcon && jsx(Icon, { dataTestId: "calendar", name: "Calendar", size: "medium", type: "solid" }), type: "date", value: formatDateToInputString(value) }, rest)));
1070
- });
1071
-
1072
- /**
1073
- * The date field component is used for entering date values.
1074
- *
1075
- * _**Do use**_ the DateField for date input.
1076
- *
1077
- * _**Do not use**_ this fields for non-serialized dates. Use TextField instead.
1078
- */
1079
- const DateField = forwardRef((_a, ref) => {
1080
- var { label, id, tip, helpText, errorMessage, helpAddon, isInvalid, className, defaultValue, dataTestId } = _a, rest = __rest(_a, ["label", "id", "tip", "helpText", "errorMessage", "helpAddon", "isInvalid", "className", "defaultValue", "dataTestId"]);
1081
- const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
1082
- const htmlForId = id ? id : "dateField-" + v4();
1083
- return (jsx(FormGroup, { dataTestId: dataTestId && `${dataTestId}-FormGroup`, disabled: rest.disabled, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, tip: tip, children: jsx(DateInput, Object.assign({ "aria-labelledby": htmlForId + "-label", defaultValue: defaultValue, id: htmlForId, isInvalid: renderAsInvalid, ref: ref }, rest, { className: className, dataTestId: dataTestId })) }));
1084
- });
1085
-
1086
- const cvaDropZone = cvaMerge([
1087
- "flex",
1088
- "component-baseInput-background",
1089
- "justify-center",
1090
- "text-slate-500",
1091
- "rounded-sm",
1092
- "border-2",
1093
- "border-gray-200",
1094
- "border-dashed",
1095
- "hover:bg-slate-100",
1096
- "hover:border-solid",
1097
- "hover:border-primary-500",
1098
- ], {
1099
- variants: {
1100
- size: {
1101
- small: ["p-2"],
1102
- medium: ["p-4"],
1103
- large: ["p-8"],
1104
- },
1105
- disabled: { true: ["bg-slate-100", "hover:bg-slate-100"], false: "" },
1106
- dragActive: { true: ["border-gray-200", "bg-slate-100"], false: "" },
1107
- dropComplete: {
1108
- true: ["border-solid", "border-primary-500", "bg-slate-100", "hover:border-solid", "hover:border-gray-200"],
1109
- false: "",
1110
- },
1111
- invalid: { true: ["border-danger-600", "text-danger-500"], false: "" },
1112
- },
1113
- });
1114
- const cvaDropZoneLabel = cvaMerge([
1115
- "h-full",
1116
- "pt-1",
1117
- "pb-1",
1118
- "gap-2",
1119
- "items-center",
1120
- "flex-col",
1121
- "flex",
1122
- "justify-center",
1123
- ]);
1124
-
1125
- /**
1126
- * The Drop Zone can be used to drag and drop files
1127
- *
1128
- * @param {DropZoneProps} props - The props for the DropZone component
1129
- * @returns {JSX.Element} DropZone component
605
+ * @param {DropZoneProps} props - The props for the DropZone component
606
+ * @returns {JSX.Element} DropZone component
1130
607
  */
1131
608
  const DropZone = (_a) => {
1132
609
  var { className, dataTestId, filesSelected, label, size = "large", isInvalid = false, disabled = false } = _a, rest = __rest(_a, ["className", "dataTestId", "filesSelected", "label", "size", "isInvalid", "disabled"]);
@@ -1206,178 +683,634 @@ const EmailInput = React.forwardRef((_a, ref) => {
1206
683
  });
1207
684
 
1208
685
  /**
1209
- * The EmailField component is used to enter email.
1210
- * EmailField validates that user enters a valid email address.
1211
- *
686
+ * The EmailField component is used to enter email.
687
+ * EmailField validates that user enters a valid email address.
688
+ *
689
+ */
690
+ const EmailField = forwardRef((_a, ref) => {
691
+ var { label, id, tip, helpText, errorMessage, helpAddon, className, defaultValue, dataTestId, value, onChange, isInvalid = false } = _a, rest = __rest(_a, ["label", "id", "tip", "helpText", "errorMessage", "helpAddon", "className", "defaultValue", "dataTestId", "value", "onChange", "isInvalid"]);
692
+ const htmlForId = id ? id : "emailField-" + v4();
693
+ // Type guard to check if value is a string
694
+ function isString(inputValue) {
695
+ return typeof inputValue === "string";
696
+ }
697
+ const renderAsInvalid = !!errorMessage || (value && isString(value) && !validateEmailAddress(value)) || isInvalid;
698
+ const handleChange = useCallback((event) => {
699
+ if (onChange) {
700
+ onChange(event);
701
+ }
702
+ }, [onChange]);
703
+ return (jsx(FormGroup, { dataTestId: dataTestId && `${dataTestId}-FormGroup`, disabled: rest.disabled, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, tip: tip, children: jsx(EmailInput, Object.assign({ "aria-labelledby": htmlForId + "-label", defaultValue: defaultValue, disabled: renderAsInvalid, id: htmlForId, isInvalid: renderAsInvalid, onChange: handleChange, ref: ref, value: value }, rest, { className: className, dataTestId: dataTestId })) }));
704
+ });
705
+
706
+ /**
707
+ * A thin wrapper around the `BaseInput` component for number input fields.
708
+ *
709
+ * NOTE: If shown with a label, please use the `NumberField` component instead.
710
+ */
711
+ const NumberInput = forwardRef((props, ref) => {
712
+ return jsx(BaseInput, Object.assign({ ref: ref, type: "number" }, props, { value: props.value }));
713
+ });
714
+
715
+ /**
716
+ * The number field component is used for entering numeric values and includes controls for incrementally increasing or decreasing the value.
717
+ *
718
+ * _**Do use**_ the NumberField when the controls to incrementally increase or decrease makes the task easier for the user.
719
+ *
720
+ * _**Do not use**_ this fields for non-serialized numbers. Use TextField instead.
721
+ */
722
+ const NumberField = forwardRef((_a, ref) => {
723
+ var { label, id, tip, helpText, errorMessage, helpAddon, isInvalid, maxLength, className, value, dataTestId } = _a, rest = __rest(_a, ["label", "id", "tip", "helpText", "errorMessage", "helpAddon", "isInvalid", "maxLength", "className", "value", "dataTestId"]);
724
+ const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
725
+ const htmlForId = id ? id : "numberField-" + v4();
726
+ return (jsx(FormGroup, { dataTestId: dataTestId && `${dataTestId}-FormGroup`, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, tip: tip, children: jsx(NumberInput, Object.assign({ "aria-labelledby": htmlForId + "-label", id: htmlForId, isInvalid: renderAsInvalid, maxLength: maxLength, ref: ref, value: value }, rest, { className: className, dataTestId: dataTestId })) }));
727
+ });
728
+
729
+ const cvaOptionCardLabel = cvaMerge([
730
+ cvaInputBase(),
731
+ "text-center",
732
+ "component-baseInput-background",
733
+ "aspect-square",
734
+ "flex",
735
+ "flex-col",
736
+ "gap-2",
737
+ "justify-center",
738
+ "items-center",
739
+ "p-responsive-space",
740
+ "w-full",
741
+ "peer-checked:bg-primary-50",
742
+ "peer-checked:border-primary-600",
743
+ "peer-checked:border-2",
744
+ ], {
745
+ variants: {
746
+ disabled: {
747
+ true: [cvaInputBaseDisabled(), "cursor-not-allowed"],
748
+ false: ["cursor-pointer"],
749
+ },
750
+ },
751
+ });
752
+ const cvaOptionCardContent = cvaMerge(["flex", "flex-col", "items-center"]);
753
+ const cvaOptionCardContainer = cvaMerge(["contents"]);
754
+
755
+ /**
756
+ * A card version of a radio button that includes an icon, headings and a description.
757
+ */
758
+ const OptionCard = forwardRef((_a, ref) => {
759
+ var { icon, heading, subheading, description, disabled, id, value, className, dataTestId } = _a, rest = __rest(_a, ["icon", "heading", "subheading", "description", "disabled", "id", "value", "className", "dataTestId"]);
760
+ const htmlForId = id !== null && id !== void 0 ? id : "option-card-" + v4();
761
+ return (jsxs("div", { className: cvaOptionCardContainer(), "data-testid": dataTestId, children: [jsx("input", Object.assign({ className: "peer hidden", id: htmlForId, ref: ref, type: "radio", value: value }, rest)), jsxs("label", { className: cvaOptionCardLabel({ className, disabled }), htmlFor: htmlForId, children: [disabled && icon && cloneElement(icon, { className: `${icon.props.className} text-secondary-400` }), !disabled && icon, heading && (jsx(Heading, { subtle: disabled, variant: "secondary", children: heading })), (subheading || description) && (jsxs("div", { className: cvaOptionCardContent(), children: [subheading && (jsx(Text, { align: "center", subtle: disabled, type: "span", weight: "thick", children: subheading })), description && (jsx(Text, { align: "center", subtle: true, type: "span", children: description }))] }))] })] }));
762
+ });
763
+
764
+ /**
765
+ * A thin wrapper around the `BaseInput` component for password input fields.
766
+ *
767
+ * NOTE: If shown with a label, please use the `PasswordField` component instead.
768
+ */
769
+ const PasswordInput = forwardRef((props, ref) => (jsx(BaseInput, Object.assign({ ref: ref }, props))));
770
+
771
+ /**
772
+ * Password fields enter a password or other confidential information. Characters are masked as they are typed.
773
+ *
774
+ * _**Do use** when the user has to input a password or something that needs to be obfuscated_
775
+ *
776
+ * _**Do not use** to confirm user actions, such as deleting. Use a checkbox for such flows._
777
+ */
778
+ const PasswordField = forwardRef((_a, ref) => {
779
+ var { id, label, tip, helpText, helpAddon, errorMessage, isInvalid, maxLength, onChange, className, value, dataTestId } = _a, rest = __rest(_a, ["id", "label", "tip", "helpText", "helpAddon", "errorMessage", "isInvalid", "maxLength", "onChange", "className", "value", "dataTestId"]);
780
+ const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
781
+ const htmlFor = id ? id : "passwordField-" + v4();
782
+ const [showPassword, setShowPassword] = useState(false);
783
+ const handleChange = useCallback((event) => {
784
+ onChange === null || onChange === void 0 ? void 0 : onChange(event);
785
+ }, [onChange]);
786
+ return (jsx(FormGroup, { dataTestId: dataTestId && `${dataTestId}-FormGroup`, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlFor, isInvalid: renderAsInvalid, label: label, tip: tip, children: jsx(PasswordInput, Object.assign({}, rest, { actions: jsx(Icon, { className: "absolute top-0 bottom-0 right-2 h-full content-center", color: "neutral", name: showPassword ? "EyeSlash" : "Eye", onClick: () => setShowPassword(prevState => !prevState), size: "small" }), "aria-labelledby": htmlFor + "-label", className: className, dataTestId: dataTestId, disabled: rest.readOnly, id: htmlFor, isInvalid: renderAsInvalid, maxLength: maxLength, onChange: handleChange, ref: ref, type: showPassword ? "text" : "password", value: value })) }));
787
+ });
788
+
789
+ /**
790
+ * @param phoneNumber - a phone number as a string
791
+ * @returns {boolean} true if the phone number starts with a plus sign
792
+ * @example checkIfPhoneNumberHasPlus("123456789") // false
793
+ * checkIfPhoneNumberHasPlus("+123456789") // true
794
+ */
795
+ const checkIfPhoneNumberHasPlus = (phoneNumber) => {
796
+ return phoneNumber.startsWith("+");
797
+ };
798
+ /**
799
+ * @param phoneNumber - a phone number as a string
800
+ * @returns {string|number} the phone number with a plus sign in front of it
801
+ * @example getPhoneNumberWithPlus("123456789") // "+123456789"
802
+ */
803
+ const getPhoneNumberWithPlus = (phoneNumber) => {
804
+ const stringPhoneNumber = phoneNumber.toString();
805
+ return checkIfPhoneNumberHasPlus(stringPhoneNumber) ? stringPhoneNumber : `+${stringPhoneNumber}`;
806
+ };
807
+ /**
808
+ * Generates a flag emoji based on the given country code.
809
+ *
810
+ * @param {string} countryCode - The two-letter country code (ISO 3166-1 alpha-2).
811
+ * @returns {string} - The corresponding flag emoji for the given country code.
812
+ * @example getPhoneNumberWithPlus("DK") // "🇩🇰"
813
+ */
814
+ const countryCodeToFlagEmoji = (countryCode) => {
815
+ let code = countryCode;
816
+ if (countryCode.startsWith("+")) {
817
+ code = getCountryAbbreviation(countryCode.substring(1));
818
+ }
819
+ else if (!isNaN(Number(countryCode))) {
820
+ code = getCountryAbbreviation(countryCode);
821
+ }
822
+ return isSupportedCountry(code.toUpperCase())
823
+ ? code.toUpperCase().replace(/./g, char => String.fromCodePoint(127397 + char.charCodeAt(0)))
824
+ : "";
825
+ };
826
+ /**
827
+ * Retrieves the ISO 3166-1 alpha-2 country code associated with a given international calling code.
828
+ *
829
+ * @param {string} callCode - The international calling code for a country.
830
+ * @returns {string} The abbreviation for a country or an empty string if no matching country is found.
831
+ * @example getCountryAbbreviation("45") // "DK"
832
+ * @example getCountryAbbreviation("+45") // "DK"
833
+ */
834
+ const getCountryAbbreviation = (callCode) => {
835
+ let code = callCode;
836
+ if (callCode.startsWith("+")) {
837
+ code = callCode.substring(1);
838
+ }
839
+ return getCountries().find(c => getCountryCallingCode(c) === code) || "";
840
+ };
841
+
842
+ /**
843
+ * A custom hook for managing phone number input state and validation.
844
+ *
845
+ * @property {Function} getPhoneNumber - A function for get formatted phone number with country code and plus sign
846
+ */
847
+ const usePhoneInput = () => {
848
+ const getPhoneNumber = ({ country, phone }) => {
849
+ if (country) {
850
+ return getPhoneNumberWithPlus(`${country}${phone || ""}`);
851
+ }
852
+ return phone || "";
853
+ };
854
+ return {
855
+ getPhoneNumber,
856
+ };
857
+ };
858
+
859
+ const cvaSelect = cvaMerge([
860
+ "relative",
861
+ "flex",
862
+ "shadow-sm",
863
+ "rounded-lg",
864
+ "border",
865
+ "border-slate-300",
866
+ "focus-within:ring-2",
867
+ "focus-within:ring-inset",
868
+ "focus-within:ring-primary-600",
869
+ "focus-within:border-slate-400",
870
+ "hover:border-slate-400",
871
+ "hover:bg-slate-50",
872
+ "bg-white",
873
+ "transition",
874
+ ], {
875
+ variants: {
876
+ invalid: {
877
+ true: "border-red-600 text-red-600 focus-within:ring-red-600 hover:border-red-600",
878
+ false: "",
879
+ },
880
+ disabled: {
881
+ true: "!bg-slate-100",
882
+ false: "",
883
+ },
884
+ },
885
+ defaultVariants: {
886
+ invalid: false,
887
+ disabled: false,
888
+ },
889
+ });
890
+ const cvaSelectIcon = cvaMerge("mr-2 flex cursor-pointer items-center justify-center text-slate-400 hover:text-slate-500");
891
+ const cvaSelectPrefix = cvaMerge(["flex", "justify-center", "items-center", "text-slate-400", "pl-2"]);
892
+ const cvaSelectXIcon = cvaMerge([
893
+ "mr-2 flex cursor-pointer items-center justify-center text-slate-400 hover:text-slate-500",
894
+ "ml-1",
895
+ ]);
896
+ const cvaSelectMenuList = cvaMerge(["min-w-min", "shadow-md", "rounded-lg", "z-20", "bg-white", "p-1", "border", "border-slate-300", "gap-1", "grid"], {
897
+ variants: {
898
+ menuIsOpen: {
899
+ true: "animate-fade-in-fast",
900
+ false: "animate-fade-out-fast",
901
+ },
902
+ },
903
+ });
904
+ const cvaSelectDynamicTagContainer = cvaMerge(["h-full", "flex", "gap-1", "items-center"], {
905
+ variants: {
906
+ visible: { true: "visible", false: "invisible" },
907
+ },
908
+ });
909
+ const cvaSelectCounter = cvaMerge(["overflow-hidden", "whitespace-nowrap"]);
910
+ const cvaSelectMenu = cvaMerge(["relative", "p-1", "grid", "gap-1"]);
911
+
912
+ /**
913
+ * @param {MultiValue<Option> | SingleValue<Option>} arg option to check type
914
+ * @returns {arg is MultiValue<Option> } is Multivalue
915
+ */
916
+ function isMultiValue(arg) {
917
+ return Array.isArray(arg);
918
+ }
919
+ function isGroupBase(arg) {
920
+ return arg.options !== undefined;
921
+ }
922
+ const isSelectedOption = (option, selected) => {
923
+ if (isGroupBase(option)) {
924
+ return false;
925
+ }
926
+ return isMultiValue(selected)
927
+ ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
928
+ selected.some(v => v.value === option.value)
929
+ : // eslint-disable-next-line @typescript-eslint/no-explicit-any
930
+ option.value === (selected === null || selected === void 0 ? void 0 : selected.value);
931
+ };
932
+ const removeSelectedFromGroups = (group, selected) => {
933
+ if (isGroupBase(group)) {
934
+ return Object.assign(Object.assign({}, group), { options: group.options.filter(option => !isSelectedOption(option, selected)) });
935
+ }
936
+ return group;
937
+ };
938
+ /**
939
+ * @template IsMulti
940
+ * @template Group
941
+ * @param {OptionsOrGroups<Option, Group> | undefined} options An array of options to select from
942
+ * @param {PropsValue<Option> | undefined} value Selected values
943
+ * @returns {OptionsOrGroups<Option, Group>} An array of ordered options with selected on top
1212
944
  */
1213
- const EmailField = forwardRef((_a, ref) => {
1214
- var { label, id, tip, helpText, errorMessage, helpAddon, className, defaultValue, dataTestId, value, onChange, isInvalid = false } = _a, rest = __rest(_a, ["label", "id", "tip", "helpText", "errorMessage", "helpAddon", "className", "defaultValue", "dataTestId", "value", "onChange", "isInvalid"]);
1215
- const htmlForId = id ? id : "emailField-" + v4();
1216
- // Type guard to check if value is a string
1217
- function isString(inputValue) {
1218
- return typeof inputValue === "string";
945
+ const getOrderedOptions = (options, value) => {
946
+ if (value && options) {
947
+ const orderedValues = isMultiValue(value)
948
+ ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
949
+ [...value].sort((a, b) => a.label.localeCompare(b.label))
950
+ : [value];
951
+ const selectableOptions = options
952
+ .filter(option => !isSelectedOption(option, value))
953
+ .map(option => removeSelectedFromGroups(option, value));
954
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
955
+ return orderedValues.concat(selectableOptions) || [];
1219
956
  }
1220
- const renderAsInvalid = !!errorMessage || (value && isString(value) && !validateEmailAddress(value)) || isInvalid;
1221
- const handleChange = useCallback((event) => {
1222
- if (onChange) {
1223
- onChange(event);
1224
- }
1225
- }, [onChange]);
1226
- return (jsx(FormGroup, { dataTestId: dataTestId && `${dataTestId}-FormGroup`, disabled: rest.disabled, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, tip: tip, children: jsx(EmailInput, Object.assign({ "aria-labelledby": htmlForId + "-label", defaultValue: defaultValue, disabled: renderAsInvalid, id: htmlForId, isInvalid: renderAsInvalid, onChange: handleChange, ref: ref, value: value }, rest, { className: className, dataTestId: dataTestId })) }));
1227
- });
957
+ return options || [];
958
+ };
1228
959
 
1229
960
  /**
1230
- * A thin wrapper around the `BaseInput` component for number input fields.
961
+ * A single select menu item is a basic wrapper around Menu item designed to be used as a single value render in Select list
1231
962
  *
1232
- * NOTE: If shown with a label, please use the `NumberField` component instead.
963
+ * @param {SelectMenuItemProps} props - The props for the SingleSelectMenuItem
964
+ * @returns {JSX.Element} SingleSelectMenuItem
1233
965
  */
1234
- const NumberInput = forwardRef((props, ref) => {
1235
- return jsx(BaseInput, Object.assign({ ref: ref, type: "number" }, props, { value: props.value }));
1236
- });
1237
-
966
+ const SingleSelectMenuItem = ({ label, icon, onClick, selected, dataTestId, focused, disabled, }) => {
967
+ return (jsx(MenuItem, { dataTestId: dataTestId, disabled: disabled, focused: focused, label: label, onClick: onClick, prefix: icon, selected: selected, suffix: selected ? jsx(Icon, { name: "Check", size: "small" }) : undefined }));
968
+ };
1238
969
  /**
1239
- * The number field component is used for entering numeric values and includes controls for incrementally increasing or decreasing the value.
1240
- *
1241
- * _**Do use**_ the NumberField when the controls to incrementally increase or decrease makes the task easier for the user.
970
+ * A multi select menu item is a basic wrapper around Menu item designed to be used as a multi value render in Select list
1242
971
  *
1243
- * _**Do not use**_ this fields for non-serialized numbers. Use TextField instead.
1244
- */
1245
- const NumberField = forwardRef((_a, ref) => {
1246
- var { label, id, tip, helpText, errorMessage, helpAddon, isInvalid, maxLength, className, value, dataTestId } = _a, rest = __rest(_a, ["label", "id", "tip", "helpText", "errorMessage", "helpAddon", "isInvalid", "maxLength", "className", "value", "dataTestId"]);
1247
- const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
1248
- const htmlForId = id ? id : "numberField-" + v4();
1249
- return (jsx(FormGroup, { dataTestId: dataTestId && `${dataTestId}-FormGroup`, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, tip: tip, children: jsx(NumberInput, Object.assign({ "aria-labelledby": htmlForId + "-label", id: htmlForId, isInvalid: renderAsInvalid, maxLength: maxLength, ref: ref, value: value }, rest, { className: className, dataTestId: dataTestId })) }));
1250
- });
1251
-
1252
- const cvaOptionCardLabel = cvaMerge([
1253
- cvaInputBase(),
1254
- "text-center",
1255
- "component-baseInput-background",
1256
- "aspect-square",
1257
- "flex",
1258
- "flex-col",
1259
- "gap-2",
1260
- "justify-center",
1261
- "items-center",
1262
- "p-responsive-space",
1263
- "w-full",
1264
- "peer-checked:bg-primary-50",
1265
- "peer-checked:border-primary-600",
1266
- "peer-checked:border-2",
1267
- ], {
1268
- variants: {
1269
- disabled: {
1270
- true: [cvaInputBaseDisabled(), "cursor-not-allowed"],
1271
- false: ["cursor-pointer"],
1272
- },
1273
- },
1274
- });
1275
- const cvaOptionCardContent = cvaMerge(["flex", "flex-col", "items-center"]);
1276
- const cvaOptionCardContainer = cvaMerge(["contents"]);
1277
-
1278
- /**
1279
- * A card version of a radio button that includes an icon, headings and a description.
972
+ * @param {SelectMenuItemProps} props - The props for the MultiSelectMenuItem
973
+ * @returns {JSX.Element} multi select menu item
1280
974
  */
1281
- const OptionCard = forwardRef((_a, ref) => {
1282
- var { icon, heading, subheading, description, disabled, id, value, className, dataTestId } = _a, rest = __rest(_a, ["icon", "heading", "subheading", "description", "disabled", "id", "value", "className", "dataTestId"]);
1283
- const htmlForId = id !== null && id !== void 0 ? id : "option-card-" + v4();
1284
- return (jsxs("div", { className: cvaOptionCardContainer(), "data-testid": dataTestId, children: [jsx("input", Object.assign({ className: "peer hidden", id: htmlForId, ref: ref, type: "radio", value: value }, rest)), jsxs("label", { className: cvaOptionCardLabel({ className, disabled }), htmlFor: htmlForId, children: [disabled && icon && cloneElement(icon, { className: `${icon.props.className} text-secondary-400` }), !disabled && icon, heading && (jsx(Heading, { subtle: disabled, variant: "secondary", children: heading })), (subheading || description) && (jsxs("div", { className: cvaOptionCardContent(), children: [subheading && (jsx(Text, { align: "center", subtle: disabled, type: "span", weight: "thick", children: subheading })), description && (jsx(Text, { align: "center", subtle: true, type: "span", children: description }))] }))] })] }));
1285
- });
975
+ const MultiSelectMenuItem = ({ label, onClick, selected, dataTestId, focused, disabled, }) => {
976
+ return (jsx(MenuItem, { dataTestId: dataTestId, disabled: disabled, focused: focused, label: label, onClick: e => {
977
+ e.stopPropagation();
978
+ onClick && onClick(e);
979
+ }, prefix: jsx(Checkbox, { checked: selected, disabled: disabled, onChange: () => null, onClick: e => {
980
+ e.stopPropagation();
981
+ }, readOnly: false }), selected: selected }));
982
+ };
1286
983
 
1287
984
  /**
1288
- * A thin wrapper around the `BaseInput` component for password input fields.
985
+ * Extended Tag component with information about its own width.
986
+ * Used in the select component.
1289
987
  *
1290
- * NOTE: If shown with a label, please use the `PasswordField` component instead.
988
+ * @param {TagProps} props - The props for the tag component
989
+ * @returns {JSX.Element} TagWithWidth component
1291
990
  */
1292
- const PasswordInput = forwardRef((props, ref) => (jsx(BaseInput, Object.assign({ ref: ref }, props))));
991
+ const TagWithWidth = (_a) => {
992
+ var { onWidthKnown, children } = _a, rest = __rest(_a, ["onWidthKnown", "children"]);
993
+ const ref = React__default.useRef(null);
994
+ React__default.useLayoutEffect(() => {
995
+ var _a;
996
+ onWidthKnown && onWidthKnown({ width: ((_a = ref.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 0 });
997
+ }, [ref, onWidthKnown]);
998
+ return (jsx(Tag, Object.assign({ ref: ref }, rest, { children: children })));
999
+ };
1293
1000
 
1294
1001
  /**
1295
- * Password fields enter a password or other confidential information. Characters are masked as they are typed.
1296
- *
1297
- * _**Do use** when the user has to input a password or something that needs to be obfuscated_
1002
+ * TagsContainer component to display tags in limited space when children can't fit space it displays counter
1298
1003
  *
1299
- * _**Do not use** to confirm user actions, such as deleting. Use a checkbox for such flows._
1004
+ * @param {TagsContainerProps} props - The props for the TagContainer
1005
+ * @returns {JSX.Element} TagsContainer
1300
1006
  */
1301
- const PasswordField = forwardRef((_a, ref) => {
1302
- var { id, label, tip, helpText, helpAddon, errorMessage, isInvalid, maxLength, onChange, className, value, dataTestId } = _a, rest = __rest(_a, ["id", "label", "tip", "helpText", "helpAddon", "errorMessage", "isInvalid", "maxLength", "onChange", "className", "value", "dataTestId"]);
1303
- const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
1304
- const htmlFor = id ? id : "passwordField-" + v4();
1305
- const [showPassword, setShowPassword] = useState(false);
1306
- const handleChange = useCallback((event) => {
1307
- onChange === null || onChange === void 0 ? void 0 : onChange(event);
1308
- }, [onChange]);
1309
- return (jsx(FormGroup, { dataTestId: dataTestId && `${dataTestId}-FormGroup`, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlFor, isInvalid: renderAsInvalid, label: label, tip: tip, children: jsx(PasswordInput, Object.assign({}, rest, { actions: jsx(Icon, { className: "absolute top-0 bottom-0 right-2 h-full content-center", color: "neutral", name: showPassword ? "EyeSlash" : "Eye", onClick: () => setShowPassword(prevState => !prevState), size: "small" }), "aria-labelledby": htmlFor + "-label", className: className, dataTestId: dataTestId, disabled: rest.readOnly, id: htmlFor, isInvalid: renderAsInvalid, maxLength: maxLength, onChange: handleChange, ref: ref, type: showPassword ? "text" : "password", value: value })) }));
1310
- });
1007
+ const TagsContainer = ({ items, width = "100%", itemsGap = 5, postFix, disabled }) => {
1008
+ const [isReady, setIsReady] = React__default.useState(false);
1009
+ const [counterWidth, setCounterWidth] = React__default.useState(0);
1010
+ const containerRef = React__default.useRef(null);
1011
+ const availableWidth = React__default.useRef();
1012
+ const childrenWidth = React__default.useRef([]);
1013
+ const itemsCount = items.length;
1014
+ React__default.useLayoutEffect(() => {
1015
+ var _a;
1016
+ availableWidth.current = ((_a = containerRef === null || containerRef === void 0 ? void 0 : containerRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 0;
1017
+ }, [containerRef]);
1018
+ const onWidthKnownHandler = ({ width: reportedWidth }) => {
1019
+ childrenWidth.current.push({ width: reportedWidth + itemsGap });
1020
+ if (childrenWidth.current.length === itemsCount) {
1021
+ setIsReady(true);
1022
+ }
1023
+ };
1024
+ const requiredSpace = childrenWidth.current.reduce((previous, current) => {
1025
+ return previous + current.width;
1026
+ }, 0);
1027
+ let counter = 0;
1028
+ const availableSpace = ((availableWidth === null || availableWidth === void 0 ? void 0 : availableWidth.current) || 0) - counterWidth;
1029
+ const renderedElements = items
1030
+ .concat({ text: "", onClick: () => null, disabled: false }) // reserved element for a potential counter
1031
+ .map((item, index) => {
1032
+ const spaceNeeded = childrenWidth.current.slice(0, index + 1).reduce((previous, current) => {
1033
+ return previous + current.width;
1034
+ }, 0);
1035
+ const isLast = index === items.length;
1036
+ const counterRequired = requiredSpace > availableSpace && counter !== 0;
1037
+ if (isLast && counterRequired) {
1038
+ return (jsx(TagWithWidth, { color: "white", disabled: disabled, onWidthKnown: ({ width: reportedWidth }) => setCounterWidth(reportedWidth), children: jsxs("div", { className: cvaSelectCounter(), "data-testid": "select-counter", children: ["+", counter] }) }, item.text + index));
1039
+ }
1040
+ if (isLast) {
1041
+ return null;
1042
+ }
1043
+ const itemCanFit = spaceNeeded <= availableSpace;
1044
+ if (itemCanFit) {
1045
+ return (jsx(TagWithWidth, { className: "inline-flex shrink-0", color: item.disabled ? "unknown" : "primary", dataTestId: `${item.text}-tag`, disabled: disabled, onClose: e => {
1046
+ e.stopPropagation();
1047
+ item.onClick();
1048
+ }, onWidthKnown: onWidthKnownHandler, children: item.text }, item.text + index));
1049
+ }
1050
+ const fromTheItems = item.text !== "";
1051
+ if (fromTheItems) {
1052
+ counter = counter + 1;
1053
+ }
1054
+ return null;
1055
+ })
1056
+ .filter(element => element !== null);
1057
+ return (jsxs("div", { className: cvaSelectDynamicTagContainer({ visible: isReady }), ref: containerRef, style: {
1058
+ width: `${width}`,
1059
+ }, children: [renderedElements, postFix] }));
1060
+ };
1311
1061
 
1312
1062
  /**
1313
- * @param phoneNumber - a phone number as a string
1314
- * @returns {boolean} true if the phone number starts with a plus sign
1315
- * @example checkIfPhoneNumberHasPlus("123456789") // false
1316
- * checkIfPhoneNumberHasPlus("+123456789") // true
1063
+ * A hook to retrieve components override object.
1064
+ * This complex object includes all the compositional components that are used in react-select. If you wish to overwrite a component, pass in an object with the appropriate namespace.
1065
+ *
1066
+ * @template IsMulti
1067
+ * @template Group
1068
+ * @param {Partial<SelectComponents<Option, IsMulti, Group>> | undefined} componentsProps a custom component prop that you can to override defaults
1069
+ * @param {boolean} disabled decide to override disabled variant
1070
+ * @param {boolean} menuIsOpen menu is open state
1071
+ * @param {React.MutableRefObject<boolean>} refMenuIsEnabled a flag to block menu from open
1072
+ * @param {string} dataTestId a test id
1073
+ * @param {number} maxSelectedDisplayCount a number of max display count
1074
+ * @param {JSX.Element} dropdownIcon an custom dropdown icon
1075
+ * @returns {Partial<SelectComponents<Option, boolean, GroupBase<Option>>> | undefined} components object to override react-select default components
1317
1076
  */
1318
- const checkIfPhoneNumberHasPlus = (phoneNumber) => {
1319
- return phoneNumber.startsWith("+");
1077
+ const useCustomComponents = (componentsProps, disabled, menuIsOpen, refMenuIsEnabled, dataTestId, maxSelectedDisplayCount, dropdownIcon) => {
1078
+ const [t] = useTranslation();
1079
+ // perhaps it should not be wrap in memo (causing some issues with opening and closing on mobiles)
1080
+ const customComponents = React.useMemo(() => {
1081
+ return Object.assign({ ValueContainer: props => {
1082
+ if (props.isMulti && Array.isArray(props.children) && props.children.length > 0) {
1083
+ const PLACEHOLDER_KEY = "placeholder";
1084
+ const key = props && props.children && props.children[0] ? props.children[0].key : "";
1085
+ const values = props && props.children ? props.children[0] : [];
1086
+ const tags = key === PLACEHOLDER_KEY ? [] : values;
1087
+ const searchInput = props && props.children && props.children[1];
1088
+ return (jsx(components.ValueContainer, Object.assign({}, props, { isDisabled: props.selectProps.isDisabled, children: maxSelectedDisplayCount === undefined ? (jsx(TagsContainer, { disabled: disabled, items: tags
1089
+ ? tags.map(({ props: tagProps }) => {
1090
+ return {
1091
+ text: tagProps.children,
1092
+ onClick: disabled
1093
+ ? undefined
1094
+ : (e) => {
1095
+ var _a, _b;
1096
+ refMenuIsEnabled.current = false;
1097
+ ((_a = tagProps === null || tagProps === void 0 ? void 0 : tagProps.removeProps) === null || _a === void 0 ? void 0 : _a.onClick) && ((_b = tagProps === null || tagProps === void 0 ? void 0 : tagProps.removeProps) === null || _b === void 0 ? void 0 : _b.onClick(e));
1098
+ },
1099
+ disabled: disabled,
1100
+ };
1101
+ })
1102
+ : [], postFix: searchInput, width: "100%" })) : (jsxs(Fragment, { children: [tags &&
1103
+ tags.slice(0, maxSelectedDisplayCount).map(({ props: tagProps }) => {
1104
+ var _a, _b;
1105
+ return (jsx(Tag, { className: "inline-flex shrink-0", color: disabled ? "unknown" : "primary", dataTestId: tagProps.children ? `${(_a = tagProps.children) === null || _a === void 0 ? void 0 : _a.toString()}-tag` : undefined, onClose: e => {
1106
+ var _a, _b;
1107
+ e.stopPropagation();
1108
+ refMenuIsEnabled.current = false;
1109
+ ((_a = tagProps === null || tagProps === void 0 ? void 0 : tagProps.removeProps) === null || _a === void 0 ? void 0 : _a.onClick) && ((_b = tagProps === null || tagProps === void 0 ? void 0 : tagProps.removeProps) === null || _b === void 0 ? void 0 : _b.onClick(e));
1110
+ }, children: tagProps.children }, (_b = tagProps.children) === null || _b === void 0 ? void 0 : _b.toString()));
1111
+ }), tags && tags.length > maxSelectedDisplayCount && (jsxs(Tag, { color: "neutral", dataTestId: "counter-tag", children: ["+", tags.length - maxSelectedDisplayCount] })), searchInput] })) })));
1112
+ }
1113
+ return (jsx(components.ValueContainer, Object.assign({}, props, { isDisabled: props.selectProps.isDisabled, children: props.children })));
1114
+ }, LoadingIndicator: props => {
1115
+ return jsx(Spinner, { className: "mt-1.5 mr-1", size: "small" });
1116
+ }, DropdownIndicator: props => {
1117
+ const icon = props.selectProps.menuIsOpen ? (jsx(Icon, { name: "ChevronUp", size: "medium" })) : (jsx(Icon, { name: "ChevronDown", size: "medium" }));
1118
+ return props.selectProps.isLoading ? null : (jsx(components.DropdownIndicator, Object.assign({}, props, { children: jsx("div", { className: cvaSelectIcon(), children: dropdownIcon ? dropdownIcon : icon }) })));
1119
+ }, IndicatorSeparator: () => null, ClearIndicator: props => {
1120
+ if (disabled) {
1121
+ return null;
1122
+ }
1123
+ return (jsx(components.ClearIndicator, Object.assign({}, props, { children: jsx("div", { className: cvaSelectXIcon(), "data-testid": dataTestId && `${dataTestId}-XMarkIcon`, onClick: props.clearValue, children: jsx(Icon, { name: "XCircle", size: "medium", title: t("clearIndicator.icon.tooltip.clearAll") }) }) })));
1124
+ }, Control: props => {
1125
+ return jsx(components.Control, Object.assign({}, props, { className: props.isDisabled ? "bg-slate-100" : "" }));
1126
+ }, SingleValue: props => {
1127
+ return (jsx(components.SingleValue, Object.assign({}, props, { className: props.isDisabled ? "text-slate-700" : "", children: jsx("div", { "data-testid": dataTestId + "-singleValue", children: props.children }) })));
1128
+ }, Menu: props => {
1129
+ return (jsx(components.Menu, Object.assign({}, props, { className: cvaSelectMenuList({ menuIsOpen: props.selectProps.menuIsOpen }) })));
1130
+ }, MenuList: props => {
1131
+ return (jsx(components.MenuList, Object.assign({}, props, { innerProps: Object.assign(Object.assign({}, props.innerProps), { onScroll: e => {
1132
+ const listEl = e.currentTarget;
1133
+ if (listEl.scrollTop + listEl.clientHeight >= listEl.scrollHeight) {
1134
+ props.selectProps.onMenuScrollToBottom && props.selectProps.onMenuScrollToBottom(new TouchEvent(""));
1135
+ }
1136
+ } }), children: props.children })));
1137
+ }, Option: props => {
1138
+ const componentProps = {
1139
+ label: props.label,
1140
+ focused: props.isFocused,
1141
+ selected: props.isSelected,
1142
+ onClick: props.innerProps.onClick,
1143
+ };
1144
+ return (jsx(components.Option, Object.assign({}, props, { innerProps: Object.assign(Object.assign({}, props.innerProps), { role: "option", onClick: () => { } }), children: props.isMulti ? (jsx(MultiSelectMenuItem, Object.assign({}, componentProps, { dataTestId: typeof props.label === "string" ? props.label : undefined, disabled: disabled }))) : (jsx(SingleSelectMenuItem, Object.assign({}, componentProps, { dataTestId: typeof props.label === "string" ? props.label : undefined, disabled: disabled || props.isDisabled }))) })));
1145
+ } }, componentsProps);
1146
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1147
+ }, [componentsProps, disabled, maxSelectedDisplayCount]); // do not add dropdownIcon (it will cause issue with opening/closing list for selects with custom icon)
1148
+ return customComponents;
1320
1149
  };
1150
+
1321
1151
  /**
1322
- * @param phoneNumber - a phone number as a string
1323
- * @returns {string|number} the phone number with a plus sign in front of it
1324
- * @example getPhoneNumberWithPlus("123456789") // "+123456789"
1152
+ * @template IsMulti
1153
+ * @template Group
1154
+ * @param {React.RefObject<HTMLDivElement>} refContainer react ref to container element
1155
+ * @param {React.RefObject<HTMLDivElement>} refPrefix react ref to prefix element
1156
+ * @param {number | undefined} maxSelectedDisplayCount a number of max display count
1157
+ * @param {StylesConfig<Option, IsMulti, Group> | undefined} styles a optional object to override styles of react-select
1158
+ * @returns {StylesConfig<Option, boolean>} styles to override in select
1325
1159
  */
1326
- const getPhoneNumberWithPlus = (phoneNumber) => {
1327
- const stringPhoneNumber = phoneNumber.toString();
1328
- return checkIfPhoneNumberHasPlus(stringPhoneNumber) ? stringPhoneNumber : `+${stringPhoneNumber}`;
1160
+ const useCustomStyles = (refContainer, refPrefix, maxSelectedDisplayCount, styles, disabled) => {
1161
+ const customStyles = React.useMemo(() => {
1162
+ return Object.assign({ control: base => {
1163
+ return Object.assign(Object.assign({}, base), { border: "0", boxShadow: "0", "&:hover": {
1164
+ border: "0",
1165
+ }, marginRight: "2px", backgroundColor: "" });
1166
+ }, singleValue: base => (Object.assign({}, base)), multiValue: base => (Object.assign({}, base)), multiValueLabel: base => (Object.assign({}, base)), indicatorsContainer: base => (Object.assign(Object.assign({}, base), (disabled && { display: "none" }))), indicatorSeparator: () => ({
1167
+ width: "0px",
1168
+ }), menu: base => {
1169
+ return Object.assign(Object.assign({}, base), { width: "100%", marginTop: "4px", marginBottom: "18px", transition: "all 1s ease-in-out" });
1170
+ }, input: base => (Object.assign(Object.assign({}, base), { marginLeft: "0px" })), placeholder: base => (Object.assign({}, base)), option: () => ({}), menuPortal: base => (Object.assign(Object.assign({}, base), { width: (refContainer === null || refContainer === void 0 ? void 0 : refContainer.current) ? `${refContainer.current.clientWidth}px` : base.width, transform: (refPrefix === null || refPrefix === void 0 ? void 0 : refPrefix.current) ? `translate(-${refPrefix.current.clientWidth + 2}px)` : "translate(-2px)", backgroundColor: "#ffffff", borderRadius: "var(--border-radius-lg)", zIndex: 20, borderColor: "rgb(var(--color-slate-300))", boxShadow: "var(--tw-ring-inset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)" })), menuList: base => {
1171
+ return Object.assign(Object.assign({}, base), { position: "relative", padding: "var(--spacing-1)", display: "grid", gap: "var(--spacing-1)", width: "100%", borderRadius: "0px", boxShadow: "none", paddingTop: "0px" });
1172
+ }, valueContainer: base => {
1173
+ return Object.assign(Object.assign({}, base), { flexWrap: maxSelectedDisplayCount !== undefined ? "wrap" : "nowrap", gap: "0.25rem" });
1174
+ }, container: base => (Object.assign(Object.assign({}, base), { border: "none", width: "calc(100% - 2px)", paddingLeft: "2px" })), dropdownIndicator: base => (Object.assign(Object.assign({}, base), { padding: "0px" })), clearIndicator: base => {
1175
+ return Object.assign(Object.assign({}, base), { padding: "0px" });
1176
+ } }, styles);
1177
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1178
+ }, [refContainer, refPrefix]);
1179
+ return { customStyles };
1329
1180
  };
1181
+
1330
1182
  /**
1331
- * Generates a flag emoji based on the given country code.
1183
+ * A hook used by selects to share the common code
1332
1184
  *
1333
- * @param {string} countryCode - The two-letter country code (ISO 3166-1 alpha-2).
1334
- * @returns {string} - The corresponding flag emoji for the given country code.
1335
- * @example getPhoneNumberWithPlus("DK") // "🇩🇰"
1185
+ * @param {SelectProps} props - The props for the Select component
1186
+ * @returns {IUseSelect} Select component
1336
1187
  */
1337
- const countryCodeToFlagEmoji = (countryCode) => {
1338
- let code = countryCode;
1339
- if (countryCode.startsWith("+")) {
1340
- code = getCountryAbbreviation(countryCode.substring(1));
1341
- }
1342
- else if (!isNaN(Number(countryCode))) {
1343
- code = getCountryAbbreviation(countryCode);
1344
- }
1345
- return isSupportedCountry(code.toUpperCase())
1346
- ? code.toUpperCase().replace(/./g, char => String.fromCodePoint(127397 + char.charCodeAt(0)))
1347
- : "";
1188
+ const useSelect = (_a) => {
1189
+ var _b;
1190
+ var { id, className, dataTestId = "select", prefix, async, dropdownIcon, maxMenuHeight = 200, label, hasError, disabled, isMulti, components, value, options, onChange, isLoading, classNamePrefix = "", onMenuOpen, onMenuClose, maxSelectedDisplayCount = undefined, isClearable = false, isSearchable = true, onMenuScrollToBottom, styles, filterOption, onInputChange } = _a, props = __rest(_a, ["id", "className", "dataTestId", "prefix", "async", "dropdownIcon", "maxMenuHeight", "label", "hasError", "disabled", "isMulti", "components", "value", "options", "onChange", "isLoading", "classNamePrefix", "onMenuOpen", "onMenuClose", "maxSelectedDisplayCount", "isClearable", "isSearchable", "onMenuScrollToBottom", "styles", "filterOption", "onInputChange"]);
1191
+ const refContainer = React__default.useRef(null);
1192
+ const refPrefix = React__default.useRef(null);
1193
+ const { customStyles } = useCustomStyles(refContainer, refPrefix, maxSelectedDisplayCount, styles, disabled);
1194
+ const [menuIsOpen, setMenuIsOpen] = React__default.useState((_b = props.menuIsOpen) !== null && _b !== void 0 ? _b : false);
1195
+ const refMenuIsEnabled = React__default.useRef(true);
1196
+ const customComponents = useCustomComponents(components, disabled || false, menuIsOpen, refMenuIsEnabled, dataTestId, maxSelectedDisplayCount, dropdownIcon);
1197
+ const menuPlacement = "auto";
1198
+ const openMenuHandler = () => __awaiter(void 0, void 0, void 0, function* () {
1199
+ onMenuOpen && onMenuOpen();
1200
+ if (refMenuIsEnabled.current) {
1201
+ setMenuIsOpen(true);
1202
+ }
1203
+ else {
1204
+ refMenuIsEnabled.current = true;
1205
+ }
1206
+ });
1207
+ const closeMenuHandler = () => {
1208
+ setMenuIsOpen(false);
1209
+ onMenuClose && onMenuClose();
1210
+ };
1211
+ const orderedOptions = React__default.useMemo(() => {
1212
+ return disabled
1213
+ ? getOrderedOptions(options, value).map(option => {
1214
+ return Object.assign(Object.assign({}, option), { disabled: true });
1215
+ })
1216
+ : getOrderedOptions(options, value);
1217
+ }, [options, value, disabled]);
1218
+ return {
1219
+ refContainer,
1220
+ refPrefix,
1221
+ customStyles,
1222
+ menuIsOpen,
1223
+ customComponents,
1224
+ menuPlacement,
1225
+ openMenuHandler,
1226
+ closeMenuHandler,
1227
+ orderedOptions,
1228
+ };
1348
1229
  };
1230
+
1349
1231
  /**
1350
- * Retrieves the ISO 3166-1 alpha-2 country code associated with a given international calling code.
1232
+ * CreatableSelects are input components used to choose a value from a set.
1351
1233
  *
1352
- * @param {string} callCode - The international calling code for a country.
1353
- * @returns {string} The abbreviation for a country or an empty string if no matching country is found.
1354
- * @example getCountryAbbreviation("45") // "DK"
1355
- * @example getCountryAbbreviation("+45") // "DK"
1234
+ * @param {CreatableSelectProps} props - The props for the CreatableSelect component
1235
+ * @returns {JSX.Element} CreatableSelect component
1356
1236
  */
1357
- const getCountryAbbreviation = (callCode) => {
1358
- let code = callCode;
1359
- if (callCode.startsWith("+")) {
1360
- code = callCode.substring(1);
1361
- }
1362
- return getCountries().find(c => getCountryCallingCode(c) === code) || "";
1237
+ const CreatableSelect = (props) => {
1238
+ const { className } = props, propsNoClassName = __rest(props, ["className"]);
1239
+ const { id, dataTestId = "creatableSelect", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, value, options, onChange, isLoading, classNamePrefix = dataTestId !== null && dataTestId !== void 0 ? dataTestId : "creatableSelect", onMenuScrollToBottom, filterOption, onInputChange, isSearchable, isClearable = false, readOnly, allowCreateWhileLoading, onCreateOption, } = propsNoClassName;
1240
+ const { refContainer, refPrefix, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler, orderedOptions, } = useSelect(props);
1241
+ const creatableSelectProps = {
1242
+ value,
1243
+ menuPlacement,
1244
+ maxMenuHeight,
1245
+ onChange,
1246
+ "aria-label": label,
1247
+ "data-testid": dataTestId,
1248
+ components: customComponents,
1249
+ styles: customStyles,
1250
+ tabSelectsValue: false,
1251
+ blurInputOnSelect: !isMulti,
1252
+ menuPortalTarget: props.menuPortalTarget || document.body,
1253
+ isSearchable: disabled || readOnly ? false : isSearchable,
1254
+ menuShouldBlockScroll: true,
1255
+ menuShouldScrollIntoView: true,
1256
+ openMenuOnFocus: true,
1257
+ menuIsOpen: !readOnly ? menuIsOpen : false,
1258
+ openMenuOnClick: true,
1259
+ closeMenuOnSelect: false,
1260
+ isMulti,
1261
+ classNamePrefix,
1262
+ isLoading,
1263
+ isClearable,
1264
+ id,
1265
+ onMenuScrollToBottom,
1266
+ onInputChange,
1267
+ allowCreateWhileLoading,
1268
+ onCreateOption,
1269
+ };
1270
+ return (jsxs("div", { className: cvaSelect({ invalid: hasError, disabled: disabled || readOnly, className }), "data-testid": dataTestId, ref: refContainer, children: [prefix !== undefined && (jsx("div", { className: cvaSelectPrefix(), "data-testid": dataTestId && `${dataTestId}-prefix`, ref: refPrefix, children: prefix })), async ? (jsx(ReactAsyncCreatableSelect, Object.assign({}, propsNoClassName, creatableSelectProps, async, { onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler }))) : (jsx(ReactCreatableSelect, Object.assign({}, propsNoClassName, creatableSelectProps, { hideSelectedOptions: false, isMulti: isMulti, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, options: filterOption ? orderedOptions : options })))] }));
1363
1271
  };
1272
+ CreatableSelect.displayName = "CreatableSelect";
1364
1273
 
1365
1274
  /**
1366
- * A custom hook for managing phone number input state and validation.
1275
+ * Selects are input components used to choose a value from a set.
1367
1276
  *
1368
- * @property {Function} getPhoneNumber - A function for get formatted phone number with country code and plus sign
1277
+ * @param {SelectProps} props - The props for the Select component
1278
+ * @returns {JSX.Element} Select component
1369
1279
  */
1370
- const usePhoneInput = () => {
1371
- const getPhoneNumber = ({ country, phone }) => {
1372
- if (country) {
1373
- return getPhoneNumberWithPlus(`${country}${phone || ""}`);
1374
- }
1375
- return phone || "";
1376
- };
1377
- return {
1378
- getPhoneNumber,
1280
+ const Select = (props) => {
1281
+ const { className } = props, propsNoClassName = __rest(props, ["className"]);
1282
+ const { id, dataTestId = "select", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, value, options, onChange, isLoading, classNamePrefix = dataTestId !== null && dataTestId !== void 0 ? dataTestId : "select", onMenuScrollToBottom, filterOption, onInputChange, isSearchable, isClearable = false, readOnly, openMenuOnClick = !disabled, openMenuOnFocus = !disabled, } = props;
1283
+ const { refContainer, refPrefix, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler, orderedOptions, } = useSelect(props);
1284
+ const selectProps = {
1285
+ value,
1286
+ menuPlacement,
1287
+ maxMenuHeight,
1288
+ onChange,
1289
+ "aria-label": label,
1290
+ "data-testid": dataTestId,
1291
+ components: customComponents,
1292
+ styles: customStyles,
1293
+ tabSelectsValue: false,
1294
+ blurInputOnSelect: !isMulti,
1295
+ menuPortalTarget: props.menuPortalTarget || document.body,
1296
+ isSearchable: disabled || readOnly ? false : isSearchable,
1297
+ menuShouldBlockScroll: true,
1298
+ menuShouldScrollIntoView: true,
1299
+ openMenuOnFocus,
1300
+ menuIsOpen: !readOnly ? menuIsOpen : false,
1301
+ openMenuOnClick,
1302
+ closeMenuOnSelect: false,
1303
+ isMulti,
1304
+ classNamePrefix,
1305
+ isLoading,
1306
+ isClearable,
1307
+ id,
1308
+ onMenuScrollToBottom,
1309
+ onInputChange,
1379
1310
  };
1311
+ return (jsxs("div", { className: cvaSelect({ invalid: hasError, disabled: disabled || readOnly, className }), "data-testid": dataTestId, ref: refContainer, children: [prefix !== undefined && (jsx("div", { className: cvaSelectPrefix(), "data-testid": dataTestId && `${dataTestId}-prefix`, ref: refPrefix, children: prefix })), async ? (jsx(ReactAsyncSelect, Object.assign({}, propsNoClassName, selectProps, async, { onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler }))) : (jsx(ReactSelect, Object.assign({}, propsNoClassName, selectProps, { hideSelectedOptions: false, isMulti: isMulti, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, options: filterOption ? orderedOptions : options })))] }));
1380
1312
  };
1313
+ Select.displayName = "Select";
1381
1314
 
1382
1315
  const COUNTRY_CODES_NOT_SUPPORTED_BY_BACKEND = ["+53", "+98", "+211", "+247", "+249", "+383", "+850", "+963"];
1383
1316
  const ADDITIONAL_COUNTRY_CODES_SUPPORTED_BY_BACKEND = [
@@ -2000,6 +1933,71 @@ const Search = forwardRef((_a, ref) => {
2000
1933
  }, children: jsx(Icon, { name: "XMark", size: "small" }) })) : undefined, value: value })));
2001
1934
  });
2002
1935
 
1936
+ const FormFieldSelectAdapter = forwardRef((_a, ref) => {
1937
+ var { className, dataTestId, helpText, helpAddon, tip, label, disabled, isInvalid, errorMessage, name, onBlur, options, value, defaultValue, id, onChange, children } = _a, rest = __rest(_a, ["className", "dataTestId", "helpText", "helpAddon", "tip", "label", "disabled", "isInvalid", "errorMessage", "name", "onBlur", "options", "value", "defaultValue", "id", "onChange", "children"]);
1938
+ const [innerValue, setInnerValue] = useState(value || defaultValue);
1939
+ const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
1940
+ const htmlFor = useMemo(() => (id ? id : "selectField-" + v4()), [id]);
1941
+ const innerRef = useRef(null);
1942
+ useImperativeHandle(ref, () => innerRef.current, []);
1943
+ const handleChange = useCallback((newValue) => {
1944
+ setInnerValue(newValue === null || newValue === void 0 ? void 0 : newValue.value);
1945
+ }, []);
1946
+ useEffect(() => {
1947
+ var _a;
1948
+ if (!innerValue) {
1949
+ return;
1950
+ }
1951
+ const event = new Event("change");
1952
+ (_a = innerRef.current) === null || _a === void 0 ? void 0 : _a.dispatchEvent(event);
1953
+ onChange === null || onChange === void 0 ? void 0 : onChange(event);
1954
+ }, [onChange, innerValue]);
1955
+ const selectedOption = options.find(option => { var _a; return option.value === ((_a = innerRef === null || innerRef === void 0 ? void 0 : innerRef.current) === null || _a === void 0 ? void 0 : _a.value); });
1956
+ const defaultSelectedOption = options.find(option => option.value === defaultValue);
1957
+ return (jsxs(FormGroup, { isInvalid: renderAsInvalid,
1958
+ htmlFor,
1959
+ className,
1960
+ dataTestId,
1961
+ helpText,
1962
+ helpAddon,
1963
+ tip,
1964
+ label,
1965
+ disabled, children: [jsx("select", { onChange, ref: innerRef, name, value: innerValue, hidden: true, children: options.map(option => {
1966
+ return (jsx("option", { value: option.value, children: option.label }, option.value));
1967
+ }) }), children(Object.assign({ id, isDisabled: disabled, onBlur,
1968
+ options, onChange: handleChange, value: selectedOption, defaultValue: defaultSelectedOption }, rest))] }));
1969
+ });
1970
+
1971
+ /**
1972
+ * The CreatableSelectField component is a CreatableSelect component wrapped in the FromGroup component.
1973
+ *
1974
+ * This means that it can easily be added to any form alongside other Field components.
1975
+ *
1976
+ * This is done to make the field compatible with the React-hook-form library.
1977
+ *
1978
+ * @param {SelectFieldProps & CreatableSelectProps} props - The props for the CreatableSelectField component
1979
+ * @returns {JSX.Element} CreatableSelectField component
1980
+ */
1981
+ const CreatableSelectField = (_a) => {
1982
+ var { allowCreateWhileLoading, onCreateOption } = _a, props = __rest(_a, ["allowCreateWhileLoading", "onCreateOption"]);
1983
+ const creatableSelectOnlyProps = { allowCreateWhileLoading, onCreateOption };
1984
+ return (jsx(FormFieldSelectAdapter, Object.assign({}, props, { children: convertedProps => jsx(CreatableSelect, Object.assign({}, convertedProps, creatableSelectOnlyProps)) })));
1985
+ };
1986
+
1987
+ /**
1988
+ * The SelectField component is a Select component wrapped in the FromGroup component.
1989
+ *
1990
+ * This means that it can easily be added to any form alongside other Field components.
1991
+ *
1992
+ * This is done to make the field compatible with the React-hook-form library.
1993
+ *
1994
+ * @param {SelectFieldProps} props - The props for the SelectField component
1995
+ * @returns {JSX.Element} SelectField component
1996
+ */
1997
+ const SelectField = (props) => {
1998
+ return jsx(FormFieldSelectAdapter, Object.assign({}, props, { children: convertedProps => jsx(Select, Object.assign({}, convertedProps)) }));
1999
+ };
2000
+
2003
2001
  const cvaTextArea = cvaMerge([
2004
2002
  cvaInputBase(),
2005
2003
  "block",
@@ -2271,4 +2269,4 @@ const UrlField = forwardRef((_a, ref) => {
2271
2269
  */
2272
2270
  setupLibraryTranslations();
2273
2271
 
2274
- export { ActionButton, BaseInput, Checkbox, CreatableSelect, DateField, DateInput, DropZone, EMAIL_REGEX, EmailField, EmailInput, FormGroup, Label, MultiSelectMenuItem, NumberField, NumberInput, OptionCard, PasswordField, PasswordInput, PhoneField, PhoneInput, RadioGroup, RadioItem, Schedule, ScheduleVariant, Search, Select, SelectField, SingleSelectMenuItem, TextArea, TextAreaField, TextField, TextInput, TimeRange, TimeRangeField, Toggle, UploadField, UploadInput, UrlField, UrlInput, checkIfPhoneNumberHasPlus, countryCodeToFlagEmoji, cvaInput, cvaInputAddon, cvaInputAddonAfter, cvaInputAddonBefore, cvaInputBase, cvaInputBaseDisabled, cvaInputBaseInvalid, cvaInputField, cvaInputPrefix, cvaInputSuffix, cvaSelect, cvaSelectCounter, cvaSelectDynamicTagContainer, cvaSelectIcon, cvaSelectMenu, cvaSelectMenuList, cvaSelectPrefix, cvaSelectXIcon, getCountryAbbreviation, getOrderedOptions, getPhoneNumberWithPlus, isInvalidCountryCode, isInvalidPhoneNumber, isMultiValue, parseSchedule, serializeSchedule, useCustomComponents, usePhoneInput, validateEmailAddress, validatePhoneNumber, weekDay };
2272
+ export { ActionButton, BaseInput, Checkbox, CreatableSelect, CreatableSelectField, DateField, DateInput, DropZone, EMAIL_REGEX, EmailField, EmailInput, FormGroup, Label, MultiSelectMenuItem, NumberField, NumberInput, OptionCard, PasswordField, PasswordInput, PhoneField, PhoneInput, RadioGroup, RadioItem, Schedule, ScheduleVariant, Search, Select, SelectField, SingleSelectMenuItem, TextArea, TextAreaField, TextField, TextInput, TimeRange, TimeRangeField, Toggle, UploadField, UploadInput, UrlField, UrlInput, checkIfPhoneNumberHasPlus, countryCodeToFlagEmoji, cvaInput, cvaInputAddon, cvaInputAddonAfter, cvaInputAddonBefore, cvaInputBase, cvaInputBaseDisabled, cvaInputBaseInvalid, cvaInputField, cvaInputPrefix, cvaInputSuffix, cvaSelect, cvaSelectCounter, cvaSelectDynamicTagContainer, cvaSelectIcon, cvaSelectMenu, cvaSelectMenuList, cvaSelectPrefix, cvaSelectXIcon, getCountryAbbreviation, getOrderedOptions, getPhoneNumberWithPlus, isInvalidCountryCode, isInvalidPhoneNumber, isMultiValue, parseSchedule, serializeSchedule, useCustomComponents, usePhoneInput, validateEmailAddress, validatePhoneNumber, weekDay };