@trackunit/react-form-components 1.0.29 → 1.0.30
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 +220 -133
- package/index.esm.js +222 -134
- package/package.json +2 -2
- package/src/components/ActionButton/ActionButton.d.ts +1 -7
- package/src/components/ActionButton/ActionButton.variants.d.ts +4 -2
- package/src/components/BaseInput/BaseInput.d.ts +26 -30
- package/src/components/BaseInput/BaseInput.variants.d.ts +9 -7
- package/src/components/BaseInput/InputLockReasonTooltip.d.ts +15 -0
- package/src/components/BaseInput/components/AddonAfterRenderer.d.ts +7 -0
- package/src/components/BaseInput/components/AddonBeforeRenderer.d.ts +7 -0
- package/src/components/BaseInput/components/GenericActionsRenderer.d.ts +8 -0
- package/src/components/BaseInput/components/LockReasonRenderer.d.ts +5 -0
- package/src/components/BaseInput/components/PrefixRenderer.d.ts +8 -0
- package/src/components/BaseInput/components/SuffixRenderer.d.ts +10 -0
- package/src/components/BaseInput/components/index.d.ts +6 -0
- package/src/components/EmailInput/EmailInput.d.ts +1 -2
- package/src/components/FormGroup/FormGroup.d.ts +6 -1
- package/src/components/FormGroup/FormGroup.variants.d.ts +1 -0
- package/src/components/PhoneInput/PhoneInput.d.ts +3 -3
- package/src/components/Select/Select.variants.d.ts +1 -0
- package/src/components/Select/SelectMenuItem/SelectMenuItem.d.ts +7 -2
- package/src/components/Select/useCustomComponents.d.ts +3 -1
- package/src/components/Select/useCustomStyles.d.ts +3 -1
- package/src/components/Select/useSelect.d.ts +10 -3
- package/src/components/TextField/TextField.d.ts +0 -4
- package/src/components/UploadInput/UploadInput.variants.d.ts +0 -1
- package/src/translation.d.ts +2 -2
- package/src/types.d.ts +1 -0
- package/src/components/BaseInput/DisabledForReasonsTip.d.ts +0 -15
package/index.esm.js
CHANGED
|
@@ -4,7 +4,7 @@ import { IconButton, Icon, Tooltip, useIsTextTruncated, Heading, Text, Spinner,
|
|
|
4
4
|
import { useCopyToClipboard } from 'usehooks-ts';
|
|
5
5
|
import { cvaMerge } from '@trackunit/css-class-variance-utilities';
|
|
6
6
|
import * as React from 'react';
|
|
7
|
-
import React__default, {
|
|
7
|
+
import React__default, { forwardRef, useRef, useImperativeHandle, useMemo, useState, useCallback, cloneElement, useEffect, useContext } from 'react';
|
|
8
8
|
import { uuidv4, nonNullable } from '@trackunit/shared-utils';
|
|
9
9
|
import { Temporal } from '@js-temporal/polyfill';
|
|
10
10
|
import parsePhoneNumberFromString, { isSupportedCountry, getCountries, getCountryCallingCode, AsYouType, parseIncompletePhoneNumber, isValidPhoneNumber } from 'libphonenumber-js';
|
|
@@ -18,6 +18,7 @@ import { twMerge } from 'tailwind-merge';
|
|
|
18
18
|
import { z } from 'zod';
|
|
19
19
|
|
|
20
20
|
var defaultTranslations = {
|
|
21
|
+
"baseInput.copyAction.toolTip": "Copy value",
|
|
21
22
|
"clearIndicator.icon.tooltip.clearAll": "Clear all",
|
|
22
23
|
"colorField.error.INVALID_HEX_CODE": "Please enter a valid HEX code",
|
|
23
24
|
"colorField.error.REQUIRED": "This field is required",
|
|
@@ -97,15 +98,30 @@ const setupLibraryTranslations = () => {
|
|
|
97
98
|
const cvaActionButton = cvaMerge(["drop-shadow-none", "rounded-md"], {
|
|
98
99
|
variants: {
|
|
99
100
|
size: {
|
|
100
|
-
small: ["w-6", "h-6"],
|
|
101
|
-
medium: ["w-
|
|
101
|
+
small: ["w-6", "h-6", "min-h-0"],
|
|
102
|
+
medium: ["w-6", "h-6", "min-h-0"],
|
|
103
|
+
large: ["w-8", "h-8"],
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
defaultVariants: {
|
|
107
|
+
size: "medium",
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
const cvaActionContainer = cvaMerge(["flex", "items-center"], {
|
|
111
|
+
variants: {
|
|
112
|
+
size: {
|
|
113
|
+
//I just measured manually the top/bottom spacing
|
|
114
|
+
//when using the action button inside an input
|
|
115
|
+
//might need tweaking in the future
|
|
116
|
+
small: ["m-[1px]"],
|
|
117
|
+
medium: ["m-[3px]"],
|
|
118
|
+
large: ["m-[3px]"],
|
|
102
119
|
},
|
|
103
120
|
},
|
|
104
121
|
defaultVariants: {
|
|
105
122
|
size: "medium",
|
|
106
123
|
},
|
|
107
124
|
});
|
|
108
|
-
const cvaActionContainer = cvaMerge(["flex", "items-center", "m-1"]);
|
|
109
125
|
|
|
110
126
|
/**
|
|
111
127
|
* The ActionButton component is a wrapper over IconButton to perform an action when the onClick event is triggered.
|
|
@@ -113,7 +129,7 @@ const cvaActionContainer = cvaMerge(["flex", "items-center", "m-1"]);
|
|
|
113
129
|
* @param {ActionButtonProps} props - The props for the ActionButton component
|
|
114
130
|
* @returns {JSX.Element} ActionButton component
|
|
115
131
|
*/
|
|
116
|
-
const ActionButton = ({ type, value, dataTestId,
|
|
132
|
+
const ActionButton = ({ type, value, dataTestId, size, disabled, className }) => {
|
|
117
133
|
const [, copyToClipboard] = useCopyToClipboard();
|
|
118
134
|
const getIconName = () => {
|
|
119
135
|
switch (type) {
|
|
@@ -142,52 +158,12 @@ const ActionButton = ({ type, value, dataTestId, iconSize, disabled, className }
|
|
|
142
158
|
case "COPY":
|
|
143
159
|
// Typescript seems to be unable to detect RefObject
|
|
144
160
|
// as one of the members of the union RefObject | string | null which gives access to the `current` property
|
|
145
|
-
// eslint-disable-next-line react/prop-types
|
|
146
161
|
return copyToClipboard(value?.current?.value ?? "");
|
|
147
162
|
default:
|
|
148
163
|
return null;
|
|
149
164
|
}
|
|
150
165
|
};
|
|
151
|
-
return (jsx("div", { className: cvaActionContainer({ className }), children: jsx(IconButton, { className: cvaActionButton({ size
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Used to compare two React nodes for deep equality.
|
|
156
|
-
*/
|
|
157
|
-
const compareReactNodes = (node1, node2) => {
|
|
158
|
-
// Base case: If both objects are identical, return true.
|
|
159
|
-
if (node1 === node2) {
|
|
160
|
-
return true;
|
|
161
|
-
}
|
|
162
|
-
// Check if both objects are valid React elements.
|
|
163
|
-
if (isValidElement(node1) && isValidElement(node2)) {
|
|
164
|
-
const { type: type1, props: props1, key: key1 } = node1;
|
|
165
|
-
const { type: type2, props: props2, key: key2 } = node2;
|
|
166
|
-
if (type1 !== type2 || key1 !== key2) {
|
|
167
|
-
return false;
|
|
168
|
-
}
|
|
169
|
-
return compareReactNodes(props1, props2);
|
|
170
|
-
}
|
|
171
|
-
// Check if both objects are objects and not null.
|
|
172
|
-
if (typeof node1 !== "object" || typeof node2 !== "object" || node1 === null || node2 === null) {
|
|
173
|
-
return false;
|
|
174
|
-
}
|
|
175
|
-
// Get the keys of both objects.
|
|
176
|
-
const keys1 = Object.keys(node1);
|
|
177
|
-
const keys2 = Object.keys(node2);
|
|
178
|
-
// Check if the number of keys is the same.
|
|
179
|
-
if (keys1.length !== keys2.length) {
|
|
180
|
-
return false;
|
|
181
|
-
}
|
|
182
|
-
// Iterate through the keys and compare their values recursively.
|
|
183
|
-
for (const key of keys1) {
|
|
184
|
-
if (!keys2.includes(key) ||
|
|
185
|
-
!compareReactNodes(node1[key], node2[key])) {
|
|
186
|
-
return false;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
// If all checks pass, the objects are deep equal.
|
|
190
|
-
return true;
|
|
166
|
+
return (jsx("div", { className: cvaActionContainer({ className, size }), children: jsx(IconButton, { className: cvaActionButton({ size }), dataTestId: dataTestId || "testIconButtonId", disabled: disabled, icon: jsx(Icon, { name: getIconName(), size: size }), onClick: buttonAction, size: "small", variant: "secondary" }) }));
|
|
191
167
|
};
|
|
192
168
|
|
|
193
169
|
const cvaInputBase = cvaMerge([
|
|
@@ -204,8 +180,9 @@ const cvaInputBaseInvalid = cvaMerge(["border-danger-600"]);
|
|
|
204
180
|
const cvaInput = cvaMerge(["relative", "flex", "h-10", cvaInputBase()], {
|
|
205
181
|
variants: {
|
|
206
182
|
size: {
|
|
207
|
-
small: ["h-
|
|
208
|
-
medium: ["h-
|
|
183
|
+
small: ["h-7"],
|
|
184
|
+
medium: ["h-8"],
|
|
185
|
+
large: ["h-10"],
|
|
209
186
|
},
|
|
210
187
|
disabled: {
|
|
211
188
|
true: cvaInputBaseDisabled(),
|
|
@@ -215,6 +192,20 @@ const cvaInput = cvaMerge(["relative", "flex", "h-10", cvaInputBase()], {
|
|
|
215
192
|
true: cvaInputBaseInvalid(),
|
|
216
193
|
false: [""],
|
|
217
194
|
},
|
|
195
|
+
isWarning: {
|
|
196
|
+
true: ["border-warning-600"],
|
|
197
|
+
false: [""],
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
compoundVariants: [
|
|
201
|
+
{
|
|
202
|
+
invalid: true,
|
|
203
|
+
isWarning: true,
|
|
204
|
+
className: ["border-danger-600"], // Ensures that 'invalid' takes precedence
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
defaultVariants: {
|
|
208
|
+
size: "medium",
|
|
218
209
|
},
|
|
219
210
|
});
|
|
220
211
|
const cvaInputField = cvaMerge([
|
|
@@ -222,18 +213,24 @@ const cvaInputField = cvaMerge([
|
|
|
222
213
|
"px-3",
|
|
223
214
|
"border-0",
|
|
224
215
|
"bg-transparent",
|
|
225
|
-
"text-base",
|
|
226
216
|
"text-slate-900",
|
|
227
217
|
"placeholder-slate-400",
|
|
228
218
|
"component-baseInput-border",
|
|
219
|
+
"text-sm",
|
|
220
|
+
"truncate",
|
|
229
221
|
], {
|
|
230
222
|
variants: {
|
|
231
223
|
size: {
|
|
232
|
-
small: ["py-
|
|
233
|
-
medium: ["py-
|
|
224
|
+
small: ["py-0.5", "text-xs"],
|
|
225
|
+
medium: ["py-1"],
|
|
226
|
+
large: ["py-2"],
|
|
234
227
|
},
|
|
235
228
|
disabled: {
|
|
236
|
-
true: ["text-slate-
|
|
229
|
+
true: ["text-slate-400"],
|
|
230
|
+
false: [""],
|
|
231
|
+
},
|
|
232
|
+
readOnly: {
|
|
233
|
+
true: ["text-slate-500"],
|
|
237
234
|
false: [""],
|
|
238
235
|
},
|
|
239
236
|
autoFocus: {
|
|
@@ -255,6 +252,11 @@ const cvaInputField = cvaMerge([
|
|
|
255
252
|
prefix: true,
|
|
256
253
|
className: ["ps-4"],
|
|
257
254
|
},
|
|
255
|
+
{
|
|
256
|
+
disabled: true,
|
|
257
|
+
readOnly: true,
|
|
258
|
+
className: "text-slate-400",
|
|
259
|
+
},
|
|
258
260
|
],
|
|
259
261
|
});
|
|
260
262
|
const cvaInputAddon = cvaMerge([
|
|
@@ -266,7 +268,15 @@ const cvaInputAddon = cvaMerge([
|
|
|
266
268
|
"text-slate-500",
|
|
267
269
|
"bg-slate-50",
|
|
268
270
|
]);
|
|
269
|
-
const cvaInputAddonBefore = cvaMerge([cvaInputAddon(), "border-r", "rounded-l-lg"]
|
|
271
|
+
const cvaInputAddonBefore = cvaMerge([cvaInputAddon(), "border-r", "rounded-l-lg"], {
|
|
272
|
+
variants: {
|
|
273
|
+
size: {
|
|
274
|
+
small: ["text-xs"],
|
|
275
|
+
medium: ["text-sm"],
|
|
276
|
+
large: ["text-sm"],
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
});
|
|
270
280
|
const cvaInputPrefix = cvaMerge([
|
|
271
281
|
"flex",
|
|
272
282
|
"justify-center",
|
|
@@ -285,7 +295,7 @@ const cvaInputPrefix = cvaMerge([
|
|
|
285
295
|
false: [""],
|
|
286
296
|
},
|
|
287
297
|
addonBefore: {
|
|
288
|
-
true: ["relative"],
|
|
298
|
+
true: ["relative", "mr-1"],
|
|
289
299
|
false: [""],
|
|
290
300
|
},
|
|
291
301
|
},
|
|
@@ -301,7 +311,7 @@ const cvaInputSuffix = cvaMerge(["flex", "justify-center", "items-center", "text
|
|
|
301
311
|
false: [""],
|
|
302
312
|
},
|
|
303
313
|
actions: {
|
|
304
|
-
true: ["right-
|
|
314
|
+
true: ["right-6"],
|
|
305
315
|
false: [""],
|
|
306
316
|
},
|
|
307
317
|
},
|
|
@@ -313,41 +323,104 @@ const cvaInputSuffix = cvaMerge(["flex", "justify-center", "items-center", "text
|
|
|
313
323
|
},
|
|
314
324
|
],
|
|
315
325
|
});
|
|
316
|
-
const cvaInputAddonAfter = cvaMerge([cvaInputAddon(), "border-l", "rounded-r-lg", "ml-[1px]"]
|
|
317
|
-
const cvaInputAction = cvaMerge(["absolute", "end-0.5"], {
|
|
326
|
+
const cvaInputAddonAfter = cvaMerge([cvaInputAddon(), "border-l", "rounded-r-lg", "ml-[1px]"], {
|
|
318
327
|
variants: {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
suffix: {
|
|
324
|
-
true: ["absolute"],
|
|
325
|
-
false: [""],
|
|
328
|
+
size: {
|
|
329
|
+
small: ["text-xs"],
|
|
330
|
+
medium: ["text-sm"],
|
|
331
|
+
large: ["text-sm"],
|
|
326
332
|
},
|
|
327
333
|
},
|
|
328
|
-
compoundVariants: [
|
|
329
|
-
{
|
|
330
|
-
addonAfter: true,
|
|
331
|
-
suffix: true,
|
|
332
|
-
className: ["relative"],
|
|
333
|
-
},
|
|
334
|
-
],
|
|
335
334
|
});
|
|
336
335
|
|
|
336
|
+
// Renders the "addonAfter" element if provided
|
|
337
|
+
const AddonAfterRenderer = ({ addonAfter, dataTestId, fieldSize, }) => {
|
|
338
|
+
if (!addonAfter) {
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
return (jsx("div", { className: cvaInputAddonAfter({ size: fieldSize }), "data-testid": dataTestId ? `${dataTestId}-addonAfter` : null, children: addonAfter }));
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
// Renders the "addonBefore" element if provided
|
|
345
|
+
const AddonBeforeRenderer = ({ addonBefore, addonBeforeClassName, dataTestId, fieldSize, }) => {
|
|
346
|
+
if (!addonBefore) {
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
return (jsx("div", { className: cvaInputAddonBefore({ className: addonBeforeClassName, size: fieldSize }), "data-testid": dataTestId ? `${dataTestId}-addonBefore` : null, children: addonBefore }));
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
// Renders generic actions like "copy" if specified
|
|
353
|
+
const GenericActionsRenderer = ({ genericAction, fieldSize, innerRef, }) => {
|
|
354
|
+
const [t] = useTranslation();
|
|
355
|
+
if (!genericAction) {
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
// Currently only supports copy, can extend if more actions are added
|
|
359
|
+
return (jsx(Tooltip, { label: t("baseInput.copyAction.toolTip"), placement: "top", children: jsx(ActionButton, { dataTestId: "copy-value-button", size: fieldSize ?? undefined, type: "COPY", value: innerRef }) }));
|
|
360
|
+
};
|
|
361
|
+
|
|
337
362
|
/**
|
|
338
363
|
* Icon with explanation tooltip for why an input is locked or disabled.
|
|
339
364
|
* If locked, a permission lacks but the input **can** sometimes be edited.
|
|
340
365
|
* If disabled, the input **cannot** be edited and is only ever for displaying information.
|
|
341
366
|
*
|
|
342
|
-
* @param {
|
|
343
|
-
* @param {
|
|
367
|
+
* @param {LockedForReasons} props - The reasons for the disabled state.
|
|
368
|
+
* @param {LockedKind} kind - The kind of disabled state. If locked, the input can sometimes be edited. If disabled, the input cannot be edited.
|
|
344
369
|
*/
|
|
345
|
-
const
|
|
370
|
+
const InputLockReasonTooltip = ({ reasons, kind }) => {
|
|
346
371
|
const [t] = useTranslation();
|
|
347
372
|
if (!reasons || reasons.length === 0) {
|
|
348
373
|
return (jsx(Tooltip, { label: t("field.notEditable.tooltip"), children: jsx(Icon, { name: kind === "disabled" ? "QuestionMarkCircle" : "LockClosed", size: "small" }) }));
|
|
349
374
|
}
|
|
350
|
-
return (jsx(Tooltip, { label: jsx("ul", { className: typeof reasons === "string"
|
|
375
|
+
return (jsx(Tooltip, { label: jsx("ul", { className: typeof reasons === "string" ? "list-none !pl-0" : "list-disc", children: typeof reasons === "string" ? jsx("li", { children: reasons }) : reasons.map(reason => jsx("li", { children: reason }, reason)) }), placement: "top", children: jsx(Icon, { name: "LockClosed", size: "small" }) }));
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
// Renders a tooltip for lock reasons if the prop is an object
|
|
379
|
+
const LockReasonRenderer = ({ lockReason, dataTestId, }) => {
|
|
380
|
+
// Only render if lockReason is an object
|
|
381
|
+
if (typeof lockReason !== "object") {
|
|
382
|
+
return null;
|
|
383
|
+
}
|
|
384
|
+
return (jsx("div", { className: cvaInputSuffix({ disabled: false }), "data-testid": dataTestId ? `${dataTestId}-locked` : undefined, children: jsx(InputLockReasonTooltip, { ...lockReason }) }));
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
// Renders the prefix element or falls back to a default prefix for certain types
|
|
388
|
+
const PrefixRenderer = ({ prefix, type, addonBefore, dataTestId, disabled, }) => {
|
|
389
|
+
// Default icons for specific input types
|
|
390
|
+
const defaultPrefixMap = {
|
|
391
|
+
email: jsx(Icon, { name: "AtSymbol", size: "small" }),
|
|
392
|
+
number: jsx(Icon, { name: "Hashtag", size: "small" }),
|
|
393
|
+
url: jsx(Icon, { name: "Link", size: "small" }),
|
|
394
|
+
};
|
|
395
|
+
// Decide what to show as prefix
|
|
396
|
+
const resolvedPrefix = prefix || (type && type !== "text" ? (defaultPrefixMap[type] ?? type) : null);
|
|
397
|
+
if (!resolvedPrefix) {
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
return (jsx("div", { className: cvaInputPrefix({ disabled, addonBefore: addonBefore !== undefined }), "data-testid": dataTestId ? `${dataTestId}-prefix` : null, children: resolvedPrefix }));
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
// Renders the suffix element or shows an icon if invalid/warning
|
|
404
|
+
const SuffixRenderer = ({ suffix, addonAfter, actions, isInvalid, isWarning, dataTestId, disabled, }) => {
|
|
405
|
+
// If user provided suffix that's not identical to addonBefore, render it
|
|
406
|
+
if (suffix) {
|
|
407
|
+
return (jsx("div", { className: cvaInputSuffix({
|
|
408
|
+
disabled,
|
|
409
|
+
addonAfter: addonAfter !== undefined,
|
|
410
|
+
actions: Boolean(actions),
|
|
411
|
+
}), "data-testid": dataTestId ? `${dataTestId}-suffix` : null, children: suffix }));
|
|
412
|
+
}
|
|
413
|
+
// If invalid or warning, render an icon (unless within FormGroup)
|
|
414
|
+
if (isInvalid || isWarning) {
|
|
415
|
+
return (jsx("div", { className: cvaInputSuffix({
|
|
416
|
+
disabled,
|
|
417
|
+
addonAfter: addonAfter !== undefined,
|
|
418
|
+
actions: Boolean(actions),
|
|
419
|
+
// Hides the icon if inside a FormGroup
|
|
420
|
+
className: "group-[.form-group]:hidden",
|
|
421
|
+
}), "data-testid": dataTestId ? `${dataTestId}-suffix` : null, children: jsx(Icon, { color: isInvalid ? "danger" : "warning", name: "ExclamationTriangle", size: "small" }) }));
|
|
422
|
+
}
|
|
423
|
+
return null;
|
|
351
424
|
};
|
|
352
425
|
|
|
353
426
|
/**
|
|
@@ -358,44 +431,33 @@ const DisabledForReasonsTip = ({ reasons, kind }) => {
|
|
|
358
431
|
* For specific input types make sure to use the corresponding input component.
|
|
359
432
|
* This is a base used by our other input components such as TextInput, NumberInput, PasswordInput, etc.
|
|
360
433
|
*/
|
|
361
|
-
const BaseInput =
|
|
362
|
-
|
|
363
|
-
const
|
|
364
|
-
|
|
365
|
-
|
|
434
|
+
const BaseInput = forwardRef(({ className, isInvalid, dataTestId, prefix, suffix, addonBefore, addonAfter, actions, fieldSize = "medium", nonInteractive = false, inputClassName, placeholder, addonBeforeClassName, isWarning, type, genericAction, style, ...rest }, ref) => {
|
|
435
|
+
// Derive final flags
|
|
436
|
+
const renderAsDisabled = Boolean(rest.disabled);
|
|
437
|
+
const renderAsReadonly = Boolean(rest.readOnly);
|
|
438
|
+
// Keep a reference to the input element
|
|
439
|
+
const innerRef = useRef(null);
|
|
440
|
+
useImperativeHandle(ref, () => innerRef.current, []);
|
|
366
441
|
return (jsxs("div", { className: cvaInput({
|
|
367
442
|
disabled: renderAsDisabled,
|
|
368
443
|
invalid: isInvalid,
|
|
444
|
+
isWarning,
|
|
369
445
|
size: fieldSize,
|
|
370
446
|
className,
|
|
371
|
-
}), "data-testid": dataTestId ? `${dataTestId}-container` : null, style: style, children: [
|
|
372
|
-
disabled: renderAsDisabled,
|
|
373
|
-
addonBefore: addonBefore !== undefined,
|
|
374
|
-
}), "data-testid": dataTestId ? `${dataTestId}-prefix` : null, children: prefix })) : null, jsx("input", { "aria-required": rest.required, className: cvaInputField({
|
|
447
|
+
}), "data-testid": dataTestId ? `${dataTestId}-container` : null, style: style, children: [jsx(AddonBeforeRenderer, { addonBefore: addonBefore, addonBeforeClassName: addonBeforeClassName, dataTestId: dataTestId, fieldSize: fieldSize }), jsx(PrefixRenderer, { addonBefore: addonBefore, dataTestId: dataTestId, disabled: renderAsDisabled, prefix: prefix, type: type }), jsx("input", { "aria-required": rest.required, className: cvaInputField({
|
|
375
448
|
autoFocus: rest.autoFocus,
|
|
449
|
+
readOnly: renderAsReadonly,
|
|
376
450
|
size: fieldSize,
|
|
377
451
|
disabled: renderAsDisabled,
|
|
378
452
|
className: inputClassName,
|
|
379
453
|
addonBefore: addonBefore !== undefined,
|
|
380
|
-
prefix:
|
|
381
|
-
}), "data-testid": dataTestId, placeholder: renderAsDisabled ? undefined : placeholder, ref: innerRef, ...rest, disabled:
|
|
382
|
-
disabled: false,
|
|
383
|
-
}), "data-testid": dataTestId ? `${dataTestId}-locked` : undefined, children: jsx(DisabledForReasonsTip, { ...rest.disabled }) })) : null, suffix && addonBefore !== suffix ? (jsx("div", { className: cvaInputSuffix({
|
|
384
|
-
disabled: renderAsDisabled,
|
|
385
|
-
addonAfter: addonAfter !== undefined && !compareReactNodes(addonBefore, addonAfter),
|
|
386
|
-
actions: (actions && !compareReactNodes(addonBefore, actions)) || false,
|
|
387
|
-
}), "data-testid": dataTestId ? `${dataTestId}-suffix` : null, children: suffix })) : null, rest.readOnly === true &&
|
|
388
|
-
showDefaultActions &&
|
|
389
|
-
innerRef.current?.value.length &&
|
|
390
|
-
innerRef.current.value.length > 0 ? (jsx(ActionButton, { type: "COPY", value: innerRef }, "default-copy-action")) : null, actions && !compareReactNodes(addonBefore, actions) ? (jsx("div", { className: cvaInputAction({
|
|
391
|
-
addonAfter: addonAfter !== undefined && !compareReactNodes(addonBefore, addonAfter),
|
|
392
|
-
suffix: !compareReactNodes(addonBefore, suffix),
|
|
393
|
-
}), children: actions })) : null, addonAfter && !compareReactNodes(addonBefore, addonAfter) && !compareReactNodes(addonAfter, suffix) ? (jsx("div", { className: cvaInputAddonAfter(), "data-testid": dataTestId ? `${dataTestId}-addonAfter` : null, children: addonAfter })) : null] }));
|
|
454
|
+
prefix: !!prefix || (type && type !== "text"),
|
|
455
|
+
}), "data-testid": dataTestId, placeholder: renderAsDisabled ? undefined : placeholder, ref: innerRef, type: type, ...rest, disabled: renderAsDisabled, readOnly: renderAsReadonly || nonInteractive }), jsx(LockReasonRenderer, { dataTestId: dataTestId + "-disabled", lockReason: rest.disabled }), jsx(LockReasonRenderer, { dataTestId: dataTestId + "-readonly", lockReason: rest.readOnly && !rest.disabled ? rest.readOnly : undefined }), jsx(GenericActionsRenderer, { fieldSize: fieldSize, genericAction: genericAction, innerRef: innerRef }), jsx(SuffixRenderer, { actions: actions, addonAfter: addonAfter, dataTestId: dataTestId, disabled: renderAsDisabled, isInvalid: isInvalid, isWarning: isWarning, suffix: suffix }), actions, jsx(AddonAfterRenderer, { addonAfter: addonAfter, dataTestId: dataTestId, fieldSize: fieldSize })] }));
|
|
394
456
|
});
|
|
395
457
|
BaseInput.displayName = "BaseInput";
|
|
396
458
|
|
|
397
459
|
const cvaLabel = cvaMerge([
|
|
398
|
-
"text-
|
|
460
|
+
"text-sm",
|
|
399
461
|
"text-slate-700",
|
|
400
462
|
"truncate",
|
|
401
463
|
"hover:text-slate-800",
|
|
@@ -596,7 +658,7 @@ const Label = ({ id, htmlFor, children, className, dataTestId, disabled, isInval
|
|
|
596
658
|
return (jsx("label", { className: cvaLabel({ invalid: isInvalid, disabled, className }), "data-testid": dataTestId, htmlFor: htmlFor || "", id: id || "", children: children }));
|
|
597
659
|
};
|
|
598
660
|
|
|
599
|
-
const cvaFormGroup = cvaMerge(["component-formGroup-gap"]);
|
|
661
|
+
const cvaFormGroup = cvaMerge(["component-formGroup-gap", "group", "form-group"]);
|
|
600
662
|
const cvaFormGroupContainerBefore = cvaMerge(["flex", "mb-1", "items-center"]);
|
|
601
663
|
const cvaFormGroupContainerAfter = cvaMerge(["flex", "justify-between", "mt-1", "text-xs", "text-slate-500"], {
|
|
602
664
|
variants: {
|
|
@@ -604,7 +666,18 @@ const cvaFormGroupContainerAfter = cvaMerge(["flex", "justify-between", "mt-1",
|
|
|
604
666
|
true: "text-danger-500",
|
|
605
667
|
false: "",
|
|
606
668
|
},
|
|
669
|
+
isWarning: {
|
|
670
|
+
true: "text-default-500 ",
|
|
671
|
+
false: "",
|
|
672
|
+
},
|
|
607
673
|
},
|
|
674
|
+
compoundVariants: [
|
|
675
|
+
{
|
|
676
|
+
invalid: true,
|
|
677
|
+
isWarning: true,
|
|
678
|
+
className: "text-danger-500 ", // Ensures that 'invalid' takes precedence
|
|
679
|
+
},
|
|
680
|
+
],
|
|
608
681
|
});
|
|
609
682
|
const cvaHelpAddon = cvaMerge(["ml-auto"]);
|
|
610
683
|
|
|
@@ -615,9 +688,13 @@ const cvaHelpAddon = cvaMerge(["ml-auto"]);
|
|
|
615
688
|
* @param {FormGroupProps} props - The props for the FormGroup component
|
|
616
689
|
* @returns {JSX.Element} FormGroup component
|
|
617
690
|
*/
|
|
618
|
-
const FormGroup = ({ isInvalid, helpText, helpAddon, tip, className, dataTestId, label, htmlFor, children, required = false, }) => {
|
|
691
|
+
const FormGroup = ({ isInvalid, isWarning, helpText, helpAddon, tip, className, dataTestId, label, htmlFor, children, required = false, }) => {
|
|
619
692
|
const [t] = useTranslation();
|
|
620
|
-
|
|
693
|
+
const validationStateIcon = React.useMemo(() => {
|
|
694
|
+
const color = isInvalid ? "danger" : isWarning ? "warning" : null;
|
|
695
|
+
return color ? jsx(Icon, { color: color, name: "ExclamationTriangle", size: "small" }) : null;
|
|
696
|
+
}, [isInvalid, isWarning]);
|
|
697
|
+
return (jsxs("div", { className: cvaFormGroup({ className }), "data-testid": dataTestId, children: [jsxs("div", { className: cvaFormGroupContainerBefore(), children: [label ? (jsxs(Fragment, { children: [jsx(Label, { className: "component-formGroup-font", dataTestId: dataTestId ? `${dataTestId}-label` : undefined, htmlFor: htmlFor, id: htmlFor + "-label", children: label }), required ? (jsx(Tooltip, { "data-testid": "required-asterisk", label: t("field.required.asterisk.tooltip"), children: "*" })) : null] })) : null, tip ? (jsx(Tooltip, { className: "ml-1", dataTestId: dataTestId ? `${dataTestId}-tooltip` : undefined, label: tip, placement: "bottom" })) : null] }), children, helpText || helpAddon ? (jsxs("div", { className: cvaFormGroupContainerAfter({ invalid: isInvalid, isWarning: isWarning }), children: [helpText ? (jsxs("div", { className: "flex gap-1", children: [validationStateIcon, jsx("span", { "data-testid": dataTestId ? `${dataTestId}-helpText` : undefined, children: helpText })] })) : undefined, helpAddon ? (jsx("span", { className: cvaHelpAddon(), "data-testid": dataTestId ? `${dataTestId}-helpAddon` : null, children: helpAddon })) : null] })) : null] }));
|
|
621
698
|
};
|
|
622
699
|
|
|
623
700
|
/**
|
|
@@ -898,8 +975,8 @@ const validateEmailId = (emailId, required) => {
|
|
|
898
975
|
* A reference to the input element is provided as the `ref` prop.
|
|
899
976
|
* For specific input types make sure to use the corresponding input component.
|
|
900
977
|
*/
|
|
901
|
-
const EmailInput =
|
|
902
|
-
const [email, setEmail] =
|
|
978
|
+
const EmailInput = forwardRef(({ fieldSize = "medium", disabled = false, dataTestId, isInvalid = false, onChange, disableAction = false, ...rest }, ref) => {
|
|
979
|
+
const [email, setEmail] = useState("");
|
|
903
980
|
const sendEmail = () => {
|
|
904
981
|
return window.open(`mailto:${email}`);
|
|
905
982
|
};
|
|
@@ -909,7 +986,7 @@ const EmailInput = React.forwardRef(({ fieldSize = "medium", disabled = false, d
|
|
|
909
986
|
setEmail(newValue);
|
|
910
987
|
}, [onChange]);
|
|
911
988
|
const renderAsInvalid = (email && !validateEmailAddress(email)) || isInvalid;
|
|
912
|
-
return (jsx(BaseInput, { actions: email && email.length > 0 ? (jsx(ActionButton, { dataTestId: dataTestId ? `${dataTestId}-emailIcon` : undefined, disabled: disableAction || isInvalid,
|
|
989
|
+
return (jsx(BaseInput, { actions: email && email.length > 0 ? (jsx(ActionButton, { dataTestId: dataTestId ? `${dataTestId}-emailIcon` : undefined, disabled: disableAction || isInvalid, onClick: sendEmail, size: fieldSize ?? undefined, type: "EMAIL", value: email })) : null, dataTestId: dataTestId, disabled: disabled, isInvalid: renderAsInvalid, onChange: handleChange, placeholder: rest.placeholder || "mail@example.com", ref: ref, type: "email", ...rest }));
|
|
913
990
|
});
|
|
914
991
|
EmailInput.displayName = "EmailInput";
|
|
915
992
|
|
|
@@ -1096,7 +1173,7 @@ OptionCard.displayName = "OptionCard";
|
|
|
1096
1173
|
*/
|
|
1097
1174
|
const PasswordInput = forwardRef((props, ref) => {
|
|
1098
1175
|
const [showPassword, setShowPassword] = useState(false);
|
|
1099
|
-
return (jsx(BaseInput, { ref: ref, ...props, actions: jsx("div", { className: cvaActionContainer(), children: jsx(IconButton, { className: cvaActionButton({ size: props.fieldSize }), icon: jsx(Icon, { name: showPassword ? "EyeSlash" : "Eye", size: "small" }), onClick: () => setShowPassword(prevState => !prevState), size: "small", variant: "secondary" }) }), type: showPassword ? "text" : "password" }));
|
|
1176
|
+
return (jsx(BaseInput, { ref: ref, ...props, actions: jsx("div", { className: cvaActionContainer({ size: props.fieldSize }), children: jsx(IconButton, { className: cvaActionButton({ size: props.fieldSize }), icon: jsx(Icon, { name: showPassword ? "EyeSlash" : "Eye", size: "small" }), onClick: () => setShowPassword(prevState => !prevState), size: "small", variant: "secondary" }) }), type: showPassword ? "text" : "password" }));
|
|
1100
1177
|
});
|
|
1101
1178
|
PasswordInput.displayName = "PasswordInput";
|
|
1102
1179
|
|
|
@@ -1224,7 +1301,7 @@ const PhoneInput = forwardRef(({ dataTestId, isInvalid, disabled = false, value,
|
|
|
1224
1301
|
onFocus?.(event);
|
|
1225
1302
|
fieldIsFocused.current = true;
|
|
1226
1303
|
}, [onFocus]);
|
|
1227
|
-
return (jsx("div", { className: "grid grid-cols-1 gap-2", "data-testid": dataTestId ? `${dataTestId}-container` : null, children: jsx(BaseInput, { actions: !disableAction && innerValue && innerValue.length > 0 ? (jsx(ActionButton, { dataTestId: dataTestId ? `${dataTestId}-phoneIcon` : undefined, disabled: isInvalid,
|
|
1304
|
+
return (jsx("div", { className: "grid grid-cols-1 gap-2", "data-testid": dataTestId ? `${dataTestId}-container` : null, children: jsx(BaseInput, { actions: !disableAction && innerValue && innerValue.length > 0 ? (jsx(ActionButton, { dataTestId: dataTestId ? `${dataTestId}-phoneIcon` : undefined, disabled: isInvalid, size: fieldSize ?? undefined, type: "PHONE_NUMBER", value: value?.toString() || "" })) : null, dataTestId: dataTestId ? `${dataTestId}-phoneNumberInput` : undefined, disabled: disabled, fieldSize: fieldSize, id: "phoneInput-number", isInvalid: isInvalid, name: name, onBlur: handleBlur, onChange: handleChange, onFocus: handleFocus, prefix: (countryCode && countryCodeToFlagEmoji(countryCode)) || undefined, readOnly: readOnly, ref: ref, type: "tel", value: innerValue, ...rest }) }));
|
|
1228
1305
|
});
|
|
1229
1306
|
PhoneInput.displayName = "PhoneInput";
|
|
1230
1307
|
|
|
@@ -1724,8 +1801,15 @@ const cvaSelect = cvaMerge([
|
|
|
1724
1801
|
"hover:bg-slate-50",
|
|
1725
1802
|
"bg-white",
|
|
1726
1803
|
"transition",
|
|
1804
|
+
"text-sm",
|
|
1805
|
+
"min-h-0",
|
|
1727
1806
|
], {
|
|
1728
1807
|
variants: {
|
|
1808
|
+
fieldSize: {
|
|
1809
|
+
small: ["h-7", "text-xs"],
|
|
1810
|
+
medium: ["h-8"],
|
|
1811
|
+
large: ["h-10"],
|
|
1812
|
+
},
|
|
1729
1813
|
invalid: {
|
|
1730
1814
|
true: "border border-red-600 text-red-600 hover:border-red-600",
|
|
1731
1815
|
false: "",
|
|
@@ -1810,8 +1894,8 @@ const cvaSelectMenu = cvaMerge(["relative", "p-1", "grid", "gap-1"]);
|
|
|
1810
1894
|
* @param {SelectMenuItemProps} props - The props for the SingleSelectMenuItem
|
|
1811
1895
|
* @returns {JSX.Element} SingleSelectMenuItem
|
|
1812
1896
|
*/
|
|
1813
|
-
const SingleSelectMenuItem = ({ label, icon, onClick, selected, dataTestId, disabled, optionLabelDescription, }) => {
|
|
1814
|
-
return (jsx(MenuItem, { dataTestId: dataTestId, disabled: disabled, label: label, onClick: onClick, optionLabelDescription: optionLabelDescription, prefix: icon, selected: selected, suffix: selected ? jsx(Icon, { className: "block text-blue-600", name: "Check", size: "medium" }) : undefined }));
|
|
1897
|
+
const SingleSelectMenuItem = ({ label, icon, onClick, selected, dataTestId, disabled, optionLabelDescription, fieldSize, }) => {
|
|
1898
|
+
return (jsx(MenuItem, { dataTestId: dataTestId, disabled: disabled, fieldSize: fieldSize, label: label, onClick: onClick, optionLabelDescription: optionLabelDescription, prefix: icon, selected: selected, suffix: selected ? jsx(Icon, { className: "block text-blue-600", name: "Check", size: "medium" }) : undefined }));
|
|
1815
1899
|
};
|
|
1816
1900
|
/**
|
|
1817
1901
|
* A multi select menu item is a basic wrapper around Menu item designed to be used as a multi value render in Select list
|
|
@@ -1819,8 +1903,8 @@ const SingleSelectMenuItem = ({ label, icon, onClick, selected, dataTestId, disa
|
|
|
1819
1903
|
* @param {SelectMenuItemProps} props - The props for the MultiSelectMenuItem
|
|
1820
1904
|
* @returns {JSX.Element} multi select menu item
|
|
1821
1905
|
*/
|
|
1822
|
-
const MultiSelectMenuItem = ({ label, onClick, selected, dataTestId, disabled, optionLabelDescription, }) => {
|
|
1823
|
-
return (jsx(MenuItem, { dataTestId: dataTestId, disabled: disabled, label: label, onClick: e => {
|
|
1906
|
+
const MultiSelectMenuItem = ({ label, onClick, selected, dataTestId, disabled, optionLabelDescription, fieldSize, }) => {
|
|
1907
|
+
return (jsx(MenuItem, { dataTestId: dataTestId, disabled: disabled, fieldSize: fieldSize, label: label, onClick: e => {
|
|
1824
1908
|
e.stopPropagation();
|
|
1825
1909
|
onClick && onClick(e);
|
|
1826
1910
|
}, optionLabelDescription: optionLabelDescription, prefix: jsx(Checkbox, { checked: selected, disabled: disabled, onChange: () => null, onClick: e => {
|
|
@@ -1920,7 +2004,7 @@ const TagsContainer = ({ items, width = "100%", itemsGap = 5, postFix, disabled
|
|
|
1920
2004
|
* @param {JSX.Element} prefix a prefix element
|
|
1921
2005
|
* @returns {Partial<SelectComponents<Option, boolean, GroupBase<Option>>> | undefined} components object to override react-select default components
|
|
1922
2006
|
*/
|
|
1923
|
-
const useCustomComponents = ({ componentsProps, disabled, readOnly, refMenuIsEnabled, dataTestId, maxSelectedDisplayCount, dropdownIcon, prefix, hasError, getOptionLabelDescription, }) => {
|
|
2007
|
+
const useCustomComponents = ({ componentsProps, disabled, readOnly, refMenuIsEnabled, dataTestId, maxSelectedDisplayCount, dropdownIcon, prefix, hasError, fieldSize, getOptionLabelDescription, }) => {
|
|
1924
2008
|
const [t] = useTranslation();
|
|
1925
2009
|
// perhaps it should not be wrap in memo (causing some issues with opening and closing on mobiles)
|
|
1926
2010
|
const customComponents = useMemo(() => {
|
|
@@ -2020,7 +2104,7 @@ const useCustomComponents = ({ componentsProps, disabled, readOnly, refMenuIsEna
|
|
|
2020
2104
|
...props.innerProps,
|
|
2021
2105
|
role: "option",
|
|
2022
2106
|
onClick: () => { },
|
|
2023
|
-
}, children: props.isMulti ? (jsx(MultiSelectMenuItem, { ...componentProps, dataTestId: typeof props.label === "string" ? props.label : undefined, disabled: disabled, optionLabelDescription: getOptionLabelDescription?.(props.data) })) : (jsx(SingleSelectMenuItem, { ...componentProps, dataTestId: typeof props.label === "string" ? props.label : undefined, disabled: disabled || props.isDisabled, optionLabelDescription: getOptionLabelDescription?.(props.data) })) }));
|
|
2107
|
+
}, children: props.isMulti ? (jsx(MultiSelectMenuItem, { ...componentProps, dataTestId: typeof props.label === "string" ? props.label : undefined, disabled: disabled, fieldSize: fieldSize, optionLabelDescription: getOptionLabelDescription?.(props.data) })) : (jsx(SingleSelectMenuItem, { ...componentProps, dataTestId: typeof props.label === "string" ? props.label : undefined, disabled: disabled || props.isDisabled, fieldSize: fieldSize, optionLabelDescription: getOptionLabelDescription?.(props.data) })) }));
|
|
2024
2108
|
},
|
|
2025
2109
|
...componentsProps,
|
|
2026
2110
|
};
|
|
@@ -2038,12 +2122,13 @@ const useCustomComponents = ({ componentsProps, disabled, readOnly, refMenuIsEna
|
|
|
2038
2122
|
* @param {StylesConfig<Option, IsMulti, Group> | undefined} styles a optional object to override styles of react-select
|
|
2039
2123
|
* @returns {StylesConfig<Option, boolean>} styles to override in select
|
|
2040
2124
|
*/
|
|
2041
|
-
const useCustomStyles = ({ refContainer, refPrefix, maxSelectedDisplayCount, styles, disabled, }) => {
|
|
2125
|
+
const useCustomStyles = ({ refContainer, refPrefix, maxSelectedDisplayCount, styles, disabled, fieldSize, }) => {
|
|
2042
2126
|
const customStyles = React.useMemo(() => {
|
|
2043
2127
|
return {
|
|
2044
2128
|
control: base => {
|
|
2045
2129
|
return {
|
|
2046
2130
|
...base,
|
|
2131
|
+
minHeight: fieldSize === "small" ? "28px" : fieldSize === "large" ? "40px" : "32px",
|
|
2047
2132
|
borderRadius: "var(--border-radius-lg)",
|
|
2048
2133
|
backgroundColor: "",
|
|
2049
2134
|
};
|
|
@@ -2106,6 +2191,7 @@ const useCustomStyles = ({ refContainer, refPrefix, maxSelectedDisplayCount, sty
|
|
|
2106
2191
|
valueContainer: base => {
|
|
2107
2192
|
return {
|
|
2108
2193
|
...base,
|
|
2194
|
+
paddingBlock: 0,
|
|
2109
2195
|
flexWrap: maxSelectedDisplayCount !== undefined ? "wrap" : "nowrap",
|
|
2110
2196
|
gap: "0.25rem",
|
|
2111
2197
|
};
|
|
@@ -2137,7 +2223,7 @@ const useCustomStyles = ({ refContainer, refPrefix, maxSelectedDisplayCount, sty
|
|
|
2137
2223
|
* @param {SelectProps} props - The props for the Select component
|
|
2138
2224
|
* @returns {UseSelectProps} Select component
|
|
2139
2225
|
*/
|
|
2140
|
-
const useSelect = ({ 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, getOptionLabelDescription, ...props }) => {
|
|
2226
|
+
const useSelect = ({ 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, getOptionLabelDescription, fieldSize = "medium", ...props }) => {
|
|
2141
2227
|
const refContainer = React__default.useRef(null);
|
|
2142
2228
|
const refPrefix = React__default.useRef(null);
|
|
2143
2229
|
const { customStyles } = useCustomStyles({
|
|
@@ -2146,6 +2232,7 @@ const useSelect = ({ id, className, dataTestId = "select", prefix, async, dropdo
|
|
|
2146
2232
|
maxSelectedDisplayCount,
|
|
2147
2233
|
styles,
|
|
2148
2234
|
disabled: Boolean(disabled),
|
|
2235
|
+
fieldSize,
|
|
2149
2236
|
});
|
|
2150
2237
|
const [menuIsOpen, setMenuIsOpen] = React__default.useState(props.menuIsOpen ?? false);
|
|
2151
2238
|
const refMenuIsEnabled = React__default.useRef(true);
|
|
@@ -2159,6 +2246,7 @@ const useSelect = ({ id, className, dataTestId = "select", prefix, async, dropdo
|
|
|
2159
2246
|
dropdownIcon,
|
|
2160
2247
|
prefix,
|
|
2161
2248
|
hasError,
|
|
2249
|
+
fieldSize,
|
|
2162
2250
|
getOptionLabelDescription,
|
|
2163
2251
|
});
|
|
2164
2252
|
const menuPlacement = "auto";
|
|
@@ -2252,7 +2340,7 @@ const CreatableSelect = (props) => {
|
|
|
2252
2340
|
value,
|
|
2253
2341
|
]);
|
|
2254
2342
|
const renderAsDisabled = Boolean(props.disabled) || props.readOnly;
|
|
2255
|
-
return (jsxs("div", { className: cvaSelect({ invalid: hasError, disabled: renderAsDisabled, className: props.className }), "data-testid": dataTestId, ref: refContainer, children: [prefix !== undefined ? (jsx("div", { className: cvaSelectPrefixSuffix({ kind: "prefix" }), "data-testid": dataTestId ? `${dataTestId}-prefix` : null, ref: refPrefix, children: prefix })) : null, async ? (jsx(ReactAsyncCreatableSelect, { ...props, ...reactCreatableSelectProps, ...async, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, placeholder: renderAsDisabled ? null : props.placeholder })) : (jsx(ReactCreatableSelect, { ...props, ...reactCreatableSelectProps, hideSelectedOptions: false, isMulti: isMulti, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, options: options, placeholder: renderAsDisabled ? null : props.placeholder })), typeof props.disabled === "object" ? (jsx("div", { className: cvaSelectPrefixSuffix({ kind: "suffix" }), "data-testid": dataTestId ? `${dataTestId}-locked` : null, children: jsx(
|
|
2343
|
+
return (jsxs("div", { className: cvaSelect({ invalid: hasError, disabled: renderAsDisabled, className: props.className }), "data-testid": dataTestId, ref: refContainer, children: [prefix !== undefined ? (jsx("div", { className: cvaSelectPrefixSuffix({ kind: "prefix" }), "data-testid": dataTestId ? `${dataTestId}-prefix` : null, ref: refPrefix, children: prefix })) : null, async ? (jsx(ReactAsyncCreatableSelect, { ...props, ...reactCreatableSelectProps, ...async, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, placeholder: renderAsDisabled ? null : props.placeholder })) : (jsx(ReactCreatableSelect, { ...props, ...reactCreatableSelectProps, hideSelectedOptions: false, isMulti: isMulti, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, options: options, placeholder: renderAsDisabled ? null : props.placeholder })), typeof props.disabled === "object" ? (jsx("div", { className: cvaSelectPrefixSuffix({ kind: "suffix" }), "data-testid": dataTestId ? `${dataTestId}-locked` : null, children: jsx(InputLockReasonTooltip, { ...props.disabled }) })) : null] }));
|
|
2256
2344
|
};
|
|
2257
2345
|
CreatableSelect.displayName = "CreatableSelect";
|
|
2258
2346
|
|
|
@@ -2263,7 +2351,7 @@ CreatableSelect.displayName = "CreatableSelect";
|
|
|
2263
2351
|
* @returns {JSX.Element} Select component
|
|
2264
2352
|
*/
|
|
2265
2353
|
const Select = (props) => {
|
|
2266
|
-
const { id, dataTestId = "select", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, menuPosition = "absolute", value, options, onChange, isLoading, classNamePrefix = "select", onMenuScrollToBottom, onInputChange, isSearchable, isClearable = false, readOnly, openMenuOnClick = !disabled, openMenuOnFocus = !disabled, hideSelectedOptions = false, } = props;
|
|
2354
|
+
const { id, dataTestId = "select", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, menuPosition = "absolute", value, options, onChange, isLoading, classNamePrefix = "select", onMenuScrollToBottom, onInputChange, isSearchable, isClearable = false, readOnly, fieldSize = "medium", openMenuOnClick = !disabled, openMenuOnFocus = !disabled, hideSelectedOptions = false, } = props;
|
|
2267
2355
|
const { refContainer, refPrefix, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler, } = useSelect(props);
|
|
2268
2356
|
const reactSelectProps = useMemo(() => ({
|
|
2269
2357
|
value,
|
|
@@ -2322,7 +2410,12 @@ const Select = (props) => {
|
|
|
2322
2410
|
value,
|
|
2323
2411
|
]);
|
|
2324
2412
|
const renderAsDisabled = Boolean(props.disabled) || props.readOnly;
|
|
2325
|
-
return (jsxs("div", { className: cvaSelect({
|
|
2413
|
+
return (jsxs("div", { className: cvaSelect({
|
|
2414
|
+
invalid: hasError,
|
|
2415
|
+
fieldSize: fieldSize,
|
|
2416
|
+
disabled: renderAsDisabled,
|
|
2417
|
+
className: props.className,
|
|
2418
|
+
}), "data-testid": dataTestId, ref: refContainer, children: [prefix !== undefined ? (jsx("div", { className: cvaSelectPrefixSuffix({ kind: "prefix" }), "data-testid": dataTestId ? `${dataTestId}-prefix` : null, ref: refPrefix, children: prefix })) : null, async ? (jsx(ReactAsyncSelect, { ...props, ...reactSelectProps, ...async, menuPosition: menuPosition, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, placeholder: renderAsDisabled ? null : props.placeholder })) : (jsx(ReactSelect, { ...props, ...reactSelectProps, isMulti: isMulti, menuPosition: menuPosition, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, options: options, placeholder: renderAsDisabled ? null : props.placeholder })), typeof props.disabled === "object" ? (jsx("div", { className: cvaSelectPrefixSuffix({ kind: "suffix" }), "data-testid": dataTestId ? `${dataTestId}-locked` : null, children: jsx(InputLockReasonTooltip, { ...props.disabled }) })) : null] }));
|
|
2326
2419
|
};
|
|
2327
2420
|
Select.displayName = "Select";
|
|
2328
2421
|
|
|
@@ -2483,12 +2576,8 @@ TextAreaField.displayName = "TextAreaField";
|
|
|
2483
2576
|
|
|
2484
2577
|
/**
|
|
2485
2578
|
* Text fields enable the user to interact with and input content and data. This component can be used for long and short form entries. Allow the size of the text input box to reflect the length of the content you expect the user to enter.
|
|
2486
|
-
*
|
|
2487
|
-
* _**Do use** when the user has to input or edit simple text based information, such as metadata._
|
|
2488
|
-
*
|
|
2489
|
-
* _**Do not use** to confirm user actions, such as deleting. Use a checkbox for such flows._
|
|
2490
2579
|
*/
|
|
2491
|
-
const TextField = React.forwardRef(({ id, label, tip, helpText, helpAddon, errorMessage, isInvalid, maxLength, onChange, className, value, dataTestId, ...rest }, ref) => {
|
|
2580
|
+
const TextField = React.forwardRef(({ id, label, tip, helpText, helpAddon, errorMessage, isInvalid, maxLength, onChange, className, value, dataTestId, isWarning, ...rest }, ref) => {
|
|
2492
2581
|
const [valueLength, setValueLength] = React.useState(value ? `${value}`.length : 0);
|
|
2493
2582
|
const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
|
|
2494
2583
|
const htmlFor = id ? id : "textField-" + uuidv4();
|
|
@@ -2499,7 +2588,7 @@ const TextField = React.forwardRef(({ id, label, tip, helpText, helpAddon, error
|
|
|
2499
2588
|
}
|
|
2500
2589
|
}, [onChange]);
|
|
2501
2590
|
return (jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon ||
|
|
2502
|
-
(typeof maxLength === "number" && jsx(TextLengthIndicator, { length: valueLength, maxLength: maxLength })), helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlFor, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsx(TextInput, { "aria-labelledby": htmlFor + "-label", id: htmlFor, isInvalid: renderAsInvalid, maxLength: maxLength, ref: ref, value: value, ...rest, className: className, dataTestId: dataTestId, onChange: handleChange }) }));
|
|
2591
|
+
(typeof maxLength === "number" && jsx(TextLengthIndicator, { length: valueLength, maxLength: maxLength })), helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlFor, isInvalid: renderAsInvalid, isWarning: isWarning, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsx(TextInput, { "aria-labelledby": htmlFor + "-label", id: htmlFor, isInvalid: renderAsInvalid, isWarning: isWarning, maxLength: maxLength, ref: ref, value: value, ...rest, className: className, dataTestId: dataTestId, onChange: handleChange }) }));
|
|
2503
2592
|
});
|
|
2504
2593
|
TextField.displayName = "TextField";
|
|
2505
2594
|
|
|
@@ -2618,20 +2707,19 @@ const cvaUploadInputField = cvaMerge([
|
|
|
2618
2707
|
"dark:text-gray-400",
|
|
2619
2708
|
"self-center",
|
|
2620
2709
|
]);
|
|
2621
|
-
const cvaUploadInputAddonBefore = cvaMerge(["block", "truncate", "w-28", "pt-2"]);
|
|
2622
2710
|
|
|
2623
2711
|
/**
|
|
2624
2712
|
* A thin wrapper around the `BaseInput` component for upload input fields.
|
|
2625
2713
|
*
|
|
2626
2714
|
* NOTE: If shown with a label, please use the `UploadField` component instead.
|
|
2627
2715
|
*/
|
|
2628
|
-
const UploadInput = forwardRef(({ disabled, acceptedTypes, nonInteractive, uploadLabel, multipleFiles, ...rest }, ref) => (jsx(
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2716
|
+
const UploadInput = forwardRef(({ disabled, acceptedTypes, nonInteractive, uploadLabel, multipleFiles, ...rest }, ref) => (jsx(BaseInput, { accept: acceptedTypes, addonBefore: uploadLabel, disabled: disabled, inputClassName: cvaUploadInputField(), multiple: multipleFiles, nonInteractive: nonInteractive, onClick: event => {
|
|
2717
|
+
// onClick used to work with nonInteractive option
|
|
2718
|
+
if (nonInteractive) {
|
|
2719
|
+
event.preventDefault();
|
|
2720
|
+
event.stopPropagation();
|
|
2721
|
+
}
|
|
2722
|
+
}, ref: ref, type: "file", ...rest })));
|
|
2635
2723
|
UploadInput.displayName = "UploadInput";
|
|
2636
2724
|
|
|
2637
2725
|
/**
|
|
@@ -2683,7 +2771,7 @@ const validateUrl = (url, required) => {
|
|
|
2683
2771
|
const UrlInput = forwardRef(({ dataTestId, isInvalid, disabled = false, fieldSize = "medium", disableAction = false, value, defaultValue, ...rest }, ref) => {
|
|
2684
2772
|
const [url, setUrl] = useState(value?.toString() || defaultValue?.toString());
|
|
2685
2773
|
const renderAsInvalid = (url && typeof url === "string" && !validateUrlAddress(url)) || isInvalid;
|
|
2686
|
-
return (jsx(BaseInput, { dataTestId: dataTestId ? `${dataTestId}-url-input` : undefined, disabled: disabled, id: "url-input", isInvalid: renderAsInvalid, onChange: e => setUrl(e.target.value), placeholder: rest.placeholder || "https://www.example.com", ref: ref, type: "url", value: url, ...rest, actions: !disableAction && (jsx(ActionButton, { dataTestId: (dataTestId && `${dataTestId}-url-input-Icon`) || "url-input-action-icon", disabled: renderAsInvalid || disableAction,
|
|
2774
|
+
return (jsx(BaseInput, { dataTestId: dataTestId ? `${dataTestId}-url-input` : undefined, disabled: disabled, id: "url-input", isInvalid: renderAsInvalid, onChange: e => setUrl(e.target.value), placeholder: rest.placeholder || "https://www.example.com", ref: ref, type: "url", value: url, ...rest, actions: !disableAction && (jsx(ActionButton, { dataTestId: (dataTestId && `${dataTestId}-url-input-Icon`) || "url-input-action-icon", disabled: renderAsInvalid || Boolean(disabled) || disableAction, size: fieldSize ?? undefined, type: "WEB_ADDRESS", value: url })) }));
|
|
2687
2775
|
});
|
|
2688
2776
|
UrlInput.displayName = "UrlField";
|
|
2689
2777
|
|
|
@@ -2823,4 +2911,4 @@ const useZodValidators = () => {
|
|
|
2823
2911
|
*/
|
|
2824
2912
|
setupLibraryTranslations();
|
|
2825
2913
|
|
|
2826
|
-
export { ActionButton, BaseInput, Checkbox, CheckboxField, ColorField, CreatableSelect, CreatableSelectField, DateField, DateInput, DropZone, DropZoneDefaultLabel, EMAIL_REGEX, EmailField, EmailInput, FormFieldSelectAdapter, FormGroup, Label, MultiSelectMenuItem, NumberField, NumberInput, OptionCard, PasswordField, PasswordInput, PhoneField, PhoneFieldWithController, PhoneInput, RadioGroup, RadioItem, Schedule, ScheduleVariant, Search, Select, SelectField, SingleSelectMenuItem, TextArea, TextAreaField, TextField, TextInput, TimeRange, TimeRangeField, Toggle, UploadField, UploadInput, UrlField, UrlInput, checkIfPhoneNumberHasPlus, countryCodeToFlagEmoji, cvaActionButton, cvaActionContainer, cvaInput,
|
|
2914
|
+
export { ActionButton, BaseInput, Checkbox, CheckboxField, ColorField, CreatableSelect, CreatableSelectField, DateField, DateInput, DropZone, DropZoneDefaultLabel, EMAIL_REGEX, EmailField, EmailInput, FormFieldSelectAdapter, FormGroup, Label, MultiSelectMenuItem, NumberField, NumberInput, OptionCard, PasswordField, PasswordInput, PhoneField, PhoneFieldWithController, PhoneInput, RadioGroup, RadioItem, Schedule, ScheduleVariant, Search, Select, SelectField, SingleSelectMenuItem, TextArea, TextAreaField, TextField, TextInput, TimeRange, TimeRangeField, Toggle, UploadField, UploadInput, UrlField, UrlInput, checkIfPhoneNumberHasPlus, countryCodeToFlagEmoji, cvaActionButton, cvaActionContainer, cvaInput, cvaInputAddon, cvaInputAddonAfter, cvaInputAddonBefore, cvaInputBase, cvaInputBaseDisabled, cvaInputBaseInvalid, cvaInputField, cvaInputPrefix, cvaInputSuffix, cvaSelect, cvaSelectControl, cvaSelectCounter, cvaSelectDynamicTagContainer, cvaSelectIcon, cvaSelectMenu, cvaSelectMenuList, cvaSelectPrefixSuffix, cvaSelectXIcon, getCountryAbbreviation, getPhoneNumberWithPlus, isInvalidCountryCode, isInvalidPhoneNumber, isValidHEXColor, parseSchedule, phoneErrorMessage, serializeSchedule, useCustomComponents, useGetPhoneValidationRules, usePhoneInput, useZodValidators, validateEmailAddress, validatePhoneNumber, weekDay };
|