@trackunit/react-form-components 0.0.330 → 0.0.332
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 +921 -978
- package/index.esm.js +922 -982
- package/package.json +4 -2
- package/src/components/FormGroup/FormGroup.d.ts +1 -0
- package/src/components/PhoneField/PhoneField.d.ts +1 -2
- package/src/components/PhoneFieldWithController/PhoneFieldWithController.d.ts +23 -0
- package/src/components/PhoneInput/PhoneInput.d.ts +2 -40
- package/src/components/PhoneInput/PhoneInputValidationUtils.d.ts +1 -6
- package/src/index.d.ts +3 -0
- package/src/utilities/useGetPhoneValidationRules.d.ts +12 -0
- package/src/utilities/useZodValidators.d.ts +11 -0
package/index.cjs.js
CHANGED
|
@@ -11,11 +11,13 @@ var React = require('react');
|
|
|
11
11
|
var uuid = require('uuid');
|
|
12
12
|
var dateFns = require('date-fns');
|
|
13
13
|
var parsePhoneNumberFromString = require('libphonenumber-js');
|
|
14
|
+
var reactHookForm = require('react-hook-form');
|
|
14
15
|
var ReactSelect = require('react-select');
|
|
15
16
|
var ReactAsyncCreatableSelect = require('react-select/async-creatable');
|
|
16
17
|
var ReactCreatableSelect = require('react-select/creatable');
|
|
17
18
|
var ReactAsyncSelect = require('react-select/async');
|
|
18
19
|
var sharedUtils = require('@trackunit/shared-utils');
|
|
20
|
+
var zod = require('zod');
|
|
19
21
|
|
|
20
22
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
21
23
|
|
|
@@ -266,7 +268,7 @@ const cvaInputPrefix = cssClassVarianceUtilities.cvaMerge([
|
|
|
266
268
|
"hover:component-search-prefix",
|
|
267
269
|
"component-baseInput-prefix",
|
|
268
270
|
"component-search-borderless",
|
|
269
|
-
"
|
|
271
|
+
"pl-3",
|
|
270
272
|
], {
|
|
271
273
|
variants: {
|
|
272
274
|
disabled: {
|
|
@@ -872,1101 +874,944 @@ const getCountryAbbreviation = (callCode) => {
|
|
|
872
874
|
return parsePhoneNumberFromString.getCountries().find(c => parsePhoneNumberFromString.getCountryCallingCode(c) === code) || "";
|
|
873
875
|
};
|
|
874
876
|
|
|
877
|
+
const DEFAULT_COUNTRY_CODE = undefined;
|
|
875
878
|
/**
|
|
876
|
-
* A
|
|
879
|
+
* A component for inputting phone numbers with an optional action button for initiating a phone call.
|
|
877
880
|
*
|
|
878
|
-
*
|
|
881
|
+
* @param {string} [dataTestId] - The data test ID for the component.
|
|
882
|
+
* @param {string|number} [value] - The value of the input field. The value should include the country code as well.
|
|
883
|
+
* @param {boolean} [disabled=false] - Whether the component is disabled or not.
|
|
884
|
+
* @param {string} [fieldSize="medium"] - The size of the input field.
|
|
885
|
+
* @param {boolean} [disableAction=false] - Whether the action button is disabled or not.
|
|
886
|
+
* @returns {JSX.Element} - The PhoneInput component.
|
|
879
887
|
*/
|
|
880
|
-
const
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
888
|
+
const PhoneInput = React.forwardRef((_a, ref) => {
|
|
889
|
+
var { dataTestId, isInvalid, disabled = false, value, defaultValue, fieldSize = "medium", disableAction = false, onChange, readOnly, onFocus, onBlur, name } = _a, rest = __rest(_a, ["dataTestId", "isInvalid", "disabled", "value", "defaultValue", "fieldSize", "disableAction", "onChange", "readOnly", "onFocus", "onBlur", "name"]);
|
|
890
|
+
const [innerValue, setInnerValue] = React.useState(() => {
|
|
891
|
+
var _a;
|
|
892
|
+
return (_a = ((value === null || value === void 0 ? void 0 : value.toString()) || (defaultValue === null || defaultValue === void 0 ? void 0 : defaultValue.toString()))) !== null && _a !== void 0 ? _a : "";
|
|
893
|
+
});
|
|
894
|
+
const fieldIsFocused = React.useRef(false);
|
|
895
|
+
const [countryCode, setCountryCode] = React.useState(DEFAULT_COUNTRY_CODE);
|
|
896
|
+
const determineCountry = React.useCallback((newValue) => {
|
|
897
|
+
const asYouType = new parsePhoneNumberFromString.AsYouType();
|
|
898
|
+
asYouType.input(newValue);
|
|
899
|
+
setCountryCode(asYouType.getCountry());
|
|
900
|
+
}, []);
|
|
901
|
+
const handleChange = React.useCallback(event => {
|
|
902
|
+
const newValue = event.target.value;
|
|
903
|
+
const noneFormattedValue = parsePhoneNumberFromString.parseIncompletePhoneNumber(newValue);
|
|
904
|
+
event.target.value = noneFormattedValue;
|
|
905
|
+
onChange === null || onChange === void 0 ? void 0 : onChange(event);
|
|
906
|
+
setInnerValue(newValue);
|
|
907
|
+
determineCountry(newValue);
|
|
908
|
+
}, [onChange, determineCountry]);
|
|
909
|
+
const makePretty = React.useCallback((newValue) => {
|
|
910
|
+
const asYouType = new parsePhoneNumberFromString.AsYouType();
|
|
911
|
+
const pretty = asYouType.input(newValue);
|
|
912
|
+
setInnerValue(pretty);
|
|
913
|
+
setCountryCode(asYouType.getCountry());
|
|
914
|
+
}, []);
|
|
915
|
+
React.useEffect(() => {
|
|
916
|
+
if (!fieldIsFocused.current) {
|
|
917
|
+
makePretty(typeof value === "string" ? value : "");
|
|
884
918
|
}
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
919
|
+
}, [makePretty, value]);
|
|
920
|
+
const handleBlur = React.useCallback(event => {
|
|
921
|
+
const newValue = event.target.value;
|
|
922
|
+
makePretty(newValue);
|
|
923
|
+
onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
|
|
924
|
+
fieldIsFocused.current = false;
|
|
925
|
+
}, [makePretty, onBlur]);
|
|
926
|
+
const handleFocus = React.useCallback(event => {
|
|
927
|
+
const newValue = event.target.value;
|
|
928
|
+
const noneFormattedValue = parsePhoneNumberFromString.parseIncompletePhoneNumber(newValue);
|
|
929
|
+
setInnerValue(noneFormattedValue);
|
|
930
|
+
onFocus === null || onFocus === void 0 ? void 0 : onFocus(event);
|
|
931
|
+
fieldIsFocused.current = true;
|
|
932
|
+
}, [onFocus]);
|
|
933
|
+
return (jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-2", "data-testid": dataTestId && `${dataTestId}-container`, children: jsxRuntime.jsx(BaseInput, Object.assign({ actions: !disableAction && (jsxRuntime.jsx(ActionButton, { dataTestId: dataTestId && `${dataTestId}-phoneIcon`, disabled: disabled || isInvalid, iconSize: fieldSize, type: "PHONE_NUMBER", value: (value === null || value === void 0 ? void 0 : value.toString()) || "" })), dataTestId: dataTestId && `${dataTestId}-phoneNumberInput`, 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)) }));
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
/**
|
|
937
|
+
* The PhoneField component is used to enter phone number.
|
|
938
|
+
* It is a wrapper around the PhoneInput component and the FormGroup component.
|
|
939
|
+
* It is used to render a phone number field with a label, a tip, a help text, a help addon and an error message.
|
|
940
|
+
*
|
|
941
|
+
* @param {string} [label] - The label for the component.
|
|
942
|
+
* @param {string} [tip] - The tip for the component.
|
|
943
|
+
* @param {string} [helpText] - The help text for the component.
|
|
944
|
+
* @param {string} [helpAddon] - The help addon for the component.
|
|
945
|
+
* @param {string} [errorMessage] - The error message for the component.
|
|
946
|
+
* @param {string} [defaultValue] - The default value for the component.
|
|
947
|
+
* @param {boolean} [disabled=false] - Whether the component is disabled or not.
|
|
948
|
+
* @param {string} [fieldSize="medium"] - The size of the input field.
|
|
949
|
+
* @param {boolean} [disableAction=false] - Whether the action button is disabled or not.
|
|
950
|
+
* @returns {JSX.Element} - The PhoneField component.
|
|
951
|
+
*/
|
|
952
|
+
const PhoneField = React.forwardRef((_a, ref) => {
|
|
953
|
+
var { label, id, tip, helpText, isInvalid, errorMessage, value, helpAddon, className, defaultValue, dataTestId, name, onChange, onBlur } = _a, rest = __rest(_a, ["label", "id", "tip", "helpText", "isInvalid", "errorMessage", "value", "helpAddon", "className", "defaultValue", "dataTestId", "name", "onChange", "onBlur"]);
|
|
954
|
+
const htmlForId = id ? id : "phoneField-" + uuid.v4();
|
|
955
|
+
const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
|
|
956
|
+
return (jsxRuntime.jsx(FormGroup, { className: className, dataTestId: dataTestId && `${dataTestId}-FormGroup`, disabled: rest.disabled, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, tip: tip, children: jsxRuntime.jsx(PhoneInput, Object.assign({ "aria-labelledby": htmlForId + "-label", dataTestId: dataTestId, defaultValue: defaultValue, id: htmlForId, isInvalid: renderAsInvalid, name: name, onBlur: onBlur, onChange: onChange, ref: ref, value: value }, rest)) }));
|
|
957
|
+
});
|
|
958
|
+
|
|
959
|
+
/**
|
|
960
|
+
* The PhoneFieldWithController component is a wrapper for the PhoneField component to connect it to react-hook-form.
|
|
961
|
+
*
|
|
962
|
+
* @returns {JSX.Element} - The PhoneFieldWithController component.
|
|
963
|
+
*/
|
|
964
|
+
const PhoneFieldWithController = React.forwardRef((_a, ref) => {
|
|
965
|
+
var { control, controllerProps, name, value } = _a, rest = __rest(_a, ["control", "controllerProps", "name", "value"]);
|
|
966
|
+
return (jsxRuntime.jsx(reactHookForm.Controller, Object.assign({ control: control, defaultValue: value, name: name }, controllerProps, { render: ({ field }) => jsxRuntime.jsx(PhoneField, Object.assign({}, rest, field, { ref: ref })) })));
|
|
967
|
+
});
|
|
968
|
+
|
|
969
|
+
/**
|
|
970
|
+
* Validates a phone number
|
|
971
|
+
*/
|
|
972
|
+
const validatePhoneNumber = (phoneNumber) => {
|
|
973
|
+
if (!phoneNumber) {
|
|
974
|
+
return "REQUIRED";
|
|
975
|
+
}
|
|
976
|
+
const asYouType = new parsePhoneNumberFromString.AsYouType();
|
|
977
|
+
asYouType.input(phoneNumber);
|
|
978
|
+
const countryCode = asYouType.getCallingCode();
|
|
979
|
+
const national = asYouType.getNationalNumber();
|
|
980
|
+
if (phoneNumber && parsePhoneNumberFromString.isValidPhoneNumber(phoneNumber)) {
|
|
981
|
+
return undefined;
|
|
982
|
+
}
|
|
983
|
+
if (!countryCode && national) {
|
|
984
|
+
return "REQUIRED_COUNTRY";
|
|
985
|
+
}
|
|
986
|
+
if (phoneNumber &&
|
|
987
|
+
(checkIfPhoneNumberHasPlus(phoneNumber) ? isNaN(+phoneNumber.slice(1, phoneNumber.length)) : isNaN(+phoneNumber))) {
|
|
988
|
+
return "NOT_A_NUMBER";
|
|
989
|
+
}
|
|
990
|
+
const safePhoneNumber = getPhoneNumberWithPlus(phoneNumber === null || phoneNumber === void 0 ? void 0 : phoneNumber.trim());
|
|
991
|
+
if (safePhoneNumber.length <= 5) {
|
|
992
|
+
//needs to be handled manually, parsePhoneNumberFromString can't parse it
|
|
993
|
+
return "TOO_SHORT";
|
|
994
|
+
}
|
|
995
|
+
const number = parsePhoneNumberFromString__default["default"](safePhoneNumber);
|
|
996
|
+
if (!number) {
|
|
997
|
+
return "NOT_A_NUMBER";
|
|
998
|
+
}
|
|
999
|
+
return "INVALID_NUMBER";
|
|
890
1000
|
};
|
|
1001
|
+
/**
|
|
1002
|
+
* Checks if the country code is valid and required
|
|
1003
|
+
*/
|
|
1004
|
+
const isInvalidCountryCode = (error, required) => (!!required && error === "REQUIRED") || error === "REQUIRED_COUNTRY";
|
|
1005
|
+
/**
|
|
1006
|
+
* Checks if the phone number is valid and required
|
|
1007
|
+
*/
|
|
1008
|
+
const isInvalidPhoneNumber = (error, required) => error !== "REQUIRED_COUNTRY" && ((!!error && error !== "REQUIRED") || (!!required && error === "REQUIRED"));
|
|
891
1009
|
|
|
892
|
-
const
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
1010
|
+
const cvaRadioGroup = cssClassVarianceUtilities.cvaMerge(["flex", "gap-2", "flex-col", "items-start"], {
|
|
1011
|
+
variants: {
|
|
1012
|
+
layout: {
|
|
1013
|
+
inline: ["flex", "gap-3", "flex-row", "items-center"],
|
|
1014
|
+
},
|
|
1015
|
+
},
|
|
1016
|
+
});
|
|
1017
|
+
const cvaRadioItem = cssClassVarianceUtilities.cvaMerge([
|
|
1018
|
+
"w-4",
|
|
1019
|
+
"h-4",
|
|
1020
|
+
"appearance-none",
|
|
1021
|
+
"rounded-3xl",
|
|
1022
|
+
"bg-white",
|
|
1023
|
+
"border-solid",
|
|
897
1024
|
"border",
|
|
898
1025
|
"border-slate-300",
|
|
899
|
-
"
|
|
900
|
-
"
|
|
901
|
-
"focus-within:ring-primary-600",
|
|
902
|
-
"focus-within:border-slate-400",
|
|
903
|
-
"hover:border-slate-400",
|
|
904
|
-
"hover:bg-slate-50",
|
|
905
|
-
"bg-white",
|
|
1026
|
+
"shadow-sm",
|
|
1027
|
+
"shrink-0",
|
|
906
1028
|
"transition",
|
|
1029
|
+
"box-border",
|
|
1030
|
+
"hover:cursor-pointer",
|
|
1031
|
+
"hover:bg-slate-100",
|
|
1032
|
+
"focus:ring-2",
|
|
1033
|
+
"focus:ring-inset",
|
|
1034
|
+
"focus:ring-blue-700",
|
|
907
1035
|
], {
|
|
908
1036
|
variants: {
|
|
1037
|
+
checked: {
|
|
1038
|
+
true: [
|
|
1039
|
+
"border-solid",
|
|
1040
|
+
"border-4",
|
|
1041
|
+
"border-blue-600",
|
|
1042
|
+
"bg-white",
|
|
1043
|
+
"hover:bg-slate-100",
|
|
1044
|
+
"hover:cursor-pointer",
|
|
1045
|
+
"outline-0",
|
|
1046
|
+
"active:bg-slate-200",
|
|
1047
|
+
"active:ring-2",
|
|
1048
|
+
"active:ring-inset",
|
|
1049
|
+
"active:ring-blue-700",
|
|
1050
|
+
"focus:bg-slate-200",
|
|
1051
|
+
"focus:ring-2",
|
|
1052
|
+
"focus:ring-inset",
|
|
1053
|
+
"focus:ring-blue-700",
|
|
1054
|
+
"group-active:ring-2",
|
|
1055
|
+
"group-active:ring-inset",
|
|
1056
|
+
"group-active:ring-blue-700",
|
|
1057
|
+
],
|
|
1058
|
+
false: "",
|
|
1059
|
+
},
|
|
909
1060
|
invalid: {
|
|
910
|
-
true:
|
|
1061
|
+
true: [
|
|
1062
|
+
"border-red-600",
|
|
1063
|
+
"active:ring-red-700",
|
|
1064
|
+
"focus:ring-red-700",
|
|
1065
|
+
"group-focus:ring-2",
|
|
1066
|
+
"group-focus:ring-inset",
|
|
1067
|
+
],
|
|
911
1068
|
false: "",
|
|
912
1069
|
},
|
|
913
1070
|
disabled: {
|
|
914
|
-
true:
|
|
1071
|
+
true: [
|
|
1072
|
+
"bg-slate-400",
|
|
1073
|
+
"border-slate-300",
|
|
1074
|
+
"cursor-not-allowed",
|
|
1075
|
+
"group-hover:bg-slate-400",
|
|
1076
|
+
"group-focus:bg-slate-400",
|
|
1077
|
+
"hover:bg-slate-400",
|
|
1078
|
+
"focus:bg-slate-400",
|
|
1079
|
+
"active:bg-slate-400",
|
|
1080
|
+
"focus:ring-0",
|
|
1081
|
+
"focus:ring-inset",
|
|
1082
|
+
"group-active:ring-0",
|
|
1083
|
+
"group-active:ring-inset",
|
|
1084
|
+
],
|
|
915
1085
|
false: "",
|
|
916
1086
|
},
|
|
917
1087
|
},
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
const cvaSelectIcon = cssClassVarianceUtilities.cvaMerge("mr-2 flex cursor-pointer items-center justify-center text-slate-400 hover:text-slate-500");
|
|
924
|
-
const cvaSelectPrefix = cssClassVarianceUtilities.cvaMerge(["flex", "justify-center", "items-center", "text-slate-400", "pl-2"]);
|
|
925
|
-
const cvaSelectXIcon = cssClassVarianceUtilities.cvaMerge([
|
|
926
|
-
"mr-2 flex cursor-pointer items-center justify-center text-slate-400 hover:text-slate-500",
|
|
927
|
-
"ml-1",
|
|
928
|
-
]);
|
|
929
|
-
const cvaSelectMenuList = cssClassVarianceUtilities.cvaMerge(["min-w-min", "shadow-md", "rounded-lg", "z-20", "bg-white", "p-1", "border", "border-slate-300", "gap-1", "grid"], {
|
|
930
|
-
variants: {
|
|
931
|
-
menuIsOpen: {
|
|
932
|
-
true: "animate-fade-in-fast",
|
|
933
|
-
false: "animate-fade-out-fast",
|
|
1088
|
+
compoundVariants: [
|
|
1089
|
+
{
|
|
1090
|
+
checked: true,
|
|
1091
|
+
disabled: true,
|
|
1092
|
+
className: ["bg-white"],
|
|
934
1093
|
},
|
|
935
|
-
|
|
1094
|
+
],
|
|
936
1095
|
});
|
|
937
|
-
const
|
|
1096
|
+
const cvaRadioItemWrapper = cssClassVarianceUtilities.cvaMerge(["flex", "gap-2", "items-center"]);
|
|
1097
|
+
const cvaRadioItemLabelContainer = cssClassVarianceUtilities.cvaMerge(["gap-y-1", "grid"]);
|
|
1098
|
+
const cvaRadioItemDescription = cssClassVarianceUtilities.cvaMerge(["text-sm", "font-normal", "text-slate-500", "text-left", "whitespace-nowrap", "text-ellipsis", "overflow-hidden"], {
|
|
938
1099
|
variants: {
|
|
939
|
-
|
|
1100
|
+
disabled: {
|
|
1101
|
+
true: ["text-slate-400", "hover:text-slate-400", "group-hover:text-slate-400"],
|
|
1102
|
+
false: "",
|
|
1103
|
+
},
|
|
940
1104
|
},
|
|
941
1105
|
});
|
|
942
|
-
|
|
943
|
-
const
|
|
1106
|
+
|
|
1107
|
+
const RadioGroupContext = React__namespace.createContext(null);
|
|
944
1108
|
|
|
945
1109
|
/**
|
|
946
|
-
*
|
|
947
|
-
*
|
|
1110
|
+
* Use radio buttons when you have a group of mutually exclusive choices and only one selection from the group is allowed.
|
|
1111
|
+
*
|
|
1112
|
+
* Radio buttons are used for mutually exclusive choices, not for multiple choices. Only one radio button can be selected at a time. When a user chooses a new item, the previous choice is automatically deselected.
|
|
1113
|
+
*
|
|
1114
|
+
* _**Do use** Radio buttons in forms, settings, or selections in a list._
|
|
1115
|
+
*
|
|
1116
|
+
* _**Do not use** Radio buttons if a user can select many option from a list, use checkboxes instead of radio buttons._
|
|
1117
|
+
*
|
|
1118
|
+
* @param {RadioGroupProps} props - The props for the RadioGroup component
|
|
1119
|
+
* @returns {JSX.Element} RadioGroup component
|
|
948
1120
|
*/
|
|
949
|
-
|
|
950
|
-
return
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
}
|
|
959
|
-
return isMultiValue(selected)
|
|
960
|
-
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
961
|
-
selected.some(v => v.value === option.value)
|
|
962
|
-
: // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
963
|
-
option.value === (selected === null || selected === void 0 ? void 0 : selected.value);
|
|
964
|
-
};
|
|
965
|
-
const removeSelectedFromGroups = (group, selected) => {
|
|
966
|
-
if (isGroupBase(group)) {
|
|
967
|
-
return Object.assign(Object.assign({}, group), { options: group.options.filter(option => !isSelectedOption(option, selected)) });
|
|
968
|
-
}
|
|
969
|
-
return group;
|
|
1121
|
+
const RadioGroup = ({ children, id, name, value, disabled, onChange, label, inline, className, dataTestId, isInvalid, }) => {
|
|
1122
|
+
return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId && `${dataTestId}-FormGroup`, label: label, children: jsxRuntime.jsx("div", { className: cvaRadioGroup({ layout: inline ? "inline" : null, className }), "data-testid": dataTestId, children: jsxRuntime.jsx(RadioGroupContext.Provider, { value: {
|
|
1123
|
+
id,
|
|
1124
|
+
value,
|
|
1125
|
+
name: name || id,
|
|
1126
|
+
onChange,
|
|
1127
|
+
disabled,
|
|
1128
|
+
isInvalid,
|
|
1129
|
+
}, children: children }) }) }));
|
|
970
1130
|
};
|
|
1131
|
+
RadioGroup.displayName = "RadioGroup";
|
|
1132
|
+
|
|
971
1133
|
/**
|
|
972
|
-
*
|
|
973
|
-
*
|
|
974
|
-
* @param {
|
|
975
|
-
* @
|
|
976
|
-
* @returns {OptionsOrGroups<Option, Group>} An array of ordered options with selected on top
|
|
1134
|
+
* The RadioItem component.
|
|
1135
|
+
*
|
|
1136
|
+
* @param {RadioItemProps} props - The props for the RadioItem component
|
|
1137
|
+
* @returns {JSX.Element} RadioItem component
|
|
977
1138
|
*/
|
|
978
|
-
const
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
.map(option => removeSelectedFromGroups(option, value));
|
|
987
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
988
|
-
return orderedValues.concat(selectableOptions) || [];
|
|
989
|
-
}
|
|
990
|
-
return options || [];
|
|
1139
|
+
const RadioItem = ({ label, value, dataTestId, className, description, }) => {
|
|
1140
|
+
const groupCtx = React__namespace.useContext(RadioGroupContext);
|
|
1141
|
+
const isChecked = (groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.value) === value;
|
|
1142
|
+
return (jsxRuntime.jsxs("label", { className: cvaRadioItemWrapper({ className }), "data-testid": dataTestId && `${dataTestId}-Wrapper`, htmlFor: `${groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.id}-${value}`, children: [jsxRuntime.jsx("input", { checked: isChecked, className: cvaRadioItem({
|
|
1143
|
+
checked: isChecked,
|
|
1144
|
+
disabled: groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.disabled,
|
|
1145
|
+
invalid: groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.isInvalid,
|
|
1146
|
+
}), "data-testid": dataTestId, id: `${groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.id}-${value}`, onChange: groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.onChange, type: "radio", value: value }), jsxRuntime.jsxs("div", { className: cvaRadioItemLabelContainer(), children: [jsxRuntime.jsx(Label, { dataTestId: dataTestId && `${dataTestId}-Label`, disabled: groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.disabled, htmlFor: `${groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.id}-${value}`, isInvalid: groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.isInvalid, children: label }), description && (jsxRuntime.jsx("label", { className: cvaRadioItemDescription({ disabled: groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.disabled }), "data-testid": dataTestId && `${dataTestId}-Description`, htmlFor: `${groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.id}-${value}`, children: description }))] })] }));
|
|
991
1147
|
};
|
|
992
1148
|
|
|
1149
|
+
const cvaTimeRange = cssClassVarianceUtilities.cvaMerge(["flex", "flex-1", "items-center", "gap-4", "border-transparent", "rounded-md"]);
|
|
1150
|
+
|
|
993
1151
|
/**
|
|
994
|
-
*
|
|
1152
|
+
* TimeRange is used to create a time range entry.
|
|
995
1153
|
*
|
|
996
|
-
* @param {
|
|
997
|
-
* @returns {JSX.Element}
|
|
1154
|
+
* @param {TimeRangeProps} props - The props for the TimeRange component
|
|
1155
|
+
* @returns {JSX.Element} TimeRange component
|
|
998
1156
|
*/
|
|
999
|
-
const
|
|
1000
|
-
|
|
1157
|
+
const TimeRange = ({ id, className, dataTestId, children, range, onChange, disabled, isInvalid, }) => {
|
|
1158
|
+
var _a, _b;
|
|
1159
|
+
const [timeRange, setTimeRange] = React__default["default"].useState(range !== null && range !== void 0 ? range : {
|
|
1160
|
+
timeFrom: "",
|
|
1161
|
+
timeTo: "",
|
|
1162
|
+
});
|
|
1163
|
+
const onChangeFrom = (timeFrom) => {
|
|
1164
|
+
setTimeRange(prev => (Object.assign(Object.assign({}, prev), { timeFrom })));
|
|
1165
|
+
};
|
|
1166
|
+
const onChangeTo = (timeTo) => {
|
|
1167
|
+
setTimeRange(prev => (Object.assign(Object.assign({}, prev), { timeTo })));
|
|
1168
|
+
};
|
|
1169
|
+
const onRangeChange = () => onChange(timeRange);
|
|
1170
|
+
return (jsxRuntime.jsxs("div", { className: cvaTimeRange({ className }), "data-testid": dataTestId, id: id, children: [jsxRuntime.jsx(BaseInput, { dataTestId: `${dataTestId}-from`, disabled: disabled, isInvalid: isInvalid, onBlur: onRangeChange, onChange: (time) => onChangeFrom(time.currentTarget.value), type: "time", value: (_a = timeRange === null || timeRange === void 0 ? void 0 : timeRange.timeFrom) !== null && _a !== void 0 ? _a : "" }), children !== null && children !== void 0 ? children : jsxRuntime.jsx("div", { "data-testid": `${dataTestId}-separator`, children: "-" }), jsxRuntime.jsx(BaseInput, { dataTestId: `${dataTestId}-to`, disabled: disabled, isInvalid: isInvalid, onBlur: onRangeChange, onChange: (time) => onChangeTo(time.currentTarget.value), type: "time", value: (_b = timeRange === null || timeRange === void 0 ? void 0 : timeRange.timeTo) !== null && _b !== void 0 ? _b : "" })] }));
|
|
1001
1171
|
};
|
|
1172
|
+
|
|
1173
|
+
const cvaScheduleItem = cssClassVarianceUtilities.cvaMerge(["grid", "pb-4", "gap-2", "grid-cols-[60px,200px,60px,2fr]"]);
|
|
1174
|
+
const cvaScheduleItemText = cssClassVarianceUtilities.cvaMerge(["flex", "font-bold", "self-center"]);
|
|
1175
|
+
|
|
1002
1176
|
/**
|
|
1003
|
-
*
|
|
1177
|
+
* Schedule is used to create a time range entries.
|
|
1004
1178
|
*
|
|
1005
|
-
* @param {
|
|
1006
|
-
* @returns {JSX.Element}
|
|
1179
|
+
* @param {ScheduleProps} props - The props for the Schedule component
|
|
1180
|
+
* @returns {JSX.Element} Schedule component
|
|
1007
1181
|
*/
|
|
1008
|
-
const
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1182
|
+
const Schedule = ({ className, dataTestId, schedule, onChange, invalidKeys = [] }) => {
|
|
1183
|
+
const onRangeChange = (range, index) => {
|
|
1184
|
+
const newSchedule = schedule.map((day, dayIndex) => (index === dayIndex ? Object.assign(Object.assign({}, day), { range: Object.assign({}, range) }) : day));
|
|
1185
|
+
onChange(newSchedule);
|
|
1186
|
+
};
|
|
1187
|
+
const onActiveChange = (isActive, index) => {
|
|
1188
|
+
const newSchedule = schedule.map((day, dayIndex) => index === dayIndex ? Object.assign(Object.assign({}, day), { range: { timeFrom: "", timeTo: "" }, isActive }) : day);
|
|
1189
|
+
onChange(newSchedule);
|
|
1190
|
+
};
|
|
1191
|
+
const onAllDayChange = (isAllDayChecked, index) => {
|
|
1192
|
+
const newSchedule = schedule.map((day, dayIndex) => index === dayIndex
|
|
1193
|
+
? Object.assign(Object.assign({}, day), { range: { timeFrom: "", timeTo: "" }, isAllDayActive: isAllDayChecked }) : day);
|
|
1194
|
+
onChange(newSchedule);
|
|
1195
|
+
};
|
|
1196
|
+
return (jsxRuntime.jsx("div", { className: className, "data-testid": dataTestId, children: schedule.map(({ label, range, isActive, key, checkboxLabel, isAllDayActive }, index) => {
|
|
1197
|
+
return (jsxRuntime.jsxs("div", { className: cvaScheduleItem(), children: [jsxRuntime.jsx(Checkbox, { checked: isActive, dataTestId: `${dataTestId}-${key}-checkbox`, label: checkboxLabel, onChange: (event) => onActiveChange(Boolean(event.currentTarget.checked), index) }), jsxRuntime.jsx(reactComponents.Text, { className: cvaScheduleItemText(), size: "medium", subtle: !isActive, children: label }), jsxRuntime.jsx(Checkbox, { checked: isAllDayActive && isActive, dataTestId: `${dataTestId}-${key}-allday-checkbox`, disabled: !isActive, onChange: (event) => onAllDayChange(Boolean(event.currentTarget.checked), index) }), jsxRuntime.jsx(TimeRange, { dataTestId: `${dataTestId}-${key}-range`, disabled: !isActive || isAllDayActive, isInvalid: !!invalidKeys.find((invalidKey) => invalidKey === key), onChange: (newRange) => onRangeChange(newRange, index), range: range })] }, key));
|
|
1198
|
+
}) }));
|
|
1015
1199
|
};
|
|
1016
1200
|
|
|
1201
|
+
const weekDay = {
|
|
1202
|
+
Monday: "monday",
|
|
1203
|
+
Tuesday: "tuesday",
|
|
1204
|
+
Wednesday: "wednesday",
|
|
1205
|
+
Thursday: "thursday",
|
|
1206
|
+
Friday: "friday",
|
|
1207
|
+
Saturday: "saturday",
|
|
1208
|
+
Sunday: "sunday",
|
|
1209
|
+
};
|
|
1210
|
+
exports.ScheduleVariant = void 0;
|
|
1211
|
+
(function (ScheduleVariant) {
|
|
1212
|
+
ScheduleVariant["ALL_DAYS"] = "all";
|
|
1213
|
+
ScheduleVariant["WEEKDAYS"] = "week";
|
|
1214
|
+
ScheduleVariant["CUSTOM"] = "custom";
|
|
1215
|
+
})(exports.ScheduleVariant || (exports.ScheduleVariant = {}));
|
|
1017
1216
|
/**
|
|
1018
|
-
*
|
|
1019
|
-
* Used in the select component.
|
|
1217
|
+
* Parse a string of week range schedule string to human readable schedule range.
|
|
1020
1218
|
*
|
|
1021
|
-
* @param {
|
|
1022
|
-
* @returns {
|
|
1219
|
+
* @param {string} scheduleString String of week schedule
|
|
1220
|
+
* @returns {WeekSchedule} Week schedule range
|
|
1023
1221
|
*/
|
|
1024
|
-
const
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1222
|
+
const parseSchedule = (scheduleString) => {
|
|
1223
|
+
if (!scheduleString) {
|
|
1224
|
+
return {
|
|
1225
|
+
variant: exports.ScheduleVariant.ALL_DAYS,
|
|
1226
|
+
schedule: [],
|
|
1227
|
+
};
|
|
1228
|
+
}
|
|
1229
|
+
const schedule = scheduleString.split(",").map(daySchedule => {
|
|
1230
|
+
const [day, timeRange] = daySchedule.split("#");
|
|
1231
|
+
const [timeFrom, timeTo] = timeRange.split("-");
|
|
1232
|
+
const isAllDay = timeFrom === "00:00" && timeTo === "24:00";
|
|
1233
|
+
return {
|
|
1234
|
+
day: Number(day),
|
|
1235
|
+
range: isAllDay
|
|
1236
|
+
? undefined
|
|
1237
|
+
: {
|
|
1238
|
+
timeFrom,
|
|
1239
|
+
timeTo,
|
|
1240
|
+
},
|
|
1241
|
+
isAllDay,
|
|
1242
|
+
};
|
|
1243
|
+
});
|
|
1244
|
+
const filteredSchedule = schedule
|
|
1245
|
+
.filter(daySchedule => daySchedule.range !== null && daySchedule.range !== undefined)
|
|
1246
|
+
.map(daySchedule => ({ day: daySchedule.day, range: daySchedule.range, isAllDay: daySchedule.isAllDay }));
|
|
1247
|
+
let variant;
|
|
1248
|
+
switch (schedule.length) {
|
|
1249
|
+
case 7:
|
|
1250
|
+
const areEqual = schedule.every((day, _, collection) => {
|
|
1251
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1252
|
+
return ((_b = (_a = collection === null || collection === void 0 ? void 0 : collection[0]) === null || _a === void 0 ? void 0 : _a.range) === null || _b === void 0 ? void 0 : _b.timeFrom) === ((_c = day === null || day === void 0 ? void 0 : day.range) === null || _c === void 0 ? void 0 : _c.timeFrom) &&
|
|
1253
|
+
((_e = (_d = collection === null || collection === void 0 ? void 0 : collection[0]) === null || _d === void 0 ? void 0 : _d.range) === null || _e === void 0 ? void 0 : _e.timeTo) === ((_f = day === null || day === void 0 ? void 0 : day.range) === null || _f === void 0 ? void 0 : _f.timeTo);
|
|
1254
|
+
});
|
|
1255
|
+
if (areEqual) {
|
|
1256
|
+
variant = exports.ScheduleVariant.ALL_DAYS;
|
|
1257
|
+
}
|
|
1258
|
+
else {
|
|
1259
|
+
variant = exports.ScheduleVariant.CUSTOM;
|
|
1260
|
+
}
|
|
1261
|
+
break;
|
|
1262
|
+
case 5:
|
|
1263
|
+
const days = [1, 2, 3, 4, 5];
|
|
1264
|
+
const hasConsecutiveDays = schedule.every(({ day }, index) => day === days[index]);
|
|
1265
|
+
if (hasConsecutiveDays) {
|
|
1266
|
+
variant = exports.ScheduleVariant.WEEKDAYS;
|
|
1267
|
+
}
|
|
1268
|
+
else {
|
|
1269
|
+
variant = exports.ScheduleVariant.CUSTOM;
|
|
1270
|
+
}
|
|
1271
|
+
break;
|
|
1272
|
+
default:
|
|
1273
|
+
return {
|
|
1274
|
+
variant: exports.ScheduleVariant.CUSTOM,
|
|
1275
|
+
schedule: filteredSchedule,
|
|
1276
|
+
};
|
|
1277
|
+
}
|
|
1278
|
+
return {
|
|
1279
|
+
variant,
|
|
1280
|
+
schedule: filteredSchedule,
|
|
1281
|
+
};
|
|
1032
1282
|
};
|
|
1033
|
-
|
|
1034
1283
|
/**
|
|
1035
|
-
*
|
|
1284
|
+
* Serialize week schedule to string schedule
|
|
1036
1285
|
*
|
|
1037
|
-
* @param {
|
|
1038
|
-
* @returns {
|
|
1286
|
+
* @param {WeekSchedule} weekSchedule Week schedule range
|
|
1287
|
+
* @returns {string} Schedule string
|
|
1039
1288
|
*/
|
|
1040
|
-
const
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
childrenWidth.current.push({ width: reportedWidth + itemsGap });
|
|
1053
|
-
if (childrenWidth.current.length === itemsCount) {
|
|
1054
|
-
setIsReady(true);
|
|
1055
|
-
}
|
|
1056
|
-
};
|
|
1057
|
-
const requiredSpace = childrenWidth.current.reduce((previous, current) => {
|
|
1058
|
-
return previous + current.width;
|
|
1059
|
-
}, 0);
|
|
1060
|
-
let counter = 0;
|
|
1061
|
-
const availableSpace = ((availableWidth === null || availableWidth === void 0 ? void 0 : availableWidth.current) || 0) - counterWidth;
|
|
1062
|
-
const renderedElements = items
|
|
1063
|
-
.concat({ text: "", onClick: () => null, disabled: false }) // reserved element for a potential counter
|
|
1064
|
-
.map((item, index) => {
|
|
1065
|
-
const spaceNeeded = childrenWidth.current.slice(0, index + 1).reduce((previous, current) => {
|
|
1066
|
-
return previous + current.width;
|
|
1067
|
-
}, 0);
|
|
1068
|
-
const isLast = index === items.length;
|
|
1069
|
-
const counterRequired = requiredSpace > availableSpace && counter !== 0;
|
|
1070
|
-
if (isLast && counterRequired) {
|
|
1071
|
-
return (jsxRuntime.jsx(TagWithWidth, { color: "white", disabled: disabled, onWidthKnown: ({ width: reportedWidth }) => setCounterWidth(reportedWidth), children: jsxRuntime.jsxs("div", { className: cvaSelectCounter(), "data-testid": "select-counter", children: ["+", counter] }) }, item.text + index));
|
|
1072
|
-
}
|
|
1073
|
-
if (isLast) {
|
|
1074
|
-
return null;
|
|
1075
|
-
}
|
|
1076
|
-
const itemCanFit = spaceNeeded <= availableSpace;
|
|
1077
|
-
if (itemCanFit) {
|
|
1078
|
-
return (jsxRuntime.jsx(TagWithWidth, { className: "inline-flex shrink-0", color: item.disabled ? "unknown" : "primary", dataTestId: `${item.text}-tag`, disabled: disabled, onClose: e => {
|
|
1079
|
-
e.stopPropagation();
|
|
1080
|
-
item.onClick();
|
|
1081
|
-
}, onWidthKnown: onWidthKnownHandler, children: item.text }, item.text + index));
|
|
1289
|
+
const serializeSchedule = (weekSchedule) => {
|
|
1290
|
+
return weekSchedule.schedule
|
|
1291
|
+
.filter(({ range, day, isAllDay }) => {
|
|
1292
|
+
const hasRange = (range === null || range === void 0 ? void 0 : range.timeFrom) && (range === null || range === void 0 ? void 0 : range.timeTo);
|
|
1293
|
+
switch (weekSchedule.variant) {
|
|
1294
|
+
case exports.ScheduleVariant.WEEKDAYS:
|
|
1295
|
+
return day <= 5 && hasRange;
|
|
1296
|
+
case exports.ScheduleVariant.ALL_DAYS:
|
|
1297
|
+
return day <= 7 && hasRange;
|
|
1298
|
+
case exports.ScheduleVariant.CUSTOM:
|
|
1299
|
+
default:
|
|
1300
|
+
return hasRange || isAllDay;
|
|
1082
1301
|
}
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1302
|
+
})
|
|
1303
|
+
.map(({ day, range, isAllDay }) => {
|
|
1304
|
+
if (isAllDay) {
|
|
1305
|
+
return `${day}#00:00-24:00`;
|
|
1086
1306
|
}
|
|
1087
|
-
return
|
|
1307
|
+
return `${day}#${range.timeFrom}-${range.timeTo}`;
|
|
1088
1308
|
})
|
|
1089
|
-
.
|
|
1090
|
-
return (jsxRuntime.jsxs("div", { className: cvaSelectDynamicTagContainer({ visible: isReady }), ref: containerRef, style: {
|
|
1091
|
-
width: `${width}`,
|
|
1092
|
-
}, children: [renderedElements, postFix] }));
|
|
1309
|
+
.join(",");
|
|
1093
1310
|
};
|
|
1094
1311
|
|
|
1095
1312
|
/**
|
|
1096
|
-
* A
|
|
1097
|
-
* This complex object includes all the compositional components that are used in react-select. If you wish to overwrite a component, pass in an object with the appropriate namespace.
|
|
1313
|
+
* A thin wrapper around the `BaseInput` component for text input fields.
|
|
1098
1314
|
*
|
|
1099
|
-
*
|
|
1100
|
-
* @template Group
|
|
1101
|
-
* @param {Partial<SelectComponents<Option, IsMulti, Group>> | undefined} componentsProps a custom component prop that you can to override defaults
|
|
1102
|
-
* @param {boolean} disabled decide to override disabled variant
|
|
1103
|
-
* @param {boolean} menuIsOpen menu is open state
|
|
1104
|
-
* @param {React.MutableRefObject<boolean>} refMenuIsEnabled a flag to block menu from open
|
|
1105
|
-
* @param {string} dataTestId a test id
|
|
1106
|
-
* @param {number} maxSelectedDisplayCount a number of max display count
|
|
1107
|
-
* @param {JSX.Element} dropdownIcon an custom dropdown icon
|
|
1108
|
-
* @returns {Partial<SelectComponents<Option, boolean, GroupBase<Option>>> | undefined} components object to override react-select default components
|
|
1109
|
-
*/
|
|
1110
|
-
const useCustomComponents = (componentsProps, disabled, menuIsOpen, refMenuIsEnabled, dataTestId, maxSelectedDisplayCount, dropdownIcon) => {
|
|
1111
|
-
const [t] = useTranslation();
|
|
1112
|
-
// perhaps it should not be wrap in memo (causing some issues with opening and closing on mobiles)
|
|
1113
|
-
const customComponents = React__namespace.useMemo(() => {
|
|
1114
|
-
return Object.assign({ ValueContainer: props => {
|
|
1115
|
-
if (props.isMulti && Array.isArray(props.children) && props.children.length > 0) {
|
|
1116
|
-
const PLACEHOLDER_KEY = "placeholder";
|
|
1117
|
-
const key = props && props.children && props.children[0] ? props.children[0].key : "";
|
|
1118
|
-
const values = props && props.children ? props.children[0] : [];
|
|
1119
|
-
const tags = key === PLACEHOLDER_KEY ? [] : values;
|
|
1120
|
-
const searchInput = props && props.children && props.children[1];
|
|
1121
|
-
return (jsxRuntime.jsx(ReactSelect.components.ValueContainer, Object.assign({}, props, { isDisabled: props.selectProps.isDisabled, children: maxSelectedDisplayCount === undefined ? (jsxRuntime.jsx(TagsContainer, { disabled: disabled, items: tags
|
|
1122
|
-
? tags.map(({ props: tagProps }) => {
|
|
1123
|
-
return {
|
|
1124
|
-
text: tagProps.children,
|
|
1125
|
-
onClick: disabled
|
|
1126
|
-
? undefined
|
|
1127
|
-
: (e) => {
|
|
1128
|
-
var _a, _b;
|
|
1129
|
-
refMenuIsEnabled.current = false;
|
|
1130
|
-
((_a = tagProps === null || tagProps === void 0 ? void 0 : tagProps.removeProps) === null || _a === void 0 ? void 0 : _a.onClick) && ((_b = tagProps === null || tagProps === void 0 ? void 0 : tagProps.removeProps) === null || _b === void 0 ? void 0 : _b.onClick(e));
|
|
1131
|
-
},
|
|
1132
|
-
disabled: disabled,
|
|
1133
|
-
};
|
|
1134
|
-
})
|
|
1135
|
-
: [], postFix: searchInput, width: "100%" })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [tags &&
|
|
1136
|
-
tags.slice(0, maxSelectedDisplayCount).map(({ props: tagProps }) => {
|
|
1137
|
-
var _a, _b;
|
|
1138
|
-
return (jsxRuntime.jsx(reactComponents.Tag, { className: "inline-flex shrink-0", color: disabled ? "unknown" : "primary", dataTestId: tagProps.children ? `${(_a = tagProps.children) === null || _a === void 0 ? void 0 : _a.toString()}-tag` : undefined, onClose: e => {
|
|
1139
|
-
var _a, _b;
|
|
1140
|
-
e.stopPropagation();
|
|
1141
|
-
refMenuIsEnabled.current = false;
|
|
1142
|
-
((_a = tagProps === null || tagProps === void 0 ? void 0 : tagProps.removeProps) === null || _a === void 0 ? void 0 : _a.onClick) && ((_b = tagProps === null || tagProps === void 0 ? void 0 : tagProps.removeProps) === null || _b === void 0 ? void 0 : _b.onClick(e));
|
|
1143
|
-
}, children: tagProps.children }, (_b = tagProps.children) === null || _b === void 0 ? void 0 : _b.toString()));
|
|
1144
|
-
}), tags && tags.length > maxSelectedDisplayCount && (jsxRuntime.jsxs(reactComponents.Tag, { color: "neutral", dataTestId: "counter-tag", children: ["+", tags.length - maxSelectedDisplayCount] })), searchInput] })) })));
|
|
1145
|
-
}
|
|
1146
|
-
return (jsxRuntime.jsx(ReactSelect.components.ValueContainer, Object.assign({}, props, { isDisabled: props.selectProps.isDisabled, children: props.children })));
|
|
1147
|
-
}, LoadingIndicator: props => {
|
|
1148
|
-
return jsxRuntime.jsx(reactComponents.Spinner, { className: "mt-1.5 mr-1", size: "small" });
|
|
1149
|
-
}, DropdownIndicator: props => {
|
|
1150
|
-
const icon = props.selectProps.menuIsOpen ? (jsxRuntime.jsx(reactComponents.Icon, { name: "ChevronUp", size: "medium" })) : (jsxRuntime.jsx(reactComponents.Icon, { name: "ChevronDown", size: "medium" }));
|
|
1151
|
-
return props.selectProps.isLoading ? null : (jsxRuntime.jsx(ReactSelect.components.DropdownIndicator, Object.assign({}, props, { children: jsxRuntime.jsx("div", { className: cvaSelectIcon(), children: dropdownIcon ? dropdownIcon : icon }) })));
|
|
1152
|
-
}, IndicatorSeparator: () => null, ClearIndicator: props => {
|
|
1153
|
-
if (disabled) {
|
|
1154
|
-
return null;
|
|
1155
|
-
}
|
|
1156
|
-
return (jsxRuntime.jsx(ReactSelect.components.ClearIndicator, Object.assign({}, props, { children: jsxRuntime.jsx("div", { className: cvaSelectXIcon(), "data-testid": dataTestId && `${dataTestId}-XMarkIcon`, onClick: props.clearValue, children: jsxRuntime.jsx(reactComponents.Icon, { name: "XCircle", size: "medium", title: t("clearIndicator.icon.tooltip.clearAll") }) }) })));
|
|
1157
|
-
}, Control: props => {
|
|
1158
|
-
return jsxRuntime.jsx(ReactSelect.components.Control, Object.assign({}, props, { className: props.isDisabled ? "bg-slate-100" : "" }));
|
|
1159
|
-
}, SingleValue: props => {
|
|
1160
|
-
return (jsxRuntime.jsx(ReactSelect.components.SingleValue, Object.assign({}, props, { className: props.isDisabled ? "text-slate-700" : "", children: jsxRuntime.jsx("div", { "data-testid": dataTestId + "-singleValue", children: props.children }) })));
|
|
1161
|
-
}, Menu: props => {
|
|
1162
|
-
return (jsxRuntime.jsx(ReactSelect.components.Menu, Object.assign({}, props, { className: cvaSelectMenuList({ menuIsOpen: props.selectProps.menuIsOpen }) })));
|
|
1163
|
-
}, Placeholder: props => {
|
|
1164
|
-
return (jsxRuntime.jsx(ReactSelect.components.Placeholder, Object.assign({}, props, { className: "!text-slate-400", children: props.children })));
|
|
1165
|
-
}, MenuList: props => {
|
|
1166
|
-
return (jsxRuntime.jsx(ReactSelect.components.MenuList, Object.assign({}, props, { innerProps: Object.assign(Object.assign({}, props.innerProps), { onScroll: e => {
|
|
1167
|
-
const listEl = e.currentTarget;
|
|
1168
|
-
if (listEl.scrollTop + listEl.clientHeight >= listEl.scrollHeight) {
|
|
1169
|
-
props.selectProps.onMenuScrollToBottom && props.selectProps.onMenuScrollToBottom(new TouchEvent(""));
|
|
1170
|
-
}
|
|
1171
|
-
} }), children: props.children })));
|
|
1172
|
-
}, Option: props => {
|
|
1173
|
-
const componentProps = {
|
|
1174
|
-
label: props.label,
|
|
1175
|
-
focused: props.isFocused,
|
|
1176
|
-
selected: props.isSelected,
|
|
1177
|
-
onClick: props.innerProps.onClick,
|
|
1178
|
-
};
|
|
1179
|
-
return (jsxRuntime.jsx(ReactSelect.components.Option, Object.assign({}, props, { innerProps: Object.assign(Object.assign({}, props.innerProps), { role: "option", onClick: () => { } }), children: props.isMulti ? (jsxRuntime.jsx(MultiSelectMenuItem, Object.assign({}, componentProps, { dataTestId: typeof props.label === "string" ? props.label : undefined, disabled: disabled }))) : (jsxRuntime.jsx(SingleSelectMenuItem, Object.assign({}, componentProps, { dataTestId: typeof props.label === "string" ? props.label : undefined, disabled: disabled || props.isDisabled }))) })));
|
|
1180
|
-
} }, componentsProps);
|
|
1181
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1182
|
-
}, [componentsProps, disabled, maxSelectedDisplayCount]); // do not add dropdownIcon (it will cause issue with opening/closing list for selects with custom icon)
|
|
1183
|
-
return customComponents;
|
|
1184
|
-
};
|
|
1185
|
-
|
|
1186
|
-
/**
|
|
1187
|
-
* @template IsMulti
|
|
1188
|
-
* @template Group
|
|
1189
|
-
* @param {React.RefObject<HTMLDivElement>} refContainer react ref to container element
|
|
1190
|
-
* @param {React.RefObject<HTMLDivElement>} refPrefix react ref to prefix element
|
|
1191
|
-
* @param {number | undefined} maxSelectedDisplayCount a number of max display count
|
|
1192
|
-
* @param {StylesConfig<Option, IsMulti, Group> | undefined} styles a optional object to override styles of react-select
|
|
1193
|
-
* @returns {StylesConfig<Option, boolean>} styles to override in select
|
|
1194
|
-
*/
|
|
1195
|
-
const useCustomStyles = (refContainer, refPrefix, maxSelectedDisplayCount, styles, disabled) => {
|
|
1196
|
-
const customStyles = React__namespace.useMemo(() => {
|
|
1197
|
-
return Object.assign({ control: base => {
|
|
1198
|
-
return Object.assign(Object.assign({}, base), { border: "0", boxShadow: "0", "&:hover": {
|
|
1199
|
-
border: "0",
|
|
1200
|
-
}, marginRight: "2px", backgroundColor: "" });
|
|
1201
|
-
}, singleValue: base => (Object.assign({}, base)), multiValue: base => (Object.assign({}, base)), multiValueLabel: base => (Object.assign({}, base)), indicatorsContainer: base => (Object.assign(Object.assign({}, base), (disabled && { display: "none" }))), indicatorSeparator: () => ({
|
|
1202
|
-
width: "0px",
|
|
1203
|
-
}), menu: base => {
|
|
1204
|
-
return Object.assign(Object.assign({}, base), { width: "100%", marginTop: "4px", marginBottom: "18px", transition: "all 1s ease-in-out" });
|
|
1205
|
-
}, input: base => (Object.assign(Object.assign({}, base), { marginLeft: "0px" })), placeholder: base => (Object.assign({}, base)), option: () => ({}), menuPortal: base => (Object.assign(Object.assign({}, base), { width: (refContainer === null || refContainer === void 0 ? void 0 : refContainer.current) ? `${refContainer.current.clientWidth}px` : base.width, transform: (refPrefix === null || refPrefix === void 0 ? void 0 : refPrefix.current) ? `translate(-${refPrefix.current.clientWidth + 2}px)` : "translate(-2px)", backgroundColor: "#ffffff", borderRadius: "var(--border-radius-lg)", zIndex: 20, borderColor: "rgb(var(--color-slate-300))", boxShadow: "var(--tw-ring-inset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)" })), menuList: base => {
|
|
1206
|
-
return Object.assign(Object.assign({}, base), { position: "relative", padding: "var(--spacing-1)", display: "grid", gap: "var(--spacing-1)", width: "100%", borderRadius: "0px", boxShadow: "none", paddingTop: "0px" });
|
|
1207
|
-
}, valueContainer: base => {
|
|
1208
|
-
return Object.assign(Object.assign({}, base), { flexWrap: maxSelectedDisplayCount !== undefined ? "wrap" : "nowrap", gap: "0.25rem" });
|
|
1209
|
-
}, container: base => (Object.assign(Object.assign({}, base), { border: "none", width: "calc(100% - 2px)", paddingLeft: "2px" })), dropdownIndicator: base => (Object.assign(Object.assign({}, base), { padding: "0px" })), clearIndicator: base => {
|
|
1210
|
-
return Object.assign(Object.assign({}, base), { padding: "0px" });
|
|
1211
|
-
} }, styles);
|
|
1212
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1213
|
-
}, [refContainer, refPrefix]);
|
|
1214
|
-
return { customStyles };
|
|
1215
|
-
};
|
|
1216
|
-
|
|
1217
|
-
/**
|
|
1218
|
-
* A hook used by selects to share the common code
|
|
1219
|
-
*
|
|
1220
|
-
* @param {SelectProps} props - The props for the Select component
|
|
1221
|
-
* @returns {IUseSelect} Select component
|
|
1222
|
-
*/
|
|
1223
|
-
const useSelect = (_a) => {
|
|
1224
|
-
var _b;
|
|
1225
|
-
var { id, className, dataTestId = "select", prefix, async, dropdownIcon, maxMenuHeight = 200, label, hasError, disabled, isMulti, components, value, options, onChange, isLoading, classNamePrefix = "", onMenuOpen, onMenuClose, maxSelectedDisplayCount = undefined, isClearable = false, isSearchable = true, onMenuScrollToBottom, styles, filterOption, onInputChange } = _a, props = __rest(_a, ["id", "className", "dataTestId", "prefix", "async", "dropdownIcon", "maxMenuHeight", "label", "hasError", "disabled", "isMulti", "components", "value", "options", "onChange", "isLoading", "classNamePrefix", "onMenuOpen", "onMenuClose", "maxSelectedDisplayCount", "isClearable", "isSearchable", "onMenuScrollToBottom", "styles", "filterOption", "onInputChange"]);
|
|
1226
|
-
const refContainer = React__default["default"].useRef(null);
|
|
1227
|
-
const refPrefix = React__default["default"].useRef(null);
|
|
1228
|
-
const { customStyles } = useCustomStyles(refContainer, refPrefix, maxSelectedDisplayCount, styles, disabled);
|
|
1229
|
-
const [menuIsOpen, setMenuIsOpen] = React__default["default"].useState((_b = props.menuIsOpen) !== null && _b !== void 0 ? _b : false);
|
|
1230
|
-
const refMenuIsEnabled = React__default["default"].useRef(true);
|
|
1231
|
-
const customComponents = useCustomComponents(components, disabled || false, menuIsOpen, refMenuIsEnabled, dataTestId, maxSelectedDisplayCount, dropdownIcon);
|
|
1232
|
-
const menuPlacement = "auto";
|
|
1233
|
-
const openMenuHandler = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
1234
|
-
onMenuOpen && onMenuOpen();
|
|
1235
|
-
if (refMenuIsEnabled.current) {
|
|
1236
|
-
setMenuIsOpen(true);
|
|
1237
|
-
}
|
|
1238
|
-
else {
|
|
1239
|
-
refMenuIsEnabled.current = true;
|
|
1240
|
-
}
|
|
1241
|
-
});
|
|
1242
|
-
const closeMenuHandler = () => {
|
|
1243
|
-
setMenuIsOpen(false);
|
|
1244
|
-
onMenuClose && onMenuClose();
|
|
1245
|
-
};
|
|
1246
|
-
const orderedOptions = React__default["default"].useMemo(() => {
|
|
1247
|
-
return disabled
|
|
1248
|
-
? getOrderedOptions(options, value).map(option => {
|
|
1249
|
-
return Object.assign(Object.assign({}, option), { disabled: true });
|
|
1250
|
-
})
|
|
1251
|
-
: getOrderedOptions(options, value);
|
|
1252
|
-
}, [options, value, disabled]);
|
|
1253
|
-
return {
|
|
1254
|
-
refContainer,
|
|
1255
|
-
refPrefix,
|
|
1256
|
-
customStyles,
|
|
1257
|
-
menuIsOpen,
|
|
1258
|
-
customComponents,
|
|
1259
|
-
menuPlacement,
|
|
1260
|
-
openMenuHandler,
|
|
1261
|
-
closeMenuHandler,
|
|
1262
|
-
orderedOptions,
|
|
1263
|
-
};
|
|
1264
|
-
};
|
|
1265
|
-
|
|
1266
|
-
/**
|
|
1267
|
-
* CreatableSelects are input components used to choose a value from a set.
|
|
1268
|
-
*
|
|
1269
|
-
* @param {CreatableSelectProps} props - The props for the CreatableSelect component
|
|
1270
|
-
* @returns {JSX.Element} CreatableSelect component
|
|
1271
|
-
*/
|
|
1272
|
-
const CreatableSelect = (props) => {
|
|
1273
|
-
const { className } = props, propsNoClassName = __rest(props, ["className"]);
|
|
1274
|
-
const { id, dataTestId = "creatableSelect", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, value, options, onChange, isLoading, classNamePrefix = dataTestId !== null && dataTestId !== void 0 ? dataTestId : "creatableSelect", onMenuScrollToBottom, filterOption, onInputChange, isSearchable, isClearable = false, readOnly, openMenuOnClick = !disabled, openMenuOnFocus = !disabled, allowCreateWhileLoading, onCreateOption, } = propsNoClassName;
|
|
1275
|
-
const { refContainer, refPrefix, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler, orderedOptions, } = useSelect(props);
|
|
1276
|
-
const creatableSelectProps = {
|
|
1277
|
-
value,
|
|
1278
|
-
menuPlacement,
|
|
1279
|
-
maxMenuHeight,
|
|
1280
|
-
onChange,
|
|
1281
|
-
"aria-label": label,
|
|
1282
|
-
"data-testid": dataTestId,
|
|
1283
|
-
components: customComponents,
|
|
1284
|
-
styles: customStyles,
|
|
1285
|
-
tabSelectsValue: false,
|
|
1286
|
-
blurInputOnSelect: !isMulti,
|
|
1287
|
-
menuPortalTarget: props.menuPortalTarget || document.body,
|
|
1288
|
-
isSearchable: disabled || readOnly ? false : isSearchable,
|
|
1289
|
-
menuShouldBlockScroll: true,
|
|
1290
|
-
menuShouldScrollIntoView: true,
|
|
1291
|
-
openMenuOnFocus,
|
|
1292
|
-
menuIsOpen: !readOnly ? menuIsOpen : false,
|
|
1293
|
-
openMenuOnClick,
|
|
1294
|
-
closeMenuOnSelect: false,
|
|
1295
|
-
isMulti,
|
|
1296
|
-
classNamePrefix,
|
|
1297
|
-
isLoading,
|
|
1298
|
-
isClearable,
|
|
1299
|
-
id,
|
|
1300
|
-
onMenuScrollToBottom,
|
|
1301
|
-
onInputChange,
|
|
1302
|
-
allowCreateWhileLoading,
|
|
1303
|
-
onCreateOption,
|
|
1304
|
-
};
|
|
1305
|
-
return (jsxRuntime.jsxs("div", { className: cvaSelect({ invalid: hasError, disabled: disabled || readOnly, className }), "data-testid": dataTestId, ref: refContainer, children: [prefix !== undefined && (jsxRuntime.jsx("div", { className: cvaSelectPrefix(), "data-testid": dataTestId && `${dataTestId}-prefix`, ref: refPrefix, children: prefix })), async ? (jsxRuntime.jsx(ReactAsyncCreatableSelect__default["default"], Object.assign({}, propsNoClassName, creatableSelectProps, async, { onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler }))) : (jsxRuntime.jsx(ReactCreatableSelect__default["default"], Object.assign({}, propsNoClassName, creatableSelectProps, { hideSelectedOptions: false, isMulti: isMulti, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, options: filterOption ? orderedOptions : options })))] }));
|
|
1306
|
-
};
|
|
1307
|
-
CreatableSelect.displayName = "CreatableSelect";
|
|
1308
|
-
|
|
1309
|
-
/**
|
|
1310
|
-
* Selects are input components used to choose a value from a set.
|
|
1311
|
-
*
|
|
1312
|
-
* @param {SelectProps} props - The props for the Select component
|
|
1313
|
-
* @returns {JSX.Element} Select component
|
|
1314
|
-
*/
|
|
1315
|
-
const Select = (props) => {
|
|
1316
|
-
const { className } = props, propsNoClassName = __rest(props, ["className"]);
|
|
1317
|
-
const { id, dataTestId = "select", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, value, options, onChange, isLoading, classNamePrefix = dataTestId !== null && dataTestId !== void 0 ? dataTestId : "select", onMenuScrollToBottom, filterOption, onInputChange, isSearchable, isClearable = false, readOnly, openMenuOnClick = !disabled, openMenuOnFocus = !disabled, } = props;
|
|
1318
|
-
const { refContainer, refPrefix, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler, orderedOptions, } = useSelect(props);
|
|
1319
|
-
const selectProps = {
|
|
1320
|
-
value,
|
|
1321
|
-
menuPlacement,
|
|
1322
|
-
maxMenuHeight,
|
|
1323
|
-
onChange,
|
|
1324
|
-
"aria-label": label,
|
|
1325
|
-
"data-testid": dataTestId,
|
|
1326
|
-
components: customComponents,
|
|
1327
|
-
styles: customStyles,
|
|
1328
|
-
tabSelectsValue: false,
|
|
1329
|
-
blurInputOnSelect: !isMulti,
|
|
1330
|
-
menuPortalTarget: props.menuPortalTarget || document.body,
|
|
1331
|
-
isSearchable: disabled || readOnly ? false : isSearchable,
|
|
1332
|
-
menuShouldBlockScroll: true,
|
|
1333
|
-
menuShouldScrollIntoView: true,
|
|
1334
|
-
openMenuOnFocus,
|
|
1335
|
-
menuIsOpen: !readOnly ? menuIsOpen : false,
|
|
1336
|
-
openMenuOnClick,
|
|
1337
|
-
closeMenuOnSelect: false,
|
|
1338
|
-
isMulti,
|
|
1339
|
-
classNamePrefix,
|
|
1340
|
-
isLoading,
|
|
1341
|
-
isClearable,
|
|
1342
|
-
id,
|
|
1343
|
-
onMenuScrollToBottom,
|
|
1344
|
-
onInputChange,
|
|
1345
|
-
};
|
|
1346
|
-
return (jsxRuntime.jsxs("div", { className: cvaSelect({ invalid: hasError, disabled: disabled || readOnly, className }), "data-testid": dataTestId, ref: refContainer, children: [prefix !== undefined && (jsxRuntime.jsx("div", { className: cvaSelectPrefix(), "data-testid": dataTestId && `${dataTestId}-prefix`, ref: refPrefix, children: prefix })), async ? (jsxRuntime.jsx(ReactAsyncSelect__default["default"], Object.assign({}, propsNoClassName, selectProps, async, { onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler }))) : (jsxRuntime.jsx(ReactSelect__default["default"], Object.assign({}, propsNoClassName, selectProps, { hideSelectedOptions: false, isMulti: isMulti, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, options: filterOption ? orderedOptions : options })))] }));
|
|
1347
|
-
};
|
|
1348
|
-
Select.displayName = "Select";
|
|
1349
|
-
|
|
1350
|
-
const COUNTRY_CODES_NOT_SUPPORTED_BY_BACKEND = ["+53", "+98", "+211", "+247", "+249", "+383", "+850", "+963"];
|
|
1351
|
-
const ADDITIONAL_COUNTRY_CODES_SUPPORTED_BY_BACKEND = [
|
|
1352
|
-
"1242",
|
|
1353
|
-
"1246",
|
|
1354
|
-
"1264",
|
|
1355
|
-
"1268",
|
|
1356
|
-
"1284",
|
|
1357
|
-
"1340",
|
|
1358
|
-
"1345",
|
|
1359
|
-
"1441",
|
|
1360
|
-
"1473",
|
|
1361
|
-
"1649",
|
|
1362
|
-
"1664",
|
|
1363
|
-
"1670",
|
|
1364
|
-
"1671",
|
|
1365
|
-
"1684",
|
|
1366
|
-
"1721",
|
|
1367
|
-
"1758",
|
|
1368
|
-
"1767",
|
|
1369
|
-
"1784",
|
|
1370
|
-
"1809",
|
|
1371
|
-
"1868",
|
|
1372
|
-
"1869",
|
|
1373
|
-
"1876",
|
|
1374
|
-
"379",
|
|
1375
|
-
"5999",
|
|
1376
|
-
"881",
|
|
1377
|
-
"882",
|
|
1378
|
-
"883",
|
|
1379
|
-
];
|
|
1380
|
-
const DUPLICATE_COUNTRY_CODES = [
|
|
1381
|
-
// +1
|
|
1382
|
-
"AG",
|
|
1383
|
-
"AI",
|
|
1384
|
-
"AS",
|
|
1385
|
-
"BB",
|
|
1386
|
-
"BM",
|
|
1387
|
-
"BS",
|
|
1388
|
-
"CA",
|
|
1389
|
-
"DM",
|
|
1390
|
-
"DO",
|
|
1391
|
-
"GD",
|
|
1392
|
-
"GU",
|
|
1393
|
-
"JM",
|
|
1394
|
-
"KN",
|
|
1395
|
-
"KY",
|
|
1396
|
-
"LC",
|
|
1397
|
-
"MP",
|
|
1398
|
-
"MS",
|
|
1399
|
-
"PR",
|
|
1400
|
-
"SX",
|
|
1401
|
-
"TC",
|
|
1402
|
-
"TT",
|
|
1403
|
-
"VC",
|
|
1404
|
-
"VG",
|
|
1405
|
-
"VI",
|
|
1406
|
-
// +7
|
|
1407
|
-
"KZ",
|
|
1408
|
-
// +39
|
|
1409
|
-
"VA",
|
|
1410
|
-
// +44
|
|
1411
|
-
"GG",
|
|
1412
|
-
"IM",
|
|
1413
|
-
"JE",
|
|
1414
|
-
// +47
|
|
1415
|
-
"SJ",
|
|
1416
|
-
// +61
|
|
1417
|
-
"CC",
|
|
1418
|
-
"CX",
|
|
1419
|
-
// 212
|
|
1420
|
-
"EH",
|
|
1421
|
-
// 262
|
|
1422
|
-
"RE",
|
|
1423
|
-
// 290
|
|
1424
|
-
"SH",
|
|
1425
|
-
// 590
|
|
1426
|
-
"BL",
|
|
1427
|
-
"MF",
|
|
1428
|
-
// 599
|
|
1429
|
-
"CW",
|
|
1430
|
-
];
|
|
1431
|
-
const countries = parsePhoneNumberFromString.getCountries()
|
|
1432
|
-
.filter(code => !DUPLICATE_COUNTRY_CODES.includes(code))
|
|
1433
|
-
.map(code => {
|
|
1434
|
-
const c = parsePhoneNumberFromString.getCountryCallingCode(code);
|
|
1435
|
-
return {
|
|
1436
|
-
label: `+${c} ${countryCodeToFlagEmoji(code)}`,
|
|
1437
|
-
value: `+${c}`,
|
|
1438
|
-
};
|
|
1439
|
-
});
|
|
1440
|
-
const additionalCountries = ADDITIONAL_COUNTRY_CODES_SUPPORTED_BY_BACKEND.map(code => ({
|
|
1441
|
-
label: `+${code}`,
|
|
1442
|
-
value: `+${code}`,
|
|
1443
|
-
}));
|
|
1444
|
-
const countryCodes = [...countries, ...additionalCountries]
|
|
1445
|
-
.filter(code => !COUNTRY_CODES_NOT_SUPPORTED_BY_BACKEND.includes(code.value))
|
|
1446
|
-
.sort((a, b) => Number(a.value) - Number(b.value));
|
|
1447
|
-
|
|
1448
|
-
/**
|
|
1449
|
-
* The CountryCodeSelect component is used to select a country code for a phone number.
|
|
1450
|
-
*
|
|
1451
|
-
* @param {CountryCodeSelectProps} props - The props for the CountryCodeSelect component
|
|
1452
|
-
* @returns {JSX.Element} CountryCodeSelect component
|
|
1453
|
-
*/
|
|
1454
|
-
const CountryCodeSelect = ({ excludedCountries, countryCode, isInvalid, onChange, disabled, readOnly, dataTestId, placeholder, onBlur, isClearable, }) => {
|
|
1455
|
-
const [isCountryCodeMissing, setIsCountryCodeMissing] = React.useState(false);
|
|
1456
|
-
React.useEffect(() => {
|
|
1457
|
-
countryCode && setIsCountryCodeMissing(false);
|
|
1458
|
-
}, [countryCode]);
|
|
1459
|
-
const filteredCodes = countryCodes.filter(code => {
|
|
1460
|
-
return !(excludedCountries === null || excludedCountries === void 0 ? void 0 : excludedCountries.some(excludedCode => excludedCode.value === code.value));
|
|
1461
|
-
});
|
|
1462
|
-
return (jsxRuntime.jsx(Select, { "aria-invalid": isCountryCodeMissing, className: "w-36", closeMenuOnSelect: true, dataTestId: dataTestId, disabled: disabled, hasError: isCountryCodeMissing || isInvalid, isClearable: isClearable, maxMenuHeight: 200, menuIsOpen: readOnly ? false : undefined, onBlur: onBlur, onChange: onChange, options: filteredCodes.map(code => code), placeholder: placeholder, readOnly: readOnly, value: filteredCodes.find(({ value }) => value === `+${countryCode}`) }));
|
|
1463
|
-
};
|
|
1464
|
-
|
|
1465
|
-
/**
|
|
1466
|
-
* A component for inputting phone numbers with an optional action button for initiating a phone call.
|
|
1467
|
-
*
|
|
1468
|
-
* @param {string} [dataTestId] - The data test ID for the component.
|
|
1469
|
-
* @param {string|number} [value] - The value of the input field. The value should include the country code as well.
|
|
1470
|
-
* @param {boolean} [disabled=false] - Whether the component is disabled or not.
|
|
1471
|
-
* @param {string} [fieldSize="medium"] - The size of the input field.
|
|
1472
|
-
* @param {boolean} [disableAction=false] - Whether the action button is disabled or not.
|
|
1473
|
-
* @returns {JSX.Element} - The PhoneInput component.
|
|
1315
|
+
* NOTE: If shown with a label, please use the `TextField` component instead.
|
|
1474
1316
|
*/
|
|
1475
|
-
const
|
|
1476
|
-
var _b, _c;
|
|
1477
|
-
var { dataTestId, isInvalid, disabled = false, value, defaultValue, fieldSize = "medium", disableAction = false, onChange, onBlurCountryCode, readOnly, countryCodePlaceholder, onChangeCountryCode, onBlur, onFieldsBlur, onChangeValue, isCountryCodeClearable } = _a, rest = __rest(_a, ["dataTestId", "isInvalid", "disabled", "value", "defaultValue", "fieldSize", "disableAction", "onChange", "onBlurCountryCode", "readOnly", "countryCodePlaceholder", "onChangeCountryCode", "onBlur", "onFieldsBlur", "onChangeValue", "isCountryCodeClearable"]);
|
|
1478
|
-
const DEFAULT_COUNTRY_CODE = "+45";
|
|
1479
|
-
const { getPhoneNumber } = usePhoneInput();
|
|
1480
|
-
const [placeholder, setPlaceholder] = React.useState();
|
|
1481
|
-
React.useEffect(() => {
|
|
1482
|
-
if (readOnly) {
|
|
1483
|
-
setPlaceholder("");
|
|
1484
|
-
}
|
|
1485
|
-
else {
|
|
1486
|
-
const countryCode = countryCodePlaceholder || DEFAULT_COUNTRY_CODE;
|
|
1487
|
-
setPlaceholder(`${countryCode} ${countryCodeToFlagEmoji(countryCode)}`);
|
|
1488
|
-
}
|
|
1489
|
-
}, [countryCodePlaceholder, readOnly]);
|
|
1490
|
-
const safePhoneNumber = getPhoneNumberWithPlus(value || "");
|
|
1491
|
-
const number = parsePhoneNumberFromString__default["default"](safePhoneNumber, { defaultCountry: "DK" });
|
|
1492
|
-
const valueHasOnlyCountryCode = (number === null || number === void 0 ? void 0 : number.isPossible) === undefined && typeof value === "string" && value[0] === "+" && value.length < 5;
|
|
1493
|
-
const [phone, setPhone] = React.useState((_b = number === null || number === void 0 ? void 0 : number.nationalNumber.toString()) !== null && _b !== void 0 ? _b : "");
|
|
1494
|
-
const [code, setCode] = React.useState(valueHasOnlyCountryCode ? value.replace("+", "") : (_c = number === null || number === void 0 ? void 0 : number.countryCallingCode.toString()) !== null && _c !== void 0 ? _c : "");
|
|
1495
|
-
const codeRef = React.useRef(code); // synchronus reliable source of truth (country code is calling onblur just after onchange, useState is too slow for this)
|
|
1496
|
-
const phoneRef = React.useRef(phone); // synchronus reliable source of truth
|
|
1497
|
-
const onChangeHandler = React__default["default"].useCallback(({ newPhone, newCode }) => {
|
|
1498
|
-
onChangeValue &&
|
|
1499
|
-
onChangeValue({
|
|
1500
|
-
phone: getPhoneNumber({ country: newCode, phone: newPhone || "" }),
|
|
1501
|
-
countryCode: newCode,
|
|
1502
|
-
national: newPhone,
|
|
1503
|
-
});
|
|
1504
|
-
}, [onChangeValue, getPhoneNumber]);
|
|
1505
|
-
const onPhoneChangeHandler = React__default["default"].useCallback((ph) => {
|
|
1506
|
-
phoneRef.current = ph;
|
|
1507
|
-
setPhone(ph);
|
|
1508
|
-
onChangeHandler({ newPhone: ph, newCode: code });
|
|
1509
|
-
}, [onChangeHandler, code, phoneRef]);
|
|
1510
|
-
const onCodeChangeHandler = React__default["default"].useCallback((codeNumber) => {
|
|
1511
|
-
codeRef.current = codeNumber;
|
|
1512
|
-
setCode(codeNumber);
|
|
1513
|
-
onChangeHandler({ newPhone: phone, newCode: codeNumber });
|
|
1514
|
-
}, [phone, onChangeHandler, codeRef]);
|
|
1515
|
-
const onBlurHandler = React__default["default"].useCallback(() => {
|
|
1516
|
-
onFieldsBlur &&
|
|
1517
|
-
onFieldsBlur({
|
|
1518
|
-
phone: getPhoneNumber({ country: codeRef.current, phone: phoneRef.current }),
|
|
1519
|
-
countryCode: codeRef.current,
|
|
1520
|
-
national: phoneRef.current,
|
|
1521
|
-
});
|
|
1522
|
-
}, [onFieldsBlur, getPhoneNumber]);
|
|
1523
|
-
const hiddenInputRef = React.useRef(null);
|
|
1524
|
-
const phoneNumber = getPhoneNumber({ country: code, phone });
|
|
1525
|
-
React.useEffect(() => {
|
|
1526
|
-
const element = hiddenInputRef.current;
|
|
1527
|
-
const event = new Event("change");
|
|
1528
|
-
element === null || element === void 0 ? void 0 : element.dispatchEvent(event);
|
|
1529
|
-
// The event as unknown as ChangeEvent<HTMLInputElement> assertion is needed because
|
|
1530
|
-
// the event's type is inferred as Event, which doesn't have a target property, whereas ChangeEvent does.
|
|
1531
|
-
onChange && onChange(event);
|
|
1532
|
-
}, [phoneNumber, onChange]);
|
|
1533
|
-
return (jsxRuntime.jsxs("div", { className: "grid-cols-min-fr grid gap-2", "data-testid": dataTestId && `${dataTestId}-container`, children: [jsxRuntime.jsx("input", { "aria-invalid": isInvalid, "data-testid": dataTestId, hidden: true, id: "phone-input", onChange: onChange, readOnly: readOnly, ref: hiddenInputRef, value: phoneNumber }), jsxRuntime.jsx(CountryCodeSelect, { countryCode: code, dataTestId: dataTestId && `${dataTestId}-countryCodeSelect`, disabled: disabled, isClearable: isCountryCodeClearable, isInvalid: isInvalid, onBlur: e => {
|
|
1534
|
-
onBlurHandler();
|
|
1535
|
-
}, onChange: e => {
|
|
1536
|
-
var _a;
|
|
1537
|
-
onCodeChangeHandler((_a = e === null || e === void 0 ? void 0 : e.value) !== null && _a !== void 0 ? _a : "");
|
|
1538
|
-
}, placeholder: placeholder, readOnly: readOnly }), jsxRuntime.jsx(BaseInput, Object.assign({ actions: !disableAction && (jsxRuntime.jsx(ActionButton, { dataTestId: dataTestId && `${dataTestId}-phoneIcon`, disabled: disabled || isInvalid, iconSize: fieldSize, type: "PHONE_NUMBER", value: phoneNumber })), dataTestId: dataTestId && `${dataTestId}-phoneNumberInput`, disabled: disabled, fieldSize: fieldSize, id: "phoneInput-number", isInvalid: isInvalid, onBlur: () => {
|
|
1539
|
-
onBlurHandler();
|
|
1540
|
-
}, onChange: e => {
|
|
1541
|
-
onPhoneChangeHandler(e.target.value);
|
|
1542
|
-
}, readOnly: readOnly, type: "tel", value: phone }, rest))] }));
|
|
1543
|
-
});
|
|
1317
|
+
const TextInput = React.forwardRef((props, ref) => (jsxRuntime.jsx(BaseInput, Object.assign({ ref: ref, type: "text" }, props))));
|
|
1544
1318
|
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
return "NOT_A_NUMBER";
|
|
1571
|
-
}
|
|
1572
|
-
return "INVALID_NUMBER";
|
|
1573
|
-
};
|
|
1574
|
-
/**
|
|
1575
|
-
* Checks if the country code is valid and required
|
|
1576
|
-
*/
|
|
1577
|
-
const isInvalidCountryCode = (error, required) => (!!required && error === "REQUIRED") || error === "REQUIRED_COUNTRY";
|
|
1578
|
-
/**
|
|
1579
|
-
* Checks if the phone number is valid and required
|
|
1580
|
-
*/
|
|
1581
|
-
const isInvalidPhoneNumber = (error, required) => error !== "REQUIRED_COUNTRY" && ((!!error && error !== "REQUIRED") || (!!required && error === "REQUIRED"));
|
|
1319
|
+
const cvaSearch = cssClassVarianceUtilities.cvaMerge([
|
|
1320
|
+
"shadow-none",
|
|
1321
|
+
"component-search-borderless",
|
|
1322
|
+
"component-search-background",
|
|
1323
|
+
"hover:component-search-background",
|
|
1324
|
+
"hover:component-search-focus-hover",
|
|
1325
|
+
"focus:component-search-focus-hover",
|
|
1326
|
+
"focus-within:component-search-focus-within",
|
|
1327
|
+
"transition-all",
|
|
1328
|
+
"duration-300",
|
|
1329
|
+
], {
|
|
1330
|
+
variants: {
|
|
1331
|
+
border: { true: ["!component-search-border"], false: "" },
|
|
1332
|
+
widenOnFocus: {
|
|
1333
|
+
true: [
|
|
1334
|
+
"component-search-width",
|
|
1335
|
+
"component-search-widen",
|
|
1336
|
+
"hover:component-search-widen",
|
|
1337
|
+
"focus-within:component-search-widen-focus",
|
|
1338
|
+
"focus-within:w-full",
|
|
1339
|
+
],
|
|
1340
|
+
false: "w-full",
|
|
1341
|
+
},
|
|
1342
|
+
},
|
|
1343
|
+
});
|
|
1582
1344
|
|
|
1583
1345
|
/**
|
|
1584
|
-
* The
|
|
1585
|
-
* It is a wrapper around the PhoneInput component and the FormGroup component.
|
|
1586
|
-
* It is used to render a phone number field with a label, a tip, a help text, a help addon and an error message.
|
|
1346
|
+
* The Search component is used to render a search input field.
|
|
1587
1347
|
*
|
|
1588
|
-
* @param {
|
|
1589
|
-
* @
|
|
1590
|
-
* @param {string} [helpText] - The help text for the component.
|
|
1591
|
-
* @param {string} [helpAddon] - The help addon for the component.
|
|
1592
|
-
* @param {string} [errorMessage] - The error message for the component.
|
|
1593
|
-
* @param {string} [defaultValue] - The default value for the component.
|
|
1594
|
-
* @param {boolean} [disabled=false] - Whether the component is disabled or not.
|
|
1595
|
-
* @param {string} [fieldSize="medium"] - The size of the input field.
|
|
1596
|
-
* @param {boolean} [disableAction=false] - Whether the action button is disabled or not.
|
|
1597
|
-
* @returns {JSX.Element} - The PhoneField component.
|
|
1348
|
+
* @param {SearchProps} props - The props for the Search component
|
|
1349
|
+
* @returns {JSX.Element} Search component
|
|
1598
1350
|
*/
|
|
1599
|
-
const
|
|
1600
|
-
var {
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
const [localError, setLocalError] = React.useState(undefined);
|
|
1605
|
-
const renderAsInvalid = !isValid || isInvalid || Boolean(errorMessage);
|
|
1606
|
-
const validate = ({ phone, national, countryCode }) => {
|
|
1607
|
-
const areFieldsPopulated = Boolean(national && countryCode);
|
|
1608
|
-
const phoneValidationResult = validatePhoneNumber({ phone, national, countryCode });
|
|
1609
|
-
setIsValid(areFieldsPopulated ? !Boolean(phoneValidationResult) : true);
|
|
1610
|
-
setLocalError(Boolean(phoneValidationResult) ? t(`phoneField.error.${phoneValidationResult}`) : undefined);
|
|
1611
|
-
};
|
|
1612
|
-
const onChangeValueHandler = (phoneNumberValue) => {
|
|
1613
|
-
validate(phoneNumberValue);
|
|
1614
|
-
onChangeValue && onChangeValue(Object.assign(Object.assign({}, phoneNumberValue), { isValid }));
|
|
1615
|
-
};
|
|
1616
|
-
const handleOnFieldBlur = (phoneNumberValue) => {
|
|
1617
|
-
validate(phoneNumberValue);
|
|
1618
|
-
onFieldsBlur && onFieldsBlur(Object.assign(Object.assign({}, phoneNumberValue), { isValid }));
|
|
1619
|
-
};
|
|
1620
|
-
return (jsxRuntime.jsx(FormGroup, { className: className, dataTestId: dataTestId && `${dataTestId}-FormGroup`, disabled: rest.disabled, helpAddon: helpAddon, helpText: (renderAsInvalid && (errorMessage || localError)) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, tip: tip, children: jsxRuntime.jsx(PhoneInput, Object.assign({ "aria-labelledby": htmlForId + "-label", dataTestId: dataTestId, defaultValue: defaultValue, id: htmlForId, isInvalid: renderAsInvalid, onChangeValue: onChangeValueHandler, onFieldsBlur: handleOnFieldBlur, ref: ref, value: value }, rest)) }));
|
|
1351
|
+
const Search = React.forwardRef((_a, ref) => {
|
|
1352
|
+
var { className, placeholder = "Search", value, widenInputOnFocus, showBorderWhenNotInFocus = false, disabled, onKeyUp, onChange, onFocus, onBlur, name, onClear, dataTestId, autoComplete = "on" } = _a, rest = __rest(_a, ["className", "placeholder", "value", "widenInputOnFocus", "showBorderWhenNotInFocus", "disabled", "onKeyUp", "onChange", "onFocus", "onBlur", "name", "onClear", "dataTestId", "autoComplete"]);
|
|
1353
|
+
return (jsxRuntime.jsx(TextInput, Object.assign({}, rest, { autoComplete: autoComplete, className: cvaSearch({ className, border: showBorderWhenNotInFocus, widenOnFocus: widenInputOnFocus }), dataTestId: dataTestId, disabled: disabled, name: name, onBlur: onBlur, onChange: onChange, onFocus: onFocus, onKeyUp: onKeyUp, placeholder: placeholder, prefix: jsxRuntime.jsx(reactComponents.Icon, { name: "MagnifyingGlass", size: "medium" }), ref: ref, suffix: onClear ? (jsxRuntime.jsx("button", { className: "flex", "data-testid": dataTestId && `${dataTestId}_suffix_component`, onClick: () => {
|
|
1354
|
+
onClear();
|
|
1355
|
+
}, children: jsxRuntime.jsx(reactComponents.Icon, { name: "XMark", size: "small" }) })) : undefined, value: value })));
|
|
1621
1356
|
});
|
|
1622
1357
|
|
|
1623
|
-
const
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
},
|
|
1629
|
-
});
|
|
1630
|
-
const cvaRadioItem = cssClassVarianceUtilities.cvaMerge([
|
|
1631
|
-
"w-4",
|
|
1632
|
-
"h-4",
|
|
1633
|
-
"appearance-none",
|
|
1634
|
-
"rounded-3xl",
|
|
1635
|
-
"bg-white",
|
|
1636
|
-
"border-solid",
|
|
1358
|
+
const cvaSelect = cssClassVarianceUtilities.cvaMerge([
|
|
1359
|
+
"relative",
|
|
1360
|
+
"flex",
|
|
1361
|
+
"shadow-sm",
|
|
1362
|
+
"rounded-lg",
|
|
1637
1363
|
"border",
|
|
1638
1364
|
"border-slate-300",
|
|
1639
|
-
"
|
|
1640
|
-
"
|
|
1365
|
+
"focus-within:ring-2",
|
|
1366
|
+
"focus-within:ring-inset",
|
|
1367
|
+
"focus-within:ring-primary-600",
|
|
1368
|
+
"focus-within:border-slate-400",
|
|
1369
|
+
"hover:border-slate-400",
|
|
1370
|
+
"hover:bg-slate-50",
|
|
1371
|
+
"bg-white",
|
|
1641
1372
|
"transition",
|
|
1642
|
-
"box-border",
|
|
1643
|
-
"hover:cursor-pointer",
|
|
1644
|
-
"hover:bg-slate-100",
|
|
1645
|
-
"focus:ring-2",
|
|
1646
|
-
"focus:ring-inset",
|
|
1647
|
-
"focus:ring-blue-700",
|
|
1648
1373
|
], {
|
|
1649
1374
|
variants: {
|
|
1650
|
-
checked: {
|
|
1651
|
-
true: [
|
|
1652
|
-
"border-solid",
|
|
1653
|
-
"border-4",
|
|
1654
|
-
"border-blue-600",
|
|
1655
|
-
"bg-white",
|
|
1656
|
-
"hover:bg-slate-100",
|
|
1657
|
-
"hover:cursor-pointer",
|
|
1658
|
-
"outline-0",
|
|
1659
|
-
"active:bg-slate-200",
|
|
1660
|
-
"active:ring-2",
|
|
1661
|
-
"active:ring-inset",
|
|
1662
|
-
"active:ring-blue-700",
|
|
1663
|
-
"focus:bg-slate-200",
|
|
1664
|
-
"focus:ring-2",
|
|
1665
|
-
"focus:ring-inset",
|
|
1666
|
-
"focus:ring-blue-700",
|
|
1667
|
-
"group-active:ring-2",
|
|
1668
|
-
"group-active:ring-inset",
|
|
1669
|
-
"group-active:ring-blue-700",
|
|
1670
|
-
],
|
|
1671
|
-
false: "",
|
|
1672
|
-
},
|
|
1673
1375
|
invalid: {
|
|
1674
|
-
true:
|
|
1675
|
-
"border-red-600",
|
|
1676
|
-
"active:ring-red-700",
|
|
1677
|
-
"focus:ring-red-700",
|
|
1678
|
-
"group-focus:ring-2",
|
|
1679
|
-
"group-focus:ring-inset",
|
|
1680
|
-
],
|
|
1376
|
+
true: "border-red-600 text-red-600 focus-within:ring-red-600 hover:border-red-600",
|
|
1681
1377
|
false: "",
|
|
1682
1378
|
},
|
|
1683
1379
|
disabled: {
|
|
1684
|
-
true:
|
|
1685
|
-
"bg-slate-400",
|
|
1686
|
-
"border-slate-300",
|
|
1687
|
-
"cursor-not-allowed",
|
|
1688
|
-
"group-hover:bg-slate-400",
|
|
1689
|
-
"group-focus:bg-slate-400",
|
|
1690
|
-
"hover:bg-slate-400",
|
|
1691
|
-
"focus:bg-slate-400",
|
|
1692
|
-
"active:bg-slate-400",
|
|
1693
|
-
"focus:ring-0",
|
|
1694
|
-
"focus:ring-inset",
|
|
1695
|
-
"group-active:ring-0",
|
|
1696
|
-
"group-active:ring-inset",
|
|
1697
|
-
],
|
|
1380
|
+
true: "!bg-slate-100",
|
|
1698
1381
|
false: "",
|
|
1699
1382
|
},
|
|
1700
1383
|
},
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
className: ["bg-white"],
|
|
1706
|
-
},
|
|
1707
|
-
],
|
|
1384
|
+
defaultVariants: {
|
|
1385
|
+
invalid: false,
|
|
1386
|
+
disabled: false,
|
|
1387
|
+
},
|
|
1708
1388
|
});
|
|
1709
|
-
const
|
|
1710
|
-
const
|
|
1711
|
-
const
|
|
1389
|
+
const cvaSelectIcon = cssClassVarianceUtilities.cvaMerge("mr-2 flex cursor-pointer items-center justify-center text-slate-400 hover:text-slate-500");
|
|
1390
|
+
const cvaSelectPrefix = cssClassVarianceUtilities.cvaMerge(["flex", "justify-center", "items-center", "text-slate-400", "pl-2"]);
|
|
1391
|
+
const cvaSelectXIcon = cssClassVarianceUtilities.cvaMerge([
|
|
1392
|
+
"mr-2 flex cursor-pointer items-center justify-center text-slate-400 hover:text-slate-500",
|
|
1393
|
+
"ml-1",
|
|
1394
|
+
]);
|
|
1395
|
+
const cvaSelectMenuList = cssClassVarianceUtilities.cvaMerge(["min-w-min", "shadow-md", "rounded-lg", "z-20", "bg-white", "p-1", "border", "border-slate-300", "gap-1", "grid"], {
|
|
1712
1396
|
variants: {
|
|
1713
|
-
|
|
1714
|
-
true:
|
|
1715
|
-
false: "",
|
|
1397
|
+
menuIsOpen: {
|
|
1398
|
+
true: "animate-fade-in-fast",
|
|
1399
|
+
false: "animate-fade-out-fast",
|
|
1716
1400
|
},
|
|
1717
1401
|
},
|
|
1718
1402
|
});
|
|
1719
|
-
|
|
1720
|
-
|
|
1403
|
+
const cvaSelectDynamicTagContainer = cssClassVarianceUtilities.cvaMerge(["h-full", "flex", "gap-1", "items-center"], {
|
|
1404
|
+
variants: {
|
|
1405
|
+
visible: { true: "visible", false: "invisible" },
|
|
1406
|
+
},
|
|
1407
|
+
});
|
|
1408
|
+
const cvaSelectCounter = cssClassVarianceUtilities.cvaMerge(["overflow-hidden", "whitespace-nowrap"]);
|
|
1409
|
+
const cvaSelectMenu = cssClassVarianceUtilities.cvaMerge(["relative", "p-1", "grid", "gap-1"]);
|
|
1721
1410
|
|
|
1722
1411
|
/**
|
|
1723
|
-
*
|
|
1724
|
-
*
|
|
1725
|
-
* Radio buttons are used for mutually exclusive choices, not for multiple choices. Only one radio button can be selected at a time. When a user chooses a new item, the previous choice is automatically deselected.
|
|
1726
|
-
*
|
|
1727
|
-
* _**Do use** Radio buttons in forms, settings, or selections in a list._
|
|
1728
|
-
*
|
|
1729
|
-
* _**Do not use** Radio buttons if a user can select many option from a list, use checkboxes instead of radio buttons._
|
|
1730
|
-
*
|
|
1731
|
-
* @param {RadioGroupProps} props - The props for the RadioGroup component
|
|
1732
|
-
* @returns {JSX.Element} RadioGroup component
|
|
1412
|
+
* @param {MultiValue<Option> | SingleValue<Option>} arg option to check type
|
|
1413
|
+
* @returns {arg is MultiValue<Option> } is Multivalue
|
|
1733
1414
|
*/
|
|
1734
|
-
|
|
1735
|
-
return
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1415
|
+
function isMultiValue(arg) {
|
|
1416
|
+
return Array.isArray(arg);
|
|
1417
|
+
}
|
|
1418
|
+
function isGroupBase(arg) {
|
|
1419
|
+
return arg.options !== undefined;
|
|
1420
|
+
}
|
|
1421
|
+
const isSelectedOption = (option, selected) => {
|
|
1422
|
+
if (isGroupBase(option)) {
|
|
1423
|
+
return false;
|
|
1424
|
+
}
|
|
1425
|
+
return isMultiValue(selected)
|
|
1426
|
+
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1427
|
+
selected.some(v => v.value === option.value)
|
|
1428
|
+
: // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1429
|
+
option.value === (selected === null || selected === void 0 ? void 0 : selected.value);
|
|
1430
|
+
};
|
|
1431
|
+
const removeSelectedFromGroups = (group, selected) => {
|
|
1432
|
+
if (isGroupBase(group)) {
|
|
1433
|
+
return Object.assign(Object.assign({}, group), { options: group.options.filter(option => !isSelectedOption(option, selected)) });
|
|
1434
|
+
}
|
|
1435
|
+
return group;
|
|
1436
|
+
};
|
|
1437
|
+
/**
|
|
1438
|
+
* @template IsMulti
|
|
1439
|
+
* @template Group
|
|
1440
|
+
* @param {OptionsOrGroups<Option, Group> | undefined} options An array of options to select from
|
|
1441
|
+
* @param {PropsValue<Option> | undefined} value Selected values
|
|
1442
|
+
* @returns {OptionsOrGroups<Option, Group>} An array of ordered options with selected on top
|
|
1443
|
+
*/
|
|
1444
|
+
const getOrderedOptions = (options, value) => {
|
|
1445
|
+
if (value && options) {
|
|
1446
|
+
const orderedValues = isMultiValue(value)
|
|
1447
|
+
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1448
|
+
[...value].sort((a, b) => a.label.localeCompare(b.label))
|
|
1449
|
+
: [value];
|
|
1450
|
+
const selectableOptions = options
|
|
1451
|
+
.filter(option => !isSelectedOption(option, value))
|
|
1452
|
+
.map(option => removeSelectedFromGroups(option, value));
|
|
1453
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1454
|
+
return orderedValues.concat(selectableOptions) || [];
|
|
1455
|
+
}
|
|
1456
|
+
return options || [];
|
|
1743
1457
|
};
|
|
1744
|
-
RadioGroup.displayName = "RadioGroup";
|
|
1745
1458
|
|
|
1746
1459
|
/**
|
|
1747
|
-
*
|
|
1460
|
+
* A single select menu item is a basic wrapper around Menu item designed to be used as a single value render in Select list
|
|
1748
1461
|
*
|
|
1749
|
-
* @param {
|
|
1750
|
-
* @returns {JSX.Element}
|
|
1462
|
+
* @param {SelectMenuItemProps} props - The props for the SingleSelectMenuItem
|
|
1463
|
+
* @returns {JSX.Element} SingleSelectMenuItem
|
|
1751
1464
|
*/
|
|
1752
|
-
const
|
|
1753
|
-
|
|
1754
|
-
const isChecked = (groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.value) === value;
|
|
1755
|
-
return (jsxRuntime.jsxs("label", { className: cvaRadioItemWrapper({ className }), "data-testid": dataTestId && `${dataTestId}-Wrapper`, htmlFor: `${groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.id}-${value}`, children: [jsxRuntime.jsx("input", { checked: isChecked, className: cvaRadioItem({
|
|
1756
|
-
checked: isChecked,
|
|
1757
|
-
disabled: groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.disabled,
|
|
1758
|
-
invalid: groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.isInvalid,
|
|
1759
|
-
}), "data-testid": dataTestId, id: `${groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.id}-${value}`, onChange: groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.onChange, type: "radio", value: value }), jsxRuntime.jsxs("div", { className: cvaRadioItemLabelContainer(), children: [jsxRuntime.jsx(Label, { dataTestId: dataTestId && `${dataTestId}-Label`, disabled: groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.disabled, htmlFor: `${groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.id}-${value}`, isInvalid: groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.isInvalid, children: label }), description && (jsxRuntime.jsx("label", { className: cvaRadioItemDescription({ disabled: groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.disabled }), "data-testid": dataTestId && `${dataTestId}-Description`, htmlFor: `${groupCtx === null || groupCtx === void 0 ? void 0 : groupCtx.id}-${value}`, children: description }))] })] }));
|
|
1465
|
+
const SingleSelectMenuItem = ({ label, icon, onClick, selected, dataTestId, focused, disabled, }) => {
|
|
1466
|
+
return (jsxRuntime.jsx(reactComponents.MenuItem, { dataTestId: dataTestId, disabled: disabled, focused: focused, label: label, onClick: onClick, prefix: icon, selected: selected, suffix: selected ? jsxRuntime.jsx(reactComponents.Icon, { name: "Check", size: "small" }) : undefined }));
|
|
1760
1467
|
};
|
|
1761
|
-
|
|
1762
|
-
const cvaTimeRange = cssClassVarianceUtilities.cvaMerge(["flex", "flex-1", "items-center", "gap-4", "border-transparent", "rounded-md"]);
|
|
1763
|
-
|
|
1764
1468
|
/**
|
|
1765
|
-
*
|
|
1469
|
+
* A multi select menu item is a basic wrapper around Menu item designed to be used as a multi value render in Select list
|
|
1766
1470
|
*
|
|
1767
|
-
* @param {
|
|
1768
|
-
* @returns {JSX.Element}
|
|
1471
|
+
* @param {SelectMenuItemProps} props - The props for the MultiSelectMenuItem
|
|
1472
|
+
* @returns {JSX.Element} multi select menu item
|
|
1769
1473
|
*/
|
|
1770
|
-
const
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
setTimeRange(prev => (Object.assign(Object.assign({}, prev), { timeFrom })));
|
|
1778
|
-
};
|
|
1779
|
-
const onChangeTo = (timeTo) => {
|
|
1780
|
-
setTimeRange(prev => (Object.assign(Object.assign({}, prev), { timeTo })));
|
|
1781
|
-
};
|
|
1782
|
-
const onRangeChange = () => onChange(timeRange);
|
|
1783
|
-
return (jsxRuntime.jsxs("div", { className: cvaTimeRange({ className }), "data-testid": dataTestId, id: id, children: [jsxRuntime.jsx(BaseInput, { dataTestId: `${dataTestId}-from`, disabled: disabled, isInvalid: isInvalid, onBlur: onRangeChange, onChange: (time) => onChangeFrom(time.currentTarget.value), type: "time", value: (_a = timeRange === null || timeRange === void 0 ? void 0 : timeRange.timeFrom) !== null && _a !== void 0 ? _a : "" }), children !== null && children !== void 0 ? children : jsxRuntime.jsx("div", { "data-testid": `${dataTestId}-separator`, children: "-" }), jsxRuntime.jsx(BaseInput, { dataTestId: `${dataTestId}-to`, disabled: disabled, isInvalid: isInvalid, onBlur: onRangeChange, onChange: (time) => onChangeTo(time.currentTarget.value), type: "time", value: (_b = timeRange === null || timeRange === void 0 ? void 0 : timeRange.timeTo) !== null && _b !== void 0 ? _b : "" })] }));
|
|
1474
|
+
const MultiSelectMenuItem = ({ label, onClick, selected, dataTestId, focused, disabled, }) => {
|
|
1475
|
+
return (jsxRuntime.jsx(reactComponents.MenuItem, { dataTestId: dataTestId, disabled: disabled, focused: focused, label: label, onClick: e => {
|
|
1476
|
+
e.stopPropagation();
|
|
1477
|
+
onClick && onClick(e);
|
|
1478
|
+
}, prefix: jsxRuntime.jsx(Checkbox, { checked: selected, disabled: disabled, onChange: () => null, onClick: e => {
|
|
1479
|
+
e.stopPropagation();
|
|
1480
|
+
}, readOnly: false }), selected: selected }));
|
|
1784
1481
|
};
|
|
1785
1482
|
|
|
1786
|
-
|
|
1787
|
-
|
|
1483
|
+
/**
|
|
1484
|
+
* Extended Tag component with information about its own width.
|
|
1485
|
+
* Used in the select component.
|
|
1486
|
+
*
|
|
1487
|
+
* @param {TagProps} props - The props for the tag component
|
|
1488
|
+
* @returns {JSX.Element} TagWithWidth component
|
|
1489
|
+
*/
|
|
1490
|
+
const TagWithWidth = (_a) => {
|
|
1491
|
+
var { onWidthKnown, children } = _a, rest = __rest(_a, ["onWidthKnown", "children"]);
|
|
1492
|
+
const ref = React__default["default"].useRef(null);
|
|
1493
|
+
React__default["default"].useLayoutEffect(() => {
|
|
1494
|
+
var _a;
|
|
1495
|
+
onWidthKnown && onWidthKnown({ width: ((_a = ref.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 0 });
|
|
1496
|
+
}, [ref, onWidthKnown]);
|
|
1497
|
+
return (jsxRuntime.jsx(reactComponents.Tag, Object.assign({ ref: ref }, rest, { children: children })));
|
|
1498
|
+
};
|
|
1788
1499
|
|
|
1789
1500
|
/**
|
|
1790
|
-
*
|
|
1501
|
+
* TagsContainer component to display tags in limited space when children can't fit space it displays counter
|
|
1791
1502
|
*
|
|
1792
|
-
* @param {
|
|
1793
|
-
* @returns {JSX.Element}
|
|
1503
|
+
* @param {TagsContainerProps} props - The props for the TagContainer
|
|
1504
|
+
* @returns {JSX.Element} TagsContainer
|
|
1794
1505
|
*/
|
|
1795
|
-
const
|
|
1796
|
-
const
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
const
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1506
|
+
const TagsContainer = ({ items, width = "100%", itemsGap = 5, postFix, disabled }) => {
|
|
1507
|
+
const [isReady, setIsReady] = React__default["default"].useState(false);
|
|
1508
|
+
const [counterWidth, setCounterWidth] = React__default["default"].useState(0);
|
|
1509
|
+
const containerRef = React__default["default"].useRef(null);
|
|
1510
|
+
const availableWidth = React__default["default"].useRef();
|
|
1511
|
+
const childrenWidth = React__default["default"].useRef([]);
|
|
1512
|
+
const itemsCount = items.length;
|
|
1513
|
+
React__default["default"].useLayoutEffect(() => {
|
|
1514
|
+
var _a;
|
|
1515
|
+
availableWidth.current = ((_a = containerRef === null || containerRef === void 0 ? void 0 : containerRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 0;
|
|
1516
|
+
}, [containerRef]);
|
|
1517
|
+
const onWidthKnownHandler = ({ width: reportedWidth }) => {
|
|
1518
|
+
childrenWidth.current.push({ width: reportedWidth + itemsGap });
|
|
1519
|
+
if (childrenWidth.current.length === itemsCount) {
|
|
1520
|
+
setIsReady(true);
|
|
1521
|
+
}
|
|
1808
1522
|
};
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1523
|
+
const requiredSpace = childrenWidth.current.reduce((previous, current) => {
|
|
1524
|
+
return previous + current.width;
|
|
1525
|
+
}, 0);
|
|
1526
|
+
let counter = 0;
|
|
1527
|
+
const availableSpace = ((availableWidth === null || availableWidth === void 0 ? void 0 : availableWidth.current) || 0) - counterWidth;
|
|
1528
|
+
const renderedElements = items
|
|
1529
|
+
.concat({ text: "", onClick: () => null, disabled: false }) // reserved element for a potential counter
|
|
1530
|
+
.map((item, index) => {
|
|
1531
|
+
const spaceNeeded = childrenWidth.current.slice(0, index + 1).reduce((previous, current) => {
|
|
1532
|
+
return previous + current.width;
|
|
1533
|
+
}, 0);
|
|
1534
|
+
const isLast = index === items.length;
|
|
1535
|
+
const counterRequired = requiredSpace > availableSpace && counter !== 0;
|
|
1536
|
+
if (isLast && counterRequired) {
|
|
1537
|
+
return (jsxRuntime.jsx(TagWithWidth, { color: "white", disabled: disabled, onWidthKnown: ({ width: reportedWidth }) => setCounterWidth(reportedWidth), children: jsxRuntime.jsxs("div", { className: cvaSelectCounter(), "data-testid": "select-counter", children: ["+", counter] }) }, item.text + index));
|
|
1538
|
+
}
|
|
1539
|
+
if (isLast) {
|
|
1540
|
+
return null;
|
|
1541
|
+
}
|
|
1542
|
+
const itemCanFit = spaceNeeded <= availableSpace;
|
|
1543
|
+
if (itemCanFit) {
|
|
1544
|
+
return (jsxRuntime.jsx(TagWithWidth, { className: "inline-flex shrink-0", color: item.disabled ? "unknown" : "primary", dataTestId: `${item.text}-tag`, disabled: disabled, onClose: e => {
|
|
1545
|
+
e.stopPropagation();
|
|
1546
|
+
item.onClick();
|
|
1547
|
+
}, onWidthKnown: onWidthKnownHandler, children: item.text }, item.text + index));
|
|
1548
|
+
}
|
|
1549
|
+
const fromTheItems = item.text !== "";
|
|
1550
|
+
if (fromTheItems) {
|
|
1551
|
+
counter = counter + 1;
|
|
1552
|
+
}
|
|
1553
|
+
return null;
|
|
1554
|
+
})
|
|
1555
|
+
.filter(element => element !== null);
|
|
1556
|
+
return (jsxRuntime.jsxs("div", { className: cvaSelectDynamicTagContainer({ visible: isReady }), ref: containerRef, style: {
|
|
1557
|
+
width: `${width}`,
|
|
1558
|
+
}, children: [renderedElements, postFix] }));
|
|
1812
1559
|
};
|
|
1813
1560
|
|
|
1814
|
-
const weekDay = {
|
|
1815
|
-
Monday: "monday",
|
|
1816
|
-
Tuesday: "tuesday",
|
|
1817
|
-
Wednesday: "wednesday",
|
|
1818
|
-
Thursday: "thursday",
|
|
1819
|
-
Friday: "friday",
|
|
1820
|
-
Saturday: "saturday",
|
|
1821
|
-
Sunday: "sunday",
|
|
1822
|
-
};
|
|
1823
|
-
exports.ScheduleVariant = void 0;
|
|
1824
|
-
(function (ScheduleVariant) {
|
|
1825
|
-
ScheduleVariant["ALL_DAYS"] = "all";
|
|
1826
|
-
ScheduleVariant["WEEKDAYS"] = "week";
|
|
1827
|
-
ScheduleVariant["CUSTOM"] = "custom";
|
|
1828
|
-
})(exports.ScheduleVariant || (exports.ScheduleVariant = {}));
|
|
1829
1561
|
/**
|
|
1830
|
-
*
|
|
1562
|
+
* A hook to retrieve components override object.
|
|
1563
|
+
* This complex object includes all the compositional components that are used in react-select. If you wish to overwrite a component, pass in an object with the appropriate namespace.
|
|
1831
1564
|
*
|
|
1832
|
-
* @
|
|
1833
|
-
* @
|
|
1565
|
+
* @template IsMulti
|
|
1566
|
+
* @template Group
|
|
1567
|
+
* @param {Partial<SelectComponents<Option, IsMulti, Group>> | undefined} componentsProps a custom component prop that you can to override defaults
|
|
1568
|
+
* @param {boolean} disabled decide to override disabled variant
|
|
1569
|
+
* @param {boolean} menuIsOpen menu is open state
|
|
1570
|
+
* @param {React.MutableRefObject<boolean>} refMenuIsEnabled a flag to block menu from open
|
|
1571
|
+
* @param {string} dataTestId a test id
|
|
1572
|
+
* @param {number} maxSelectedDisplayCount a number of max display count
|
|
1573
|
+
* @param {JSX.Element} dropdownIcon an custom dropdown icon
|
|
1574
|
+
* @returns {Partial<SelectComponents<Option, boolean, GroupBase<Option>>> | undefined} components object to override react-select default components
|
|
1834
1575
|
*/
|
|
1835
|
-
const
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1576
|
+
const useCustomComponents = (componentsProps, disabled, menuIsOpen, refMenuIsEnabled, dataTestId, maxSelectedDisplayCount, dropdownIcon) => {
|
|
1577
|
+
const [t] = useTranslation();
|
|
1578
|
+
// perhaps it should not be wrap in memo (causing some issues with opening and closing on mobiles)
|
|
1579
|
+
const customComponents = React__namespace.useMemo(() => {
|
|
1580
|
+
return Object.assign({ ValueContainer: props => {
|
|
1581
|
+
if (props.isMulti && Array.isArray(props.children) && props.children.length > 0) {
|
|
1582
|
+
const PLACEHOLDER_KEY = "placeholder";
|
|
1583
|
+
const key = props && props.children && props.children[0] ? props.children[0].key : "";
|
|
1584
|
+
const values = props && props.children ? props.children[0] : [];
|
|
1585
|
+
const tags = key === PLACEHOLDER_KEY ? [] : values;
|
|
1586
|
+
const searchInput = props && props.children && props.children[1];
|
|
1587
|
+
return (jsxRuntime.jsx(ReactSelect.components.ValueContainer, Object.assign({}, props, { isDisabled: props.selectProps.isDisabled, children: maxSelectedDisplayCount === undefined ? (jsxRuntime.jsx(TagsContainer, { disabled: disabled, items: tags
|
|
1588
|
+
? tags.map(({ props: tagProps }) => {
|
|
1589
|
+
return {
|
|
1590
|
+
text: tagProps.children,
|
|
1591
|
+
onClick: disabled
|
|
1592
|
+
? undefined
|
|
1593
|
+
: (e) => {
|
|
1594
|
+
var _a, _b;
|
|
1595
|
+
refMenuIsEnabled.current = false;
|
|
1596
|
+
((_a = tagProps === null || tagProps === void 0 ? void 0 : tagProps.removeProps) === null || _a === void 0 ? void 0 : _a.onClick) && ((_b = tagProps === null || tagProps === void 0 ? void 0 : tagProps.removeProps) === null || _b === void 0 ? void 0 : _b.onClick(e));
|
|
1597
|
+
},
|
|
1598
|
+
disabled: disabled,
|
|
1599
|
+
};
|
|
1600
|
+
})
|
|
1601
|
+
: [], postFix: searchInput, width: "100%" })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [tags &&
|
|
1602
|
+
tags.slice(0, maxSelectedDisplayCount).map(({ props: tagProps }) => {
|
|
1603
|
+
var _a, _b;
|
|
1604
|
+
return (jsxRuntime.jsx(reactComponents.Tag, { className: "inline-flex shrink-0", color: disabled ? "unknown" : "primary", dataTestId: tagProps.children ? `${(_a = tagProps.children) === null || _a === void 0 ? void 0 : _a.toString()}-tag` : undefined, onClose: e => {
|
|
1605
|
+
var _a, _b;
|
|
1606
|
+
e.stopPropagation();
|
|
1607
|
+
refMenuIsEnabled.current = false;
|
|
1608
|
+
((_a = tagProps === null || tagProps === void 0 ? void 0 : tagProps.removeProps) === null || _a === void 0 ? void 0 : _a.onClick) && ((_b = tagProps === null || tagProps === void 0 ? void 0 : tagProps.removeProps) === null || _b === void 0 ? void 0 : _b.onClick(e));
|
|
1609
|
+
}, children: tagProps.children }, (_b = tagProps.children) === null || _b === void 0 ? void 0 : _b.toString()));
|
|
1610
|
+
}), tags && tags.length > maxSelectedDisplayCount && (jsxRuntime.jsxs(reactComponents.Tag, { color: "neutral", dataTestId: "counter-tag", children: ["+", tags.length - maxSelectedDisplayCount] })), searchInput] })) })));
|
|
1611
|
+
}
|
|
1612
|
+
return (jsxRuntime.jsx(ReactSelect.components.ValueContainer, Object.assign({}, props, { isDisabled: props.selectProps.isDisabled, children: props.children })));
|
|
1613
|
+
}, LoadingIndicator: props => {
|
|
1614
|
+
return jsxRuntime.jsx(reactComponents.Spinner, { className: "mt-1.5 mr-1", size: "small" });
|
|
1615
|
+
}, DropdownIndicator: props => {
|
|
1616
|
+
const icon = props.selectProps.menuIsOpen ? (jsxRuntime.jsx(reactComponents.Icon, { name: "ChevronUp", size: "medium" })) : (jsxRuntime.jsx(reactComponents.Icon, { name: "ChevronDown", size: "medium" }));
|
|
1617
|
+
return props.selectProps.isLoading ? null : (jsxRuntime.jsx(ReactSelect.components.DropdownIndicator, Object.assign({}, props, { children: jsxRuntime.jsx("div", { className: cvaSelectIcon(), children: dropdownIcon ? dropdownIcon : icon }) })));
|
|
1618
|
+
}, IndicatorSeparator: () => null, ClearIndicator: props => {
|
|
1619
|
+
if (disabled) {
|
|
1620
|
+
return null;
|
|
1621
|
+
}
|
|
1622
|
+
return (jsxRuntime.jsx(ReactSelect.components.ClearIndicator, Object.assign({}, props, { children: jsxRuntime.jsx("div", { className: cvaSelectXIcon(), "data-testid": dataTestId && `${dataTestId}-XMarkIcon`, onClick: props.clearValue, children: jsxRuntime.jsx(reactComponents.Icon, { name: "XCircle", size: "medium", title: t("clearIndicator.icon.tooltip.clearAll") }) }) })));
|
|
1623
|
+
}, Control: props => {
|
|
1624
|
+
return jsxRuntime.jsx(ReactSelect.components.Control, Object.assign({}, props, { className: props.isDisabled ? "bg-slate-100" : "" }));
|
|
1625
|
+
}, SingleValue: props => {
|
|
1626
|
+
return (jsxRuntime.jsx(ReactSelect.components.SingleValue, Object.assign({}, props, { className: props.isDisabled ? "text-slate-700" : "", children: jsxRuntime.jsx("div", { "data-testid": dataTestId + "-singleValue", children: props.children }) })));
|
|
1627
|
+
}, Menu: props => {
|
|
1628
|
+
return (jsxRuntime.jsx(ReactSelect.components.Menu, Object.assign({}, props, { className: cvaSelectMenuList({ menuIsOpen: props.selectProps.menuIsOpen }) })));
|
|
1629
|
+
}, Placeholder: props => {
|
|
1630
|
+
return (jsxRuntime.jsx(ReactSelect.components.Placeholder, Object.assign({}, props, { className: "!text-slate-400", children: props.children })));
|
|
1631
|
+
}, MenuList: props => {
|
|
1632
|
+
return (jsxRuntime.jsx(ReactSelect.components.MenuList, Object.assign({}, props, { innerProps: Object.assign(Object.assign({}, props.innerProps), { onScroll: e => {
|
|
1633
|
+
const listEl = e.currentTarget;
|
|
1634
|
+
if (listEl.scrollTop + listEl.clientHeight >= listEl.scrollHeight) {
|
|
1635
|
+
props.selectProps.onMenuScrollToBottom && props.selectProps.onMenuScrollToBottom(new TouchEvent(""));
|
|
1636
|
+
}
|
|
1637
|
+
} }), children: props.children })));
|
|
1638
|
+
}, Option: props => {
|
|
1639
|
+
const componentProps = {
|
|
1640
|
+
label: props.label,
|
|
1641
|
+
focused: props.isFocused,
|
|
1642
|
+
selected: props.isSelected,
|
|
1643
|
+
onClick: props.innerProps.onClick,
|
|
1644
|
+
};
|
|
1645
|
+
return (jsxRuntime.jsx(ReactSelect.components.Option, Object.assign({}, props, { innerProps: Object.assign(Object.assign({}, props.innerProps), { role: "option", onClick: () => { } }), children: props.isMulti ? (jsxRuntime.jsx(MultiSelectMenuItem, Object.assign({}, componentProps, { dataTestId: typeof props.label === "string" ? props.label : undefined, disabled: disabled }))) : (jsxRuntime.jsx(SingleSelectMenuItem, Object.assign({}, componentProps, { dataTestId: typeof props.label === "string" ? props.label : undefined, disabled: disabled || props.isDisabled }))) })));
|
|
1646
|
+
} }, componentsProps);
|
|
1647
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1648
|
+
}, [componentsProps, disabled, maxSelectedDisplayCount]); // do not add dropdownIcon (it will cause issue with opening/closing list for selects with custom icon)
|
|
1649
|
+
return customComponents;
|
|
1895
1650
|
};
|
|
1651
|
+
|
|
1896
1652
|
/**
|
|
1897
|
-
*
|
|
1653
|
+
* @template IsMulti
|
|
1654
|
+
* @template Group
|
|
1655
|
+
* @param {React.RefObject<HTMLDivElement>} refContainer react ref to container element
|
|
1656
|
+
* @param {React.RefObject<HTMLDivElement>} refPrefix react ref to prefix element
|
|
1657
|
+
* @param {number | undefined} maxSelectedDisplayCount a number of max display count
|
|
1658
|
+
* @param {StylesConfig<Option, IsMulti, Group> | undefined} styles a optional object to override styles of react-select
|
|
1659
|
+
* @returns {StylesConfig<Option, boolean>} styles to override in select
|
|
1660
|
+
*/
|
|
1661
|
+
const useCustomStyles = (refContainer, refPrefix, maxSelectedDisplayCount, styles, disabled) => {
|
|
1662
|
+
const customStyles = React__namespace.useMemo(() => {
|
|
1663
|
+
return Object.assign({ control: base => {
|
|
1664
|
+
return Object.assign(Object.assign({}, base), { border: "0", boxShadow: "0", "&:hover": {
|
|
1665
|
+
border: "0",
|
|
1666
|
+
}, marginRight: "2px", backgroundColor: "" });
|
|
1667
|
+
}, singleValue: base => (Object.assign({}, base)), multiValue: base => (Object.assign({}, base)), multiValueLabel: base => (Object.assign({}, base)), indicatorsContainer: base => (Object.assign(Object.assign({}, base), (disabled && { display: "none" }))), indicatorSeparator: () => ({
|
|
1668
|
+
width: "0px",
|
|
1669
|
+
}), menu: base => {
|
|
1670
|
+
return Object.assign(Object.assign({}, base), { width: "100%", marginTop: "4px", marginBottom: "18px", transition: "all 1s ease-in-out" });
|
|
1671
|
+
}, input: base => (Object.assign(Object.assign({}, base), { marginLeft: "0px" })), placeholder: base => (Object.assign({}, base)), option: () => ({}), menuPortal: base => (Object.assign(Object.assign({}, base), { width: (refContainer === null || refContainer === void 0 ? void 0 : refContainer.current) ? `${refContainer.current.clientWidth}px` : base.width, transform: (refPrefix === null || refPrefix === void 0 ? void 0 : refPrefix.current) ? `translate(-${refPrefix.current.clientWidth + 2}px)` : "translate(-2px)", backgroundColor: "#ffffff", borderRadius: "var(--border-radius-lg)", zIndex: 20, borderColor: "rgb(var(--color-slate-300))", boxShadow: "var(--tw-ring-inset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)" })), menuList: base => {
|
|
1672
|
+
return Object.assign(Object.assign({}, base), { position: "relative", padding: "var(--spacing-1)", display: "grid", gap: "var(--spacing-1)", width: "100%", borderRadius: "0px", boxShadow: "none", paddingTop: "0px" });
|
|
1673
|
+
}, valueContainer: base => {
|
|
1674
|
+
return Object.assign(Object.assign({}, base), { flexWrap: maxSelectedDisplayCount !== undefined ? "wrap" : "nowrap", gap: "0.25rem" });
|
|
1675
|
+
}, container: base => (Object.assign(Object.assign({}, base), { border: "none", width: "calc(100% - 2px)", paddingLeft: "2px" })), dropdownIndicator: base => (Object.assign(Object.assign({}, base), { padding: "0px" })), clearIndicator: base => {
|
|
1676
|
+
return Object.assign(Object.assign({}, base), { padding: "0px" });
|
|
1677
|
+
} }, styles);
|
|
1678
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1679
|
+
}, [refContainer, refPrefix]);
|
|
1680
|
+
return { customStyles };
|
|
1681
|
+
};
|
|
1682
|
+
|
|
1683
|
+
/**
|
|
1684
|
+
* A hook used by selects to share the common code
|
|
1898
1685
|
*
|
|
1899
|
-
* @param {
|
|
1900
|
-
* @returns {
|
|
1686
|
+
* @param {SelectProps} props - The props for the Select component
|
|
1687
|
+
* @returns {IUseSelect} Select component
|
|
1901
1688
|
*/
|
|
1902
|
-
const
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1689
|
+
const useSelect = (_a) => {
|
|
1690
|
+
var _b;
|
|
1691
|
+
var { id, className, dataTestId = "select", prefix, async, dropdownIcon, maxMenuHeight = 200, label, hasError, disabled, isMulti, components, value, options, onChange, isLoading, classNamePrefix = "", onMenuOpen, onMenuClose, maxSelectedDisplayCount = undefined, isClearable = false, isSearchable = true, onMenuScrollToBottom, styles, filterOption, onInputChange } = _a, props = __rest(_a, ["id", "className", "dataTestId", "prefix", "async", "dropdownIcon", "maxMenuHeight", "label", "hasError", "disabled", "isMulti", "components", "value", "options", "onChange", "isLoading", "classNamePrefix", "onMenuOpen", "onMenuClose", "maxSelectedDisplayCount", "isClearable", "isSearchable", "onMenuScrollToBottom", "styles", "filterOption", "onInputChange"]);
|
|
1692
|
+
const refContainer = React__default["default"].useRef(null);
|
|
1693
|
+
const refPrefix = React__default["default"].useRef(null);
|
|
1694
|
+
const { customStyles } = useCustomStyles(refContainer, refPrefix, maxSelectedDisplayCount, styles, disabled);
|
|
1695
|
+
const [menuIsOpen, setMenuIsOpen] = React__default["default"].useState((_b = props.menuIsOpen) !== null && _b !== void 0 ? _b : false);
|
|
1696
|
+
const refMenuIsEnabled = React__default["default"].useRef(true);
|
|
1697
|
+
const customComponents = useCustomComponents(components, disabled || false, menuIsOpen, refMenuIsEnabled, dataTestId, maxSelectedDisplayCount, dropdownIcon);
|
|
1698
|
+
const menuPlacement = "auto";
|
|
1699
|
+
const openMenuHandler = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
1700
|
+
onMenuOpen && onMenuOpen();
|
|
1701
|
+
if (refMenuIsEnabled.current) {
|
|
1702
|
+
setMenuIsOpen(true);
|
|
1914
1703
|
}
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
if (isAllDay) {
|
|
1918
|
-
return `${day}#00:00-24:00`;
|
|
1704
|
+
else {
|
|
1705
|
+
refMenuIsEnabled.current = true;
|
|
1919
1706
|
}
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1707
|
+
});
|
|
1708
|
+
const closeMenuHandler = () => {
|
|
1709
|
+
setMenuIsOpen(false);
|
|
1710
|
+
onMenuClose && onMenuClose();
|
|
1711
|
+
};
|
|
1712
|
+
const orderedOptions = React__default["default"].useMemo(() => {
|
|
1713
|
+
return disabled
|
|
1714
|
+
? getOrderedOptions(options, value).map(option => {
|
|
1715
|
+
return Object.assign(Object.assign({}, option), { disabled: true });
|
|
1716
|
+
})
|
|
1717
|
+
: getOrderedOptions(options, value);
|
|
1718
|
+
}, [options, value, disabled]);
|
|
1719
|
+
return {
|
|
1720
|
+
refContainer,
|
|
1721
|
+
refPrefix,
|
|
1722
|
+
customStyles,
|
|
1723
|
+
menuIsOpen,
|
|
1724
|
+
customComponents,
|
|
1725
|
+
menuPlacement,
|
|
1726
|
+
openMenuHandler,
|
|
1727
|
+
closeMenuHandler,
|
|
1728
|
+
orderedOptions,
|
|
1729
|
+
};
|
|
1923
1730
|
};
|
|
1924
1731
|
|
|
1925
1732
|
/**
|
|
1926
|
-
*
|
|
1733
|
+
* CreatableSelects are input components used to choose a value from a set.
|
|
1927
1734
|
*
|
|
1928
|
-
*
|
|
1735
|
+
* @param {CreatableSelectProps} props - The props for the CreatableSelect component
|
|
1736
|
+
* @returns {JSX.Element} CreatableSelect component
|
|
1929
1737
|
*/
|
|
1930
|
-
const
|
|
1931
|
-
|
|
1932
|
-
const
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1738
|
+
const CreatableSelect = (props) => {
|
|
1739
|
+
const { className } = props, propsNoClassName = __rest(props, ["className"]);
|
|
1740
|
+
const { id, dataTestId = "creatableSelect", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, value, options, onChange, isLoading, classNamePrefix = dataTestId !== null && dataTestId !== void 0 ? dataTestId : "creatableSelect", onMenuScrollToBottom, filterOption, onInputChange, isSearchable, isClearable = false, readOnly, openMenuOnClick = !disabled, openMenuOnFocus = !disabled, allowCreateWhileLoading, onCreateOption, } = propsNoClassName;
|
|
1741
|
+
const { refContainer, refPrefix, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler, orderedOptions, } = useSelect(props);
|
|
1742
|
+
const creatableSelectProps = {
|
|
1743
|
+
value,
|
|
1744
|
+
menuPlacement,
|
|
1745
|
+
maxMenuHeight,
|
|
1746
|
+
onChange,
|
|
1747
|
+
"aria-label": label,
|
|
1748
|
+
"data-testid": dataTestId,
|
|
1749
|
+
components: customComponents,
|
|
1750
|
+
styles: customStyles,
|
|
1751
|
+
tabSelectsValue: false,
|
|
1752
|
+
blurInputOnSelect: !isMulti,
|
|
1753
|
+
menuPortalTarget: props.menuPortalTarget || document.body,
|
|
1754
|
+
isSearchable: disabled || readOnly ? false : isSearchable,
|
|
1755
|
+
menuShouldBlockScroll: true,
|
|
1756
|
+
menuShouldScrollIntoView: true,
|
|
1757
|
+
openMenuOnFocus,
|
|
1758
|
+
menuIsOpen: !readOnly ? menuIsOpen : false,
|
|
1759
|
+
openMenuOnClick,
|
|
1760
|
+
closeMenuOnSelect: false,
|
|
1761
|
+
isMulti,
|
|
1762
|
+
classNamePrefix,
|
|
1763
|
+
isLoading,
|
|
1764
|
+
isClearable,
|
|
1765
|
+
id,
|
|
1766
|
+
onMenuScrollToBottom,
|
|
1767
|
+
onInputChange,
|
|
1768
|
+
allowCreateWhileLoading,
|
|
1769
|
+
onCreateOption,
|
|
1770
|
+
};
|
|
1771
|
+
return (jsxRuntime.jsxs("div", { className: cvaSelect({ invalid: hasError, disabled: disabled || readOnly, className }), "data-testid": dataTestId, ref: refContainer, children: [prefix !== undefined && (jsxRuntime.jsx("div", { className: cvaSelectPrefix(), "data-testid": dataTestId && `${dataTestId}-prefix`, ref: refPrefix, children: prefix })), async ? (jsxRuntime.jsx(ReactAsyncCreatableSelect__default["default"], Object.assign({}, propsNoClassName, creatableSelectProps, async, { onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler }))) : (jsxRuntime.jsx(ReactCreatableSelect__default["default"], Object.assign({}, propsNoClassName, creatableSelectProps, { hideSelectedOptions: false, isMulti: isMulti, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, options: filterOption ? orderedOptions : options })))] }));
|
|
1772
|
+
};
|
|
1773
|
+
CreatableSelect.displayName = "CreatableSelect";
|
|
1957
1774
|
|
|
1958
1775
|
/**
|
|
1959
|
-
*
|
|
1776
|
+
* Selects are input components used to choose a value from a set.
|
|
1960
1777
|
*
|
|
1961
|
-
* @param {
|
|
1962
|
-
* @returns {JSX.Element}
|
|
1778
|
+
* @param {SelectProps} props - The props for the Select component
|
|
1779
|
+
* @returns {JSX.Element} Select component
|
|
1963
1780
|
*/
|
|
1964
|
-
const
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1781
|
+
const Select = (props) => {
|
|
1782
|
+
const { className } = props, propsNoClassName = __rest(props, ["className"]);
|
|
1783
|
+
const { id, dataTestId = "select", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, value, options, onChange, isLoading, classNamePrefix = dataTestId !== null && dataTestId !== void 0 ? dataTestId : "select", onMenuScrollToBottom, filterOption, onInputChange, isSearchable, isClearable = false, readOnly, openMenuOnClick = !disabled, openMenuOnFocus = !disabled, } = props;
|
|
1784
|
+
const { refContainer, refPrefix, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler, orderedOptions, } = useSelect(props);
|
|
1785
|
+
const selectProps = {
|
|
1786
|
+
value,
|
|
1787
|
+
menuPlacement,
|
|
1788
|
+
maxMenuHeight,
|
|
1789
|
+
onChange,
|
|
1790
|
+
"aria-label": label,
|
|
1791
|
+
"data-testid": dataTestId,
|
|
1792
|
+
components: customComponents,
|
|
1793
|
+
styles: customStyles,
|
|
1794
|
+
tabSelectsValue: false,
|
|
1795
|
+
blurInputOnSelect: !isMulti,
|
|
1796
|
+
menuPortalTarget: props.menuPortalTarget || document.body,
|
|
1797
|
+
isSearchable: disabled || readOnly ? false : isSearchable,
|
|
1798
|
+
menuShouldBlockScroll: true,
|
|
1799
|
+
menuShouldScrollIntoView: true,
|
|
1800
|
+
openMenuOnFocus,
|
|
1801
|
+
menuIsOpen: !readOnly ? menuIsOpen : false,
|
|
1802
|
+
openMenuOnClick,
|
|
1803
|
+
closeMenuOnSelect: false,
|
|
1804
|
+
isMulti,
|
|
1805
|
+
classNamePrefix,
|
|
1806
|
+
isLoading,
|
|
1807
|
+
isClearable,
|
|
1808
|
+
id,
|
|
1809
|
+
onMenuScrollToBottom,
|
|
1810
|
+
onInputChange,
|
|
1811
|
+
};
|
|
1812
|
+
return (jsxRuntime.jsxs("div", { className: cvaSelect({ invalid: hasError, disabled: disabled || readOnly, className }), "data-testid": dataTestId, ref: refContainer, children: [prefix !== undefined && (jsxRuntime.jsx("div", { className: cvaSelectPrefix(), "data-testid": dataTestId && `${dataTestId}-prefix`, ref: refPrefix, children: prefix })), async ? (jsxRuntime.jsx(ReactAsyncSelect__default["default"], Object.assign({}, propsNoClassName, selectProps, async, { onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler }))) : (jsxRuntime.jsx(ReactSelect__default["default"], Object.assign({}, propsNoClassName, selectProps, { hideSelectedOptions: false, isMulti: isMulti, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, options: filterOption ? orderedOptions : options })))] }));
|
|
1813
|
+
};
|
|
1814
|
+
Select.displayName = "Select";
|
|
1970
1815
|
|
|
1971
1816
|
const FormFieldSelectAdapter = React.forwardRef((_a, ref) => {
|
|
1972
1817
|
var { className, dataTestId, helpText, helpAddon, tip, label, disabled, isInvalid, errorMessage, name, onBlur, options, value, defaultValue, id, onChange, children } = _a, rest = __rest(_a, ["className", "dataTestId", "helpText", "helpAddon", "tip", "label", "disabled", "isInvalid", "errorMessage", "name", "onBlur", "options", "value", "defaultValue", "id", "onChange", "children"]);
|
|
@@ -2302,6 +2147,101 @@ const UrlField = React.forwardRef((_a, ref) => {
|
|
|
2302
2147
|
return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId && `${dataTestId}-FormGroup`, disabled: rest.disabled, helpAddon: helpAddon, helpText: renderAsInvalid ? errorMessage : helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, tip: tip, children: jsxRuntime.jsx(UrlInput, Object.assign({ "aria-labelledby": htmlForId + "-label", disabled: rest.disabled, id: htmlForId, isInvalid: renderAsInvalid, ref: ref, value: value || defaultValue }, rest, { className: className, dataTestId: dataTestId })) }));
|
|
2303
2148
|
});
|
|
2304
2149
|
|
|
2150
|
+
/**
|
|
2151
|
+
* A custom hook for managing phone number input state and validation.
|
|
2152
|
+
*
|
|
2153
|
+
* @property {Function} getPhoneNumber - A function for get formatted phone number with country code and plus sign
|
|
2154
|
+
*/
|
|
2155
|
+
const usePhoneInput = () => {
|
|
2156
|
+
const getPhoneNumber = ({ country, phone }) => {
|
|
2157
|
+
if (country) {
|
|
2158
|
+
return getPhoneNumberWithPlus(`${country}${phone || ""}`);
|
|
2159
|
+
}
|
|
2160
|
+
return phone || "";
|
|
2161
|
+
};
|
|
2162
|
+
return {
|
|
2163
|
+
getPhoneNumber,
|
|
2164
|
+
};
|
|
2165
|
+
};
|
|
2166
|
+
|
|
2167
|
+
/**
|
|
2168
|
+
* Provides Zod validation schemas with custom validators.
|
|
2169
|
+
*
|
|
2170
|
+
* @returns {object} An object containing various Zod validators.
|
|
2171
|
+
* @example
|
|
2172
|
+
* const { ZodPhoneValidator } = useZodValidators();
|
|
2173
|
+
*/
|
|
2174
|
+
const useZodValidators = () => {
|
|
2175
|
+
const [t] = useTranslation();
|
|
2176
|
+
const ZodPhoneValidator = zod.z.string().superRefine((phoneNumber, ctx) => {
|
|
2177
|
+
if (!phoneNumber) {
|
|
2178
|
+
return undefined;
|
|
2179
|
+
}
|
|
2180
|
+
const phoneValidationResult = validatePhoneNumber(phoneNumber);
|
|
2181
|
+
if (phoneValidationResult === "REQUIRED") {
|
|
2182
|
+
ctx.addIssue({
|
|
2183
|
+
code: zod.z.ZodIssueCode.custom,
|
|
2184
|
+
message: t("phoneField.error.REQUIRED"),
|
|
2185
|
+
});
|
|
2186
|
+
}
|
|
2187
|
+
if (phoneValidationResult === "REQUIRED_COUNTRY") {
|
|
2188
|
+
ctx.addIssue({
|
|
2189
|
+
code: zod.z.ZodIssueCode.custom,
|
|
2190
|
+
message: t("phoneField.error.REQUIRED_COUNTRY"),
|
|
2191
|
+
});
|
|
2192
|
+
}
|
|
2193
|
+
if (phoneValidationResult === "INVALID_NUMBER" || phoneValidationResult === "INVALID_LENGTH") {
|
|
2194
|
+
ctx.addIssue({
|
|
2195
|
+
code: zod.z.ZodIssueCode.custom,
|
|
2196
|
+
message: t("phoneField.error.INVALID_NUMBER"),
|
|
2197
|
+
});
|
|
2198
|
+
}
|
|
2199
|
+
if (phoneValidationResult === "NOT_A_NUMBER") {
|
|
2200
|
+
ctx.addIssue({
|
|
2201
|
+
code: zod.z.ZodIssueCode.custom,
|
|
2202
|
+
message: t("phoneField.error.NOT_A_NUMBER"),
|
|
2203
|
+
});
|
|
2204
|
+
}
|
|
2205
|
+
if (phoneValidationResult === "TOO_LONG") {
|
|
2206
|
+
ctx.addIssue({
|
|
2207
|
+
code: zod.z.ZodIssueCode.custom,
|
|
2208
|
+
message: t("phoneField.error.TOO_LONG"),
|
|
2209
|
+
});
|
|
2210
|
+
}
|
|
2211
|
+
if (phoneValidationResult === "TOO_SHORT") {
|
|
2212
|
+
ctx.addIssue({
|
|
2213
|
+
code: zod.z.ZodIssueCode.custom,
|
|
2214
|
+
message: t("phoneField.error.TOO_SHORT"),
|
|
2215
|
+
});
|
|
2216
|
+
}
|
|
2217
|
+
});
|
|
2218
|
+
return React.useMemo(() => ({ ZodPhoneValidator }), [ZodPhoneValidator]);
|
|
2219
|
+
};
|
|
2220
|
+
|
|
2221
|
+
/**
|
|
2222
|
+
* Custom hook to get phone number validation rules.
|
|
2223
|
+
*
|
|
2224
|
+
* @returns {object} An object containing the `getPhoneNumberValidationRules` method.
|
|
2225
|
+
* @example
|
|
2226
|
+
* const { getPhoneNumberValidationRules } = useGetPhoneValidationRules();
|
|
2227
|
+
* const validationRules = getPhoneNumberValidationRules(false);
|
|
2228
|
+
*/
|
|
2229
|
+
const useGetPhoneValidationRules = () => {
|
|
2230
|
+
const [t] = useTranslation();
|
|
2231
|
+
const getPhoneNumberValidationRules = React.useCallback((skipValidation = false) => {
|
|
2232
|
+
const defaultRules = {};
|
|
2233
|
+
const pattern = {
|
|
2234
|
+
validate: (value) => {
|
|
2235
|
+
const validationResult = t(`phoneField.error.${validatePhoneNumber(value)}`);
|
|
2236
|
+
return !validationResult || value === "" || value === undefined || value === null || validationResult;
|
|
2237
|
+
},
|
|
2238
|
+
};
|
|
2239
|
+
return !skipValidation
|
|
2240
|
+
? Object.assign(Object.assign({}, pattern), defaultRules) : defaultRules;
|
|
2241
|
+
}, [t]);
|
|
2242
|
+
return { getPhoneNumberValidationRules };
|
|
2243
|
+
};
|
|
2244
|
+
|
|
2305
2245
|
/*
|
|
2306
2246
|
* ----------------------------
|
|
2307
2247
|
* | SETUP TRANSLATIONS START |
|
|
@@ -2336,6 +2276,7 @@ exports.OptionCard = OptionCard;
|
|
|
2336
2276
|
exports.PasswordField = PasswordField;
|
|
2337
2277
|
exports.PasswordInput = PasswordInput;
|
|
2338
2278
|
exports.PhoneField = PhoneField;
|
|
2279
|
+
exports.PhoneFieldWithController = PhoneFieldWithController;
|
|
2339
2280
|
exports.PhoneInput = PhoneInput;
|
|
2340
2281
|
exports.RadioGroup = RadioGroup;
|
|
2341
2282
|
exports.RadioItem = RadioItem;
|
|
@@ -2384,7 +2325,9 @@ exports.isMultiValue = isMultiValue;
|
|
|
2384
2325
|
exports.parseSchedule = parseSchedule;
|
|
2385
2326
|
exports.serializeSchedule = serializeSchedule;
|
|
2386
2327
|
exports.useCustomComponents = useCustomComponents;
|
|
2328
|
+
exports.useGetPhoneValidationRules = useGetPhoneValidationRules;
|
|
2387
2329
|
exports.usePhoneInput = usePhoneInput;
|
|
2330
|
+
exports.useZodValidators = useZodValidators;
|
|
2388
2331
|
exports.validateEmailAddress = validateEmailAddress;
|
|
2389
2332
|
exports.validatePhoneNumber = validatePhoneNumber;
|
|
2390
2333
|
exports.weekDay = weekDay;
|