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