@trackunit/react-form-components 0.0.288 → 0.0.290
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 +924 -871
- package/index.esm.js +927 -875
- package/package.json +1 -1
- package/src/SelectField/SelectField.d.ts +50 -0
- package/src/index.d.ts +1 -0
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
|
|
12
|
-
var
|
|
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
|
|
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-
|
|
223
|
-
"
|
|
224
|
-
"
|
|
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
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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:
|
|
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
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
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:
|
|
176
|
+
true: "pointer-events-none",
|
|
261
177
|
false: "",
|
|
262
178
|
},
|
|
263
179
|
},
|
|
264
180
|
});
|
|
265
|
-
const
|
|
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
|
-
|
|
268
|
-
true:
|
|
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
|
-
*
|
|
276
|
-
*
|
|
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
|
-
*
|
|
280
|
-
*
|
|
196
|
+
* @param {FormGroupProps} props - The props for the FormGroup component
|
|
197
|
+
* @returns {JSX.Element} FormGroup component
|
|
281
198
|
*/
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
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
|
|
299
|
-
"
|
|
300
|
-
"
|
|
301
|
-
"
|
|
302
|
-
"
|
|
303
|
-
"
|
|
304
|
-
"
|
|
305
|
-
"
|
|
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: "
|
|
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: "
|
|
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
|
|
257
|
+
* The SelectContainer component.
|
|
325
258
|
*
|
|
326
|
-
* @param {
|
|
327
|
-
* @returns {JSX.Element}
|
|
259
|
+
* @param {SelectContainerProps} props - The props for the SelectContainer component
|
|
260
|
+
* @returns {JSX.Element} SelectContainer component
|
|
328
261
|
*/
|
|
329
|
-
const
|
|
330
|
-
return (jsxRuntime.
|
|
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
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
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
|
|
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 {
|
|
528
|
-
* @returns {JSX.Element}
|
|
504
|
+
* @param {SelectMenuItemProps} props - The props for the SingleSelectMenuItem
|
|
505
|
+
* @returns {JSX.Element} SingleSelectMenuItem
|
|
529
506
|
*/
|
|
530
|
-
const
|
|
531
|
-
return (jsxRuntime.jsx(
|
|
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
|
-
*
|
|
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 {
|
|
558
|
-
* @returns {JSX.Element}
|
|
513
|
+
* @param {SelectMenuItemProps} props - The props for the MultiSelectMenuItem
|
|
514
|
+
* @returns {JSX.Element} multi select menu item
|
|
559
515
|
*/
|
|
560
|
-
const
|
|
561
|
-
return (jsxRuntime.
|
|
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
|
-
*
|
|
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
|
-
*
|
|
529
|
+
* @param {TagProps} props - The props for the tag component
|
|
530
|
+
* @returns {JSX.Element} TagWithWidth component
|
|
570
531
|
*/
|
|
571
|
-
const
|
|
572
|
-
var {
|
|
573
|
-
const
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
});
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
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
|
-
*
|
|
543
|
+
* TagsContainer component to display tags in limited space when children can't fit space it displays counter
|
|
619
544
|
*
|
|
620
|
-
* @param {
|
|
621
|
-
* @returns {JSX.Element}
|
|
545
|
+
* @param {TagsContainerProps} props - The props for the TagContainer
|
|
546
|
+
* @returns {JSX.Element} TagsContainer
|
|
622
547
|
*/
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
const [
|
|
626
|
-
const
|
|
627
|
-
|
|
628
|
-
const
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
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
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
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
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
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
|
-
*
|
|
669
|
-
*
|
|
670
|
-
*
|
|
671
|
-
* @
|
|
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
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
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
|
-
*
|
|
682
|
-
*
|
|
683
|
-
*
|
|
684
|
-
*
|
|
685
|
-
*
|
|
686
|
-
*
|
|
687
|
-
*
|
|
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
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
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
|
-
*
|
|
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
|
|
706
|
-
var
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
const
|
|
713
|
-
const
|
|
714
|
-
|
|
715
|
-
|
|
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
|
-
|
|
718
|
-
|
|
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
|
-
*
|
|
772
|
+
* The CreatableSelect component.
|
|
723
773
|
*
|
|
724
|
-
*
|
|
774
|
+
* @param {CreateableSelectProps} props - The props for the CreatableSelect component
|
|
775
|
+
* @returns {JSX.Element} CreatableSelect component
|
|
725
776
|
*/
|
|
726
|
-
const
|
|
727
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
|
774
|
-
|
|
775
|
-
const
|
|
776
|
-
|
|
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
|
-
*
|
|
861
|
+
* The SelectField component is a Select component wrapped in the FromGroup component.
|
|
781
862
|
*
|
|
782
|
-
*
|
|
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
|
-
*
|
|
865
|
+
* This is done to make the field compatible with the React-hook-form library.
|
|
790
866
|
*
|
|
791
|
-
*
|
|
867
|
+
* @param {SelectFieldProps} props - The props for the SelectField component
|
|
868
|
+
* @returns {JSX.Element} SelectField component
|
|
792
869
|
*/
|
|
793
|
-
const
|
|
794
|
-
var {
|
|
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 : "
|
|
797
|
-
const
|
|
798
|
-
|
|
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
|
-
|
|
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
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
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
|
-
*
|
|
926
|
+
* The ActionButton component is a wrapper over IconButton to perform an action when the onClick event is triggered.
|
|
859
927
|
*
|
|
860
|
-
*
|
|
928
|
+
* @param {ActionButtonProps} props - The props for the ActionButton component
|
|
929
|
+
* @returns {JSX.Element} ActionButton component
|
|
861
930
|
*/
|
|
862
|
-
const
|
|
863
|
-
const
|
|
864
|
-
|
|
865
|
-
|
|
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
|
|
875
|
-
"
|
|
876
|
-
"
|
|
877
|
-
"
|
|
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-
|
|
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:
|
|
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: "
|
|
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
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
"
|
|
909
|
-
"
|
|
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
|
|
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
|
-
|
|
914
|
-
true: "
|
|
915
|
-
false: "
|
|
1034
|
+
disabled: {
|
|
1035
|
+
true: ["text-slate-500"],
|
|
1036
|
+
false: "",
|
|
916
1037
|
},
|
|
917
1038
|
},
|
|
918
1039
|
});
|
|
919
|
-
const
|
|
1040
|
+
const cvaInputSuffix = cssClassVarianceUtilities.cvaMerge(["flex", "justify-center", "items-center", "text-slate-400", "px-3"], {
|
|
920
1041
|
variants: {
|
|
921
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
931
|
-
*
|
|
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
|
|
934
|
-
|
|
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
|
-
*
|
|
939
|
-
*
|
|
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
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
}
|
|
961
|
-
|
|
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
|
-
*
|
|
965
|
-
* @
|
|
966
|
-
* @
|
|
967
|
-
* @
|
|
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
|
|
971
|
-
if (
|
|
972
|
-
|
|
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
|
|
1199
|
+
return EMAIL_REGEX.test(email);
|
|
983
1200
|
};
|
|
984
1201
|
|
|
985
1202
|
/**
|
|
986
|
-
* A
|
|
1203
|
+
* A Email Input component is used for input of the type Email.
|
|
987
1204
|
*
|
|
988
|
-
*
|
|
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
|
-
*
|
|
998
|
-
*
|
|
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
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
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
|
-
*
|
|
1011
|
-
*
|
|
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
|
|
1017
|
-
var {
|
|
1018
|
-
const
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
}
|
|
1023
|
-
|
|
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
|
-
*
|
|
1244
|
+
* A thin wrapper around the `BaseInput` component for number input fields.
|
|
1028
1245
|
*
|
|
1029
|
-
*
|
|
1030
|
-
* @returns {JSX.Element} TagsContainer
|
|
1246
|
+
* NOTE: If shown with a label, please use the `NumberField` component instead.
|
|
1031
1247
|
*/
|
|
1032
|
-
const
|
|
1033
|
-
|
|
1034
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
1092
|
-
*
|
|
1093
|
-
*
|
|
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
|
|
1103
|
-
|
|
1104
|
-
const
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
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
|
-
*
|
|
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
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
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
|
|
1302
|
+
* A thin wrapper around the `BaseInput` component for password input fields.
|
|
1208
1303
|
*
|
|
1209
|
-
*
|
|
1210
|
-
* @returns {IUseSelect} Select component
|
|
1304
|
+
* NOTE: If shown with a label, please use the `PasswordField` component instead.
|
|
1211
1305
|
*/
|
|
1212
|
-
const
|
|
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
|
-
*
|
|
1309
|
+
* Password fields enter a password or other confidential information. Characters are masked as they are typed.
|
|
1257
1310
|
*
|
|
1258
|
-
*
|
|
1259
|
-
*
|
|
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
|
|
1262
|
-
|
|
1263
|
-
const
|
|
1264
|
-
const
|
|
1265
|
-
const
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
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
|
-
*
|
|
1380
|
+
* A custom hook for managing phone number input state and validation.
|
|
1305
1381
|
*
|
|
1306
|
-
*
|
|
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
|
|
1310
|
-
const
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
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;
|