@trackunit/react-form-components 0.0.288 → 0.0.289

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