@trackunit/react-form-components 1.3.136 → 1.3.138
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.cjs.js
CHANGED
|
@@ -6,7 +6,7 @@ var reactComponents = require('@trackunit/react-components');
|
|
|
6
6
|
var usehooksTs = require('usehooks-ts');
|
|
7
7
|
var cssClassVarianceUtilities = require('@trackunit/css-class-variance-utilities');
|
|
8
8
|
var uiDesignTokens = require('@trackunit/ui-design-tokens');
|
|
9
|
-
var
|
|
9
|
+
var react = require('react');
|
|
10
10
|
var stringTs = require('string-ts');
|
|
11
11
|
var sharedUtils = require('@trackunit/shared-utils');
|
|
12
12
|
var polyfill = require('@js-temporal/polyfill');
|
|
@@ -19,25 +19,6 @@ var ReactAsyncSelect = require('react-select/async');
|
|
|
19
19
|
var tailwindMerge = require('tailwind-merge');
|
|
20
20
|
var zod = require('zod');
|
|
21
21
|
|
|
22
|
-
function _interopNamespaceDefault(e) {
|
|
23
|
-
var n = Object.create(null);
|
|
24
|
-
if (e) {
|
|
25
|
-
Object.keys(e).forEach(function (k) {
|
|
26
|
-
if (k !== 'default') {
|
|
27
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
28
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
29
|
-
enumerable: true,
|
|
30
|
-
get: function () { return e[k]; }
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
n.default = e;
|
|
36
|
-
return Object.freeze(n);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
|
40
|
-
|
|
41
22
|
var defaultTranslations = {
|
|
42
23
|
"baseInput.copyAction.toolTip": "Copy value",
|
|
43
24
|
"clearIndicator.icon.tooltip.clearAll": "Clear all",
|
|
@@ -396,7 +377,7 @@ const LockReasonRenderer = ({ lockReason, dataTestId, }) => {
|
|
|
396
377
|
};
|
|
397
378
|
|
|
398
379
|
// Renders the prefix element or falls back to a default prefix for certain types
|
|
399
|
-
const PrefixRenderer =
|
|
380
|
+
const PrefixRenderer = react.forwardRef(({ prefix, type, dataTestId, disabled }, ref) => {
|
|
400
381
|
// Default icons for specific input types
|
|
401
382
|
const defaultPrefixMap = {
|
|
402
383
|
email: jsxRuntime.jsx(reactComponents.Icon, { name: "AtSymbol", size: "small" }),
|
|
@@ -442,13 +423,13 @@ const BaseInput = ({ className, isInvalid, dataTestId, prefix, suffix, addonBefo
|
|
|
442
423
|
// Derive final flags
|
|
443
424
|
const renderAsDisabled = Boolean(rest.disabled);
|
|
444
425
|
const renderAsReadonly = Boolean(rest.readOnly);
|
|
445
|
-
const beforeContainerRef =
|
|
426
|
+
const beforeContainerRef = react.useRef(null);
|
|
446
427
|
const { width: beforeContainerWidth } = reactComponents.useGeometry(beforeContainerRef);
|
|
447
|
-
const afterContainerRef =
|
|
428
|
+
const afterContainerRef = react.useRef(null);
|
|
448
429
|
const { width: afterContainerWidth } = reactComponents.useGeometry(afterContainerRef);
|
|
449
430
|
// Keep a reference to the input element
|
|
450
|
-
const innerRef =
|
|
451
|
-
|
|
431
|
+
const innerRef = react.useRef(null);
|
|
432
|
+
react.useImperativeHandle(ref, () => innerRef.current, []);
|
|
452
433
|
return (jsxRuntime.jsxs("div", { className: cvaInput$1({
|
|
453
434
|
disabled: renderAsDisabled,
|
|
454
435
|
invalid: isInvalid,
|
|
@@ -661,7 +642,7 @@ const IndeterminateIcon = ({ className }) => (jsxRuntime.jsx("svg", { className:
|
|
|
661
642
|
*/
|
|
662
643
|
const Checkbox = ({ className, dataTestId = "checkbox", onChange, checked = false, disabled = false, isInvalid = false, readOnly, indeterminate = false, suffix, label, tabIndex = 0, stopPropagation, ref, ...rest }) => {
|
|
663
644
|
const icon = indeterminate ? (jsxRuntime.jsx(IndeterminateIcon, { className: cvaCheckboxIcon() })) : (checked && jsxRuntime.jsx(CheckIcon, { className: cvaCheckboxIcon() }));
|
|
664
|
-
const internalRef =
|
|
645
|
+
const internalRef = react.useRef(null);
|
|
665
646
|
const { isTextTruncated: isLabelCutOff, ref: labelRef } = reactComponents.useIsTextTruncated();
|
|
666
647
|
const isReadonly = disabled || readOnly;
|
|
667
648
|
const onKeyPress = e => {
|
|
@@ -728,7 +709,7 @@ const cvaHelpAddon = cssClassVarianceUtilities.cvaMerge(["ml-auto"]);
|
|
|
728
709
|
*/
|
|
729
710
|
const FormGroup = ({ isInvalid, isWarning, helpText, helpAddon, tip, className, dataTestId, label, htmlFor, children, required = false, }) => {
|
|
730
711
|
const [t] = useTranslation();
|
|
731
|
-
const validationStateIcon =
|
|
712
|
+
const validationStateIcon = react.useMemo(() => {
|
|
732
713
|
const color = isInvalid ? "danger" : isWarning ? "warning" : null;
|
|
733
714
|
return color ? jsxRuntime.jsx(reactComponents.Icon, { color: color, name: "ExclamationTriangle", size: "small" }) : null;
|
|
734
715
|
}, [isInvalid, isWarning]);
|
|
@@ -820,26 +801,26 @@ const isValidHEXColor = (value) => {
|
|
|
820
801
|
* ColorField validates that user enters a valid color address.
|
|
821
802
|
*
|
|
822
803
|
*/
|
|
823
|
-
const ColorField =
|
|
804
|
+
const ColorField = react.forwardRef(({ label, id, tip, helpText, errorMessage, helpAddon, className, defaultValue, dataTestId, value: propValue, onChange, isInvalid = false, onBlur, fieldSize = "medium", ...rest }, ref) => {
|
|
824
805
|
const renderAsDisabled = Boolean(rest.disabled);
|
|
825
806
|
const renderAsReadonly = Boolean(rest.readOnly);
|
|
826
|
-
const htmlForId =
|
|
827
|
-
const innerRef =
|
|
828
|
-
|
|
807
|
+
const htmlForId = react.useMemo(() => (id ? id : "colorField-" + sharedUtils.uuidv4()), [id]);
|
|
808
|
+
const innerRef = react.useRef(null);
|
|
809
|
+
react.useImperativeHandle(ref, () => innerRef.current, []);
|
|
829
810
|
const [t] = useTranslation();
|
|
830
811
|
// Internal state for color value
|
|
831
|
-
const [innerValue, setInnerValue] =
|
|
832
|
-
const [renderAsInvalid, setRenderAsInvalid] =
|
|
833
|
-
const errorType =
|
|
834
|
-
const error =
|
|
835
|
-
const handleInputChange =
|
|
812
|
+
const [innerValue, setInnerValue] = react.useState(propValue || defaultValue || "");
|
|
813
|
+
const [renderAsInvalid, setRenderAsInvalid] = react.useState(!!errorMessage || (innerValue && typeof innerValue === "string" && !isValidHEXColor(innerValue)) || isInvalid);
|
|
814
|
+
const errorType = react.useMemo(() => validateColorCode(innerValue, rest.required), [rest.required, innerValue]);
|
|
815
|
+
const error = react.useMemo(() => (errorType ? t(`colorField.error.${errorType}`) : errorMessage), [errorType, errorMessage, t]);
|
|
816
|
+
const handleInputChange = react.useCallback((event) => {
|
|
836
817
|
const newValue = event.target.value;
|
|
837
818
|
setInnerValue(newValue);
|
|
838
819
|
if (onChange) {
|
|
839
820
|
onChange(event);
|
|
840
821
|
}
|
|
841
822
|
}, [onChange]);
|
|
842
|
-
const handleBlur =
|
|
823
|
+
const handleBlur = react.useCallback(event => {
|
|
843
824
|
const newValue = event.target.value;
|
|
844
825
|
setInnerValue(newValue);
|
|
845
826
|
setRenderAsInvalid(!!errorType);
|
|
@@ -954,10 +935,10 @@ const DropZoneDefaultLabel = () => (jsxRuntime.jsx(Trans, { components: {
|
|
|
954
935
|
* @returns {ReactElement} DropZone component
|
|
955
936
|
*/
|
|
956
937
|
const DropZone = ({ className, dataTestId, filesSelected, label = jsxRuntime.jsx(DropZoneDefaultLabel, {}), size = "large", isInvalid = false, disabled = false, accept, multiple = false, ...rest }) => {
|
|
957
|
-
const [dragActive, setDragActive] =
|
|
958
|
-
const [fileDropped, setFileDropped] =
|
|
938
|
+
const [dragActive, setDragActive] = react.useState(false);
|
|
939
|
+
const [fileDropped, setFileDropped] = react.useState(false);
|
|
959
940
|
const [t] = useTranslation();
|
|
960
|
-
const inputLabelRef =
|
|
941
|
+
const inputLabelRef = react.useRef(null);
|
|
961
942
|
// function that handles drag enter, drag leave and drag over
|
|
962
943
|
const handleDrag = (e) => {
|
|
963
944
|
e.preventDefault();
|
|
@@ -1047,11 +1028,11 @@ const validateEmailId = (emailId, required) => {
|
|
|
1047
1028
|
* For specific input types make sure to use the corresponding input component.
|
|
1048
1029
|
*/
|
|
1049
1030
|
const EmailInput = ({ fieldSize = "medium", disabled = false, dataTestId, isInvalid = false, onChange, disableAction = false, ref, ...rest }) => {
|
|
1050
|
-
const [email, setEmail] =
|
|
1031
|
+
const [email, setEmail] = react.useState("");
|
|
1051
1032
|
const sendEmail = () => {
|
|
1052
1033
|
return window.open(`mailto:${email}`);
|
|
1053
1034
|
};
|
|
1054
|
-
const handleChange =
|
|
1035
|
+
const handleChange = react.useCallback(event => {
|
|
1055
1036
|
const newValue = event.target.value;
|
|
1056
1037
|
onChange?.(event);
|
|
1057
1038
|
setEmail(newValue);
|
|
@@ -1069,19 +1050,19 @@ EmailInput.displayName = "EmailInput";
|
|
|
1069
1050
|
const EmailField = ({ label, id, tip, helpText, errorMessage, helpAddon, className, defaultValue, dataTestId, value, onChange, onBlur, isInvalid = false, ref, ...rest }) => {
|
|
1070
1051
|
const htmlForId = id ? id : "emailField-" + sharedUtils.uuidv4();
|
|
1071
1052
|
const [t] = useTranslation();
|
|
1072
|
-
const [innerValue, setInnerValue] =
|
|
1053
|
+
const [innerValue, setInnerValue] = react.useState(() => {
|
|
1073
1054
|
return (value?.toString() || defaultValue?.toString()) ?? "";
|
|
1074
1055
|
});
|
|
1075
|
-
const [renderAsInvalid, setRenderAsInvalid] =
|
|
1076
|
-
const errorType =
|
|
1077
|
-
const error =
|
|
1078
|
-
const handleBlur =
|
|
1056
|
+
const [renderAsInvalid, setRenderAsInvalid] = react.useState(!!errorMessage || (value && isString(value) && !validateEmailAddress(value)) || isInvalid);
|
|
1057
|
+
const errorType = react.useMemo(() => validateEmailId(innerValue ?? "", rest.required), [rest.required, innerValue]);
|
|
1058
|
+
const error = react.useMemo(() => (errorType ? t(`emailField.error.${errorType}`) : errorMessage), [errorType, errorMessage, t]);
|
|
1059
|
+
const handleBlur = react.useCallback(event => {
|
|
1079
1060
|
const newValue = event.target.value;
|
|
1080
1061
|
setInnerValue(newValue);
|
|
1081
1062
|
setRenderAsInvalid(!!errorType);
|
|
1082
1063
|
onBlur?.(event);
|
|
1083
1064
|
}, [errorType, onBlur]);
|
|
1084
|
-
const handleChange =
|
|
1065
|
+
const handleChange = react.useCallback((event) => {
|
|
1085
1066
|
setInnerValue(event.target.value);
|
|
1086
1067
|
if (onChange) {
|
|
1087
1068
|
onChange(event);
|
|
@@ -1161,13 +1142,13 @@ NumberInput.displayName = "NumberInput";
|
|
|
1161
1142
|
const NumberField = ({ label, id, tip, helpText, errorMessage, helpAddon, isInvalid, maxLength, className, value, dataTestId, defaultValue, onBlur, onChange, ref, ...rest }) => {
|
|
1162
1143
|
const htmlForId = id ? id : "numberField-" + sharedUtils.uuidv4();
|
|
1163
1144
|
const [t] = useTranslation();
|
|
1164
|
-
const [innerValue, setInnerValue] =
|
|
1145
|
+
const [innerValue, setInnerValue] = react.useState(() => {
|
|
1165
1146
|
return Number(value?.toString()) || Number(defaultValue?.toString());
|
|
1166
1147
|
});
|
|
1167
|
-
const [renderAsInvalid, setRenderAsInvalid] =
|
|
1148
|
+
const [renderAsInvalid, setRenderAsInvalid] = react.useState((isInvalid === undefined ? Boolean(errorMessage) : isInvalid) ||
|
|
1168
1149
|
!!validateNumber(value?.toString(), rest.required, rest.min, rest.max));
|
|
1169
|
-
const errorType =
|
|
1170
|
-
const error =
|
|
1150
|
+
const errorType = react.useMemo(() => validateNumber(innerValue, rest.required, rest.min, rest.max), [innerValue, rest.max, rest.min, rest.required]);
|
|
1151
|
+
const error = react.useMemo(() => {
|
|
1171
1152
|
// for the case when a custom error message is provided
|
|
1172
1153
|
if (errorMessage) {
|
|
1173
1154
|
return errorMessage;
|
|
@@ -1177,12 +1158,12 @@ const NumberField = ({ label, id, tip, helpText, errorMessage, helpAddon, isInva
|
|
|
1177
1158
|
}
|
|
1178
1159
|
return errorMessage;
|
|
1179
1160
|
}, [errorMessage, errorType, rest.max, rest.min, t]);
|
|
1180
|
-
|
|
1161
|
+
react.useEffect(() => {
|
|
1181
1162
|
if (errorMessage) {
|
|
1182
1163
|
setRenderAsInvalid(Boolean(errorMessage));
|
|
1183
1164
|
}
|
|
1184
1165
|
}, [errorMessage]);
|
|
1185
|
-
const handleBlur =
|
|
1166
|
+
const handleBlur = react.useCallback(event => {
|
|
1186
1167
|
const newValue = event.target.value;
|
|
1187
1168
|
setInnerValue(newValue.toString());
|
|
1188
1169
|
// for the case when a custom error message is provided
|
|
@@ -1194,7 +1175,7 @@ const NumberField = ({ label, id, tip, helpText, errorMessage, helpAddon, isInva
|
|
|
1194
1175
|
}
|
|
1195
1176
|
onBlur?.(event);
|
|
1196
1177
|
}, [errorMessage, onBlur, rest.max, rest.min, rest.required]);
|
|
1197
|
-
const handleChange =
|
|
1178
|
+
const handleChange = react.useCallback((event) => {
|
|
1198
1179
|
setInnerValue(event.target.value);
|
|
1199
1180
|
if (onChange) {
|
|
1200
1181
|
onChange(event);
|
|
@@ -1209,12 +1190,11 @@ const cvaOptionCardLabel = cssClassVarianceUtilities.cvaMerge([
|
|
|
1209
1190
|
"transition",
|
|
1210
1191
|
"bg-white",
|
|
1211
1192
|
"outline",
|
|
1212
|
-
"outline-
|
|
1193
|
+
"outline-1",
|
|
1213
1194
|
"outline-slate-300",
|
|
1214
1195
|
"hover:bg-slate-100",
|
|
1215
1196
|
"focus:bg-slate-200",
|
|
1216
1197
|
"active:bg-slate-200",
|
|
1217
|
-
"disabled:bg-slate-200",
|
|
1218
1198
|
"peer-checked:bg-primary-50",
|
|
1219
1199
|
"peer-checked:outline-primary-600",
|
|
1220
1200
|
"peer-checked:outline-2",
|
|
@@ -1224,10 +1204,11 @@ const cvaOptionCardLabel = cssClassVarianceUtilities.cvaMerge([
|
|
|
1224
1204
|
"items-center",
|
|
1225
1205
|
"text-center",
|
|
1226
1206
|
"rounded-md",
|
|
1207
|
+
"relative"
|
|
1227
1208
|
], {
|
|
1228
1209
|
variants: {
|
|
1229
1210
|
disabled: {
|
|
1230
|
-
true: ["cursor-not-allowed"],
|
|
1211
|
+
true: ["cursor-not-allowed", "bg-slate-100"],
|
|
1231
1212
|
false: ["cursor-pointer"],
|
|
1232
1213
|
},
|
|
1233
1214
|
layout: {
|
|
@@ -1250,27 +1231,63 @@ const cvaOptionCardLabel = cssClassVarianceUtilities.cvaMerge([
|
|
|
1250
1231
|
});
|
|
1251
1232
|
const cvaOptionCardContent = cssClassVarianceUtilities.cvaMerge(["flex", "flex-col", "items-center"]);
|
|
1252
1233
|
const cvaOptionCardContainer = cssClassVarianceUtilities.cvaMerge(["contents"]);
|
|
1253
|
-
const
|
|
1254
|
-
"hover:text-slate-700",
|
|
1255
|
-
"focus:text-slate-800",
|
|
1256
|
-
"active:text-slate-800",
|
|
1257
|
-
"disabled:text-slate-400",
|
|
1258
|
-
"text-sm",
|
|
1234
|
+
const cvaOptionCardTitle = cssClassVarianceUtilities.cvaMerge([
|
|
1259
1235
|
"text-slate-600",
|
|
1260
1236
|
"whitespace-nowrap",
|
|
1261
|
-
]
|
|
1237
|
+
], {
|
|
1238
|
+
variants: {
|
|
1239
|
+
layout: {
|
|
1240
|
+
default: ["text-lg"],
|
|
1241
|
+
compact: ["text-sm"]
|
|
1242
|
+
},
|
|
1243
|
+
disabled: {
|
|
1244
|
+
true: ["text-slate-400"],
|
|
1245
|
+
false: ["focus:text-slate-800", "active:text-slate-800"]
|
|
1246
|
+
},
|
|
1247
|
+
},
|
|
1248
|
+
});
|
|
1249
|
+
const cvaOptionCardText = cssClassVarianceUtilities.cvaMerge([
|
|
1250
|
+
"text-slate-600",
|
|
1251
|
+
"text-sm"
|
|
1252
|
+
], {
|
|
1253
|
+
variants: {
|
|
1254
|
+
type: {
|
|
1255
|
+
subheading: ["font-medium"],
|
|
1256
|
+
description: ["font-normal"]
|
|
1257
|
+
},
|
|
1258
|
+
disabled: {
|
|
1259
|
+
true: ["text-slate-400"],
|
|
1260
|
+
false: ["focus:text-slate-800", "active:text-slate-800"]
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
});
|
|
1262
1264
|
const cvaInput = cssClassVarianceUtilities.cvaMerge(["peer", "absolute", "h-0", "w-0", "opacity-0"]);
|
|
1263
|
-
const cvaCustomImage = cssClassVarianceUtilities.cvaMerge(["text-
|
|
1265
|
+
const cvaCustomImage = cssClassVarianceUtilities.cvaMerge(["text-slate-400"], {
|
|
1266
|
+
variants: {
|
|
1267
|
+
disabled: {
|
|
1268
|
+
true: ["!text-slate-400"],
|
|
1269
|
+
false: [""]
|
|
1270
|
+
},
|
|
1271
|
+
},
|
|
1272
|
+
});
|
|
1273
|
+
const cvaTag = cssClassVarianceUtilities.cvaMerge([], {
|
|
1274
|
+
variants: {
|
|
1275
|
+
layout: {
|
|
1276
|
+
default: ["absolute", "top-2", "right-2"],
|
|
1277
|
+
compact: [],
|
|
1278
|
+
},
|
|
1279
|
+
},
|
|
1280
|
+
});
|
|
1264
1281
|
|
|
1265
1282
|
/**
|
|
1266
1283
|
* A card version of a radio button that includes an icon, headings and a description.
|
|
1267
1284
|
*/
|
|
1268
|
-
const OptionCard = ({ icon, heading, subheading, description, disabled, id, value, className, contentClassName, dataTestId, customImage, layout = "default", ref, ...rest }) => {
|
|
1285
|
+
const OptionCard = ({ icon, heading, subheading, description, disabled, id, value, className, contentClassName, dataTestId, customImage, layout = "default", ref, tagProps, ...rest }) => {
|
|
1269
1286
|
const htmlForId = id ?? "option-card-" + sharedUtils.uuidv4();
|
|
1270
|
-
const subContent =
|
|
1287
|
+
const subContent = react.useMemo(() => (jsxRuntime.jsxs("div", { className: cvaOptionCardContent({ className: contentClassName }), children: [subheading ? (jsxRuntime.jsx(reactComponents.Text, { align: "center", className: cvaOptionCardText({ type: "subheading", disabled }), children: subheading })) : null, description ? (jsxRuntime.jsx(reactComponents.Text, { align: "center", className: cvaOptionCardText({ type: "description", disabled }), children: description })) : null] })), [subheading, description, contentClassName, disabled]);
|
|
1271
1288
|
return (jsxRuntime.jsx(reactComponents.Tooltip, { className: "w-fit", disabled: layout !== "compact" || (!subheading && !description), label: subContent, mode: "light", placement: "top", children: jsxRuntime.jsxs("div", { className: cvaOptionCardContainer(), "data-testid": dataTestId, children: [jsxRuntime.jsx("input", { className: cvaInput(), "data-testid": `${dataTestId}-option-card`, disabled: disabled, id: htmlForId, ref: ref, type: "radio", value: value, ...rest }), jsxRuntime.jsxs("label", { className: cvaOptionCardLabel({ className, disabled, layout }), "data-testid": `${dataTestId}-option-card-label`, htmlFor: htmlForId, children: [disabled && icon && !customImage
|
|
1272
|
-
?
|
|
1273
|
-
: null, disabled && customImage ? jsxRuntime.jsx("img", { alt: "logo", className: customImage.className, src: customImage.src }) : null, !disabled && !customImage && icon, !disabled && customImage ? jsxRuntime.jsx("img", { alt: "logo", className: customImage.className, src: customImage.src }) : null, heading ? (layout === "default" ? (jsxRuntime.jsx(reactComponents.Heading, { subtle: disabled, variant: "secondary", children: heading })) : (jsxRuntime.jsx(reactComponents.Text, { align: "center", className:
|
|
1289
|
+
? react.cloneElement(icon, { className: cvaCustomImage({ disabled, className: icon.props.className }) })
|
|
1290
|
+
: null, disabled && customImage ? jsxRuntime.jsx("img", { alt: "logo", className: customImage.className, src: customImage.src }) : null, !disabled && !customImage && icon, !disabled && customImage ? jsxRuntime.jsx("img", { alt: "logo", className: customImage.className, src: customImage.src }) : null, heading ? (layout === "default" ? (jsxRuntime.jsx(reactComponents.Heading, { className: cvaOptionCardTitle({ disabled, layout }), subtle: disabled, variant: "secondary", children: heading })) : (jsxRuntime.jsx(reactComponents.Text, { align: "center", className: cvaOptionCardTitle({ disabled, layout }), subtle: disabled, type: "span", weight: "thick", children: heading }))) : null, layout === "default" && (subheading || description) ? subContent : null, tagProps ? jsxRuntime.jsx(reactComponents.Tag, { className: cvaTag({ className: tagProps.className, layout }), ...tagProps }) : null] })] }) }));
|
|
1274
1291
|
};
|
|
1275
1292
|
OptionCard.displayName = "OptionCard";
|
|
1276
1293
|
|
|
@@ -1280,7 +1297,7 @@ OptionCard.displayName = "OptionCard";
|
|
|
1280
1297
|
* NOTE: If shown with a label, please use the `PasswordField` component instead.
|
|
1281
1298
|
*/
|
|
1282
1299
|
const PasswordInput = ({ ref, fieldSize, ...rest }) => {
|
|
1283
|
-
const [showPassword, setShowPassword] =
|
|
1300
|
+
const [showPassword, setShowPassword] = react.useState(false);
|
|
1284
1301
|
return (jsxRuntime.jsx(BaseInput, { ref: ref, ...rest, actions: jsxRuntime.jsx("div", { className: cvaActionContainer({ size: fieldSize }), children: jsxRuntime.jsx(reactComponents.IconButton, { className: cvaActionButton({ size: fieldSize }), icon: jsxRuntime.jsx(reactComponents.Icon, { name: showPassword ? "EyeSlash" : "Eye", size: "small" }), onClick: () => setShowPassword(prevState => !prevState), size: "small", variant: "secondary" }) }), type: showPassword ? "text" : "password" }));
|
|
1285
1302
|
};
|
|
1286
1303
|
PasswordInput.displayName = "PasswordInput";
|
|
@@ -1295,7 +1312,7 @@ PasswordInput.displayName = "PasswordInput";
|
|
|
1295
1312
|
const PasswordField = ({ id, label, tip, helpText, helpAddon, errorMessage, isInvalid, maxLength, onChange, className, value, dataTestId, ref, ...rest }) => {
|
|
1296
1313
|
const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
|
|
1297
1314
|
const htmlFor = id ? id : "passwordField-" + sharedUtils.uuidv4();
|
|
1298
|
-
const handleChange =
|
|
1315
|
+
const handleChange = react.useCallback((event) => {
|
|
1299
1316
|
onChange?.(event);
|
|
1300
1317
|
}, [onChange]);
|
|
1301
1318
|
return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlFor, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(PasswordInput, { ...rest, "aria-labelledby": htmlFor + "-label", className: className, dataTestId: dataTestId, disabled: rest.readOnly, id: htmlFor, isInvalid: renderAsInvalid, maxLength: maxLength, onChange: handleChange, ref: ref, value: value }) }));
|
|
@@ -1366,41 +1383,41 @@ const DEFAULT_COUNTRY_CODE = undefined;
|
|
|
1366
1383
|
* @param {boolean} [disableAction=false] - Whether the action button is disabled or not.
|
|
1367
1384
|
*/
|
|
1368
1385
|
const PhoneInput = ({ dataTestId, isInvalid, disabled = false, value, defaultValue, fieldSize = "medium", disableAction = false, onChange, readOnly, onFocus, onBlur, name, ref, ...rest }) => {
|
|
1369
|
-
const [innerValue, setInnerValue] =
|
|
1386
|
+
const [innerValue, setInnerValue] = react.useState(() => {
|
|
1370
1387
|
return (value?.toString() || defaultValue?.toString()) ?? "";
|
|
1371
1388
|
});
|
|
1372
|
-
const fieldIsFocused =
|
|
1373
|
-
const [countryCode, setCountryCode] =
|
|
1374
|
-
const determineCountry =
|
|
1389
|
+
const fieldIsFocused = react.useRef(false);
|
|
1390
|
+
const [countryCode, setCountryCode] = react.useState(DEFAULT_COUNTRY_CODE);
|
|
1391
|
+
const determineCountry = react.useCallback((newValue) => {
|
|
1375
1392
|
const asYouType = new parsePhoneNumberFromString.AsYouType();
|
|
1376
1393
|
asYouType.input(newValue);
|
|
1377
1394
|
setCountryCode(asYouType.getCountry());
|
|
1378
1395
|
}, []);
|
|
1379
|
-
const handleChange =
|
|
1396
|
+
const handleChange = react.useCallback(event => {
|
|
1380
1397
|
const newValue = event.target.value;
|
|
1381
1398
|
event.target.value = parsePhoneNumberFromString.parseIncompletePhoneNumber(newValue);
|
|
1382
1399
|
onChange?.(event);
|
|
1383
1400
|
setInnerValue(newValue);
|
|
1384
1401
|
determineCountry(newValue);
|
|
1385
1402
|
}, [onChange, determineCountry]);
|
|
1386
|
-
const makePretty =
|
|
1403
|
+
const makePretty = react.useCallback((newValue) => {
|
|
1387
1404
|
const asYouType = new parsePhoneNumberFromString.AsYouType();
|
|
1388
1405
|
const pretty = asYouType.input(newValue);
|
|
1389
1406
|
setInnerValue(pretty);
|
|
1390
1407
|
setCountryCode(asYouType.getCountry());
|
|
1391
1408
|
}, []);
|
|
1392
|
-
|
|
1409
|
+
react.useEffect(() => {
|
|
1393
1410
|
if (!fieldIsFocused.current) {
|
|
1394
1411
|
makePretty(typeof value === "string" ? value : "");
|
|
1395
1412
|
}
|
|
1396
1413
|
}, [makePretty, value]);
|
|
1397
|
-
const handleBlur =
|
|
1414
|
+
const handleBlur = react.useCallback(event => {
|
|
1398
1415
|
const newValue = event.target.value;
|
|
1399
1416
|
makePretty(newValue);
|
|
1400
1417
|
onBlur?.(event);
|
|
1401
1418
|
fieldIsFocused.current = false;
|
|
1402
1419
|
}, [makePretty, onBlur]);
|
|
1403
|
-
const handleFocus =
|
|
1420
|
+
const handleFocus = react.useCallback(event => {
|
|
1404
1421
|
const newValue = event.target.value;
|
|
1405
1422
|
const noneFormattedValue = parsePhoneNumberFromString.parseIncompletePhoneNumber(newValue);
|
|
1406
1423
|
setInnerValue(noneFormattedValue);
|
|
@@ -1479,13 +1496,13 @@ const phoneErrorMessage = (phoneNumber, required) => {
|
|
|
1479
1496
|
const PhoneField = ({ label, id, tip, helpText, isInvalid, errorMessage, value, helpAddon, className, defaultValue, dataTestId, name, onBlur, ref, ...rest }) => {
|
|
1480
1497
|
const htmlForId = id ? id : "phoneField-" + sharedUtils.uuidv4();
|
|
1481
1498
|
const [t] = useTranslation();
|
|
1482
|
-
const [innerValue, setInnerValue] =
|
|
1499
|
+
const [innerValue, setInnerValue] = react.useState(() => {
|
|
1483
1500
|
return (value?.toString() || defaultValue?.toString()) ?? undefined;
|
|
1484
1501
|
});
|
|
1485
|
-
const [renderAsInvalid, setRenderAsInvalid] =
|
|
1502
|
+
const [renderAsInvalid, setRenderAsInvalid] = react.useState((isInvalid === undefined ? Boolean(errorMessage) : isInvalid) ||
|
|
1486
1503
|
!!phoneErrorMessage(value?.toString(), rest.required));
|
|
1487
|
-
const errorType =
|
|
1488
|
-
const error =
|
|
1504
|
+
const errorType = react.useMemo(() => phoneErrorMessage(innerValue, rest.required), [innerValue, rest.required]);
|
|
1505
|
+
const error = react.useMemo(() => {
|
|
1489
1506
|
// for the case when a custom error message is provided
|
|
1490
1507
|
if (errorMessage) {
|
|
1491
1508
|
return errorMessage;
|
|
@@ -1495,10 +1512,10 @@ const PhoneField = ({ label, id, tip, helpText, isInvalid, errorMessage, value,
|
|
|
1495
1512
|
}
|
|
1496
1513
|
return errorMessage;
|
|
1497
1514
|
}, [errorMessage, errorType, t]);
|
|
1498
|
-
|
|
1515
|
+
react.useEffect(() => {
|
|
1499
1516
|
setRenderAsInvalid(Boolean(errorMessage));
|
|
1500
1517
|
}, [errorMessage]);
|
|
1501
|
-
const handleBlur =
|
|
1518
|
+
const handleBlur = react.useCallback(event => {
|
|
1502
1519
|
const newValue = event.target.value;
|
|
1503
1520
|
setInnerValue(newValue);
|
|
1504
1521
|
// for the case when a custom error message is provided
|
|
@@ -1594,7 +1611,7 @@ const cvaRadioItem = cssClassVarianceUtilities.cvaMerge([
|
|
|
1594
1611
|
],
|
|
1595
1612
|
});
|
|
1596
1613
|
|
|
1597
|
-
const RadioGroupContext =
|
|
1614
|
+
const RadioGroupContext = react.createContext(null);
|
|
1598
1615
|
|
|
1599
1616
|
/**
|
|
1600
1617
|
* Use radio buttons when you have a group of mutually exclusive choices and only one selection from the group is allowed.
|
|
@@ -1627,7 +1644,7 @@ RadioGroup.displayName = "RadioGroup";
|
|
|
1627
1644
|
* @returns {ReactElement} RadioItem component
|
|
1628
1645
|
*/
|
|
1629
1646
|
const RadioItem = ({ label, value, dataTestId, className, description, suffix, ...rest }) => {
|
|
1630
|
-
const groupCtx =
|
|
1647
|
+
const groupCtx = react.useContext(RadioGroupContext);
|
|
1631
1648
|
const isChecked = groupCtx?.value === value;
|
|
1632
1649
|
const { ref: labelRef, isTextTruncated: isLabelTruncated } = reactComponents.useIsTextTruncated();
|
|
1633
1650
|
const { ref: descriptionRef, isTextTruncated: isDescriptionTruncated } = reactComponents.useIsTextTruncated();
|
|
@@ -1660,7 +1677,7 @@ const cvaTimeRange = cssClassVarianceUtilities.cvaMerge([
|
|
|
1660
1677
|
* @returns {ReactElement} TimeRange component
|
|
1661
1678
|
*/
|
|
1662
1679
|
const TimeRange = ({ id, className, dataTestId, children, range, onChange, disabled, isInvalid, }) => {
|
|
1663
|
-
const [timeRange, setTimeRange] =
|
|
1680
|
+
const [timeRange, setTimeRange] = react.useState(range ?? {
|
|
1664
1681
|
timeFrom: DEFAULT_TIME,
|
|
1665
1682
|
timeTo: DEFAULT_TIME,
|
|
1666
1683
|
});
|
|
@@ -2014,8 +2031,8 @@ const MultiSelectMenuItem = ({ label, onClick, selected, dataTestId, disabled, o
|
|
|
2014
2031
|
* @returns {ReactElement} TagWithWidth component
|
|
2015
2032
|
*/
|
|
2016
2033
|
const TagWithWidth = ({ onWidthKnown, children, ...rest }) => {
|
|
2017
|
-
const ref =
|
|
2018
|
-
|
|
2034
|
+
const ref = react.useRef(null);
|
|
2035
|
+
react.useLayoutEffect(() => {
|
|
2019
2036
|
onWidthKnown && onWidthKnown({ width: ref.current?.offsetWidth || 0 });
|
|
2020
2037
|
}, [ref, onWidthKnown]);
|
|
2021
2038
|
return (jsxRuntime.jsx(reactComponents.Tag, { ref: ref, ...rest, children: children }));
|
|
@@ -2028,19 +2045,19 @@ const TagWithWidth = ({ onWidthKnown, children, ...rest }) => {
|
|
|
2028
2045
|
* @returns {ReactElement} TagsContainer
|
|
2029
2046
|
*/
|
|
2030
2047
|
const TagsContainer = ({ items, width = "100%", itemsGap = 5, postFix, disabled }) => {
|
|
2031
|
-
const containerRef =
|
|
2032
|
-
const [isReady, setIsReady] =
|
|
2033
|
-
const [counterWidth, setCounterWidth] =
|
|
2034
|
-
const [availableSpaceWidth, setAvailableSpaceWidth] =
|
|
2035
|
-
const [childrenWidths, setChildrenWidths] =
|
|
2048
|
+
const containerRef = react.useRef(null);
|
|
2049
|
+
const [isReady, setIsReady] = react.useState(false);
|
|
2050
|
+
const [counterWidth, setCounterWidth] = react.useState(0);
|
|
2051
|
+
const [availableSpaceWidth, setAvailableSpaceWidth] = react.useState(0);
|
|
2052
|
+
const [childrenWidths, setChildrenWidths] = react.useState([]);
|
|
2036
2053
|
const itemsCount = items.length;
|
|
2037
2054
|
const dimensions = reactComponents.useResize();
|
|
2038
2055
|
const { width: windowWidth } = reactComponents.useDebounce(dimensions, 100);
|
|
2039
|
-
|
|
2056
|
+
react.useEffect(() => {
|
|
2040
2057
|
const containerWidth = containerRef.current?.offsetWidth || 0;
|
|
2041
2058
|
setAvailableSpaceWidth(containerWidth);
|
|
2042
2059
|
}, [windowWidth]);
|
|
2043
|
-
const onWidthKnownHandler =
|
|
2060
|
+
const onWidthKnownHandler = react.useCallback(({ width: reportedWidth }) => {
|
|
2044
2061
|
setChildrenWidths(prev => {
|
|
2045
2062
|
const next = [...prev, { width: reportedWidth + itemsGap }];
|
|
2046
2063
|
if (next.length === itemsCount) {
|
|
@@ -2049,7 +2066,7 @@ const TagsContainer = ({ items, width = "100%", itemsGap = 5, postFix, disabled
|
|
|
2049
2066
|
return next;
|
|
2050
2067
|
});
|
|
2051
2068
|
}, [itemsCount, itemsGap]);
|
|
2052
|
-
const renderedElements =
|
|
2069
|
+
const renderedElements = react.useMemo(() => {
|
|
2053
2070
|
const requiredSpace = childrenWidths.reduce((previous, current) => {
|
|
2054
2071
|
return previous + current.width;
|
|
2055
2072
|
}, 0);
|
|
@@ -2117,7 +2134,7 @@ const TagsContainer = ({ items, width = "100%", itemsGap = 5, postFix, disabled
|
|
|
2117
2134
|
const useCustomComponents = ({ componentsProps, disabled, readOnly, setMenuIsEnabled, dataTestId, maxSelectedDisplayCount, prefix, hasError, fieldSize, getOptionLabelDescription, }) => {
|
|
2118
2135
|
const [t] = useTranslation();
|
|
2119
2136
|
// perhaps it should not be wrap in memo (causing some issues with opening and closing on mobiles)
|
|
2120
|
-
const customComponents =
|
|
2137
|
+
const customComponents = react.useMemo(() => {
|
|
2121
2138
|
return {
|
|
2122
2139
|
ValueContainer: props => {
|
|
2123
2140
|
if (props.isMulti && Array.isArray(props.children) && props.children.length > 0) {
|
|
@@ -2243,7 +2260,7 @@ const useCustomComponents = ({ componentsProps, disabled, readOnly, setMenuIsEna
|
|
|
2243
2260
|
* @returns {StylesConfig<Option, boolean>} styles to override in select
|
|
2244
2261
|
*/
|
|
2245
2262
|
const useCustomStyles = ({ refContainer, maxSelectedDisplayCount, styles, disabled, fieldSize, }) => {
|
|
2246
|
-
const customStyles =
|
|
2263
|
+
const customStyles = react.useMemo(() => {
|
|
2247
2264
|
return {
|
|
2248
2265
|
control: base => {
|
|
2249
2266
|
return {
|
|
@@ -2343,7 +2360,7 @@ const useCustomStyles = ({ refContainer, maxSelectedDisplayCount, styles, disabl
|
|
|
2343
2360
|
* @returns {UseSelectProps} Select component
|
|
2344
2361
|
*/
|
|
2345
2362
|
const useSelect = ({ id, className, dataTestId = "select", prefix, async, 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 }) => {
|
|
2346
|
-
const refContainer =
|
|
2363
|
+
const refContainer = react.useRef(document.createElement("div"));
|
|
2347
2364
|
const { customStyles } = useCustomStyles({
|
|
2348
2365
|
refContainer,
|
|
2349
2366
|
maxSelectedDisplayCount,
|
|
@@ -2351,8 +2368,8 @@ const useSelect = ({ id, className, dataTestId = "select", prefix, async, maxMen
|
|
|
2351
2368
|
disabled: Boolean(disabled),
|
|
2352
2369
|
fieldSize,
|
|
2353
2370
|
});
|
|
2354
|
-
const [menuIsOpen, setMenuIsOpen] =
|
|
2355
|
-
const [menuIsEnabled, setMenuIsEnabled] =
|
|
2371
|
+
const [menuIsOpen, setMenuIsOpen] = react.useState(props.menuIsOpen ?? false);
|
|
2372
|
+
const [menuIsEnabled, setMenuIsEnabled] = react.useState(true);
|
|
2356
2373
|
const customComponents = useCustomComponents({
|
|
2357
2374
|
componentsProps: components,
|
|
2358
2375
|
disabled: Boolean(disabled),
|
|
@@ -2399,7 +2416,7 @@ const useSelect = ({ id, className, dataTestId = "select", prefix, async, maxMen
|
|
|
2399
2416
|
const CreatableSelect = (props) => {
|
|
2400
2417
|
const { id, dataTestId = "creatableSelect", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, value, options, onChange, isLoading, classNamePrefix = "creatableSelect", onMenuScrollToBottom, onInputChange, isSearchable, isClearable = false, readOnly, openMenuOnClick = !disabled, openMenuOnFocus = !disabled, allowCreateWhileLoading, onCreateOption, } = props;
|
|
2401
2418
|
const { refContainer, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler } = useSelect(props);
|
|
2402
|
-
const reactCreatableSelectProps =
|
|
2419
|
+
const reactCreatableSelectProps = react.useMemo(() => ({
|
|
2403
2420
|
value,
|
|
2404
2421
|
menuPlacement,
|
|
2405
2422
|
maxMenuHeight,
|
|
@@ -2471,7 +2488,7 @@ const ReactSyncSelect = ReactSelect.default || ReactSelect;
|
|
|
2471
2488
|
const Select = (props) => {
|
|
2472
2489
|
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;
|
|
2473
2490
|
const { refContainer, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler } = useSelect(props);
|
|
2474
|
-
const reactSelectProps =
|
|
2491
|
+
const reactSelectProps = react.useMemo(() => ({
|
|
2475
2492
|
value,
|
|
2476
2493
|
menuPlacement,
|
|
2477
2494
|
maxMenuHeight,
|
|
@@ -2542,15 +2559,15 @@ Select.displayName = "Select";
|
|
|
2542
2559
|
*/
|
|
2543
2560
|
const FormFieldSelectAdapter = ({ className, dataTestId, helpText, helpAddon, tip, label, isInvalid, errorMessage, name, onBlur, options, value, defaultValue, id, onChange, children, ref, ...rest }) => {
|
|
2544
2561
|
const isFirstRender = reactComponents.useIsFirstRender();
|
|
2545
|
-
const [innerValue, setInnerValue] =
|
|
2546
|
-
|
|
2562
|
+
const [innerValue, setInnerValue] = react.useState(value || defaultValue);
|
|
2563
|
+
react.useEffect(() => {
|
|
2547
2564
|
setInnerValue(defaultValue);
|
|
2548
2565
|
}, [defaultValue]);
|
|
2549
2566
|
const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
|
|
2550
|
-
const htmlFor =
|
|
2551
|
-
const innerRef =
|
|
2552
|
-
|
|
2553
|
-
|
|
2567
|
+
const htmlFor = react.useMemo(() => (id ? id : "selectField-" + sharedUtils.uuidv4()), [id]);
|
|
2568
|
+
const innerRef = react.useRef(null);
|
|
2569
|
+
react.useImperativeHandle(ref, () => innerRef.current, []);
|
|
2570
|
+
react.useEffect(() => {
|
|
2554
2571
|
if (innerValue === undefined) {
|
|
2555
2572
|
return;
|
|
2556
2573
|
}
|
|
@@ -2682,10 +2699,10 @@ const TextLengthIndicator = ({ length, maxLength }) => {
|
|
|
2682
2699
|
*
|
|
2683
2700
|
*/
|
|
2684
2701
|
const TextAreaField = ({ id, label, tip, helpText, helpAddon, errorMessage, isInvalid, maxLength, onChange, className, value, dataTestId, ref, ...rest }) => {
|
|
2685
|
-
const [valueLength, setValueLength] =
|
|
2702
|
+
const [valueLength, setValueLength] = react.useState(value ? `${value}`.length : 0);
|
|
2686
2703
|
const renderAsInvalid = isInvalid || Boolean(errorMessage);
|
|
2687
2704
|
const htmlForId = id ? id : "textAreaField-" + sharedUtils.uuidv4();
|
|
2688
|
-
const handleChange =
|
|
2705
|
+
const handleChange = react.useCallback((event) => {
|
|
2689
2706
|
setValueLength(event.target.value.length);
|
|
2690
2707
|
if (onChange) {
|
|
2691
2708
|
onChange(event);
|
|
@@ -2700,10 +2717,10 @@ TextAreaField.displayName = "TextAreaField";
|
|
|
2700
2717
|
* 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.
|
|
2701
2718
|
*/
|
|
2702
2719
|
const TextField = ({ id, label, tip, helpText, helpAddon, errorMessage, isInvalid, maxLength, onChange, className, value, dataTestId, isWarning, ref, ...rest }) => {
|
|
2703
|
-
const [valueLength, setValueLength] =
|
|
2720
|
+
const [valueLength, setValueLength] = react.useState(value ? `${value}`.length : 0);
|
|
2704
2721
|
const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
|
|
2705
2722
|
const htmlFor = id ? id : "textField-" + sharedUtils.uuidv4();
|
|
2706
|
-
const handleChange =
|
|
2723
|
+
const handleChange = react.useCallback((event) => {
|
|
2707
2724
|
setValueLength(event.target.value.length);
|
|
2708
2725
|
if (onChange) {
|
|
2709
2726
|
onChange(event);
|
|
@@ -2808,8 +2825,8 @@ const cvaToggleSwitchThumb = cssClassVarianceUtilities.cvaMerge(["block", "round
|
|
|
2808
2825
|
* @param {ToggleSwitchProps} props - The props for the ToggleSwitch component
|
|
2809
2826
|
* @returns {ReactElement} ToggleSwitch component
|
|
2810
2827
|
*/
|
|
2811
|
-
const ToggleSwitch =
|
|
2812
|
-
const localInputRef =
|
|
2828
|
+
const ToggleSwitch = react.forwardRef(({ onChange, onClick, preventDefaultOnClick, className, dataTestId = "toggle-switch", showInputFocus, toggled, size = "medium", tabIndex = 0, readOnly, disabled, ...rest }, ref) => {
|
|
2829
|
+
const localInputRef = react.useRef(null);
|
|
2813
2830
|
const inputRef = typeof ref === "function" ? localInputRef : ref || localInputRef;
|
|
2814
2831
|
const handleWrapperClick = (e) => {
|
|
2815
2832
|
// Prevents double-toggling when wrapped in a label or if preventDefaultOnClick is true
|
|
@@ -2935,7 +2952,7 @@ const validateUrl = (url, required) => {
|
|
|
2935
2952
|
* NOTE: If shown with a label, please use the `UrlField` component instead.
|
|
2936
2953
|
*/
|
|
2937
2954
|
const UrlInput = ({ dataTestId, isInvalid, disabled = false, fieldSize = "medium", disableAction = false, value, defaultValue, ref, ...rest }) => {
|
|
2938
|
-
const [url, setUrl] =
|
|
2955
|
+
const [url, setUrl] = react.useState(value?.toString() || defaultValue?.toString());
|
|
2939
2956
|
const renderAsInvalid = (url && typeof url === "string" && !validateUrlAddress(url)) || isInvalid;
|
|
2940
2957
|
return (jsxRuntime.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 && (jsxRuntime.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 })) }));
|
|
2941
2958
|
};
|
|
@@ -2949,13 +2966,13 @@ UrlInput.displayName = "UrlField";
|
|
|
2949
2966
|
const UrlField = ({ label, id, tip, helpText, errorMessage, helpAddon, className, defaultValue, dataTestId, isInvalid = false, value, onBlur, ref, ...rest }) => {
|
|
2950
2967
|
const htmlForId = id ? id : "urlField-" + sharedUtils.uuidv4();
|
|
2951
2968
|
const [t] = useTranslation();
|
|
2952
|
-
const [innerValue, setInnerValue] =
|
|
2969
|
+
const [innerValue, setInnerValue] = react.useState(() => {
|
|
2953
2970
|
return (value?.toString() || defaultValue?.toString()) ?? "";
|
|
2954
2971
|
});
|
|
2955
|
-
const [renderAsInvalid, setRenderAsInvalid] =
|
|
2956
|
-
const errorType =
|
|
2957
|
-
const error =
|
|
2958
|
-
const handleBlur =
|
|
2972
|
+
const [renderAsInvalid, setRenderAsInvalid] = react.useState(!!errorMessage || (value && isString(value) && !validateUrlAddress(value)) || isInvalid);
|
|
2973
|
+
const errorType = react.useMemo(() => validateUrl(innerValue ?? "", rest.required), [rest.required, innerValue]);
|
|
2974
|
+
const error = react.useMemo(() => (errorType ? t(`urlField.error.${errorType}`) : errorMessage), [errorType, errorMessage, t]);
|
|
2975
|
+
const handleBlur = react.useCallback(event => {
|
|
2959
2976
|
const newValue = event.target.value;
|
|
2960
2977
|
setInnerValue(newValue);
|
|
2961
2978
|
setRenderAsInvalid(!!validateUrl(newValue, rest.required));
|
|
@@ -2975,7 +2992,7 @@ UrlField.displayName = "UrlField";
|
|
|
2975
2992
|
*/
|
|
2976
2993
|
const useGetPhoneValidationRules = () => {
|
|
2977
2994
|
const [t] = useTranslation();
|
|
2978
|
-
const getPhoneNumberValidationRules =
|
|
2995
|
+
const getPhoneNumberValidationRules = react.useCallback((skipValidation = false) => {
|
|
2979
2996
|
const defaultRules = {};
|
|
2980
2997
|
const pattern = {
|
|
2981
2998
|
...defaultRules,
|
|
@@ -3023,7 +3040,7 @@ const usePhoneInput = () => {
|
|
|
3023
3040
|
*/
|
|
3024
3041
|
const useZodValidators = () => {
|
|
3025
3042
|
const [t] = useTranslation();
|
|
3026
|
-
const ZodPhoneValidator =
|
|
3043
|
+
const ZodPhoneValidator = react.useMemo(() => zod.z.string().superRefine((phoneNumber, ctx) => {
|
|
3027
3044
|
if (!phoneNumber) {
|
|
3028
3045
|
return undefined;
|
|
3029
3046
|
}
|
|
@@ -3065,7 +3082,7 @@ const useZodValidators = () => {
|
|
|
3065
3082
|
});
|
|
3066
3083
|
}
|
|
3067
3084
|
}), [t]);
|
|
3068
|
-
return
|
|
3085
|
+
return react.useMemo(() => ({ ZodPhoneValidator }), [ZodPhoneValidator]);
|
|
3069
3086
|
};
|
|
3070
3087
|
|
|
3071
3088
|
/*
|
package/index.esm.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { useNamespaceTranslation, registerTranslations, NamespaceTrans } from '@trackunit/i18n-library-translation';
|
|
3
|
-
import { IconButton, Icon, Tooltip, useGeometry, useIsTextTruncated, Text, Heading, Spinner, MenuItem,
|
|
3
|
+
import { IconButton, Icon, Tooltip, useGeometry, useIsTextTruncated, Text, Heading, Tag, Spinner, MenuItem, useResize, useDebounce, useIsFirstRender } from '@trackunit/react-components';
|
|
4
4
|
import { useCopyToClipboard } from 'usehooks-ts';
|
|
5
5
|
import { cvaMerge } from '@trackunit/css-class-variance-utilities';
|
|
6
6
|
import { themeSpacing } from '@trackunit/ui-design-tokens';
|
|
7
|
-
import
|
|
8
|
-
import { forwardRef, useRef, useImperativeHandle, useMemo, useState, useCallback, useEffect, cloneElement, useContext, useLayoutEffect } from 'react';
|
|
7
|
+
import { forwardRef, useRef, useImperativeHandle, useMemo, useState, useCallback, useEffect, cloneElement, createContext, useContext, useLayoutEffect } from 'react';
|
|
9
8
|
import { titleCase } from 'string-ts';
|
|
10
9
|
import { uuidv4, nonNullable } from '@trackunit/shared-utils';
|
|
11
10
|
import { Temporal } from '@js-temporal/polyfill';
|
|
@@ -1190,12 +1189,11 @@ const cvaOptionCardLabel = cvaMerge([
|
|
|
1190
1189
|
"transition",
|
|
1191
1190
|
"bg-white",
|
|
1192
1191
|
"outline",
|
|
1193
|
-
"outline-
|
|
1192
|
+
"outline-1",
|
|
1194
1193
|
"outline-slate-300",
|
|
1195
1194
|
"hover:bg-slate-100",
|
|
1196
1195
|
"focus:bg-slate-200",
|
|
1197
1196
|
"active:bg-slate-200",
|
|
1198
|
-
"disabled:bg-slate-200",
|
|
1199
1197
|
"peer-checked:bg-primary-50",
|
|
1200
1198
|
"peer-checked:outline-primary-600",
|
|
1201
1199
|
"peer-checked:outline-2",
|
|
@@ -1205,10 +1203,11 @@ const cvaOptionCardLabel = cvaMerge([
|
|
|
1205
1203
|
"items-center",
|
|
1206
1204
|
"text-center",
|
|
1207
1205
|
"rounded-md",
|
|
1206
|
+
"relative"
|
|
1208
1207
|
], {
|
|
1209
1208
|
variants: {
|
|
1210
1209
|
disabled: {
|
|
1211
|
-
true: ["cursor-not-allowed"],
|
|
1210
|
+
true: ["cursor-not-allowed", "bg-slate-100"],
|
|
1212
1211
|
false: ["cursor-pointer"],
|
|
1213
1212
|
},
|
|
1214
1213
|
layout: {
|
|
@@ -1231,27 +1230,63 @@ const cvaOptionCardLabel = cvaMerge([
|
|
|
1231
1230
|
});
|
|
1232
1231
|
const cvaOptionCardContent = cvaMerge(["flex", "flex-col", "items-center"]);
|
|
1233
1232
|
const cvaOptionCardContainer = cvaMerge(["contents"]);
|
|
1234
|
-
const
|
|
1235
|
-
"hover:text-slate-700",
|
|
1236
|
-
"focus:text-slate-800",
|
|
1237
|
-
"active:text-slate-800",
|
|
1238
|
-
"disabled:text-slate-400",
|
|
1239
|
-
"text-sm",
|
|
1233
|
+
const cvaOptionCardTitle = cvaMerge([
|
|
1240
1234
|
"text-slate-600",
|
|
1241
1235
|
"whitespace-nowrap",
|
|
1242
|
-
]
|
|
1236
|
+
], {
|
|
1237
|
+
variants: {
|
|
1238
|
+
layout: {
|
|
1239
|
+
default: ["text-lg"],
|
|
1240
|
+
compact: ["text-sm"]
|
|
1241
|
+
},
|
|
1242
|
+
disabled: {
|
|
1243
|
+
true: ["text-slate-400"],
|
|
1244
|
+
false: ["focus:text-slate-800", "active:text-slate-800"]
|
|
1245
|
+
},
|
|
1246
|
+
},
|
|
1247
|
+
});
|
|
1248
|
+
const cvaOptionCardText = cvaMerge([
|
|
1249
|
+
"text-slate-600",
|
|
1250
|
+
"text-sm"
|
|
1251
|
+
], {
|
|
1252
|
+
variants: {
|
|
1253
|
+
type: {
|
|
1254
|
+
subheading: ["font-medium"],
|
|
1255
|
+
description: ["font-normal"]
|
|
1256
|
+
},
|
|
1257
|
+
disabled: {
|
|
1258
|
+
true: ["text-slate-400"],
|
|
1259
|
+
false: ["focus:text-slate-800", "active:text-slate-800"]
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
});
|
|
1243
1263
|
const cvaInput = cvaMerge(["peer", "absolute", "h-0", "w-0", "opacity-0"]);
|
|
1244
|
-
const cvaCustomImage = cvaMerge(["text-
|
|
1264
|
+
const cvaCustomImage = cvaMerge(["text-slate-400"], {
|
|
1265
|
+
variants: {
|
|
1266
|
+
disabled: {
|
|
1267
|
+
true: ["!text-slate-400"],
|
|
1268
|
+
false: [""]
|
|
1269
|
+
},
|
|
1270
|
+
},
|
|
1271
|
+
});
|
|
1272
|
+
const cvaTag = cvaMerge([], {
|
|
1273
|
+
variants: {
|
|
1274
|
+
layout: {
|
|
1275
|
+
default: ["absolute", "top-2", "right-2"],
|
|
1276
|
+
compact: [],
|
|
1277
|
+
},
|
|
1278
|
+
},
|
|
1279
|
+
});
|
|
1245
1280
|
|
|
1246
1281
|
/**
|
|
1247
1282
|
* A card version of a radio button that includes an icon, headings and a description.
|
|
1248
1283
|
*/
|
|
1249
|
-
const OptionCard = ({ icon, heading, subheading, description, disabled, id, value, className, contentClassName, dataTestId, customImage, layout = "default", ref, ...rest }) => {
|
|
1284
|
+
const OptionCard = ({ icon, heading, subheading, description, disabled, id, value, className, contentClassName, dataTestId, customImage, layout = "default", ref, tagProps, ...rest }) => {
|
|
1250
1285
|
const htmlForId = id ?? "option-card-" + uuidv4();
|
|
1251
|
-
const subContent = useMemo(() => (jsxs("div", { className: cvaOptionCardContent({ className: contentClassName }), children: [subheading ? (jsx(Text, { align: "center",
|
|
1286
|
+
const subContent = useMemo(() => (jsxs("div", { className: cvaOptionCardContent({ className: contentClassName }), children: [subheading ? (jsx(Text, { align: "center", className: cvaOptionCardText({ type: "subheading", disabled }), children: subheading })) : null, description ? (jsx(Text, { align: "center", className: cvaOptionCardText({ type: "description", disabled }), children: description })) : null] })), [subheading, description, contentClassName, disabled]);
|
|
1252
1287
|
return (jsx(Tooltip, { className: "w-fit", disabled: layout !== "compact" || (!subheading && !description), label: subContent, mode: "light", placement: "top", children: jsxs("div", { className: cvaOptionCardContainer(), "data-testid": dataTestId, children: [jsx("input", { className: cvaInput(), "data-testid": `${dataTestId}-option-card`, disabled: disabled, id: htmlForId, ref: ref, type: "radio", value: value, ...rest }), jsxs("label", { className: cvaOptionCardLabel({ className, disabled, layout }), "data-testid": `${dataTestId}-option-card-label`, htmlFor: htmlForId, children: [disabled && icon && !customImage
|
|
1253
|
-
? cloneElement(icon, { className: cvaCustomImage({ className: icon.props.className }) })
|
|
1254
|
-
: null, disabled && customImage ? jsx("img", { alt: "logo", className: customImage.className, src: customImage.src }) : null, !disabled && !customImage && icon, !disabled && customImage ? jsx("img", { alt: "logo", className: customImage.className, src: customImage.src }) : null, heading ? (layout === "default" ? (jsx(Heading, { subtle: disabled, variant: "secondary", children: heading })) : (jsx(Text, { align: "center", className:
|
|
1288
|
+
? cloneElement(icon, { className: cvaCustomImage({ disabled, className: icon.props.className }) })
|
|
1289
|
+
: null, disabled && customImage ? jsx("img", { alt: "logo", className: customImage.className, src: customImage.src }) : null, !disabled && !customImage && icon, !disabled && customImage ? jsx("img", { alt: "logo", className: customImage.className, src: customImage.src }) : null, heading ? (layout === "default" ? (jsx(Heading, { className: cvaOptionCardTitle({ disabled, layout }), subtle: disabled, variant: "secondary", children: heading })) : (jsx(Text, { align: "center", className: cvaOptionCardTitle({ disabled, layout }), subtle: disabled, type: "span", weight: "thick", children: heading }))) : null, layout === "default" && (subheading || description) ? subContent : null, tagProps ? jsx(Tag, { className: cvaTag({ className: tagProps.className, layout }), ...tagProps }) : null] })] }) }));
|
|
1255
1290
|
};
|
|
1256
1291
|
OptionCard.displayName = "OptionCard";
|
|
1257
1292
|
|
|
@@ -1575,7 +1610,7 @@ const cvaRadioItem = cvaMerge([
|
|
|
1575
1610
|
],
|
|
1576
1611
|
});
|
|
1577
1612
|
|
|
1578
|
-
const RadioGroupContext =
|
|
1613
|
+
const RadioGroupContext = createContext(null);
|
|
1579
1614
|
|
|
1580
1615
|
/**
|
|
1581
1616
|
* Use radio buttons when you have a group of mutually exclusive choices and only one selection from the group is allowed.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trackunit/react-form-components",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.138",
|
|
4
4
|
"repository": "https://github.com/Trackunit/manager",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"engines": {
|
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
"zod": "3.22.4",
|
|
18
18
|
"react-hook-form": "7.53.1",
|
|
19
19
|
"tailwind-merge": "^2.0.0",
|
|
20
|
-
"@trackunit/css-class-variance-utilities": "1.3.
|
|
21
|
-
"@trackunit/react-components": "1.4.
|
|
22
|
-
"@trackunit/ui-icons": "1.3.
|
|
23
|
-
"@trackunit/shared-utils": "1.5.
|
|
24
|
-
"@trackunit/ui-design-tokens": "1.3.
|
|
25
|
-
"@trackunit/i18n-library-translation": "1.3.
|
|
20
|
+
"@trackunit/css-class-variance-utilities": "1.3.101",
|
|
21
|
+
"@trackunit/react-components": "1.4.122",
|
|
22
|
+
"@trackunit/ui-icons": "1.3.103",
|
|
23
|
+
"@trackunit/shared-utils": "1.5.101",
|
|
24
|
+
"@trackunit/ui-design-tokens": "1.3.101",
|
|
25
|
+
"@trackunit/i18n-library-translation": "1.3.112",
|
|
26
26
|
"string-ts": "^2.0.0"
|
|
27
27
|
},
|
|
28
28
|
"module": "./index.esm.js",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CommonProps, IconProps } from "@trackunit/react-components";
|
|
1
|
+
import { CommonProps, IconProps, TagProps } from "@trackunit/react-components";
|
|
2
2
|
import { InputHTMLAttributes, ReactElement, ReactNode, Ref } from "react";
|
|
3
3
|
export interface OptionCardProps extends InputHTMLAttributes<HTMLInputElement>, CommonProps {
|
|
4
4
|
/**
|
|
@@ -33,6 +33,10 @@ export interface OptionCardProps extends InputHTMLAttributes<HTMLInputElement>,
|
|
|
33
33
|
* The layout of the component.
|
|
34
34
|
*/
|
|
35
35
|
layout?: "compact" | "default";
|
|
36
|
+
/**
|
|
37
|
+
* Props for the tag.
|
|
38
|
+
*/
|
|
39
|
+
tagProps?: TagProps;
|
|
36
40
|
}
|
|
37
41
|
interface CustomImage {
|
|
38
42
|
src: string;
|
|
@@ -42,7 +46,7 @@ interface CustomImage {
|
|
|
42
46
|
* A card version of a radio button that includes an icon, headings and a description.
|
|
43
47
|
*/
|
|
44
48
|
export declare const OptionCard: {
|
|
45
|
-
({ icon, heading, subheading, description, disabled, id, value, className, contentClassName, dataTestId, customImage, layout, ref, ...rest }: OptionCardProps): import("react/jsx-runtime").JSX.Element;
|
|
49
|
+
({ icon, heading, subheading, description, disabled, id, value, className, contentClassName, dataTestId, customImage, layout, ref, tagProps, ...rest }: OptionCardProps): import("react/jsx-runtime").JSX.Element;
|
|
46
50
|
displayName: string;
|
|
47
51
|
};
|
|
48
52
|
export {};
|
|
@@ -4,6 +4,18 @@ export declare const cvaOptionCardLabel: (props?: ({
|
|
|
4
4
|
} & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
|
|
5
5
|
export declare const cvaOptionCardContent: (props?: import("class-variance-authority/dist/types").ClassProp | undefined) => string;
|
|
6
6
|
export declare const cvaOptionCardContainer: (props?: import("class-variance-authority/dist/types").ClassProp | undefined) => string;
|
|
7
|
-
export declare const
|
|
7
|
+
export declare const cvaOptionCardTitle: (props?: ({
|
|
8
|
+
layout?: "default" | "compact" | null | undefined;
|
|
9
|
+
disabled?: boolean | null | undefined;
|
|
10
|
+
} & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
|
|
11
|
+
export declare const cvaOptionCardText: (props?: ({
|
|
12
|
+
type?: "subheading" | "description" | null | undefined;
|
|
13
|
+
disabled?: boolean | null | undefined;
|
|
14
|
+
} & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
|
|
8
15
|
export declare const cvaInput: (props?: import("class-variance-authority/dist/types").ClassProp | undefined) => string;
|
|
9
|
-
export declare const cvaCustomImage: (props?:
|
|
16
|
+
export declare const cvaCustomImage: (props?: ({
|
|
17
|
+
disabled?: boolean | null | undefined;
|
|
18
|
+
} & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
|
|
19
|
+
export declare const cvaTag: (props?: ({
|
|
20
|
+
layout?: "default" | "compact" | null | undefined;
|
|
21
|
+
} & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ChangeEvent } from "react";
|
|
2
2
|
interface RadioGroupContextProps {
|
|
3
3
|
id: string;
|
|
4
4
|
name: string;
|
|
5
5
|
value: string | number;
|
|
6
6
|
disabled?: boolean;
|
|
7
7
|
isInvalid?: boolean;
|
|
8
|
-
onChange: (e:
|
|
8
|
+
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
|
|
9
9
|
}
|
|
10
|
-
export declare const RadioGroupContext:
|
|
10
|
+
export declare const RadioGroupContext: import("react").Context<RadioGroupContextProps | null>;
|
|
11
11
|
export {};
|