@trackunit/react-form-components 1.8.64 → 1.8.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.cjs.js CHANGED
@@ -10,12 +10,12 @@ var cssClassVarianceUtilities = require('@trackunit/css-class-variance-utilities
10
10
  var stringTs = require('string-ts');
11
11
  var usehooksTs = require('usehooks-ts');
12
12
  var parsePhoneNumberFromString = require('libphonenumber-js');
13
- var sharedUtils = require('@trackunit/shared-utils');
14
- var reactHookForm = require('react-hook-form');
15
13
  var ReactSelect = require('react-select');
14
+ var ReactAsyncSelect = require('react-select/async');
16
15
  var ReactAsyncCreatableSelect = require('react-select/async-creatable');
17
16
  var ReactCreatableSelect = require('react-select/creatable');
18
- var ReactAsyncSelect = require('react-select/async');
17
+ var sharedUtils = require('@trackunit/shared-utils');
18
+ var reactHookForm = require('react-hook-form');
19
19
  var tailwindMerge = require('tailwind-merge');
20
20
  var zod = require('zod');
21
21
 
@@ -698,6 +698,103 @@ const TextAreaBaseInput = ({ id, name, value, rows, disabled, placeholder, readO
698
698
  */
699
699
  const TextBaseInput = ({ ref, ...rest }) => jsxRuntime.jsx(BaseInput, { ref: ref, type: "text", ...rest });
700
700
 
701
+ const cvaSelect = cssClassVarianceUtilities.cvaMerge([
702
+ "relative",
703
+ "flex",
704
+ "shadow-sm",
705
+ "rounded-lg",
706
+ "border-neutral-300",
707
+ "hover:border-neutral-400",
708
+ "hover:bg-neutral-50",
709
+ "bg-white",
710
+ "transition",
711
+ "text-sm",
712
+ "min-h-0",
713
+ ], {
714
+ variants: {
715
+ fieldSize: {
716
+ small: ["h-7", "text-xs"],
717
+ medium: ["h-8"],
718
+ large: ["h-10"],
719
+ },
720
+ invalid: {
721
+ true: "border border-red-600 text-red-600 hover:border-red-600",
722
+ false: "",
723
+ },
724
+ disabled: {
725
+ true: "!bg-neutral-100 hover:border-neutral-300",
726
+ false: "",
727
+ },
728
+ },
729
+ defaultVariants: {
730
+ invalid: false,
731
+ disabled: false,
732
+ },
733
+ });
734
+ const cvaSelectControl = cssClassVarianceUtilities.cvaMerge([], {
735
+ variants: {
736
+ isDisabled: {
737
+ true: "!bg-neutral-100",
738
+ false: "",
739
+ },
740
+ prefix: {
741
+ true: ["ps-7"],
742
+ false: "",
743
+ },
744
+ invalid: {
745
+ true: "!border-0",
746
+ false: "",
747
+ },
748
+ },
749
+ defaultVariants: {
750
+ isDisabled: false,
751
+ prefix: false,
752
+ invalid: false,
753
+ },
754
+ });
755
+ const cvaSelectIcon = cssClassVarianceUtilities.cvaMerge([
756
+ "mr-2",
757
+ "flex",
758
+ "cursor-pointer",
759
+ "items-center",
760
+ "justify-center",
761
+ "text-neutral-400",
762
+ "hover:text-neutral-500",
763
+ ]);
764
+ const cvaSelectPrefixSuffix = cssClassVarianceUtilities.cvaMerge(["flex", "justify-center", "items-center", "text-neutral-400", "absolute", "inset-y-0"], {
765
+ variants: {
766
+ kind: {
767
+ prefix: ["pl-3", "left-0"],
768
+ suffix: ["pr-3", "right-0"],
769
+ },
770
+ },
771
+ });
772
+ const cvaSelectXIcon = cssClassVarianceUtilities.cvaMerge([
773
+ "mr-2",
774
+ "flex",
775
+ "cursor-pointer",
776
+ "items-center",
777
+ "justify-center",
778
+ "text-neutral-400",
779
+ "hover:text-neutral-500",
780
+ "ml-1",
781
+ ]);
782
+ const cvaSelectMenuList = cssClassVarianceUtilities.cvaMerge([], {
783
+ variants: {
784
+ menuIsOpen: {
785
+ true: "animate-fade-in-fast",
786
+ false: "animate-fade-out-fast",
787
+ },
788
+ },
789
+ });
790
+ const cvaSelectDynamicTagContainer = cssClassVarianceUtilities.cvaMerge(["h-full", "flex", "gap-1", "items-center"], {
791
+ variants: {
792
+ visible: { true: "visible", false: "invisible" },
793
+ },
794
+ });
795
+ const cvaSelectCounter = cssClassVarianceUtilities.cvaMerge(["overflow-hidden", "whitespace-nowrap"]);
796
+ const cvaSelectMenu = cssClassVarianceUtilities.cvaMerge(["relative", "p-1", "grid", "gap-1"]);
797
+
701
798
  /**
702
799
  * Shared CVA for binary control items: Checkbox, RadioItem, ToggleSwitchOption
703
800
  */
@@ -924,137 +1021,709 @@ const Checkbox = ({ className, dataTestId = "checkbox", onChange, checked = fals
924
1021
  Checkbox.displayName = "Checkbox";
925
1022
 
926
1023
  /**
927
- * The Label component is used for labels for input fields.
928
- * This component is **not used directly**, but is part of the FormGroup and Field components.
929
- *
930
- * @param {LabelProps} props - The props for the Label component
931
- * @returns {ReactElement} Label component
932
- */
933
- const Label = ({ id, htmlFor, children, className, dataTestId, disabled, isInvalid, }) => {
934
- return (jsxRuntime.jsx("label", { className: cvaLabel({ invalid: isInvalid, disabled, className }), "data-testid": dataTestId, htmlFor: htmlFor || "", id: id || "", children: children }));
935
- };
936
-
937
- const cvaFormGroup = cssClassVarianceUtilities.cvaMerge(["component-formGroup-gap", "group", "form-group"]);
938
- const cvaFormGroupContainerBefore = cssClassVarianceUtilities.cvaMerge(["flex", "mb-1", "items-center"]);
939
- const cvaFormGroupContainerAfter = cssClassVarianceUtilities.cvaMerge(["flex", "justify-between", "mt-1", "text-xs", "text-neutral-500"], {
940
- variants: {
941
- invalid: {
942
- true: "text-danger-500",
943
- false: "",
944
- },
945
- isWarning: {
946
- true: "text-default-500 ",
947
- false: "",
948
- },
949
- },
950
- compoundVariants: [
951
- {
952
- invalid: true,
953
- isWarning: true,
954
- className: "text-danger-500 ", // Ensures that 'invalid' takes precedence
955
- },
956
- ],
957
- });
958
- const cvaHelpAddon = cssClassVarianceUtilities.cvaMerge(["ml-auto"]);
959
-
960
- /**
961
- * The FormGroup component should be used to wrap any Input element that needs a label.
962
- * Besides a label the component supplies an optional Tooltip, HelpText and HelpAddon support.
1024
+ * A single select menu item is a basic wrapper around Menu item designed to be used as a single value render in Select list
963
1025
  *
964
- * @param {FormGroupProps} props - The props for the FormGroup component
965
- * @returns {ReactElement} FormGroup component
1026
+ * @param {SelectMenuItemProps} props - The props for the SingleSelectMenuItem
1027
+ * @returns {ReactElement} SingleSelectMenuItem
966
1028
  */
967
- const FormGroup = ({ isInvalid, isWarning, helpText, helpAddon, tip, className, dataTestId, label, htmlFor, children, required = false, }) => {
968
- const [t] = useTranslation();
969
- const validationStateIcon = react.useMemo(() => {
970
- const color = isInvalid ? "danger" : isWarning ? "warning" : null;
971
- return color ? jsxRuntime.jsx(reactComponents.Icon, { color: color, name: "ExclamationTriangle", size: "small" }) : null;
972
- }, [isInvalid, isWarning]);
973
- return (jsxRuntime.jsxs("div", { className: cvaFormGroup({ className }), "data-testid": dataTestId, children: [label ? (jsxRuntime.jsxs("div", { className: cvaFormGroupContainerBefore(), children: [jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Label, { className: "component-formGroup-font", dataTestId: dataTestId ? `${dataTestId}-label` : undefined, htmlFor: htmlFor, id: htmlFor + "-label", children: label }), required ? (jsxRuntime.jsx(reactComponents.Tooltip, { "data-testid": "required-asterisk", label: t("field.required.asterisk.tooltip"), children: "*" })) : null] }), tip ? (jsxRuntime.jsx(reactComponents.Tooltip, { className: "ml-1", dataTestId: dataTestId ? `${dataTestId}-tooltip` : undefined, label: tip, placement: "bottom" })) : null] })) : null, children, helpText || helpAddon ? (jsxRuntime.jsxs("div", { className: cvaFormGroupContainerAfter({ invalid: isInvalid, isWarning: isWarning }), children: [helpText ? (jsxRuntime.jsxs("div", { className: "flex gap-1", children: [validationStateIcon, jsxRuntime.jsx("span", { "data-testid": dataTestId ? `${dataTestId}-helpText` : undefined, children: helpText })] })) : undefined, helpAddon ? (jsxRuntime.jsx("span", { className: cvaHelpAddon(), "data-testid": dataTestId ? `${dataTestId}-helpAddon` : null, children: helpAddon })) : null] })) : null] }));
1029
+ const SingleSelectMenuItem = ({ label, icon, onClick, selected, focused, dataTestId, disabled, optionLabelDescription, optionPrefix, fieldSize, }) => {
1030
+ return (jsxRuntime.jsx(reactComponents.MenuItem, { dataTestId: dataTestId, disabled: disabled, fieldSize: fieldSize, focused: focused, label: label, onClick: onClick, optionLabelDescription: optionLabelDescription, optionPrefix: react.isValidElement(optionPrefix)
1031
+ ? react.cloneElement(optionPrefix, {
1032
+ className: "mr-1 flex items-center",
1033
+ size: "medium",
1034
+ })
1035
+ : optionPrefix, prefix: icon, selected: selected, suffix: selected ? jsxRuntime.jsx(reactComponents.Icon, { className: "block text-blue-600", name: "Check", size: "medium" }) : undefined }));
974
1036
  };
975
-
976
1037
  /**
977
- * The checkbox field component is used for entering boolean values.
1038
+ * A multi select menu item is a basic wrapper around Menu item designed to be used as a multi value render in Select list
978
1039
  *
979
- * _**Do use**_ the CheckboxField for boolean input.
1040
+ * @param {SelectMenuItemProps} props - The props for the MultiSelectMenuItem
1041
+ * @returns {ReactElement} multi select menu item
980
1042
  */
981
- const CheckboxField = ({ label, id, tip, helpText, helpAddon, isInvalid, className, checked, dataTestId, checkboxLabel, onChange, ref, ...rest }) => {
982
- const htmlForId = id ? id : "checkboxField-" + sharedUtils.uuidv4();
983
- return (jsxRuntime.jsx(FormGroup, { className: "flex flex-col gap-1", dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: helpText, htmlFor: htmlForId, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(Checkbox, { checked: checked, className: className, dataTestId: dataTestId, id: htmlForId, label: checkboxLabel, onChange: onChange, ref: ref, ...rest }) }));
1043
+ const MultiSelectMenuItem = ({ label, onClick, selected, focused, dataTestId, disabled, optionLabelDescription, optionPrefix, fieldSize, }) => {
1044
+ return (jsxRuntime.jsx(reactComponents.MenuItem, { dataTestId: dataTestId, disabled: disabled, fieldSize: fieldSize, focused: focused, label: label, onClick: e => {
1045
+ e.stopPropagation();
1046
+ onClick && onClick(e);
1047
+ }, optionLabelDescription: optionLabelDescription, optionPrefix: react.isValidElement(optionPrefix)
1048
+ ? react.cloneElement(optionPrefix, {
1049
+ className: "mr-1 flex items-center",
1050
+ size: "medium",
1051
+ })
1052
+ : optionPrefix, prefix: jsxRuntime.jsx(Checkbox, { checked: selected, className: "gap-x-0", disabled: disabled, onChange: () => null, onClick: e => {
1053
+ e.stopPropagation();
1054
+ }, readOnly: false }), selected: selected }));
984
1055
  };
985
- CheckboxField.displayName = "CheckboxField";
986
1056
 
987
1057
  /**
1058
+ * Extended Tag component with information about its own width.
1059
+ * Used in the select component.
988
1060
  *
989
- * @param inputValue - value to check if it is a string
990
- * @returns {boolean} - true if value is a string
991
- */
992
- const isString = (inputValue) => {
993
- return typeof inputValue === "string";
994
- };
995
- /**
996
- *
997
- * @param inputValue - value to check if it is a number
998
- * @returns {boolean} - true if value is a number
999
- */
1000
- const isNumber = (inputValue) => {
1001
- return typeof inputValue === "number";
1002
- };
1003
-
1004
- /**
1005
- * Validates a url
1061
+ * @param {TagProps} props - The props for the tag component
1062
+ * @returns {ReactElement} TagWithWidth component
1006
1063
  */
1007
- const validateColorCode = (colorCode, required) => {
1008
- if (!colorCode && !required) {
1009
- return undefined;
1010
- }
1011
- if (!colorCode && required) {
1012
- return "REQUIRED";
1013
- }
1014
- if (colorCode && isString(colorCode) && isValidHEXColor(colorCode)) {
1015
- return undefined;
1016
- }
1017
- return "INVALID_HEX_CODE";
1064
+ const TagWithWidth = ({ onWidthKnown, children, ...rest }) => {
1065
+ const ref = react.useRef(null);
1066
+ react.useLayoutEffect(() => {
1067
+ onWidthKnown && onWidthKnown({ width: ref.current?.offsetWidth || 0 });
1068
+ }, [ref, onWidthKnown]);
1069
+ return (jsxRuntime.jsx(reactComponents.Tag, { ref: ref, ...rest, icon: react.isValidElement(rest.icon) ? react.cloneElement(rest.icon, { size: "small" }) : rest.icon, children: children }));
1018
1070
  };
1019
1071
 
1020
- const cvaInputColorField = cssClassVarianceUtilities.cvaMerge([
1021
- "ml-3",
1022
- "h-4",
1023
- "w-4",
1024
- "self-center",
1025
- "bg-inherit",
1026
- "disabled:opacity-50",
1027
- "disabled:pointer-events-none",
1028
- "rounded-[4px]",
1029
- ], {
1030
- variants: {
1031
- readOnly: {
1032
- true: "pointer-events-none",
1033
- false: "",
1034
- },
1035
- },
1036
- compoundVariants: [
1037
- {
1038
- readOnly: true,
1039
- },
1040
- ],
1041
- defaultVariants: {
1042
- readOnly: false,
1043
- },
1044
- });
1045
-
1046
1072
  /**
1047
- * Validates if the given value is a valid hex color.
1073
+ * TagsContainer component to display tags in limited space when children can't fit space it displays counter
1048
1074
  *
1049
- * @param value - The string value to be validated.
1050
- * @returns {boolean} True if the value is a valid hex color, otherwise false.
1075
+ * @param {TagsContainerProps} props - The props for the TagContainer
1076
+ * @returns {ReactElement} TagsContainer
1051
1077
  */
1052
- const isValidHEXColor = (value) => {
1053
- const hexRegex = /^#([0-9A-F]{6})$/i;
1054
- return hexRegex.test(value);
1055
- };
1056
- /**
1057
- * The ColorField component is used to enter color.
1078
+ const TagsContainer = ({ items, width = "100%", itemsGap = 6, postFix, preFix, disabled, }) => {
1079
+ const containerRef = react.useRef(null);
1080
+ const [isReady, setIsReady] = react.useState(false);
1081
+ const [counterWidth, setCounterWidth] = react.useState(0);
1082
+ const [availableSpaceWidth, setAvailableSpaceWidth] = react.useState(0);
1083
+ const [childrenWidths, setChildrenWidths] = react.useState([]);
1084
+ const itemsCount = items.length;
1085
+ const dimensions = reactComponents.useResize();
1086
+ const { width: windowWidth } = reactComponents.useDebounce(dimensions, 100);
1087
+ react.useEffect(() => {
1088
+ const containerWidth = containerRef.current?.offsetWidth || 0;
1089
+ setAvailableSpaceWidth(containerWidth);
1090
+ }, [windowWidth]);
1091
+ const onWidthKnownHandler = react.useCallback(({ width: reportedWidth }) => {
1092
+ setChildrenWidths(prev => {
1093
+ const next = [...prev, { width: reportedWidth + itemsGap }];
1094
+ if (next.length === itemsCount) {
1095
+ setIsReady(true);
1096
+ }
1097
+ return next;
1098
+ });
1099
+ }, [itemsCount, itemsGap]);
1100
+ const renderedElements = react.useMemo(() => {
1101
+ const requiredSpace = childrenWidths.reduce((previous, current) => {
1102
+ return previous + current.width;
1103
+ }, 0);
1104
+ const availableSpace = availableSpaceWidth - counterWidth;
1105
+ const { elements } = items
1106
+ .concat({ text: "", onClick: () => null, disabled: false })
1107
+ .reduce((acc, item, index) => {
1108
+ const spaceNeeded = childrenWidths.slice(0, index + 1).reduce((previous, current) => {
1109
+ return previous + current.width;
1110
+ }, 0);
1111
+ const isLast = index === items.length;
1112
+ const counterRequired = requiredSpace > availableSpace && acc.counter !== 0;
1113
+ if (isLast && counterRequired) {
1114
+ return {
1115
+ ...acc,
1116
+ elements: [
1117
+ ...acc.elements,
1118
+ jsxRuntime.jsx(TagWithWidth, { color: "white", disabled: disabled, icon: item.Icon, onWidthKnown: ({ width: reportedWidth }) => setCounterWidth(reportedWidth), children: jsxRuntime.jsxs("div", { className: cvaSelectCounter(), "data-testid": "select-counter", children: ["+", acc.counter] }) }, item.text + index),
1119
+ ],
1120
+ };
1121
+ }
1122
+ if (isLast) {
1123
+ return acc;
1124
+ }
1125
+ const itemCanFit = spaceNeeded <= availableSpace;
1126
+ if (itemCanFit) {
1127
+ return {
1128
+ ...acc,
1129
+ elements: [
1130
+ ...acc.elements,
1131
+ jsxRuntime.jsx(TagWithWidth, { className: "inline-flex shrink-0", color: item.disabled ? "neutral" : "white", dataTestId: `${item.text}-tag`, disabled: disabled, icon: item.Icon, onClose: e => {
1132
+ e.stopPropagation();
1133
+ item.onClick();
1134
+ }, onWidthKnown: onWidthKnownHandler, children: item.text }, item.text + index),
1135
+ ],
1136
+ };
1137
+ }
1138
+ return {
1139
+ elements: acc.elements,
1140
+ counter: item.text !== "" ? acc.counter + 1 : acc.counter,
1141
+ };
1142
+ }, { elements: [], counter: 0 });
1143
+ return elements;
1144
+ }, [items, availableSpaceWidth, counterWidth, disabled, onWidthKnownHandler, childrenWidths]);
1145
+ return (jsxRuntime.jsxs("div", { className: cvaSelectDynamicTagContainer({ visible: isReady || !!preFix }), ref: containerRef, style: {
1146
+ width: `${width}`,
1147
+ }, children: [preFix, renderedElements, postFix] }));
1148
+ };
1149
+
1150
+ /**
1151
+ * A hook to retrieve components override object.
1152
+ * 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.
1153
+ *
1154
+ * @template IsMulti
1155
+ * @template Group
1156
+ * @param {Partial<SelectComponents<Option, IsMulti, Group>> | undefined} componentsProps a custom component prop that you can to override defaults
1157
+ * @param {boolean} disabled decide to override disabled variant
1158
+ * @param {boolean} menuIsOpen menu is open state
1159
+ * @param {string} dataTestId a test id
1160
+ * @param {number} maxSelectedDisplayCount a number of max display count
1161
+ * @param {boolean} hasError decide to override hasError variant
1162
+ * @param {ReactNode} prefix a prefix element
1163
+ * @returns {Partial<SelectComponents<Option, boolean, GroupBase<Option>>> | undefined} components object to override react-select default components
1164
+ */
1165
+ const useCustomComponents = ({ componentsProps, disabled, readOnly, setMenuIsEnabled, dataTestId, maxSelectedDisplayCount, prefix, hasError, fieldSize, getOptionLabelDescription, getOptionPrefix, }) => {
1166
+ const [t] = useTranslation();
1167
+ // perhaps it should not be wrap in memo (causing some issues with opening and closing on mobiles)
1168
+ const customComponents = react.useMemo(() => {
1169
+ return {
1170
+ ValueContainer: props => {
1171
+ if (props.isMulti && Array.isArray(props.children) && props.children.length > 0) {
1172
+ const PLACEHOLDER_KEY = "placeholder";
1173
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1174
+ const key = props && props.children && props.children[0] ? props.children[0]?.key : "";
1175
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1176
+ const values = props && props.children ? props.children[0] : [];
1177
+ const tags = key === PLACEHOLDER_KEY ? [] : values;
1178
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1179
+ const searchInput = props && props.children && props.children[1];
1180
+ const placeholderElement = Array.isArray(props.children)
1181
+ ? props.children.find(child => child && child.key === PLACEHOLDER_KEY)
1182
+ : null;
1183
+ return (jsxRuntime.jsx(ReactSelect.components.ValueContainer, { ...props, isDisabled: props.selectProps.isDisabled, children: maxSelectedDisplayCount === undefined ? (jsxRuntime.jsx(TagsContainer, { disabled: disabled, items: tags
1184
+ ? tags.map(({ props: tagProps }) => {
1185
+ const optionPrefix = tagProps.data && getOptionPrefix ? getOptionPrefix(tagProps.data) : null;
1186
+ return {
1187
+ text: tagProps.children,
1188
+ onClick: disabled
1189
+ ? undefined
1190
+ : (e) => {
1191
+ setMenuIsEnabled(false);
1192
+ tagProps.removeProps.onClick && tagProps.removeProps.onClick(e);
1193
+ },
1194
+ disabled: disabled,
1195
+ Icon: optionPrefix,
1196
+ };
1197
+ })
1198
+ : [], postFix: searchInput, preFix: placeholderElement ? jsxRuntime.jsx("span", { className: "absolute", children: placeholderElement }) : null, width: "100%" })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [tags
1199
+ ? tags.slice(0, maxSelectedDisplayCount).map(({ props: tagProps }) => {
1200
+ return (jsxRuntime.jsx(reactComponents.Tag, { className: "inline-flex shrink-0", color: disabled ? "unknown" : "primary", dataTestId: tagProps.children ? `${tagProps.children.toString()}-tag` : undefined, onClose: e => {
1201
+ e.stopPropagation();
1202
+ setMenuIsEnabled(false);
1203
+ tagProps.removeProps.onClick && tagProps.removeProps.onClick(e);
1204
+ }, children: tagProps.children }, tagProps.children?.toString()));
1205
+ })
1206
+ : null, tags && tags.length > maxSelectedDisplayCount ? (jsxRuntime.jsxs(reactComponents.Tag, { color: "neutral", dataTestId: "counter-tag", children: ["+", tags.length - maxSelectedDisplayCount] })) : null, searchInput, placeholderElement] })) }));
1207
+ }
1208
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(ReactSelect.components.ValueContainer, { ...props, isDisabled: props.selectProps.isDisabled, children: props.children }) }));
1209
+ },
1210
+ LoadingIndicator: () => {
1211
+ return jsxRuntime.jsx(reactComponents.Spinner, { centering: "vertically", className: "mr-2", size: "small" });
1212
+ },
1213
+ DropdownIndicator: props => {
1214
+ const icon = props.selectProps.menuIsOpen ? (jsxRuntime.jsx(reactComponents.Icon, { name: "ChevronUp", size: "medium" })) : (jsxRuntime.jsx(reactComponents.Icon, { name: "ChevronDown", size: "medium" }));
1215
+ return props.selectProps.isLoading || props.selectProps.isDisabled || readOnly ? null : (jsxRuntime.jsx(ReactSelect.components.DropdownIndicator, { ...props, children: jsxRuntime.jsx("div", { className: cvaSelectIcon(), children: icon }) }));
1216
+ },
1217
+ IndicatorSeparator: () => null,
1218
+ ClearIndicator: props => {
1219
+ if (disabled) {
1220
+ return null;
1221
+ }
1222
+ return (jsxRuntime.jsx(ReactSelect.components.ClearIndicator, { ...props, innerProps: {
1223
+ ...props.innerProps,
1224
+ onMouseDown: e => {
1225
+ e.preventDefault();
1226
+ },
1227
+ }, children: jsxRuntime.jsx("div", { className: cvaSelectXIcon(), "data-testid": dataTestId ? `${dataTestId}-XMarkIcon` : null, onClick: props.clearValue, children: jsxRuntime.jsx(reactComponents.Icon, { ariaLabel: t("clearIndicator.icon.tooltip.clearAll"), name: "XCircle", size: "medium" }) }) }));
1228
+ },
1229
+ Control: props => {
1230
+ return (jsxRuntime.jsx(ReactSelect.components.Control, { ...props, className: cvaSelectControl({
1231
+ isDisabled: props.isDisabled,
1232
+ prefix: prefix ? true : false,
1233
+ invalid: hasError,
1234
+ }) }));
1235
+ },
1236
+ SingleValue: props => {
1237
+ const optionPrefix = getOptionPrefix ? getOptionPrefix(props.data) : null;
1238
+ return (jsxRuntime.jsx(ReactSelect.components.SingleValue, { ...props, className: props.isDisabled ? "text-neutral-700" : "", children: jsxRuntime.jsxs("div", { className: "flex items-center gap-1", "data-testid": dataTestId + "-singleValue", children: [optionPrefix !== null ? optionPrefix : null, props.children, getOptionLabelDescription && getOptionLabelDescription(props.data) ? (jsxRuntime.jsxs("span", { className: "ml-1 text-neutral-400", children: ["(", getOptionLabelDescription(props.data), ")"] })) : null] }) }));
1239
+ },
1240
+ Menu: props => {
1241
+ return (jsxRuntime.jsx(ReactSelect.components.Menu, { ...props, className: cvaSelectMenuList({ menuIsOpen: props.selectProps.menuIsOpen }) }));
1242
+ },
1243
+ Placeholder: props => {
1244
+ return (jsxRuntime.jsx(ReactSelect.components.Placeholder, { ...props, className: "!text-neutral-400", children: props.children }));
1245
+ },
1246
+ MenuList: props => {
1247
+ return (jsxRuntime.jsx(ReactSelect.components.MenuList, { ...props, innerProps: {
1248
+ ...props.innerProps,
1249
+ onScroll: e => {
1250
+ const listEl = e.currentTarget;
1251
+ if (listEl.scrollTop + listEl.clientHeight >= listEl.scrollHeight &&
1252
+ props.selectProps.onMenuScrollToBottom) {
1253
+ /Firefox/.test(navigator.userAgent)
1254
+ ? props.selectProps.onMenuScrollToBottom(new WheelEvent("scroll"))
1255
+ : props.selectProps.onMenuScrollToBottom(new TouchEvent(""));
1256
+ }
1257
+ },
1258
+ }, children: props.children }));
1259
+ },
1260
+ Option: props => {
1261
+ const componentProps = {
1262
+ label: props.label,
1263
+ focused: props.isFocused,
1264
+ selected: props.isSelected,
1265
+ onClick: props.innerProps.onClick,
1266
+ };
1267
+ return (jsxRuntime.jsx(ReactSelect.components.Option, { ...props, innerProps: {
1268
+ ...props.innerProps,
1269
+ role: "option",
1270
+ onClick: () => { },
1271
+ }, children: props.isMulti ? (jsxRuntime.jsx(MultiSelectMenuItem, { ...componentProps, dataTestId: typeof props.label === "string" ? props.label : undefined, disabled: disabled, fieldSize: fieldSize, optionLabelDescription: getOptionLabelDescription?.(props.data), optionPrefix: getOptionPrefix?.(props.data) })) : (jsxRuntime.jsx(SingleSelectMenuItem, { ...componentProps, dataTestId: typeof props.label === "string" ? props.label : undefined, disabled: disabled || props.isDisabled, fieldSize: fieldSize, optionLabelDescription: getOptionLabelDescription?.(props.data), optionPrefix: getOptionPrefix?.(props.data) })) }));
1272
+ },
1273
+ ...componentsProps,
1274
+ };
1275
+ }, [
1276
+ componentsProps,
1277
+ maxSelectedDisplayCount,
1278
+ disabled,
1279
+ setMenuIsEnabled,
1280
+ readOnly,
1281
+ dataTestId,
1282
+ t,
1283
+ prefix,
1284
+ hasError,
1285
+ getOptionLabelDescription,
1286
+ fieldSize,
1287
+ getOptionPrefix,
1288
+ ]);
1289
+ return customComponents;
1290
+ };
1291
+
1292
+ /**
1293
+ * @template IsMulti
1294
+ * @template Group
1295
+ * @param {RefObject<HTMLDivElement | null>} refContainer react ref to container element
1296
+ * @param {number | undefined} maxSelectedDisplayCount a number of max display count
1297
+ * @param {StylesConfig<Option, IsMulti, Group> | undefined} styles a optional object to override styles of react-select
1298
+ * @returns {StylesConfig<Option, boolean>} styles to override in select
1299
+ */
1300
+ const useCustomStyles = ({ refContainer, maxSelectedDisplayCount, styles, disabled, fieldSize, }) => {
1301
+ const customStyles = react.useMemo(() => {
1302
+ return {
1303
+ control: base => {
1304
+ return {
1305
+ ...base,
1306
+ minHeight: fieldSize === "small" ? "28px" : fieldSize === "large" ? "40px" : "32px",
1307
+ borderRadius: "var(--border-radius-lg)",
1308
+ backgroundColor: "inherit",
1309
+ };
1310
+ },
1311
+ singleValue: base => ({
1312
+ ...base,
1313
+ }),
1314
+ multiValue: base => ({
1315
+ ...base,
1316
+ }),
1317
+ multiValueLabel: base => ({
1318
+ ...base,
1319
+ }),
1320
+ indicatorsContainer: base => ({
1321
+ ...base,
1322
+ ...(disabled && { display: "none" }),
1323
+ }),
1324
+ indicatorSeparator: () => ({
1325
+ width: "0px",
1326
+ }),
1327
+ menu: base => {
1328
+ return {
1329
+ ...base,
1330
+ width: "100%",
1331
+ marginTop: "4px",
1332
+ marginBottom: "18px",
1333
+ transition: "all 1s ease-in-out",
1334
+ };
1335
+ },
1336
+ input: base => ({
1337
+ ...base,
1338
+ marginLeft: "0px",
1339
+ }),
1340
+ placeholder: base => ({
1341
+ ...base,
1342
+ }),
1343
+ option: () => ({}),
1344
+ menuPortal: base => ({
1345
+ ...base,
1346
+ width: refContainer.current ? `${refContainer.current.clientWidth}px` : base.width,
1347
+ backgroundColor: "#ffffff",
1348
+ borderRadius: "var(--border-radius-lg)",
1349
+ zIndex: "var(--z-overlay)",
1350
+ borderColor: "rgb(var(--color-neutral-300))",
1351
+ boxShadow: "var(--tw-ring-inset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)",
1352
+ }),
1353
+ menuList: base => {
1354
+ return {
1355
+ ...base,
1356
+ position: "relative",
1357
+ padding: "var(--spacing-1)",
1358
+ display: "grid",
1359
+ gap: "var(--spacing-1)",
1360
+ width: "100%",
1361
+ borderRadius: "0px",
1362
+ boxShadow: "none",
1363
+ paddingTop: "0px",
1364
+ };
1365
+ },
1366
+ valueContainer: base => {
1367
+ return {
1368
+ ...base,
1369
+ paddingBlock: 0,
1370
+ flexWrap: maxSelectedDisplayCount !== undefined ? "wrap" : "nowrap",
1371
+ gap: "0.25rem",
1372
+ };
1373
+ },
1374
+ container: base => ({
1375
+ ...base,
1376
+ width: "100%",
1377
+ }),
1378
+ dropdownIndicator: base => ({
1379
+ ...base,
1380
+ padding: "0px",
1381
+ }),
1382
+ clearIndicator: base => {
1383
+ return {
1384
+ ...base,
1385
+ padding: "0px",
1386
+ };
1387
+ },
1388
+ ...styles,
1389
+ };
1390
+ }, [refContainer, disabled, fieldSize, maxSelectedDisplayCount, styles]);
1391
+ return { customStyles };
1392
+ };
1393
+
1394
+ /**
1395
+ * A hook used by selects to share the common code
1396
+ *
1397
+ * @param {SelectProps} props - The props for the Select component
1398
+ * @returns {UseSelectProps} Select component
1399
+ */
1400
+ const useSelect = ({ id, className, dataTestId = "select", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, components, value, options, onChange, isLoading, classNamePrefix = "", onMenuOpen, onMenuClose, maxSelectedDisplayCount = undefined, isClearable = false, isSearchable = true, onMenuScrollToBottom, styles, filterOption, onInputChange, getOptionLabelDescription, getOptionPrefix, fieldSize = "medium", ...props }) => {
1401
+ const refContainer = react.useRef(document.createElement("div"));
1402
+ const { customStyles } = useCustomStyles({
1403
+ refContainer,
1404
+ maxSelectedDisplayCount,
1405
+ styles,
1406
+ disabled: Boolean(disabled),
1407
+ fieldSize,
1408
+ });
1409
+ const [menuIsOpen, setMenuIsOpen] = react.useState(props.menuIsOpen ?? false);
1410
+ const [menuIsEnabled, setMenuIsEnabled] = react.useState(true);
1411
+ const customComponents = useCustomComponents({
1412
+ componentsProps: components,
1413
+ disabled: Boolean(disabled),
1414
+ readOnly: Boolean(props.readOnly),
1415
+ setMenuIsEnabled,
1416
+ dataTestId,
1417
+ maxSelectedDisplayCount,
1418
+ prefix,
1419
+ hasError,
1420
+ fieldSize,
1421
+ getOptionLabelDescription,
1422
+ getOptionPrefix,
1423
+ });
1424
+ const menuPlacement = "auto";
1425
+ const openMenuHandler = async () => {
1426
+ onMenuOpen?.();
1427
+ if (menuIsEnabled) {
1428
+ setMenuIsOpen(true);
1429
+ }
1430
+ else {
1431
+ setMenuIsEnabled(true);
1432
+ }
1433
+ };
1434
+ const closeMenuHandler = () => {
1435
+ setMenuIsOpen(false);
1436
+ onMenuClose && onMenuClose();
1437
+ };
1438
+ return {
1439
+ refContainer,
1440
+ customStyles,
1441
+ menuIsOpen,
1442
+ customComponents,
1443
+ menuPlacement,
1444
+ openMenuHandler,
1445
+ closeMenuHandler,
1446
+ };
1447
+ };
1448
+
1449
+ // This is here to ensure the bundled react-components can expose the react-select for jest in external iris apps.
1450
+ const ReactSyncSelect = ReactSelect.default || ReactSelect;
1451
+ /**
1452
+ * Selects are input components used to choose a value from a set.
1453
+ *
1454
+ * @param {SelectProps} props - The props for the Select component
1455
+ * @returns {ReactElement} Select component
1456
+ */
1457
+ const BaseSelect = (props) => {
1458
+ const { id, dataTestId = "select", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, menuPosition = "absolute", value, options, onChange, isLoading, classNamePrefix = "select", onMenuScrollToBottom, onInputChange, isSearchable, isClearable = false, readOnly, fieldSize = "medium", openMenuOnClick = !disabled, openMenuOnFocus = false, hideSelectedOptions = false, } = props;
1459
+ const { refContainer, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler } = useSelect(props);
1460
+ const reactSelectProps = react.useMemo(() => ({
1461
+ value,
1462
+ menuPlacement,
1463
+ maxMenuHeight,
1464
+ onChange,
1465
+ "aria-label": label,
1466
+ "data-testid": dataTestId,
1467
+ components: customComponents,
1468
+ styles: customStyles,
1469
+ tabSelectsValue: false,
1470
+ blurInputOnSelect: false,
1471
+ // This configuration allows for more flexible positioning control of the dropdown.
1472
+ // Setting menuPortalTarget to 'null' specifies that the dropdown should be rendered within
1473
+ // the parent element instead of 'document.body'.
1474
+ menuPortalTarget: props.menuPortalTarget !== undefined ? props.menuPortalTarget : document.body,
1475
+ isSearchable: disabled || readOnly ? false : isSearchable,
1476
+ menuShouldBlockScroll: true,
1477
+ menuShouldScrollIntoView: true,
1478
+ openMenuOnFocus,
1479
+ menuIsOpen: !readOnly ? menuIsOpen : false,
1480
+ openMenuOnClick,
1481
+ closeMenuOnSelect: !isMulti,
1482
+ isMulti,
1483
+ classNamePrefix,
1484
+ isLoading,
1485
+ isClearable,
1486
+ id,
1487
+ onMenuScrollToBottom,
1488
+ onInputChange,
1489
+ hideSelectedOptions,
1490
+ isDisabled: Boolean(disabled),
1491
+ }), [
1492
+ classNamePrefix,
1493
+ customComponents,
1494
+ customStyles,
1495
+ dataTestId,
1496
+ disabled,
1497
+ hideSelectedOptions,
1498
+ id,
1499
+ isClearable,
1500
+ isLoading,
1501
+ isMulti,
1502
+ isSearchable,
1503
+ label,
1504
+ maxMenuHeight,
1505
+ menuIsOpen,
1506
+ menuPlacement,
1507
+ onChange,
1508
+ onInputChange,
1509
+ onMenuScrollToBottom,
1510
+ openMenuOnClick,
1511
+ openMenuOnFocus,
1512
+ props.menuPortalTarget,
1513
+ readOnly,
1514
+ value,
1515
+ ]);
1516
+ const renderAsDisabled = Boolean(props.disabled) || props.readOnly;
1517
+ return (jsxRuntime.jsxs("div", { className: cvaSelect({
1518
+ invalid: hasError,
1519
+ fieldSize: fieldSize,
1520
+ disabled: renderAsDisabled,
1521
+ className: props.className,
1522
+ }), "data-testid": dataTestId, ref: refContainer, children: [prefix !== undefined ? (jsxRuntime.jsx("div", { className: cvaSelectPrefixSuffix({ kind: "prefix" }), "data-testid": dataTestId ? `${dataTestId}-prefix` : null, children: prefix })) : null, async ? (jsxRuntime.jsx(ReactAsyncSelect, { ...props, ...reactSelectProps, ...async, menuPosition: menuPosition, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, placeholder: renderAsDisabled ? null : props.placeholder })) : (jsxRuntime.jsx(ReactSyncSelect, { ...props, ...reactSelectProps, isMulti: isMulti, menuPosition: menuPosition, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, options: options, placeholder: renderAsDisabled ? null : props.placeholder })), typeof props.disabled === "object" ? (jsxRuntime.jsx("div", { className: cvaSelectPrefixSuffix({ kind: "suffix" }), "data-testid": dataTestId ? `${dataTestId}-locked` : null, children: jsxRuntime.jsx(InputLockReasonTooltip, { ...props.disabled }) })) : null] }));
1523
+ };
1524
+ BaseSelect.displayName = "BaseSelect";
1525
+
1526
+ /**
1527
+ * CreatableSelects are input components used to choose a value from a set.
1528
+ *
1529
+ * @param {CreatableSelectProps} props - The props for the CreatableSelect component
1530
+ * @returns {ReactElement} CreatableSelect component
1531
+ */
1532
+ const CreatableSelect = (props) => {
1533
+ const { id, dataTestId = "creatableSelect", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, value, options, onChange, isLoading, classNamePrefix = "creatableSelect", onMenuScrollToBottom, onInputChange, isSearchable, isClearable = false, readOnly, openMenuOnClick = !disabled, openMenuOnFocus = !disabled, allowCreateWhileLoading, onCreateOption, } = props;
1534
+ const { refContainer, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler } = useSelect(props);
1535
+ const reactCreatableSelectProps = react.useMemo(() => ({
1536
+ value,
1537
+ menuPlacement,
1538
+ maxMenuHeight,
1539
+ onChange,
1540
+ "aria-label": label,
1541
+ "data-testid": dataTestId,
1542
+ components: customComponents,
1543
+ styles: customStyles,
1544
+ tabSelectsValue: false,
1545
+ blurInputOnSelect: !isMulti,
1546
+ menuPortalTarget: props.menuPortalTarget || document.body,
1547
+ isSearchable: disabled || readOnly ? false : isSearchable,
1548
+ menuShouldBlockScroll: true,
1549
+ menuShouldScrollIntoView: true,
1550
+ openMenuOnFocus,
1551
+ menuIsOpen: !readOnly ? menuIsOpen : false,
1552
+ openMenuOnClick,
1553
+ closeMenuOnSelect: false,
1554
+ isMulti,
1555
+ classNamePrefix,
1556
+ isLoading,
1557
+ isClearable,
1558
+ id,
1559
+ onMenuScrollToBottom,
1560
+ onInputChange,
1561
+ allowCreateWhileLoading,
1562
+ onCreateOption,
1563
+ isDisabled: Boolean(disabled),
1564
+ }), [
1565
+ allowCreateWhileLoading,
1566
+ classNamePrefix,
1567
+ customComponents,
1568
+ customStyles,
1569
+ dataTestId,
1570
+ disabled,
1571
+ id,
1572
+ isClearable,
1573
+ isLoading,
1574
+ isMulti,
1575
+ isSearchable,
1576
+ label,
1577
+ maxMenuHeight,
1578
+ menuIsOpen,
1579
+ menuPlacement,
1580
+ onChange,
1581
+ onCreateOption,
1582
+ onInputChange,
1583
+ onMenuScrollToBottom,
1584
+ openMenuOnClick,
1585
+ openMenuOnFocus,
1586
+ props.menuPortalTarget,
1587
+ readOnly,
1588
+ value,
1589
+ ]);
1590
+ const renderAsDisabled = Boolean(props.disabled) || props.readOnly;
1591
+ return (jsxRuntime.jsxs("div", { className: cvaSelect({ invalid: hasError, disabled: renderAsDisabled, className: props.className }), "data-testid": dataTestId, ref: refContainer, children: [prefix !== undefined ? (jsxRuntime.jsx("div", { className: cvaSelectPrefixSuffix({ kind: "prefix" }), "data-testid": dataTestId ? `${dataTestId}-prefix` : null, children: prefix })) : null, async ? (jsxRuntime.jsx(ReactAsyncCreatableSelect, { ...props, ...reactCreatableSelectProps, ...async, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, placeholder: renderAsDisabled ? null : props.placeholder })) : (jsxRuntime.jsx(ReactCreatableSelect, { ...props, ...reactCreatableSelectProps, hideSelectedOptions: false, isMulti: isMulti, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, options: options, placeholder: renderAsDisabled ? null : props.placeholder })), typeof props.disabled === "object" ? (jsxRuntime.jsx("div", { className: cvaSelectPrefixSuffix({ kind: "suffix" }), "data-testid": dataTestId ? `${dataTestId}-locked` : null, children: jsxRuntime.jsx(InputLockReasonTooltip, { ...props.disabled }) })) : null] }));
1592
+ };
1593
+ CreatableSelect.displayName = "CreatableSelect";
1594
+
1595
+ /**
1596
+ * The Label component is used for labels for input fields.
1597
+ * This component is **not used directly**, but is part of the FormGroup and Field components.
1598
+ *
1599
+ * @param {LabelProps} props - The props for the Label component
1600
+ * @returns {ReactElement} Label component
1601
+ */
1602
+ const Label = ({ id, htmlFor, children, className, dataTestId, disabled, isInvalid, }) => {
1603
+ return (jsxRuntime.jsx("label", { className: cvaLabel({ invalid: isInvalid, disabled, className }), "data-testid": dataTestId, htmlFor: htmlFor || "", id: id || "", children: children }));
1604
+ };
1605
+
1606
+ const cvaFormGroup = cssClassVarianceUtilities.cvaMerge(["component-formGroup-gap", "group", "form-group"]);
1607
+ const cvaFormGroupContainerBefore = cssClassVarianceUtilities.cvaMerge(["flex", "mb-1", "items-center"]);
1608
+ const cvaFormGroupContainerAfter = cssClassVarianceUtilities.cvaMerge(["flex", "justify-between", "mt-1", "text-xs", "text-neutral-500"], {
1609
+ variants: {
1610
+ invalid: {
1611
+ true: "text-danger-500",
1612
+ false: "",
1613
+ },
1614
+ isWarning: {
1615
+ true: "text-default-500 ",
1616
+ false: "",
1617
+ },
1618
+ },
1619
+ compoundVariants: [
1620
+ {
1621
+ invalid: true,
1622
+ isWarning: true,
1623
+ className: "text-danger-500 ", // Ensures that 'invalid' takes precedence
1624
+ },
1625
+ ],
1626
+ });
1627
+ const cvaHelpAddon = cssClassVarianceUtilities.cvaMerge(["ml-auto"]);
1628
+
1629
+ /**
1630
+ * The FormGroup component should be used to wrap any Input element that needs a label.
1631
+ * Besides a label the component supplies an optional Tooltip, HelpText and HelpAddon support.
1632
+ *
1633
+ * @param {FormGroupProps} props - The props for the FormGroup component
1634
+ * @returns {ReactElement} FormGroup component
1635
+ */
1636
+ const FormGroup = ({ isInvalid, isWarning, helpText, helpAddon, tip, className, dataTestId, label, htmlFor, children, required = false, }) => {
1637
+ const [t] = useTranslation();
1638
+ const validationStateIcon = react.useMemo(() => {
1639
+ const color = isInvalid ? "danger" : isWarning ? "warning" : null;
1640
+ return color ? jsxRuntime.jsx(reactComponents.Icon, { color: color, name: "ExclamationTriangle", size: "small" }) : null;
1641
+ }, [isInvalid, isWarning]);
1642
+ return (jsxRuntime.jsxs("div", { className: cvaFormGroup({ className }), "data-testid": dataTestId, children: [label ? (jsxRuntime.jsxs("div", { className: cvaFormGroupContainerBefore(), children: [jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Label, { className: "component-formGroup-font", dataTestId: dataTestId ? `${dataTestId}-label` : undefined, htmlFor: htmlFor, id: htmlFor + "-label", children: label }), required ? (jsxRuntime.jsx(reactComponents.Tooltip, { "data-testid": "required-asterisk", label: t("field.required.asterisk.tooltip"), children: "*" })) : null] }), tip ? (jsxRuntime.jsx(reactComponents.Tooltip, { className: "ml-1", dataTestId: dataTestId ? `${dataTestId}-tooltip` : undefined, label: tip, placement: "bottom" })) : null] })) : null, children, helpText || helpAddon ? (jsxRuntime.jsxs("div", { className: cvaFormGroupContainerAfter({ invalid: isInvalid, isWarning: isWarning }), children: [helpText ? (jsxRuntime.jsxs("div", { className: "flex gap-1", children: [validationStateIcon, jsxRuntime.jsx("span", { "data-testid": dataTestId ? `${dataTestId}-helpText` : undefined, children: helpText })] })) : undefined, helpAddon ? (jsxRuntime.jsx("span", { className: cvaHelpAddon(), "data-testid": dataTestId ? `${dataTestId}-helpAddon` : null, children: helpAddon })) : null] })) : null] }));
1643
+ };
1644
+
1645
+ /**
1646
+ * The checkbox field component is used for entering boolean values.
1647
+ *
1648
+ * _**Do use**_ the CheckboxField for boolean input.
1649
+ */
1650
+ const CheckboxField = ({ label, id, tip, helpText, helpAddon, isInvalid, className, checked, dataTestId, checkboxLabel, onChange, ref, ...rest }) => {
1651
+ const htmlForId = id ? id : "checkboxField-" + sharedUtils.uuidv4();
1652
+ return (jsxRuntime.jsx(FormGroup, { className: "flex flex-col gap-1", dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: helpText, htmlFor: htmlForId, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(Checkbox, { checked: checked, className: className, dataTestId: dataTestId, id: htmlForId, label: checkboxLabel, onChange: onChange, ref: ref, ...rest }) }));
1653
+ };
1654
+ CheckboxField.displayName = "CheckboxField";
1655
+
1656
+ /**
1657
+ *
1658
+ * @param inputValue - value to check if it is a string
1659
+ * @returns {boolean} - true if value is a string
1660
+ */
1661
+ const isString = (inputValue) => {
1662
+ return typeof inputValue === "string";
1663
+ };
1664
+ /**
1665
+ *
1666
+ * @param inputValue - value to check if it is a number
1667
+ * @returns {boolean} - true if value is a number
1668
+ */
1669
+ const isNumber = (inputValue) => {
1670
+ return typeof inputValue === "number";
1671
+ };
1672
+
1673
+ /**
1674
+ * Validates a url
1675
+ */
1676
+ const validateColorCode = (colorCode, required) => {
1677
+ if (!colorCode && !required) {
1678
+ return undefined;
1679
+ }
1680
+ if (!colorCode && required) {
1681
+ return "REQUIRED";
1682
+ }
1683
+ if (colorCode && isString(colorCode) && isValidHEXColor(colorCode)) {
1684
+ return undefined;
1685
+ }
1686
+ return "INVALID_HEX_CODE";
1687
+ };
1688
+
1689
+ const cvaInputColorField = cssClassVarianceUtilities.cvaMerge([
1690
+ "ml-3",
1691
+ "h-4",
1692
+ "w-4",
1693
+ "self-center",
1694
+ "bg-inherit",
1695
+ "disabled:opacity-50",
1696
+ "disabled:pointer-events-none",
1697
+ "rounded-[4px]",
1698
+ ], {
1699
+ variants: {
1700
+ readOnly: {
1701
+ true: "pointer-events-none",
1702
+ false: "",
1703
+ },
1704
+ },
1705
+ compoundVariants: [
1706
+ {
1707
+ readOnly: true,
1708
+ },
1709
+ ],
1710
+ defaultVariants: {
1711
+ readOnly: false,
1712
+ },
1713
+ });
1714
+
1715
+ /**
1716
+ * Validates if the given value is a valid hex color.
1717
+ *
1718
+ * @param value - The string value to be validated.
1719
+ * @returns {boolean} True if the value is a valid hex color, otherwise false.
1720
+ */
1721
+ const isValidHEXColor = (value) => {
1722
+ const hexRegex = /^#([0-9A-F]{6})$/i;
1723
+ return hexRegex.test(value);
1724
+ };
1725
+ /**
1726
+ * The ColorField component is used to enter color.
1058
1727
  * ColorField validates that user enters a valid color address.
1059
1728
  *
1060
1729
  */
@@ -1311,6 +1980,73 @@ const EmailField = ({ label, id, tip, helpText, errorMessage, helpAddon, classNa
1311
1980
  };
1312
1981
  EmailField.displayName = "EmailField";
1313
1982
 
1983
+ /** Type guard for function refs vs. object refs without deprecated types or assertions */
1984
+ function isWritableRef(r) {
1985
+ return typeof r === "object" && r !== null && "current" in r;
1986
+ }
1987
+ /**
1988
+ * Multi adapter:
1989
+ * - keeps Option[] semantics (via `MultiValue<Option>`)
1990
+ * - renders FormGroup chrome (label, help, error)
1991
+ * - exposes a hidden <select> for a stable ref target
1992
+ * - optionally renders one hidden <input> per selected option IF `getOptionValue` is provided
1993
+ * - passes through all remaining BaseSelect props with isMulti=true
1994
+ */
1995
+ const FormFieldSelectAdapterMulti = (props) => {
1996
+ const { className, dataTestId, helpText, helpAddon, tip, label, isInvalid, errorMessage, name, onBlur, options, value, defaultValue, id, onChange, children, ref, ...selectProps } = props;
1997
+ // Hidden select for a stable DOM ref target (API parity with single adapter)
1998
+ const innerRef = react.useRef(null);
1999
+ // Bridge external ref (supports both callback and object refs)
2000
+ react.useEffect(() => {
2001
+ if (typeof ref === "function") {
2002
+ ref(innerRef.current);
2003
+ }
2004
+ else if (isWritableRef(ref)) {
2005
+ ref.current = innerRef.current;
2006
+ }
2007
+ }, [ref]);
2008
+ // Determine invalid state
2009
+ const renderAsInvalid = react.useMemo(() => (isInvalid === undefined ? Boolean(errorMessage) : isInvalid), [errorMessage, isInvalid]);
2010
+ // id to connect label and control
2011
+ const controlId = react.useMemo(() => (id ? id : "multiSelectField-" + sharedUtils.uuidv4()), [id]);
2012
+ // If consumers provided getOptionValue (from BaseSelect props),
2013
+ // we can render hidden inputs for native form submit / RHF.
2014
+ const selectPropsWithAccessors = selectProps;
2015
+ const getOptionValue = typeof selectPropsWithAccessors.getOptionValue === "function" ? selectPropsWithAccessors.getOptionValue : undefined;
2016
+ // Compute selected options snapshot for hidden inputs (prefer controlled `value`)
2017
+ const selectedOptions = react.useMemo(() => value ?? defaultValue ?? [], [value, defaultValue]);
2018
+ // Build the exact prop bag for BaseSelect (multi=true).
2019
+ const childProps = {
2020
+ ...selectProps,
2021
+ id: controlId,
2022
+ onBlur,
2023
+ options,
2024
+ isMulti: true,
2025
+ value: value ?? null,
2026
+ defaultValue,
2027
+ onChange: next => onChange?.(next),
2028
+ };
2029
+ return (jsxRuntime.jsxs(FormGroup, { className: className, dataTestId: dataTestId, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: controlId, isInvalid: renderAsInvalid, label: label, required: "required" in selectProps && selectProps.required
2030
+ ? !(("disabled" in selectProps && Boolean(selectProps.disabled)) ||
2031
+ ("readOnly" in selectProps && Boolean(selectProps.readOnly)))
2032
+ : false, tip: tip, children: [jsxRuntime.jsx("select", { "aria-hidden": "true", defaultValue: "", hidden: true, name: name, ref: innerRef }), typeof getOptionValue === "function" &&
2033
+ selectedOptions.map((opt, idx) => {
2034
+ const primitiveValue = getOptionValue(opt);
2035
+ return typeof primitiveValue === "string" ? (jsxRuntime.jsx("input", { name: name, type: "hidden", value: primitiveValue }, `${primitiveValue}-${idx}`)) : null;
2036
+ }), children(childProps)] }));
2037
+ };
2038
+ FormFieldSelectAdapterMulti.displayName = "FormFieldSelectAdapterMulti";
2039
+
2040
+ /**
2041
+ * MultiSelectField — validated multi-select field.
2042
+ * Types mirror BaseSelect: options: Option[], value/defaultValue: Option[], onChange: (Option[] | null) => void
2043
+ * Implemented as a generic const component (no forwardRef, no assertions).
2044
+ */
2045
+ const MultiSelectField = ({ ref, ...props }) => {
2046
+ return (jsxRuntime.jsx(FormFieldSelectAdapterMulti, { ...props, ref: ref, children: convertedProps => jsxRuntime.jsx(BaseSelect, { ...convertedProps }) }));
2047
+ };
2048
+ MultiSelectField.displayName = "MultiSelectField";
2049
+
1314
2050
  const isNumberValid = (number) => {
1315
2051
  if (!isNaN(+number) === false) {
1316
2052
  return false;
@@ -1352,1333 +2088,664 @@ const validateNumber = (number, required = false, min, max) => {
1352
2088
  }
1353
2089
  // if the value is greater than max
1354
2090
  if (isNumberValid(parsedNumber) && maxValue !== undefined && parsedNumber > maxValue) {
1355
- return "LESS_THAN";
1356
- }
1357
- // if the value is a number and is valid
1358
- if (isNumber(parsedNumber) && isNumberValid(parsedNumber)) {
1359
- return undefined;
1360
- }
1361
- return "INVALID_NUMBER";
1362
- };
1363
-
1364
- /**
1365
- * The number field component is used for entering numeric values and includes controls for incrementally increasing or decreasing the value.
1366
- *
1367
- * _**Do use**_ the NumberField when the controls to incrementally increase or decrease makes the task easier for the user.
1368
- *
1369
- * _**Do not use**_ this fields for non-serialized numbers. Use TextField instead.
1370
- */
1371
- const NumberField = ({ label, id, tip, helpText, errorMessage, helpAddon, isInvalid, maxLength, className, value, dataTestId, defaultValue, onBlur, onChange, ref, ...rest }) => {
1372
- const htmlForId = id ? id : "numberField-" + sharedUtils.uuidv4();
1373
- const [t] = useTranslation();
1374
- const [innerValue, setInnerValue] = react.useState(() => {
1375
- return Number(value?.toString()) || Number(defaultValue?.toString());
1376
- });
1377
- const [renderAsInvalid, setRenderAsInvalid] = react.useState((isInvalid === undefined ? Boolean(errorMessage) : isInvalid) ||
1378
- !!validateNumber(value?.toString(), rest.required, rest.min, rest.max));
1379
- const errorType = react.useMemo(() => validateNumber(innerValue, rest.required, rest.min, rest.max), [innerValue, rest.max, rest.min, rest.required]);
1380
- const error = react.useMemo(() => {
1381
- // for the case when a custom error message is provided
1382
- if (errorMessage) {
1383
- return errorMessage;
1384
- }
1385
- else if (errorType) {
1386
- return t(`numberField.error.${errorType}`, { min: rest.min, max: rest.max });
1387
- }
1388
- return errorMessage;
1389
- }, [errorMessage, errorType, rest.max, rest.min, t]);
1390
- react.useEffect(() => {
1391
- if (errorMessage) {
1392
- setRenderAsInvalid(Boolean(errorMessage));
1393
- }
1394
- }, [errorMessage]);
1395
- const handleBlur = react.useCallback(event => {
1396
- const newValue = event.target.value;
1397
- setInnerValue(newValue.toString());
1398
- // for the case when a custom error message is provided
1399
- if (errorMessage && !validateNumber(newValue, rest.required, rest.min, rest.max)) {
1400
- setRenderAsInvalid(Boolean(errorMessage));
1401
- }
1402
- else {
1403
- setRenderAsInvalid(!!validateNumber(newValue, rest.required, rest.min, rest.max));
1404
- }
1405
- onBlur?.(event);
1406
- }, [errorMessage, onBlur, rest.max, rest.min, rest.required]);
1407
- const handleChange = react.useCallback((event) => {
1408
- setInnerValue(event.target.value);
1409
- if (onChange) {
1410
- onChange(event);
1411
- }
1412
- }, [onChange]);
1413
- return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && error) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(NumberBaseInput, { "aria-labelledby": htmlForId + "-label", id: htmlForId, isInvalid: renderAsInvalid, maxLength: maxLength, onBlur: handleBlur, onChange: handleChange, ref: ref, value: value, ...rest, className: className, dataTestId: dataTestId }) }));
1414
- };
1415
- NumberField.displayName = "NumberField";
1416
-
1417
- const cvaOptionCardLabel = cssClassVarianceUtilities.cvaMerge([
1418
- "group",
1419
- "transition",
1420
- "bg-white",
1421
- "outline",
1422
- "outline-1",
1423
- "outline-neutral-300",
1424
- "hover:bg-neutral-100",
1425
- "focus:bg-neutral-200",
1426
- "active:bg-neutral-200",
1427
- "peer-checked:bg-primary-50",
1428
- "peer-checked:outline-primary-600",
1429
- "peer-checked:outline-2",
1430
- "flex",
1431
- "gap-2",
1432
- "justify-center",
1433
- "items-center",
1434
- "text-center",
1435
- "rounded-md",
1436
- "relative",
1437
- ], {
1438
- variants: {
1439
- disabled: {
1440
- true: ["cursor-not-allowed", "bg-neutral-100"],
1441
- false: ["cursor-pointer"],
1442
- },
1443
- layout: {
1444
- default: ["flex-col", "p-responsive-space", "w-full", "aspect-square"],
1445
- compact: ["px-3", "py-1.5", "h-8", "min-h-[calc(var(--line-height-sm)+var(--spacing-3))]", "flex-row", "w-fit"],
1446
- },
1447
- },
1448
- });
1449
- const cvaOptionCardContent = cssClassVarianceUtilities.cvaMerge(["flex", "flex-col", "items-center"]);
1450
- const cvaOptionCardContainer = cssClassVarianceUtilities.cvaMerge(["contents"]);
1451
- const cvaOptionCardTitle = cssClassVarianceUtilities.cvaMerge(["text-neutral-600"], {
1452
- variants: {
1453
- layout: {
1454
- default: ["text-lg", "line-clamp-2"],
1455
- compact: ["text-sm", "line-clamp-1"],
1456
- },
1457
- disabled: {
1458
- true: ["text-neutral-400"],
1459
- false: ["focus:text-neutral-800", "active:text-neutral-800"],
1460
- },
1461
- },
1462
- });
1463
- const cvaOptionCardText = cssClassVarianceUtilities.cvaMerge(["text-neutral-600", "text-sm"], {
1464
- variants: {
1465
- type: {
1466
- subheading: ["font-medium"],
1467
- description: ["font-normal"],
1468
- },
1469
- disabled: {
1470
- true: ["text-neutral-400"],
1471
- false: ["focus:text-neutral-800", "active:text-neutral-800"],
1472
- },
1473
- },
1474
- });
1475
- const cvaInput = cssClassVarianceUtilities.cvaMerge(["peer", "absolute", "h-0", "w-0", "opacity-0"]);
1476
- const cvaCustomImage = cssClassVarianceUtilities.cvaMerge(["text-neutral-400"], {
1477
- variants: {
1478
- disabled: {
1479
- true: ["!text-neutral-400"],
1480
- false: [""],
1481
- },
1482
- },
1483
- });
1484
- const cvaTag = cssClassVarianceUtilities.cvaMerge([], {
1485
- variants: {
1486
- layout: {
1487
- default: ["absolute", "top-2", "right-2"],
1488
- compact: [],
1489
- },
1490
- },
1491
- });
1492
-
1493
- /**
1494
- * A card version of a radio button that includes an icon, headings and a description.
1495
- */
1496
- const OptionCard = ({ icon, heading, subheading, description, disabled, id, value, className, contentClassName, dataTestId, customImage, layout = "default", ref, tagProps, ...rest }) => {
1497
- const htmlForId = id ?? "option-card-" + sharedUtils.uuidv4();
1498
- const subContent = react.useMemo(() => (jsxRuntime.jsxs("div", { className: cvaOptionCardContent({ className: contentClassName }), children: [subheading ? (jsxRuntime.jsx(reactComponents.Text, { align: "center", className: cvaOptionCardText({ type: "subheading", disabled }), type: "span", children: subheading })) : null, description ? (jsxRuntime.jsx(reactComponents.Text, { align: "center", className: cvaOptionCardText({ type: "description", disabled }), type: "span", children: description })) : null] })), [subheading, description, contentClassName, disabled]);
1499
- return (jsxRuntime.jsx(reactComponents.Tooltip, { className: "w-fit", disabled: layout !== "compact" || (!subheading && !description), label: subContent, mode: "light", placement: "top", children: jsxRuntime.jsxs("div", { className: cvaOptionCardContainer(), "data-testid": dataTestId, children: [jsxRuntime.jsx("input", { className: cvaInput(), "data-testid": `${dataTestId}-option-card`, disabled: disabled, id: htmlForId, ref: ref, type: "radio", value: value, ...rest }), jsxRuntime.jsxs("label", { className: cvaOptionCardLabel({ className, disabled, layout }), "data-testid": `${dataTestId}-option-card-label`, htmlFor: htmlForId, children: [disabled && icon && !customImage
1500
- ? react.cloneElement(icon, { className: cvaCustomImage({ disabled, className: icon.props.className }) })
1501
- : null, disabled && customImage ? jsxRuntime.jsx("img", { alt: "logo", className: customImage.className, src: customImage.src }) : null, !disabled && !customImage && icon, !disabled && customImage ? jsxRuntime.jsx("img", { alt: "logo", className: customImage.className, src: customImage.src }) : null, heading ? (layout === "default" ? (jsxRuntime.jsx(reactComponents.Heading, { className: cvaOptionCardTitle({ disabled, layout }), subtle: disabled, variant: "secondary", children: heading })) : (jsxRuntime.jsx(reactComponents.Text, { align: "center", className: cvaOptionCardTitle({ disabled, layout }), subtle: disabled, type: "span", weight: "thick", children: heading }))) : null, layout === "default" && (subheading || description) ? subContent : null, tagProps ? jsxRuntime.jsx(reactComponents.Tag, { className: cvaTag({ className: tagProps.className, layout }), ...tagProps }) : null] })] }) }));
1502
- };
1503
- OptionCard.displayName = "OptionCard";
1504
-
1505
- /**
1506
- * A thin wrapper around the `BaseInput` component for password input fields.
1507
- *
1508
- * NOTE: If shown with a label, please use the `PasswordField` component instead.
1509
- */
1510
- const PasswordBaseInput = ({ ref, fieldSize, ...rest }) => {
1511
- const [showPassword, setShowPassword] = react.useState(false);
1512
- return (jsxRuntime.jsx(BaseInput, { ref: ref, ...rest, actions: jsxRuntime.jsx("div", { className: cvaActionContainer({ size: fieldSize }), children: jsxRuntime.jsx(reactComponents.IconButton, { className: cvaActionButton({ size: fieldSize }), icon: jsxRuntime.jsx(reactComponents.Icon, { name: showPassword ? "EyeSlash" : "Eye", size: "small" }), onClick: () => setShowPassword(prevState => !prevState), size: "small", variant: "secondary" }) }), type: showPassword ? "text" : "password" }));
1513
- };
1514
-
1515
- /**
1516
- * Password fields enter a password or other confidential information. Characters are masked as they are typed.
1517
- *
1518
- * _**Do use** when the user has to input a password or something that needs to be obfuscated_
1519
- *
1520
- * _**Do not use** to confirm user actions, such as deleting. Use a checkbox for such flows._
1521
- */
1522
- const PasswordField = ({ id, label, tip, helpText, helpAddon, errorMessage, isInvalid, maxLength, onChange, className, value, dataTestId, ref, ...rest }) => {
1523
- const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
1524
- const htmlFor = id ? id : "passwordField-" + sharedUtils.uuidv4();
1525
- const handleChange = react.useCallback((event) => {
1526
- onChange?.(event);
1527
- }, [onChange]);
1528
- return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlFor, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(PasswordBaseInput, { ...rest, "aria-labelledby": htmlFor + "-label", className: className, dataTestId: dataTestId, disabled: rest.readOnly, id: htmlFor, isInvalid: renderAsInvalid, maxLength: maxLength, onChange: handleChange, ref: ref, value: value }) }));
1529
- };
1530
- PasswordField.displayName = "PasswordField";
1531
-
1532
- /**
1533
- * Validates a phone number
1534
- */
1535
- const validatePhoneNumber = (phoneNumber) => {
1536
- if (!phoneNumber) {
1537
- return "REQUIRED";
1538
- }
1539
- const asYouType = new parsePhoneNumberFromString.AsYouType();
1540
- asYouType.input(phoneNumber);
1541
- const countryCode = asYouType.getCallingCode();
1542
- const national = asYouType.getNationalNumber();
1543
- const safePhoneNumber = getPhoneNumberWithPlus(phoneNumber.trim());
1544
- const number = parsePhoneNumberFromString(safePhoneNumber);
1545
- if (phoneNumber && parsePhoneNumberFromString.isValidPhoneNumber(phoneNumber)) {
1546
- return undefined;
1547
- }
1548
- if (!countryCode && national) {
1549
- return "REQUIRED_COUNTRY";
1550
- }
1551
- if (phoneNumber &&
1552
- (checkIfPhoneNumberHasPlus(phoneNumber)
1553
- ? isNaN(+phoneNumber.slice(1, phoneNumber.length))
1554
- : isNaN(+phoneNumber) || !number)) {
1555
- return "NOT_A_NUMBER";
1556
- }
1557
- if (safePhoneNumber.length <= 5) {
1558
- //needs to be handled manually, parsePhoneNumberFromString can't parse it
1559
- return "TOO_SHORT";
2091
+ return "LESS_THAN";
1560
2092
  }
1561
- return "INVALID_NUMBER";
1562
- };
1563
- /**
1564
- * Checks if the country code is valid and required
1565
- */
1566
- const isInvalidCountryCode = (error, required) => (!!required && error === "REQUIRED") || error === "REQUIRED_COUNTRY";
1567
- /**
1568
- * Checks if the phone number is valid and required
1569
- */
1570
- const isInvalidPhoneNumber = (error, required) => error !== "REQUIRED_COUNTRY" && ((!!error && error !== "REQUIRED") || (!!required && error === "REQUIRED"));
1571
- /**
1572
- * Checks if the phone number is valid and returns corresponding error message
1573
- */
1574
- const phoneErrorMessage = (phoneNumber, required) => {
1575
- if ((validatePhoneNumber(phoneNumber) === "REQUIRED" && !required) ||
1576
- (validatePhoneNumber(phoneNumber) === "REQUIRED" && required && phoneNumber === undefined)) {
2093
+ // if the value is a number and is valid
2094
+ if (isNumber(parsedNumber) && isNumberValid(parsedNumber)) {
1577
2095
  return undefined;
1578
2096
  }
1579
- return validatePhoneNumber(phoneNumber);
2097
+ return "INVALID_NUMBER";
1580
2098
  };
1581
2099
 
1582
2100
  /**
1583
- * The PhoneField component is used to enter phone number.
1584
- * It is a wrapper around the PhoneInput component and the FormGroup component.
1585
- * It is used to render a phone number field with a label, a tip, a help text, a help addon and an error message.
2101
+ * The number field component is used for entering numeric values and includes controls for incrementally increasing or decreasing the value.
1586
2102
  *
1587
- * @param {string} [label] - The label for the component.
1588
- * @param {string} [tip] - The tip for the component.
1589
- * @param {string} [helpText] - The help text for the component.
1590
- * @param {string} [helpAddon] - The help addon for the component.
1591
- * @param {string} [errorMessage] - The error message for the component.
1592
- * @param {string} [defaultValue] - The default value for the component.
1593
- * @param {boolean} [disabled=false] - Whether the component is disabled or not.
1594
- * @param {string} [fieldSize="medium"] - The size of the input field.
1595
- * @param {boolean} [disableAction=false] - Whether the action button is disabled or not.
2103
+ * _**Do use**_ the NumberField when the controls to incrementally increase or decrease makes the task easier for the user.
2104
+ *
2105
+ * _**Do not use**_ this fields for non-serialized numbers. Use TextField instead.
1596
2106
  */
1597
- const PhoneField = ({ label, id, tip, helpText, isInvalid, errorMessage, value, helpAddon, className, defaultValue, dataTestId, name, onBlur, ref, ...rest }) => {
1598
- const htmlForId = id ? id : "phoneField-" + sharedUtils.uuidv4();
2107
+ const NumberField = ({ label, id, tip, helpText, errorMessage, helpAddon, isInvalid, maxLength, className, value, dataTestId, defaultValue, onBlur, onChange, ref, ...rest }) => {
2108
+ const htmlForId = id ? id : "numberField-" + sharedUtils.uuidv4();
1599
2109
  const [t] = useTranslation();
1600
2110
  const [innerValue, setInnerValue] = react.useState(() => {
1601
- return (value?.toString() || defaultValue?.toString()) ?? undefined;
2111
+ return Number(value?.toString()) || Number(defaultValue?.toString());
1602
2112
  });
1603
2113
  const [renderAsInvalid, setRenderAsInvalid] = react.useState((isInvalid === undefined ? Boolean(errorMessage) : isInvalid) ||
1604
- !!phoneErrorMessage(value?.toString(), rest.required));
1605
- const errorType = react.useMemo(() => phoneErrorMessage(innerValue, rest.required), [innerValue, rest.required]);
2114
+ !!validateNumber(value?.toString(), rest.required, rest.min, rest.max));
2115
+ const errorType = react.useMemo(() => validateNumber(innerValue, rest.required, rest.min, rest.max), [innerValue, rest.max, rest.min, rest.required]);
1606
2116
  const error = react.useMemo(() => {
1607
2117
  // for the case when a custom error message is provided
1608
2118
  if (errorMessage) {
1609
2119
  return errorMessage;
1610
2120
  }
1611
2121
  else if (errorType) {
1612
- return t(`phoneField.error.${errorType}`);
2122
+ return t(`numberField.error.${errorType}`, { min: rest.min, max: rest.max });
1613
2123
  }
1614
2124
  return errorMessage;
1615
- }, [errorMessage, errorType, t]);
2125
+ }, [errorMessage, errorType, rest.max, rest.min, t]);
1616
2126
  react.useEffect(() => {
1617
- setRenderAsInvalid(Boolean(errorMessage));
2127
+ if (errorMessage) {
2128
+ setRenderAsInvalid(Boolean(errorMessage));
2129
+ }
1618
2130
  }, [errorMessage]);
1619
2131
  const handleBlur = react.useCallback(event => {
1620
2132
  const newValue = event.target.value;
1621
- setInnerValue(newValue);
2133
+ setInnerValue(newValue.toString());
1622
2134
  // for the case when a custom error message is provided
1623
- if (errorMessage && !phoneErrorMessage(newValue.toString(), rest.required)) {
2135
+ if (errorMessage && !validateNumber(newValue, rest.required, rest.min, rest.max)) {
1624
2136
  setRenderAsInvalid(Boolean(errorMessage));
1625
2137
  }
1626
2138
  else {
1627
- setRenderAsInvalid(!!phoneErrorMessage(newValue.toString(), rest.required));
2139
+ setRenderAsInvalid(!!validateNumber(newValue, rest.required, rest.min, rest.max));
1628
2140
  }
1629
2141
  onBlur?.(event);
1630
- }, [errorMessage, onBlur, rest.required]);
1631
- return (jsxRuntime.jsx(FormGroup, { className: className, dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && error) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(PhoneBaseInput, { "aria-labelledby": htmlForId + "-label", dataTestId: dataTestId, defaultValue: defaultValue, id: htmlForId, isInvalid: renderAsInvalid, name: name, onBlur: handleBlur, ref: ref, value: value, ...rest }) }));
1632
- };
1633
- PhoneField.displayName = "PhoneField";
1634
-
1635
- /**
1636
- * The PhoneFieldWithController component is a wrapper for the PhoneField component to connect it to react-hook-form.
1637
- *
1638
- */
1639
- const PhoneFieldWithController = ({ control, controllerProps, name, value, ref, ...rest }) => {
1640
- return (jsxRuntime.jsx(reactHookForm.Controller, { control: control, defaultValue: value, name: name, ...controllerProps, render: ({ field }) => jsxRuntime.jsx(PhoneField, { ...rest, ...field, ref: ref }) }));
2142
+ }, [errorMessage, onBlur, rest.max, rest.min, rest.required]);
2143
+ const handleChange = react.useCallback((event) => {
2144
+ setInnerValue(event.target.value);
2145
+ if (onChange) {
2146
+ onChange(event);
2147
+ }
2148
+ }, [onChange]);
2149
+ return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && error) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(NumberBaseInput, { "aria-labelledby": htmlForId + "-label", id: htmlForId, isInvalid: renderAsInvalid, maxLength: maxLength, onBlur: handleBlur, onChange: handleChange, ref: ref, value: value, ...rest, className: className, dataTestId: dataTestId }) }));
1641
2150
  };
1642
- PhoneFieldWithController.displayName = "PhoneFieldWithController";
2151
+ NumberField.displayName = "NumberField";
1643
2152
 
1644
- const cvaRadioGroup = cssClassVarianceUtilities.cvaMerge(["flex", "gap-2", "flex-col", "items-start"], {
2153
+ const cvaOptionCardLabel = cssClassVarianceUtilities.cvaMerge([
2154
+ "group",
2155
+ "transition",
2156
+ "bg-white",
2157
+ "outline",
2158
+ "outline-1",
2159
+ "outline-neutral-300",
2160
+ "hover:bg-neutral-100",
2161
+ "focus:bg-neutral-200",
2162
+ "active:bg-neutral-200",
2163
+ "peer-checked:bg-primary-50",
2164
+ "peer-checked:outline-primary-600",
2165
+ "peer-checked:outline-2",
2166
+ "flex",
2167
+ "gap-2",
2168
+ "justify-center",
2169
+ "items-center",
2170
+ "text-center",
2171
+ "rounded-md",
2172
+ "relative",
2173
+ ], {
1645
2174
  variants: {
2175
+ disabled: {
2176
+ true: ["cursor-not-allowed", "bg-neutral-100"],
2177
+ false: ["cursor-pointer"],
2178
+ },
1646
2179
  layout: {
1647
- inline: ["flex", "gap-3", "flex-row", "items-center"],
2180
+ default: ["flex-col", "p-responsive-space", "w-full", "aspect-square"],
2181
+ compact: ["px-3", "py-1.5", "h-8", "min-h-[calc(var(--line-height-sm)+var(--spacing-3))]", "flex-row", "w-fit"],
1648
2182
  },
1649
2183
  },
1650
2184
  });
1651
- const cvaRadioItem = cssClassVarianceUtilities.cvaMerge([
1652
- "self-center",
1653
- "w-4",
1654
- "h-4",
1655
- "appearance-none",
1656
- "rounded-3xl",
1657
- "bg-white",
1658
- "border-solid",
1659
- "border",
1660
- "border-neutral-300",
1661
- "shadow-sm",
1662
- "shrink-0",
1663
- "transition",
1664
- "box-border",
1665
- "hover:cursor-pointer",
1666
- "hover:bg-neutral-100",
1667
- "focus-visible:outline-primary-700",
1668
- ], {
2185
+ const cvaOptionCardContent = cssClassVarianceUtilities.cvaMerge(["flex", "flex-col", "items-center"]);
2186
+ const cvaOptionCardContainer = cssClassVarianceUtilities.cvaMerge(["contents"]);
2187
+ const cvaOptionCardTitle = cssClassVarianceUtilities.cvaMerge(["text-neutral-600"], {
1669
2188
  variants: {
1670
- checked: {
1671
- true: [
1672
- "border-solid",
1673
- "border-4",
1674
- "border-primary-600",
1675
- "bg-white",
1676
- "hover:bg-neutral-100",
1677
- "hover:cursor-pointer",
1678
- "outline-0",
1679
- "active:bg-neutral-200",
1680
- "active:ring-2",
1681
- "active:ring-inset",
1682
- "active:ring-primary-700",
1683
- "group-active:ring-2",
1684
- "group-active:ring-inset",
1685
- "group-active:ring-primary-700",
1686
- ],
1687
- false: "",
2189
+ layout: {
2190
+ default: ["text-lg", "line-clamp-2"],
2191
+ compact: ["text-sm", "line-clamp-1"],
1688
2192
  },
1689
- invalid: {
1690
- true: ["border-red-600", "active:ring-red-700"],
1691
- false: "",
2193
+ disabled: {
2194
+ true: ["text-neutral-400"],
2195
+ false: ["focus:text-neutral-800", "active:text-neutral-800"],
2196
+ },
2197
+ },
2198
+ });
2199
+ const cvaOptionCardText = cssClassVarianceUtilities.cvaMerge(["text-neutral-600", "text-sm"], {
2200
+ variants: {
2201
+ type: {
2202
+ subheading: ["font-medium"],
2203
+ description: ["font-normal"],
1692
2204
  },
1693
2205
  disabled: {
1694
- true: [
1695
- "bg-neutral-400",
1696
- "border-neutral-300",
1697
- "cursor-not-allowed",
1698
- "hover:bg-neutral-400",
1699
- "active:bg-neutral-400",
1700
- "group-active:ring-0",
1701
- "group-active:ring-inset",
1702
- ],
1703
- false: "",
2206
+ true: ["text-neutral-400"],
2207
+ false: ["focus:text-neutral-800", "active:text-neutral-800"],
1704
2208
  },
1705
2209
  },
1706
- compoundVariants: [
1707
- {
1708
- checked: true,
1709
- disabled: true,
1710
- className: ["bg-white"],
2210
+ });
2211
+ const cvaInput = cssClassVarianceUtilities.cvaMerge(["peer", "absolute", "h-0", "w-0", "opacity-0"]);
2212
+ const cvaCustomImage = cssClassVarianceUtilities.cvaMerge(["text-neutral-400"], {
2213
+ variants: {
2214
+ disabled: {
2215
+ true: ["!text-neutral-400"],
2216
+ false: [""],
1711
2217
  },
1712
- ],
2218
+ },
2219
+ });
2220
+ const cvaTag = cssClassVarianceUtilities.cvaMerge([], {
2221
+ variants: {
2222
+ layout: {
2223
+ default: ["absolute", "top-2", "right-2"],
2224
+ compact: [],
2225
+ },
2226
+ },
1713
2227
  });
1714
-
1715
- const RadioGroupContext = react.createContext(null);
1716
-
1717
- /**
1718
- * Use radio buttons when you have a group of mutually exclusive choices and only one selection from the group is allowed.
1719
- *
1720
- * 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.
1721
- *
1722
- * _**Do use** Radio buttons in forms, settings, or selections in a list._
1723
- *
1724
- * _**Do not use** Radio buttons if a user can select many option from a list, use checkboxes instead of radio buttons._
1725
- *
1726
- * @param {RadioGroupProps} props - The props for the RadioGroup component
1727
- * @returns {ReactElement} RadioGroup component
1728
- */
1729
- const RadioGroup = ({ children, id, name, value, disabled, onChange, label, inline, className, dataTestId, isInvalid, }) => {
1730
- return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, label: label, children: jsxRuntime.jsx("div", { className: cvaRadioGroup({ layout: inline ? "inline" : null, className }), "data-testid": dataTestId, children: jsxRuntime.jsx(RadioGroupContext.Provider, { value: {
1731
- id,
1732
- value,
1733
- name: name || id,
1734
- onChange,
1735
- disabled,
1736
- isInvalid,
1737
- }, children: children }) }) }));
1738
- };
1739
- RadioGroup.displayName = "RadioGroup";
1740
2228
 
1741
2229
  /**
1742
- * The RadioItem component.
1743
- *
1744
- * @param {RadioItemProps} props - The props for the RadioItem component
1745
- * @returns {ReactElement} RadioItem component
2230
+ * A card version of a radio button that includes an icon, headings and a description.
1746
2231
  */
1747
- const RadioItem = ({ label, value, dataTestId, className, description, suffix, ...rest }) => {
1748
- const groupCtx = react.useContext(RadioGroupContext);
1749
- const isChecked = groupCtx?.value === value;
1750
- const { ref: labelRef, isTextTruncated: isLabelTruncated } = reactComponents.useIsTextTruncated();
1751
- const { ref: descriptionRef, isTextTruncated: isDescriptionTruncated } = reactComponents.useIsTextTruncated();
1752
- const descriptionId = description ? `${groupCtx?.id}-${value}-description` : undefined;
1753
- const inputId = `${groupCtx?.id}-${value}`;
1754
- const hasLabel = label !== undefined && label !== null && label !== "";
1755
- return (jsxRuntime.jsxs("label", { className: hasLabel
1756
- ? cvaBinaryControlWrapper({ className })
1757
- : `inline-flex w-fit items-center gap-2 ${className || ""}`.trim(), "data-testid": dataTestId ? `${dataTestId}-Wrapper` : undefined, htmlFor: inputId, children: [jsxRuntime.jsx("input", { "aria-describedby": descriptionId, checked: isChecked, className: cvaRadioItem({
1758
- checked: isChecked,
1759
- disabled: groupCtx?.disabled,
1760
- invalid: groupCtx?.isInvalid,
1761
- }), "data-testid": dataTestId, id: inputId, onChange: groupCtx?.onChange, type: "radio", value: value, ...rest }), hasLabel ? (jsxRuntime.jsx(reactComponents.Tooltip, { className: cvaBinaryControlLabelTooltip(), dataTestId: dataTestId ? `${dataTestId}-Label-Tooltip` : undefined, disabled: !isLabelTruncated, label: label, placement: "top", children: jsxRuntime.jsx("span", { className: cvaLabel({
1762
- invalid: groupCtx?.isInvalid,
1763
- disabled: groupCtx?.disabled,
1764
- }), "data-testid": dataTestId ? `${dataTestId}-Label` : undefined, ref: labelRef, children: label }) }, "tooltip-" + rest.name)) : null, suffix ? (jsxRuntime.jsx("div", { className: cvaBinaryControlSuffixContainer(), "data-testid": dataTestId ? `${dataTestId}-suffix-container` : undefined, children: suffix })) : null, description ? (jsxRuntime.jsx(reactComponents.Tooltip, { className: cvaBinaryControlDescriptionTooltip(), dataTestId: dataTestId ? `${dataTestId}-Description-Tooltip` : undefined, disabled: !isDescriptionTruncated, label: description, placement: "top", children: jsxRuntime.jsx("span", { className: cvaBinaryControlDescription({ disabled: groupCtx?.disabled }), "data-testid": dataTestId ? `${dataTestId}-Description` : undefined, id: descriptionId, ref: descriptionRef, children: description }) }, "description-tooltip-" + rest.name)) : null] }));
2232
+ const OptionCard = ({ icon, heading, subheading, description, disabled, id, value, className, contentClassName, dataTestId, customImage, layout = "default", ref, tagProps, ...rest }) => {
2233
+ const htmlForId = id ?? "option-card-" + sharedUtils.uuidv4();
2234
+ const subContent = react.useMemo(() => (jsxRuntime.jsxs("div", { className: cvaOptionCardContent({ className: contentClassName }), children: [subheading ? (jsxRuntime.jsx(reactComponents.Text, { align: "center", className: cvaOptionCardText({ type: "subheading", disabled }), type: "span", children: subheading })) : null, description ? (jsxRuntime.jsx(reactComponents.Text, { align: "center", className: cvaOptionCardText({ type: "description", disabled }), type: "span", children: description })) : null] })), [subheading, description, contentClassName, disabled]);
2235
+ return (jsxRuntime.jsx(reactComponents.Tooltip, { className: "w-fit", disabled: layout !== "compact" || (!subheading && !description), label: subContent, mode: "light", placement: "top", children: jsxRuntime.jsxs("div", { className: cvaOptionCardContainer(), "data-testid": dataTestId, children: [jsxRuntime.jsx("input", { className: cvaInput(), "data-testid": `${dataTestId}-option-card`, disabled: disabled, id: htmlForId, ref: ref, type: "radio", value: value, ...rest }), jsxRuntime.jsxs("label", { className: cvaOptionCardLabel({ className, disabled, layout }), "data-testid": `${dataTestId}-option-card-label`, htmlFor: htmlForId, children: [disabled && icon && !customImage
2236
+ ? react.cloneElement(icon, { className: cvaCustomImage({ disabled, className: icon.props.className }) })
2237
+ : null, disabled && customImage ? jsxRuntime.jsx("img", { alt: "logo", className: customImage.className, src: customImage.src }) : null, !disabled && !customImage && icon, !disabled && customImage ? jsxRuntime.jsx("img", { alt: "logo", className: customImage.className, src: customImage.src }) : null, heading ? (layout === "default" ? (jsxRuntime.jsx(reactComponents.Heading, { className: cvaOptionCardTitle({ disabled, layout }), subtle: disabled, variant: "secondary", children: heading })) : (jsxRuntime.jsx(reactComponents.Text, { align: "center", className: cvaOptionCardTitle({ disabled, layout }), subtle: disabled, type: "span", weight: "thick", children: heading }))) : null, layout === "default" && (subheading || description) ? subContent : null, tagProps ? jsxRuntime.jsx(reactComponents.Tag, { className: cvaTag({ className: tagProps.className, layout }), ...tagProps }) : null] })] }) }));
1765
2238
  };
1766
-
1767
- const cvaTimeRange = cssClassVarianceUtilities.cvaMerge([
1768
- "flex",
1769
- "flex-1",
1770
- "items-center",
1771
- "gap-4",
1772
- "max-sm:gap-2",
1773
- "border-transparent",
1774
- "rounded-md",
1775
- ]);
2239
+ OptionCard.displayName = "OptionCard";
1776
2240
 
1777
2241
  /**
1778
- * TimeRange is used to create a time range entry.
2242
+ * A thin wrapper around the `BaseInput` component for password input fields.
1779
2243
  *
1780
- * @param {TimeRangeProps} props - The props for the TimeRange component
1781
- * @returns {ReactElement} TimeRange component
2244
+ * NOTE: If shown with a label, please use the `PasswordField` component instead.
1782
2245
  */
1783
- const TimeRange = ({ id, className, dataTestId, children, range, onChange, disabled, isInvalid, }) => {
1784
- const [timeRange, setTimeRange] = react.useState(range ?? {
1785
- timeFrom: DEFAULT_TIME,
1786
- timeTo: DEFAULT_TIME,
1787
- });
1788
- const onChangeFrom = (timeFrom) => {
1789
- setTimeRange(prev => ({ ...prev, timeFrom }));
1790
- };
1791
- const onChangeTo = (timeTo) => {
1792
- setTimeRange(prev => ({ ...prev, timeTo }));
1793
- };
1794
- const onRangeChange = () => onChange(timeRange);
1795
- return (jsxRuntime.jsxs("div", { className: cvaTimeRange({ className }), "data-testid": dataTestId, id: id, children: [jsxRuntime.jsx(BaseInput, { dataTestId: `${dataTestId}-from`, disabled: disabled, isInvalid: isInvalid, onBlur: onRangeChange, onChange: (time) => onChangeFrom(time.currentTarget.value), type: "time", value: timeRange.timeFrom === "" ? DEFAULT_TIME : timeRange.timeFrom }), children ?? jsxRuntime.jsx("div", { "data-testid": `${dataTestId}-separator`, children: "-" }), jsxRuntime.jsx(BaseInput, { dataTestId: `${dataTestId}-to`, disabled: disabled, isInvalid: isInvalid, onBlur: onRangeChange, onChange: (time) => onChangeTo(time.currentTarget.value), type: "time", value: timeRange.timeTo === "" ? DEFAULT_TIME : timeRange.timeTo })] }));
2246
+ const PasswordBaseInput = ({ ref, fieldSize, ...rest }) => {
2247
+ const [showPassword, setShowPassword] = react.useState(false);
2248
+ return (jsxRuntime.jsx(BaseInput, { ref: ref, ...rest, actions: jsxRuntime.jsx("div", { className: cvaActionContainer({ size: fieldSize }), children: jsxRuntime.jsx(reactComponents.IconButton, { className: cvaActionButton({ size: fieldSize }), icon: jsxRuntime.jsx(reactComponents.Icon, { name: showPassword ? "EyeSlash" : "Eye", size: "small" }), onClick: () => setShowPassword(prevState => !prevState), size: "small", variant: "secondary" }) }), type: showPassword ? "text" : "password" }));
1796
2249
  };
1797
- const DEFAULT_TIME = "12:00";
1798
-
1799
- const cvaScheduleItem = cssClassVarianceUtilities.cvaMerge([
1800
- "grid",
1801
- "pb-4",
1802
- "gap-2",
1803
- "grid-cols-[60px,200px,60px,2fr]",
1804
- "max-sm:grid-cols-1",
1805
- ]);
1806
- const cvaScheduleItemText = cssClassVarianceUtilities.cvaMerge(["flex", "font-bold", "self-center"]);
1807
2250
 
1808
2251
  /**
1809
- * Schedule is used to create a time range entries.
2252
+ * Password fields enter a password or other confidential information. Characters are masked as they are typed.
1810
2253
  *
1811
- * @param {ScheduleProps} props - The props for the Schedule component
1812
- * @returns {ReactElement} Schedule component
2254
+ * _**Do use** when the user has to input a password or something that needs to be obfuscated_
2255
+ *
2256
+ * _**Do not use** to confirm user actions, such as deleting. Use a checkbox for such flows._
1813
2257
  */
1814
- const Schedule = ({ className, dataTestId, schedule, onChange, invalidKeys = [] }) => {
1815
- const [t] = useTranslation();
1816
- const onRangeChange = (range, index) => {
1817
- const newSchedule = schedule.map((day, dayIndex) => (index === dayIndex ? { ...day, range: { ...range } } : day));
1818
- onChange(newSchedule);
1819
- };
1820
- const onActiveChange = (isActive, index) => {
1821
- const newSchedule = schedule.map((day, dayIndex) => index === dayIndex
1822
- ? {
1823
- ...day,
1824
- range: {
1825
- timeFrom: day.range.timeFrom ? day.range.timeFrom : DEFAULT_TIME,
1826
- timeTo: day.range.timeTo ? day.range.timeTo : DEFAULT_TIME,
1827
- },
1828
- isActive,
1829
- }
1830
- : day);
1831
- onChange(newSchedule);
1832
- };
1833
- const onAllDayChange = (isAllDayChecked, index) => {
1834
- const newSchedule = schedule.map((day, dayIndex) => index === dayIndex
1835
- ? {
1836
- ...day,
1837
- range: {
1838
- timeFrom: day.range.timeFrom ? day.range.timeFrom : DEFAULT_TIME,
1839
- timeTo: day.range.timeTo ? day.range.timeTo : DEFAULT_TIME,
1840
- },
1841
- isAllDay: isAllDayChecked,
1842
- }
1843
- : day);
1844
- onChange(newSchedule);
1845
- };
1846
- return (jsxRuntime.jsx("div", { className: className, "data-testid": dataTestId, children: schedule.map(({ label, range, isActive, key, checkboxLabel, isAllDay }, index) => {
1847
- return (jsxRuntime.jsxs("div", { className: cvaScheduleItem(), children: [jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-4 sm:hidden", children: [jsxRuntime.jsx(reactComponents.Text, { className: "font-medium text-neutral-500", children: t("schedule.label.day") }), jsxRuntime.jsx(reactComponents.Text, { className: cvaScheduleItemText(), size: "medium", subtle: !isActive, children: label }), jsxRuntime.jsx(reactComponents.Text, { className: "font-medium text-neutral-500", children: t("schedule.label.active") }), jsxRuntime.jsx(Checkbox, { checked: isActive, label: checkboxLabel, onChange: (event) => onActiveChange(Boolean(event.currentTarget.checked), index) }), jsxRuntime.jsx(reactComponents.Text, { className: "font-medium text-neutral-500", children: t("schedule.label.allDay") }), jsxRuntime.jsx(Checkbox, { checked: isAllDay ? isActive : undefined, disabled: !isActive, onChange: (event) => onAllDayChange(Boolean(event.currentTarget.checked), index) }), jsxRuntime.jsx(TimeRange, { disabled: !isActive || isAllDay, isInvalid: !!invalidKeys.find((invalidKey) => invalidKey === key), onChange: (newRange) => onRangeChange(newRange, index), range: range })] }), jsxRuntime.jsxs("div", { className: "max-sm:hidden sm:grid sm:grid-cols-[100px,200px,60px,250px,250px] sm:gap-2", children: [jsxRuntime.jsx(Checkbox, { checked: isActive, dataTestId: `${dataTestId}-${key}-checkbox`, label: checkboxLabel, onChange: (event) => onActiveChange(Boolean(event.currentTarget.checked), index) }), jsxRuntime.jsx(reactComponents.Text, { className: cvaScheduleItemText(), size: "medium", subtle: !isActive, children: label }), jsxRuntime.jsx(Checkbox, { checked: isAllDay ? isActive : undefined, dataTestId: `${dataTestId}-${key}-allday-checkbox`, disabled: !isActive, onChange: (event) => onAllDayChange(Boolean(event.currentTarget.checked), index) }), jsxRuntime.jsx(TimeRange, { dataTestId: `${dataTestId}-${key}-range`, disabled: !isActive || isAllDay, isInvalid: !!invalidKeys.find((invalidKey) => invalidKey === key), onChange: (newRange) => onRangeChange(newRange, index), range: isAllDay ? undefined : range })] })] }, key + label));
1848
- }) }));
2258
+ const PasswordField = ({ id, label, tip, helpText, helpAddon, errorMessage, isInvalid, maxLength, onChange, className, value, dataTestId, ref, ...rest }) => {
2259
+ const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
2260
+ const htmlFor = id ? id : "passwordField-" + sharedUtils.uuidv4();
2261
+ const handleChange = react.useCallback((event) => {
2262
+ onChange?.(event);
2263
+ }, [onChange]);
2264
+ return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlFor, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(PasswordBaseInput, { ...rest, "aria-labelledby": htmlFor + "-label", className: className, dataTestId: dataTestId, disabled: rest.readOnly, id: htmlFor, isInvalid: renderAsInvalid, maxLength: maxLength, onChange: handleChange, ref: ref, value: value }) }));
1849
2265
  };
2266
+ PasswordField.displayName = "PasswordField";
1850
2267
 
1851
- const weekDay = {
1852
- Monday: "monday",
1853
- Tuesday: "tuesday",
1854
- Wednesday: "wednesday",
1855
- Thursday: "thursday",
1856
- Friday: "friday",
1857
- Saturday: "saturday",
1858
- Sunday: "sunday",
1859
- };
1860
- exports.ScheduleVariant = void 0;
1861
- (function (ScheduleVariant) {
1862
- ScheduleVariant["ALL_DAYS"] = "all";
1863
- ScheduleVariant["WEEKDAYS"] = "week";
1864
- ScheduleVariant["CUSTOM"] = "custom";
1865
- })(exports.ScheduleVariant || (exports.ScheduleVariant = {}));
1866
2268
  /**
1867
- * Parse a string of week range schedule string to human readable schedule range.
1868
- *
1869
- * @param {string} scheduleString String of week schedule
1870
- * @returns {WeekSchedule} Week schedule range
2269
+ * Validates a phone number
1871
2270
  */
1872
- const parseSchedule = (scheduleString) => {
1873
- if (!scheduleString) {
1874
- return {
1875
- variant: exports.ScheduleVariant.CUSTOM,
1876
- schedule: [1, 2, 3, 4, 5, 6, 7].map(day => ({
1877
- day,
1878
- range: { timeFrom: "", timeTo: "" },
1879
- isAllDay: false,
1880
- isActive: false,
1881
- })),
1882
- };
2271
+ const validatePhoneNumber = (phoneNumber) => {
2272
+ if (!phoneNumber) {
2273
+ return "REQUIRED";
1883
2274
  }
1884
- const schedule = scheduleString.split(",").map(daySchedule => {
1885
- const [day, timeRange] = daySchedule.split("#");
1886
- const [timeFrom, timeTo] = (timeRange ?? "").split("-");
1887
- const isAllDay = timeFrom === "00:00" && timeTo === "24:00";
1888
- return {
1889
- day: Number(day),
1890
- range: timeFrom === undefined || timeTo === undefined
1891
- ? undefined
1892
- : {
1893
- timeFrom: timeFrom,
1894
- timeTo: timeTo,
1895
- },
1896
- isAllDay,
1897
- isActive: Boolean(timeFrom) && Boolean(timeTo),
1898
- };
1899
- });
1900
- const filteredSchedule = schedule
1901
- .filter(daySchedule => daySchedule.range)
1902
- .map(daySchedule => ({
1903
- day: daySchedule.day,
1904
- range: daySchedule.range,
1905
- isAllDay: daySchedule.isAllDay,
1906
- isActive: daySchedule.isActive,
1907
- }));
1908
- let variant;
1909
- switch (schedule.length) {
1910
- case 7:
1911
- variant = isUniform(schedule) ? exports.ScheduleVariant.ALL_DAYS : exports.ScheduleVariant.CUSTOM;
1912
- break;
1913
- case 5:
1914
- variant = hasConsecutiveDays(schedule) ? exports.ScheduleVariant.WEEKDAYS : exports.ScheduleVariant.CUSTOM;
1915
- break;
1916
- default:
1917
- return {
1918
- variant: exports.ScheduleVariant.CUSTOM,
1919
- schedule: filteredSchedule,
1920
- };
2275
+ const asYouType = new parsePhoneNumberFromString.AsYouType();
2276
+ asYouType.input(phoneNumber);
2277
+ const countryCode = asYouType.getCallingCode();
2278
+ const national = asYouType.getNationalNumber();
2279
+ const safePhoneNumber = getPhoneNumberWithPlus(phoneNumber.trim());
2280
+ const number = parsePhoneNumberFromString(safePhoneNumber);
2281
+ if (phoneNumber && parsePhoneNumberFromString.isValidPhoneNumber(phoneNumber)) {
2282
+ return undefined;
1921
2283
  }
1922
- return {
1923
- variant,
1924
- schedule: filteredSchedule,
1925
- };
2284
+ if (!countryCode && national) {
2285
+ return "REQUIRED_COUNTRY";
2286
+ }
2287
+ if (phoneNumber &&
2288
+ (checkIfPhoneNumberHasPlus(phoneNumber)
2289
+ ? isNaN(+phoneNumber.slice(1, phoneNumber.length))
2290
+ : isNaN(+phoneNumber) || !number)) {
2291
+ return "NOT_A_NUMBER";
2292
+ }
2293
+ if (safePhoneNumber.length <= 5) {
2294
+ //needs to be handled manually, parsePhoneNumberFromString can't parse it
2295
+ return "TOO_SHORT";
2296
+ }
2297
+ return "INVALID_NUMBER";
1926
2298
  };
1927
2299
  /**
1928
- * Serialize week schedule to string schedule
2300
+ * Checks if the country code is valid and required
2301
+ */
2302
+ const isInvalidCountryCode = (error, required) => (!!required && error === "REQUIRED") || error === "REQUIRED_COUNTRY";
2303
+ /**
2304
+ * Checks if the phone number is valid and required
2305
+ */
2306
+ const isInvalidPhoneNumber = (error, required) => error !== "REQUIRED_COUNTRY" && ((!!error && error !== "REQUIRED") || (!!required && error === "REQUIRED"));
2307
+ /**
2308
+ * Checks if the phone number is valid and returns corresponding error message
2309
+ */
2310
+ const phoneErrorMessage = (phoneNumber, required) => {
2311
+ if ((validatePhoneNumber(phoneNumber) === "REQUIRED" && !required) ||
2312
+ (validatePhoneNumber(phoneNumber) === "REQUIRED" && required && phoneNumber === undefined)) {
2313
+ return undefined;
2314
+ }
2315
+ return validatePhoneNumber(phoneNumber);
2316
+ };
2317
+
2318
+ /**
2319
+ * The PhoneField component is used to enter phone number.
2320
+ * It is a wrapper around the PhoneInput component and the FormGroup component.
2321
+ * It is used to render a phone number field with a label, a tip, a help text, a help addon and an error message.
1929
2322
  *
1930
- * @param {WeekSchedule} weekSchedule Week schedule range
1931
- * @returns {string} Schedule string
2323
+ * @param {string} [label] - The label for the component.
2324
+ * @param {string} [tip] - The tip for the component.
2325
+ * @param {string} [helpText] - The help text for the component.
2326
+ * @param {string} [helpAddon] - The help addon for the component.
2327
+ * @param {string} [errorMessage] - The error message for the component.
2328
+ * @param {string} [defaultValue] - The default value for the component.
2329
+ * @param {boolean} [disabled=false] - Whether the component is disabled or not.
2330
+ * @param {string} [fieldSize="medium"] - The size of the input field.
2331
+ * @param {boolean} [disableAction=false] - Whether the action button is disabled or not.
1932
2332
  */
1933
- const serializeSchedule = (weekSchedule) => {
1934
- return weekSchedule.schedule
1935
- .filter(({ range, day, isAllDay }) => {
1936
- const hasRange = range.timeFrom && range.timeTo;
1937
- switch (weekSchedule.variant) {
1938
- case exports.ScheduleVariant.WEEKDAYS:
1939
- return day <= 5 && hasRange;
1940
- case exports.ScheduleVariant.ALL_DAYS:
1941
- return day <= 7 && hasRange;
1942
- case exports.ScheduleVariant.CUSTOM:
1943
- default:
1944
- return hasRange || isAllDay;
2333
+ const PhoneField = ({ label, id, tip, helpText, isInvalid, errorMessage, value, helpAddon, className, defaultValue, dataTestId, name, onBlur, ref, ...rest }) => {
2334
+ const htmlForId = id ? id : "phoneField-" + sharedUtils.uuidv4();
2335
+ const [t] = useTranslation();
2336
+ const [innerValue, setInnerValue] = react.useState(() => {
2337
+ return (value?.toString() || defaultValue?.toString()) ?? undefined;
2338
+ });
2339
+ const [renderAsInvalid, setRenderAsInvalid] = react.useState((isInvalid === undefined ? Boolean(errorMessage) : isInvalid) ||
2340
+ !!phoneErrorMessage(value?.toString(), rest.required));
2341
+ const errorType = react.useMemo(() => phoneErrorMessage(innerValue, rest.required), [innerValue, rest.required]);
2342
+ const error = react.useMemo(() => {
2343
+ // for the case when a custom error message is provided
2344
+ if (errorMessage) {
2345
+ return errorMessage;
2346
+ }
2347
+ else if (errorType) {
2348
+ return t(`phoneField.error.${errorType}`);
2349
+ }
2350
+ return errorMessage;
2351
+ }, [errorMessage, errorType, t]);
2352
+ react.useEffect(() => {
2353
+ setRenderAsInvalid(Boolean(errorMessage));
2354
+ }, [errorMessage]);
2355
+ const handleBlur = react.useCallback(event => {
2356
+ const newValue = event.target.value;
2357
+ setInnerValue(newValue);
2358
+ // for the case when a custom error message is provided
2359
+ if (errorMessage && !phoneErrorMessage(newValue.toString(), rest.required)) {
2360
+ setRenderAsInvalid(Boolean(errorMessage));
1945
2361
  }
1946
- })
1947
- .map(({ day, range, isAllDay }) => {
1948
- if (isAllDay) {
1949
- return `${day}#00:00-24:00`;
2362
+ else {
2363
+ setRenderAsInvalid(!!phoneErrorMessage(newValue.toString(), rest.required));
1950
2364
  }
1951
- return `${day}#${range.timeFrom}-${range.timeTo}`;
1952
- })
1953
- .join(",");
1954
- };
1955
- /**
1956
- * Checks if a list of schedule objects have the same ranges
1957
- *
1958
- * @param {RawSchedule[]} schedule List of schedule objects
1959
- * @returns {boolean} Whether the schedule is uniform
1960
- */
1961
- const isUniform = (schedule) => {
1962
- return schedule.every((day, _, collection) => collection[0]?.range?.timeFrom === day.range?.timeFrom && collection[0]?.range?.timeTo === day.range?.timeTo);
2365
+ onBlur?.(event);
2366
+ }, [errorMessage, onBlur, rest.required]);
2367
+ return (jsxRuntime.jsx(FormGroup, { className: className, dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && error) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required ? !(rest.disabled || rest.readOnly) : false, tip: tip, children: jsxRuntime.jsx(PhoneBaseInput, { "aria-labelledby": htmlForId + "-label", dataTestId: dataTestId, defaultValue: defaultValue, id: htmlForId, isInvalid: renderAsInvalid, name: name, onBlur: handleBlur, ref: ref, value: value, ...rest }) }));
1963
2368
  };
2369
+ PhoneField.displayName = "PhoneField";
2370
+
1964
2371
  /**
1965
- * Checks if a list of schedule objects are consecutive days
2372
+ * The PhoneFieldWithController component is a wrapper for the PhoneField component to connect it to react-hook-form.
1966
2373
  *
1967
- * @param {RawSchedule[]} schedule List of schedule objects
1968
- * @returns {boolean} Whether the schedule has consecutive days
1969
2374
  */
1970
- const hasConsecutiveDays = (schedule) => {
1971
- const days = [1, 2, 3, 4, 5];
1972
- return schedule.every(({ day }, index) => day === days[index]);
2375
+ const PhoneFieldWithController = ({ control, controllerProps, name, value, ref, ...rest }) => {
2376
+ return (jsxRuntime.jsx(reactHookForm.Controller, { control: control, defaultValue: value, name: name, ...controllerProps, render: ({ field }) => jsxRuntime.jsx(PhoneField, { ...rest, ...field, ref: ref }) }));
1973
2377
  };
2378
+ PhoneFieldWithController.displayName = "PhoneFieldWithController";
1974
2379
 
1975
- const cvaSearch = cssClassVarianceUtilities.cvaMerge([
1976
- "shadow-none",
1977
- "component-search-border",
1978
- "component-search-background",
1979
- "hover:component-search-background",
1980
- "hover:component-search-focus-hover",
1981
- "transition-all",
1982
- "duration-300",
1983
- ], {
2380
+ const cvaRadioGroup = cssClassVarianceUtilities.cvaMerge(["flex", "gap-2", "flex-col", "items-start"], {
1984
2381
  variants: {
1985
- border: { true: ["!component-search-borderless"], false: "" },
1986
- widenOnFocus: {
1987
- true: [
1988
- "component-search-width",
1989
- "component-search-widen",
1990
- "hover:component-search-widen",
1991
- "focus-within:w-full",
1992
- "max-w-sm",
1993
- ],
1994
- false: "w-full",
2382
+ layout: {
2383
+ inline: ["flex", "gap-3", "flex-row", "items-center"],
1995
2384
  },
1996
2385
  },
1997
2386
  });
1998
-
1999
- /**
2000
- * The Search component is used to render a search input field.
2001
- *
2002
- * @param {SearchProps} props - The props for the Search component
2003
- */
2004
- const Search = ({ className, placeholder, value, widenInputOnFocus, hideBorderWhenNotInFocus = false, disabled = false, onKeyUp, onChange, onFocus, onBlur, name, onClear, dataTestId, autoComplete = "on", loading = false, inputClassName, iconName = "MagnifyingGlass", style, xMarkRef, ref, ...rest }) => {
2005
- const { t } = useTranslation();
2006
- return (jsxRuntime.jsx(TextBaseInput, { ...rest, autoComplete: autoComplete, className: cvaSearch({ className, border: hideBorderWhenNotInFocus, widenOnFocus: widenInputOnFocus }), dataTestId: dataTestId, disabled: disabled, inputClassName: inputClassName, name: name, onBlur: onBlur, onChange: onChange, onFocus: onFocus, onKeyUp: onKeyUp, placeholder: placeholder ?? t("search.placeholder"), prefix: loading ? (jsxRuntime.jsx(reactComponents.Spinner, { centering: "centered", size: rest.fieldSize ?? undefined })) : (jsxRuntime.jsx(reactComponents.Icon, { name: iconName, size: rest.fieldSize ?? undefined })), ref: ref, suffix:
2007
- //only show the clear button if there is a value and the onClear function is provided
2008
- onClear && value ? (jsxRuntime.jsx("button", { className: "flex", "data-testid": dataTestId ? `${dataTestId}_suffix_component` : null, onClick: () => {
2009
- onClear();
2010
- }, ref: xMarkRef, type: "button", children: jsxRuntime.jsx(reactComponents.Icon, { name: "XMark", size: "small" }) })) : undefined, value: value }));
2011
- };
2012
- Search.displayName = "Search";
2013
-
2014
- const cvaSelect = cssClassVarianceUtilities.cvaMerge([
2015
- "relative",
2016
- "flex",
2017
- "shadow-sm",
2018
- "rounded-lg",
2019
- "border-neutral-300",
2020
- "hover:border-neutral-400",
2021
- "hover:bg-neutral-50",
2387
+ const cvaRadioItem = cssClassVarianceUtilities.cvaMerge([
2388
+ "self-center",
2389
+ "w-4",
2390
+ "h-4",
2391
+ "appearance-none",
2392
+ "rounded-3xl",
2022
2393
  "bg-white",
2394
+ "border-solid",
2395
+ "border",
2396
+ "border-neutral-300",
2397
+ "shadow-sm",
2398
+ "shrink-0",
2023
2399
  "transition",
2024
- "text-sm",
2025
- "min-h-0",
2400
+ "box-border",
2401
+ "hover:cursor-pointer",
2402
+ "hover:bg-neutral-100",
2403
+ "focus-visible:outline-primary-700",
2026
2404
  ], {
2027
2405
  variants: {
2028
- fieldSize: {
2029
- small: ["h-7", "text-xs"],
2030
- medium: ["h-8"],
2031
- large: ["h-10"],
2406
+ checked: {
2407
+ true: [
2408
+ "border-solid",
2409
+ "border-4",
2410
+ "border-primary-600",
2411
+ "bg-white",
2412
+ "hover:bg-neutral-100",
2413
+ "hover:cursor-pointer",
2414
+ "outline-0",
2415
+ "active:bg-neutral-200",
2416
+ "active:ring-2",
2417
+ "active:ring-inset",
2418
+ "active:ring-primary-700",
2419
+ "group-active:ring-2",
2420
+ "group-active:ring-inset",
2421
+ "group-active:ring-primary-700",
2422
+ ],
2423
+ false: "",
2032
2424
  },
2033
2425
  invalid: {
2034
- true: "border border-red-600 text-red-600 hover:border-red-600",
2426
+ true: ["border-red-600", "active:ring-red-700"],
2035
2427
  false: "",
2036
2428
  },
2037
2429
  disabled: {
2038
- true: "!bg-neutral-100 hover:border-neutral-300",
2039
- false: "",
2040
- },
2041
- },
2042
- defaultVariants: {
2043
- invalid: false,
2044
- disabled: false,
2045
- },
2046
- });
2047
- const cvaSelectControl = cssClassVarianceUtilities.cvaMerge([], {
2048
- variants: {
2049
- isDisabled: {
2050
- true: "!bg-neutral-100",
2051
- false: "",
2052
- },
2053
- prefix: {
2054
- true: ["ps-7"],
2055
- false: "",
2056
- },
2057
- invalid: {
2058
- true: "!border-0",
2430
+ true: [
2431
+ "bg-neutral-400",
2432
+ "border-neutral-300",
2433
+ "cursor-not-allowed",
2434
+ "hover:bg-neutral-400",
2435
+ "active:bg-neutral-400",
2436
+ "group-active:ring-0",
2437
+ "group-active:ring-inset",
2438
+ ],
2059
2439
  false: "",
2060
- },
2061
- },
2062
- defaultVariants: {
2063
- isDisabled: false,
2064
- prefix: false,
2065
- invalid: false,
2066
- },
2067
- });
2068
- const cvaSelectIcon = cssClassVarianceUtilities.cvaMerge([
2069
- "mr-2",
2070
- "flex",
2071
- "cursor-pointer",
2072
- "items-center",
2073
- "justify-center",
2074
- "text-neutral-400",
2075
- "hover:text-neutral-500",
2076
- ]);
2077
- const cvaSelectPrefixSuffix = cssClassVarianceUtilities.cvaMerge(["flex", "justify-center", "items-center", "text-neutral-400", "absolute", "inset-y-0"], {
2078
- variants: {
2079
- kind: {
2080
- prefix: ["pl-3", "left-0"],
2081
- suffix: ["pr-3", "right-0"],
2082
- },
2083
- },
2084
- });
2085
- const cvaSelectXIcon = cssClassVarianceUtilities.cvaMerge([
2086
- "mr-2",
2087
- "flex",
2088
- "cursor-pointer",
2089
- "items-center",
2090
- "justify-center",
2091
- "text-neutral-400",
2092
- "hover:text-neutral-500",
2093
- "ml-1",
2094
- ]);
2095
- const cvaSelectMenuList = cssClassVarianceUtilities.cvaMerge([], {
2096
- variants: {
2097
- menuIsOpen: {
2098
- true: "animate-fade-in-fast",
2099
- false: "animate-fade-out-fast",
2100
- },
2101
- },
2102
- });
2103
- const cvaSelectDynamicTagContainer = cssClassVarianceUtilities.cvaMerge(["h-full", "flex", "gap-1", "items-center"], {
2104
- variants: {
2105
- visible: { true: "visible", false: "invisible" },
2106
- },
2107
- });
2108
- const cvaSelectCounter = cssClassVarianceUtilities.cvaMerge(["overflow-hidden", "whitespace-nowrap"]);
2109
- const cvaSelectMenu = cssClassVarianceUtilities.cvaMerge(["relative", "p-1", "grid", "gap-1"]);
2110
-
2111
- /**
2112
- * A single select menu item is a basic wrapper around Menu item designed to be used as a single value render in Select list
2113
- *
2114
- * @param {SelectMenuItemProps} props - The props for the SingleSelectMenuItem
2115
- * @returns {ReactElement} SingleSelectMenuItem
2116
- */
2117
- const SingleSelectMenuItem = ({ label, icon, onClick, selected, focused, dataTestId, disabled, optionLabelDescription, optionPrefix, fieldSize, }) => {
2118
- return (jsxRuntime.jsx(reactComponents.MenuItem, { dataTestId: dataTestId, disabled: disabled, fieldSize: fieldSize, focused: focused, label: label, onClick: onClick, optionLabelDescription: optionLabelDescription, optionPrefix: react.isValidElement(optionPrefix)
2119
- ? react.cloneElement(optionPrefix, {
2120
- className: "mr-1 flex items-center",
2121
- size: "medium",
2122
- })
2123
- : optionPrefix, prefix: icon, selected: selected, suffix: selected ? jsxRuntime.jsx(reactComponents.Icon, { className: "block text-blue-600", name: "Check", size: "medium" }) : undefined }));
2124
- };
2125
- /**
2126
- * A multi select menu item is a basic wrapper around Menu item designed to be used as a multi value render in Select list
2127
- *
2128
- * @param {SelectMenuItemProps} props - The props for the MultiSelectMenuItem
2129
- * @returns {ReactElement} multi select menu item
2130
- */
2131
- const MultiSelectMenuItem = ({ label, onClick, selected, focused, dataTestId, disabled, optionLabelDescription, optionPrefix, fieldSize, }) => {
2132
- return (jsxRuntime.jsx(reactComponents.MenuItem, { dataTestId: dataTestId, disabled: disabled, fieldSize: fieldSize, focused: focused, label: label, onClick: e => {
2133
- e.stopPropagation();
2134
- onClick && onClick(e);
2135
- }, optionLabelDescription: optionLabelDescription, optionPrefix: react.isValidElement(optionPrefix)
2136
- ? react.cloneElement(optionPrefix, {
2137
- className: "mr-1 flex items-center",
2138
- size: "medium",
2139
- })
2140
- : optionPrefix, prefix: jsxRuntime.jsx(Checkbox, { checked: selected, className: "gap-x-0", disabled: disabled, onChange: () => null, onClick: e => {
2141
- e.stopPropagation();
2142
- }, readOnly: false }), selected: selected }));
2143
- };
2144
-
2145
- /**
2146
- * Extended Tag component with information about its own width.
2147
- * Used in the select component.
2148
- *
2149
- * @param {TagProps} props - The props for the tag component
2150
- * @returns {ReactElement} TagWithWidth component
2151
- */
2152
- const TagWithWidth = ({ onWidthKnown, children, ...rest }) => {
2153
- const ref = react.useRef(null);
2154
- react.useLayoutEffect(() => {
2155
- onWidthKnown && onWidthKnown({ width: ref.current?.offsetWidth || 0 });
2156
- }, [ref, onWidthKnown]);
2157
- return (jsxRuntime.jsx(reactComponents.Tag, { ref: ref, ...rest, icon: react.isValidElement(rest.icon) ? react.cloneElement(rest.icon, { size: "small" }) : rest.icon, children: children }));
2158
- };
2440
+ },
2441
+ },
2442
+ compoundVariants: [
2443
+ {
2444
+ checked: true,
2445
+ disabled: true,
2446
+ className: ["bg-white"],
2447
+ },
2448
+ ],
2449
+ });
2450
+
2451
+ const RadioGroupContext = react.createContext(null);
2159
2452
 
2160
2453
  /**
2161
- * TagsContainer component to display tags in limited space when children can't fit space it displays counter
2454
+ * Use radio buttons when you have a group of mutually exclusive choices and only one selection from the group is allowed.
2162
2455
  *
2163
- * @param {TagsContainerProps} props - The props for the TagContainer
2164
- * @returns {ReactElement} TagsContainer
2456
+ * 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.
2457
+ *
2458
+ * _**Do use** Radio buttons in forms, settings, or selections in a list._
2459
+ *
2460
+ * _**Do not use** Radio buttons if a user can select many option from a list, use checkboxes instead of radio buttons._
2461
+ *
2462
+ * @param {RadioGroupProps} props - The props for the RadioGroup component
2463
+ * @returns {ReactElement} RadioGroup component
2165
2464
  */
2166
- const TagsContainer = ({ items, width = "100%", itemsGap = 6, postFix, preFix, disabled, }) => {
2167
- const containerRef = react.useRef(null);
2168
- const [isReady, setIsReady] = react.useState(false);
2169
- const [counterWidth, setCounterWidth] = react.useState(0);
2170
- const [availableSpaceWidth, setAvailableSpaceWidth] = react.useState(0);
2171
- const [childrenWidths, setChildrenWidths] = react.useState([]);
2172
- const itemsCount = items.length;
2173
- const dimensions = reactComponents.useResize();
2174
- const { width: windowWidth } = reactComponents.useDebounce(dimensions, 100);
2175
- react.useEffect(() => {
2176
- const containerWidth = containerRef.current?.offsetWidth || 0;
2177
- setAvailableSpaceWidth(containerWidth);
2178
- }, [windowWidth]);
2179
- const onWidthKnownHandler = react.useCallback(({ width: reportedWidth }) => {
2180
- setChildrenWidths(prev => {
2181
- const next = [...prev, { width: reportedWidth + itemsGap }];
2182
- if (next.length === itemsCount) {
2183
- setIsReady(true);
2184
- }
2185
- return next;
2186
- });
2187
- }, [itemsCount, itemsGap]);
2188
- const renderedElements = react.useMemo(() => {
2189
- const requiredSpace = childrenWidths.reduce((previous, current) => {
2190
- return previous + current.width;
2191
- }, 0);
2192
- const availableSpace = availableSpaceWidth - counterWidth;
2193
- const { elements } = items
2194
- .concat({ text: "", onClick: () => null, disabled: false })
2195
- .reduce((acc, item, index) => {
2196
- const spaceNeeded = childrenWidths.slice(0, index + 1).reduce((previous, current) => {
2197
- return previous + current.width;
2198
- }, 0);
2199
- const isLast = index === items.length;
2200
- const counterRequired = requiredSpace > availableSpace && acc.counter !== 0;
2201
- if (isLast && counterRequired) {
2202
- return {
2203
- ...acc,
2204
- elements: [
2205
- ...acc.elements,
2206
- jsxRuntime.jsx(TagWithWidth, { color: "white", disabled: disabled, icon: item.Icon, onWidthKnown: ({ width: reportedWidth }) => setCounterWidth(reportedWidth), children: jsxRuntime.jsxs("div", { className: cvaSelectCounter(), "data-testid": "select-counter", children: ["+", acc.counter] }) }, item.text + index),
2207
- ],
2208
- };
2209
- }
2210
- if (isLast) {
2211
- return acc;
2212
- }
2213
- const itemCanFit = spaceNeeded <= availableSpace;
2214
- if (itemCanFit) {
2215
- return {
2216
- ...acc,
2217
- elements: [
2218
- ...acc.elements,
2219
- jsxRuntime.jsx(TagWithWidth, { className: "inline-flex shrink-0", color: item.disabled ? "neutral" : "white", dataTestId: `${item.text}-tag`, disabled: disabled, icon: item.Icon, onClose: e => {
2220
- e.stopPropagation();
2221
- item.onClick();
2222
- }, onWidthKnown: onWidthKnownHandler, children: item.text }, item.text + index),
2223
- ],
2224
- };
2225
- }
2226
- return {
2227
- elements: acc.elements,
2228
- counter: item.text !== "" ? acc.counter + 1 : acc.counter,
2229
- };
2230
- }, { elements: [], counter: 0 });
2231
- return elements;
2232
- }, [items, availableSpaceWidth, counterWidth, disabled, onWidthKnownHandler, childrenWidths]);
2233
- return (jsxRuntime.jsxs("div", { className: cvaSelectDynamicTagContainer({ visible: isReady || !!preFix }), ref: containerRef, style: {
2234
- width: `${width}`,
2235
- }, children: [preFix, renderedElements, postFix] }));
2465
+ const RadioGroup = ({ children, id, name, value, disabled, onChange, label, inline, className, dataTestId, isInvalid, }) => {
2466
+ return (jsxRuntime.jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, label: label, children: jsxRuntime.jsx("div", { className: cvaRadioGroup({ layout: inline ? "inline" : null, className }), "data-testid": dataTestId, children: jsxRuntime.jsx(RadioGroupContext.Provider, { value: {
2467
+ id,
2468
+ value,
2469
+ name: name || id,
2470
+ onChange,
2471
+ disabled,
2472
+ isInvalid,
2473
+ }, children: children }) }) }));
2236
2474
  };
2475
+ RadioGroup.displayName = "RadioGroup";
2237
2476
 
2238
2477
  /**
2239
- * A hook to retrieve components override object.
2240
- * 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.
2478
+ * The RadioItem component.
2241
2479
  *
2242
- * @template IsMulti
2243
- * @template Group
2244
- * @param {Partial<SelectComponents<Option, IsMulti, Group>> | undefined} componentsProps a custom component prop that you can to override defaults
2245
- * @param {boolean} disabled decide to override disabled variant
2246
- * @param {boolean} menuIsOpen menu is open state
2247
- * @param {string} dataTestId a test id
2248
- * @param {number} maxSelectedDisplayCount a number of max display count
2249
- * @param {boolean} hasError decide to override hasError variant
2250
- * @param {ReactNode} prefix a prefix element
2251
- * @returns {Partial<SelectComponents<Option, boolean, GroupBase<Option>>> | undefined} components object to override react-select default components
2480
+ * @param {RadioItemProps} props - The props for the RadioItem component
2481
+ * @returns {ReactElement} RadioItem component
2252
2482
  */
2253
- const useCustomComponents = ({ componentsProps, disabled, readOnly, setMenuIsEnabled, dataTestId, maxSelectedDisplayCount, prefix, hasError, fieldSize, getOptionLabelDescription, getOptionPrefix, }) => {
2254
- const [t] = useTranslation();
2255
- // perhaps it should not be wrap in memo (causing some issues with opening and closing on mobiles)
2256
- const customComponents = react.useMemo(() => {
2257
- return {
2258
- ValueContainer: props => {
2259
- if (props.isMulti && Array.isArray(props.children) && props.children.length > 0) {
2260
- const PLACEHOLDER_KEY = "placeholder";
2261
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
2262
- const key = props && props.children && props.children[0] ? props.children[0]?.key : "";
2263
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
2264
- const values = props && props.children ? props.children[0] : [];
2265
- const tags = key === PLACEHOLDER_KEY ? [] : values;
2266
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
2267
- const searchInput = props && props.children && props.children[1];
2268
- const placeholderElement = Array.isArray(props.children)
2269
- ? props.children.find(child => child && child.key === PLACEHOLDER_KEY)
2270
- : null;
2271
- return (jsxRuntime.jsx(ReactSelect.components.ValueContainer, { ...props, isDisabled: props.selectProps.isDisabled, children: maxSelectedDisplayCount === undefined ? (jsxRuntime.jsx(TagsContainer, { disabled: disabled, items: tags
2272
- ? tags.map(({ props: tagProps }) => {
2273
- const optionPrefix = tagProps.data && getOptionPrefix ? getOptionPrefix(tagProps.data) : null;
2274
- return {
2275
- text: tagProps.children,
2276
- onClick: disabled
2277
- ? undefined
2278
- : (e) => {
2279
- setMenuIsEnabled(false);
2280
- tagProps.removeProps.onClick && tagProps.removeProps.onClick(e);
2281
- },
2282
- disabled: disabled,
2283
- Icon: optionPrefix,
2284
- };
2285
- })
2286
- : [], postFix: searchInput, preFix: placeholderElement ? jsxRuntime.jsx("span", { className: "absolute", children: placeholderElement }) : null, width: "100%" })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [tags
2287
- ? tags.slice(0, maxSelectedDisplayCount).map(({ props: tagProps }) => {
2288
- return (jsxRuntime.jsx(reactComponents.Tag, { className: "inline-flex shrink-0", color: disabled ? "unknown" : "primary", dataTestId: tagProps.children ? `${tagProps.children.toString()}-tag` : undefined, onClose: e => {
2289
- e.stopPropagation();
2290
- setMenuIsEnabled(false);
2291
- tagProps.removeProps.onClick && tagProps.removeProps.onClick(e);
2292
- }, children: tagProps.children }, tagProps.children?.toString()));
2293
- })
2294
- : null, tags && tags.length > maxSelectedDisplayCount ? (jsxRuntime.jsxs(reactComponents.Tag, { color: "neutral", dataTestId: "counter-tag", children: ["+", tags.length - maxSelectedDisplayCount] })) : null, searchInput, placeholderElement] })) }));
2295
- }
2296
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(ReactSelect.components.ValueContainer, { ...props, isDisabled: props.selectProps.isDisabled, children: props.children }) }));
2297
- },
2298
- LoadingIndicator: () => {
2299
- return jsxRuntime.jsx(reactComponents.Spinner, { centering: "vertically", className: "mr-2", size: "small" });
2300
- },
2301
- DropdownIndicator: props => {
2302
- const icon = props.selectProps.menuIsOpen ? (jsxRuntime.jsx(reactComponents.Icon, { name: "ChevronUp", size: "medium" })) : (jsxRuntime.jsx(reactComponents.Icon, { name: "ChevronDown", size: "medium" }));
2303
- return props.selectProps.isLoading || props.selectProps.isDisabled || readOnly ? null : (jsxRuntime.jsx(ReactSelect.components.DropdownIndicator, { ...props, children: jsxRuntime.jsx("div", { className: cvaSelectIcon(), children: icon }) }));
2304
- },
2305
- IndicatorSeparator: () => null,
2306
- ClearIndicator: props => {
2307
- if (disabled) {
2308
- return null;
2309
- }
2310
- return (jsxRuntime.jsx(ReactSelect.components.ClearIndicator, { ...props, innerProps: {
2311
- ...props.innerProps,
2312
- onMouseDown: e => {
2313
- e.preventDefault();
2314
- },
2315
- }, children: jsxRuntime.jsx("div", { className: cvaSelectXIcon(), "data-testid": dataTestId ? `${dataTestId}-XMarkIcon` : null, onClick: props.clearValue, children: jsxRuntime.jsx(reactComponents.Icon, { ariaLabel: t("clearIndicator.icon.tooltip.clearAll"), name: "XCircle", size: "medium" }) }) }));
2316
- },
2317
- Control: props => {
2318
- return (jsxRuntime.jsx(ReactSelect.components.Control, { ...props, className: cvaSelectControl({
2319
- isDisabled: props.isDisabled,
2320
- prefix: prefix ? true : false,
2321
- invalid: hasError,
2322
- }) }));
2323
- },
2324
- SingleValue: props => {
2325
- const optionPrefix = getOptionPrefix ? getOptionPrefix(props.data) : null;
2326
- return (jsxRuntime.jsx(ReactSelect.components.SingleValue, { ...props, className: props.isDisabled ? "text-neutral-700" : "", children: jsxRuntime.jsxs("div", { className: "flex items-center gap-1", "data-testid": dataTestId + "-singleValue", children: [optionPrefix !== null ? optionPrefix : null, props.children, getOptionLabelDescription && getOptionLabelDescription(props.data) ? (jsxRuntime.jsxs("span", { className: "ml-1 text-neutral-400", children: ["(", getOptionLabelDescription(props.data), ")"] })) : null] }) }));
2327
- },
2328
- Menu: props => {
2329
- return (jsxRuntime.jsx(ReactSelect.components.Menu, { ...props, className: cvaSelectMenuList({ menuIsOpen: props.selectProps.menuIsOpen }) }));
2330
- },
2331
- Placeholder: props => {
2332
- return (jsxRuntime.jsx(ReactSelect.components.Placeholder, { ...props, className: "!text-neutral-400", children: props.children }));
2333
- },
2334
- MenuList: props => {
2335
- return (jsxRuntime.jsx(ReactSelect.components.MenuList, { ...props, innerProps: {
2336
- ...props.innerProps,
2337
- onScroll: e => {
2338
- const listEl = e.currentTarget;
2339
- if (listEl.scrollTop + listEl.clientHeight >= listEl.scrollHeight &&
2340
- props.selectProps.onMenuScrollToBottom) {
2341
- /Firefox/.test(navigator.userAgent)
2342
- ? props.selectProps.onMenuScrollToBottom(new WheelEvent("scroll"))
2343
- : props.selectProps.onMenuScrollToBottom(new TouchEvent(""));
2344
- }
2345
- },
2346
- }, children: props.children }));
2347
- },
2348
- Option: props => {
2349
- const componentProps = {
2350
- label: props.label,
2351
- focused: props.isFocused,
2352
- selected: props.isSelected,
2353
- onClick: props.innerProps.onClick,
2354
- };
2355
- return (jsxRuntime.jsx(ReactSelect.components.Option, { ...props, innerProps: {
2356
- ...props.innerProps,
2357
- role: "option",
2358
- onClick: () => { },
2359
- }, children: props.isMulti ? (jsxRuntime.jsx(MultiSelectMenuItem, { ...componentProps, dataTestId: typeof props.label === "string" ? props.label : undefined, disabled: disabled, fieldSize: fieldSize, optionLabelDescription: getOptionLabelDescription?.(props.data), optionPrefix: getOptionPrefix?.(props.data) })) : (jsxRuntime.jsx(SingleSelectMenuItem, { ...componentProps, dataTestId: typeof props.label === "string" ? props.label : undefined, disabled: disabled || props.isDisabled, fieldSize: fieldSize, optionLabelDescription: getOptionLabelDescription?.(props.data), optionPrefix: getOptionPrefix?.(props.data) })) }));
2360
- },
2361
- ...componentsProps,
2362
- };
2363
- }, [
2364
- componentsProps,
2365
- maxSelectedDisplayCount,
2366
- disabled,
2367
- setMenuIsEnabled,
2368
- readOnly,
2369
- dataTestId,
2370
- t,
2371
- prefix,
2372
- hasError,
2373
- getOptionLabelDescription,
2374
- fieldSize,
2375
- getOptionPrefix,
2376
- ]);
2377
- return customComponents;
2483
+ const RadioItem = ({ label, value, dataTestId, className, description, suffix, ...rest }) => {
2484
+ const groupCtx = react.useContext(RadioGroupContext);
2485
+ const isChecked = groupCtx?.value === value;
2486
+ const { ref: labelRef, isTextTruncated: isLabelTruncated } = reactComponents.useIsTextTruncated();
2487
+ const { ref: descriptionRef, isTextTruncated: isDescriptionTruncated } = reactComponents.useIsTextTruncated();
2488
+ const descriptionId = description ? `${groupCtx?.id}-${value}-description` : undefined;
2489
+ const inputId = `${groupCtx?.id}-${value}`;
2490
+ const hasLabel = label !== undefined && label !== null && label !== "";
2491
+ return (jsxRuntime.jsxs("label", { className: hasLabel
2492
+ ? cvaBinaryControlWrapper({ className })
2493
+ : `inline-flex w-fit items-center gap-2 ${className || ""}`.trim(), "data-testid": dataTestId ? `${dataTestId}-Wrapper` : undefined, htmlFor: inputId, children: [jsxRuntime.jsx("input", { "aria-describedby": descriptionId, checked: isChecked, className: cvaRadioItem({
2494
+ checked: isChecked,
2495
+ disabled: groupCtx?.disabled,
2496
+ invalid: groupCtx?.isInvalid,
2497
+ }), "data-testid": dataTestId, id: inputId, onChange: groupCtx?.onChange, type: "radio", value: value, ...rest }), hasLabel ? (jsxRuntime.jsx(reactComponents.Tooltip, { className: cvaBinaryControlLabelTooltip(), dataTestId: dataTestId ? `${dataTestId}-Label-Tooltip` : undefined, disabled: !isLabelTruncated, label: label, placement: "top", children: jsxRuntime.jsx("span", { className: cvaLabel({
2498
+ invalid: groupCtx?.isInvalid,
2499
+ disabled: groupCtx?.disabled,
2500
+ }), "data-testid": dataTestId ? `${dataTestId}-Label` : undefined, ref: labelRef, children: label }) }, "tooltip-" + rest.name)) : null, suffix ? (jsxRuntime.jsx("div", { className: cvaBinaryControlSuffixContainer(), "data-testid": dataTestId ? `${dataTestId}-suffix-container` : undefined, children: suffix })) : null, description ? (jsxRuntime.jsx(reactComponents.Tooltip, { className: cvaBinaryControlDescriptionTooltip(), dataTestId: dataTestId ? `${dataTestId}-Description-Tooltip` : undefined, disabled: !isDescriptionTruncated, label: description, placement: "top", children: jsxRuntime.jsx("span", { className: cvaBinaryControlDescription({ disabled: groupCtx?.disabled }), "data-testid": dataTestId ? `${dataTestId}-Description` : undefined, id: descriptionId, ref: descriptionRef, children: description }) }, "description-tooltip-" + rest.name)) : null] }));
2378
2501
  };
2379
2502
 
2503
+ const cvaTimeRange = cssClassVarianceUtilities.cvaMerge([
2504
+ "flex",
2505
+ "flex-1",
2506
+ "items-center",
2507
+ "gap-4",
2508
+ "max-sm:gap-2",
2509
+ "border-transparent",
2510
+ "rounded-md",
2511
+ ]);
2512
+
2380
2513
  /**
2381
- * @template IsMulti
2382
- * @template Group
2383
- * @param {RefObject<HTMLDivElement | null>} refContainer react ref to container element
2384
- * @param {number | undefined} maxSelectedDisplayCount a number of max display count
2385
- * @param {StylesConfig<Option, IsMulti, Group> | undefined} styles a optional object to override styles of react-select
2386
- * @returns {StylesConfig<Option, boolean>} styles to override in select
2514
+ * TimeRange is used to create a time range entry.
2515
+ *
2516
+ * @param {TimeRangeProps} props - The props for the TimeRange component
2517
+ * @returns {ReactElement} TimeRange component
2387
2518
  */
2388
- const useCustomStyles = ({ refContainer, maxSelectedDisplayCount, styles, disabled, fieldSize, }) => {
2389
- const customStyles = react.useMemo(() => {
2519
+ const TimeRange = ({ id, className, dataTestId, children, range, onChange, disabled, isInvalid, }) => {
2520
+ const [timeRange, setTimeRange] = react.useState(range ?? {
2521
+ timeFrom: DEFAULT_TIME,
2522
+ timeTo: DEFAULT_TIME,
2523
+ });
2524
+ const onChangeFrom = (timeFrom) => {
2525
+ setTimeRange(prev => ({ ...prev, timeFrom }));
2526
+ };
2527
+ const onChangeTo = (timeTo) => {
2528
+ setTimeRange(prev => ({ ...prev, timeTo }));
2529
+ };
2530
+ const onRangeChange = () => onChange(timeRange);
2531
+ return (jsxRuntime.jsxs("div", { className: cvaTimeRange({ className }), "data-testid": dataTestId, id: id, children: [jsxRuntime.jsx(BaseInput, { dataTestId: `${dataTestId}-from`, disabled: disabled, isInvalid: isInvalid, onBlur: onRangeChange, onChange: (time) => onChangeFrom(time.currentTarget.value), type: "time", value: timeRange.timeFrom === "" ? DEFAULT_TIME : timeRange.timeFrom }), children ?? jsxRuntime.jsx("div", { "data-testid": `${dataTestId}-separator`, children: "-" }), jsxRuntime.jsx(BaseInput, { dataTestId: `${dataTestId}-to`, disabled: disabled, isInvalid: isInvalid, onBlur: onRangeChange, onChange: (time) => onChangeTo(time.currentTarget.value), type: "time", value: timeRange.timeTo === "" ? DEFAULT_TIME : timeRange.timeTo })] }));
2532
+ };
2533
+ const DEFAULT_TIME = "12:00";
2534
+
2535
+ const cvaScheduleItem = cssClassVarianceUtilities.cvaMerge([
2536
+ "grid",
2537
+ "pb-4",
2538
+ "gap-2",
2539
+ "grid-cols-[60px,200px,60px,2fr]",
2540
+ "max-sm:grid-cols-1",
2541
+ ]);
2542
+ const cvaScheduleItemText = cssClassVarianceUtilities.cvaMerge(["flex", "font-bold", "self-center"]);
2543
+
2544
+ /**
2545
+ * Schedule is used to create a time range entries.
2546
+ *
2547
+ * @param {ScheduleProps} props - The props for the Schedule component
2548
+ * @returns {ReactElement} Schedule component
2549
+ */
2550
+ const Schedule = ({ className, dataTestId, schedule, onChange, invalidKeys = [] }) => {
2551
+ const [t] = useTranslation();
2552
+ const onRangeChange = (range, index) => {
2553
+ const newSchedule = schedule.map((day, dayIndex) => (index === dayIndex ? { ...day, range: { ...range } } : day));
2554
+ onChange(newSchedule);
2555
+ };
2556
+ const onActiveChange = (isActive, index) => {
2557
+ const newSchedule = schedule.map((day, dayIndex) => index === dayIndex
2558
+ ? {
2559
+ ...day,
2560
+ range: {
2561
+ timeFrom: day.range.timeFrom ? day.range.timeFrom : DEFAULT_TIME,
2562
+ timeTo: day.range.timeTo ? day.range.timeTo : DEFAULT_TIME,
2563
+ },
2564
+ isActive,
2565
+ }
2566
+ : day);
2567
+ onChange(newSchedule);
2568
+ };
2569
+ const onAllDayChange = (isAllDayChecked, index) => {
2570
+ const newSchedule = schedule.map((day, dayIndex) => index === dayIndex
2571
+ ? {
2572
+ ...day,
2573
+ range: {
2574
+ timeFrom: day.range.timeFrom ? day.range.timeFrom : DEFAULT_TIME,
2575
+ timeTo: day.range.timeTo ? day.range.timeTo : DEFAULT_TIME,
2576
+ },
2577
+ isAllDay: isAllDayChecked,
2578
+ }
2579
+ : day);
2580
+ onChange(newSchedule);
2581
+ };
2582
+ return (jsxRuntime.jsx("div", { className: className, "data-testid": dataTestId, children: schedule.map(({ label, range, isActive, key, checkboxLabel, isAllDay }, index) => {
2583
+ return (jsxRuntime.jsxs("div", { className: cvaScheduleItem(), children: [jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-4 sm:hidden", children: [jsxRuntime.jsx(reactComponents.Text, { className: "font-medium text-neutral-500", children: t("schedule.label.day") }), jsxRuntime.jsx(reactComponents.Text, { className: cvaScheduleItemText(), size: "medium", subtle: !isActive, children: label }), jsxRuntime.jsx(reactComponents.Text, { className: "font-medium text-neutral-500", children: t("schedule.label.active") }), jsxRuntime.jsx(Checkbox, { checked: isActive, label: checkboxLabel, onChange: (event) => onActiveChange(Boolean(event.currentTarget.checked), index) }), jsxRuntime.jsx(reactComponents.Text, { className: "font-medium text-neutral-500", children: t("schedule.label.allDay") }), jsxRuntime.jsx(Checkbox, { checked: isAllDay ? isActive : undefined, disabled: !isActive, onChange: (event) => onAllDayChange(Boolean(event.currentTarget.checked), index) }), jsxRuntime.jsx(TimeRange, { disabled: !isActive || isAllDay, isInvalid: !!invalidKeys.find((invalidKey) => invalidKey === key), onChange: (newRange) => onRangeChange(newRange, index), range: range })] }), jsxRuntime.jsxs("div", { className: "max-sm:hidden sm:grid sm:grid-cols-[100px,200px,60px,250px,250px] sm:gap-2", children: [jsxRuntime.jsx(Checkbox, { checked: isActive, dataTestId: `${dataTestId}-${key}-checkbox`, label: checkboxLabel, onChange: (event) => onActiveChange(Boolean(event.currentTarget.checked), index) }), jsxRuntime.jsx(reactComponents.Text, { className: cvaScheduleItemText(), size: "medium", subtle: !isActive, children: label }), jsxRuntime.jsx(Checkbox, { checked: isAllDay ? isActive : undefined, dataTestId: `${dataTestId}-${key}-allday-checkbox`, disabled: !isActive, onChange: (event) => onAllDayChange(Boolean(event.currentTarget.checked), index) }), jsxRuntime.jsx(TimeRange, { dataTestId: `${dataTestId}-${key}-range`, disabled: !isActive || isAllDay, isInvalid: !!invalidKeys.find((invalidKey) => invalidKey === key), onChange: (newRange) => onRangeChange(newRange, index), range: isAllDay ? undefined : range })] })] }, key + label));
2584
+ }) }));
2585
+ };
2586
+
2587
+ const weekDay = {
2588
+ Monday: "monday",
2589
+ Tuesday: "tuesday",
2590
+ Wednesday: "wednesday",
2591
+ Thursday: "thursday",
2592
+ Friday: "friday",
2593
+ Saturday: "saturday",
2594
+ Sunday: "sunday",
2595
+ };
2596
+ exports.ScheduleVariant = void 0;
2597
+ (function (ScheduleVariant) {
2598
+ ScheduleVariant["ALL_DAYS"] = "all";
2599
+ ScheduleVariant["WEEKDAYS"] = "week";
2600
+ ScheduleVariant["CUSTOM"] = "custom";
2601
+ })(exports.ScheduleVariant || (exports.ScheduleVariant = {}));
2602
+ /**
2603
+ * Parse a string of week range schedule string to human readable schedule range.
2604
+ *
2605
+ * @param {string} scheduleString String of week schedule
2606
+ * @returns {WeekSchedule} Week schedule range
2607
+ */
2608
+ const parseSchedule = (scheduleString) => {
2609
+ if (!scheduleString) {
2390
2610
  return {
2391
- control: base => {
2392
- return {
2393
- ...base,
2394
- minHeight: fieldSize === "small" ? "28px" : fieldSize === "large" ? "40px" : "32px",
2395
- borderRadius: "var(--border-radius-lg)",
2396
- backgroundColor: "inherit",
2397
- };
2398
- },
2399
- singleValue: base => ({
2400
- ...base,
2401
- }),
2402
- multiValue: base => ({
2403
- ...base,
2404
- }),
2405
- multiValueLabel: base => ({
2406
- ...base,
2407
- }),
2408
- indicatorsContainer: base => ({
2409
- ...base,
2410
- ...(disabled && { display: "none" }),
2411
- }),
2412
- indicatorSeparator: () => ({
2413
- width: "0px",
2414
- }),
2415
- menu: base => {
2416
- return {
2417
- ...base,
2418
- width: "100%",
2419
- marginTop: "4px",
2420
- marginBottom: "18px",
2421
- transition: "all 1s ease-in-out",
2422
- };
2423
- },
2424
- input: base => ({
2425
- ...base,
2426
- marginLeft: "0px",
2427
- }),
2428
- placeholder: base => ({
2429
- ...base,
2430
- }),
2431
- option: () => ({}),
2432
- menuPortal: base => ({
2433
- ...base,
2434
- width: refContainer.current ? `${refContainer.current.clientWidth}px` : base.width,
2435
- backgroundColor: "#ffffff",
2436
- borderRadius: "var(--border-radius-lg)",
2437
- zIndex: "var(--z-overlay)",
2438
- borderColor: "rgb(var(--color-neutral-300))",
2439
- boxShadow: "var(--tw-ring-inset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)",
2440
- }),
2441
- menuList: base => {
2442
- return {
2443
- ...base,
2444
- position: "relative",
2445
- padding: "var(--spacing-1)",
2446
- display: "grid",
2447
- gap: "var(--spacing-1)",
2448
- width: "100%",
2449
- borderRadius: "0px",
2450
- boxShadow: "none",
2451
- paddingTop: "0px",
2452
- };
2453
- },
2454
- valueContainer: base => {
2455
- return {
2456
- ...base,
2457
- paddingBlock: 0,
2458
- flexWrap: maxSelectedDisplayCount !== undefined ? "wrap" : "nowrap",
2459
- gap: "0.25rem",
2460
- };
2461
- },
2462
- container: base => ({
2463
- ...base,
2464
- width: "100%",
2465
- }),
2466
- dropdownIndicator: base => ({
2467
- ...base,
2468
- padding: "0px",
2469
- }),
2470
- clearIndicator: base => {
2471
- return {
2472
- ...base,
2473
- padding: "0px",
2474
- };
2475
- },
2476
- ...styles,
2611
+ variant: exports.ScheduleVariant.CUSTOM,
2612
+ schedule: [1, 2, 3, 4, 5, 6, 7].map(day => ({
2613
+ day,
2614
+ range: { timeFrom: "", timeTo: "" },
2615
+ isAllDay: false,
2616
+ isActive: false,
2617
+ })),
2477
2618
  };
2478
- }, [refContainer, disabled, fieldSize, maxSelectedDisplayCount, styles]);
2479
- return { customStyles };
2619
+ }
2620
+ const schedule = scheduleString.split(",").map(daySchedule => {
2621
+ const [day, timeRange] = daySchedule.split("#");
2622
+ const [timeFrom, timeTo] = (timeRange ?? "").split("-");
2623
+ const isAllDay = timeFrom === "00:00" && timeTo === "24:00";
2624
+ return {
2625
+ day: Number(day),
2626
+ range: timeFrom === undefined || timeTo === undefined
2627
+ ? undefined
2628
+ : {
2629
+ timeFrom: timeFrom,
2630
+ timeTo: timeTo,
2631
+ },
2632
+ isAllDay,
2633
+ isActive: Boolean(timeFrom) && Boolean(timeTo),
2634
+ };
2635
+ });
2636
+ const filteredSchedule = schedule
2637
+ .filter(daySchedule => daySchedule.range)
2638
+ .map(daySchedule => ({
2639
+ day: daySchedule.day,
2640
+ range: daySchedule.range,
2641
+ isAllDay: daySchedule.isAllDay,
2642
+ isActive: daySchedule.isActive,
2643
+ }));
2644
+ let variant;
2645
+ switch (schedule.length) {
2646
+ case 7:
2647
+ variant = isUniform(schedule) ? exports.ScheduleVariant.ALL_DAYS : exports.ScheduleVariant.CUSTOM;
2648
+ break;
2649
+ case 5:
2650
+ variant = hasConsecutiveDays(schedule) ? exports.ScheduleVariant.WEEKDAYS : exports.ScheduleVariant.CUSTOM;
2651
+ break;
2652
+ default:
2653
+ return {
2654
+ variant: exports.ScheduleVariant.CUSTOM,
2655
+ schedule: filteredSchedule,
2656
+ };
2657
+ }
2658
+ return {
2659
+ variant,
2660
+ schedule: filteredSchedule,
2661
+ };
2480
2662
  };
2481
-
2482
2663
  /**
2483
- * A hook used by selects to share the common code
2664
+ * Serialize week schedule to string schedule
2484
2665
  *
2485
- * @param {SelectProps} props - The props for the Select component
2486
- * @returns {UseSelectProps} Select component
2666
+ * @param {WeekSchedule} weekSchedule Week schedule range
2667
+ * @returns {string} Schedule string
2487
2668
  */
2488
- const useSelect = ({ id, className, dataTestId = "select", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, components, value, options, onChange, isLoading, classNamePrefix = "", onMenuOpen, onMenuClose, maxSelectedDisplayCount = undefined, isClearable = false, isSearchable = true, onMenuScrollToBottom, styles, filterOption, onInputChange, getOptionLabelDescription, getOptionPrefix, fieldSize = "medium", ...props }) => {
2489
- const refContainer = react.useRef(document.createElement("div"));
2490
- const { customStyles } = useCustomStyles({
2491
- refContainer,
2492
- maxSelectedDisplayCount,
2493
- styles,
2494
- disabled: Boolean(disabled),
2495
- fieldSize,
2496
- });
2497
- const [menuIsOpen, setMenuIsOpen] = react.useState(props.menuIsOpen ?? false);
2498
- const [menuIsEnabled, setMenuIsEnabled] = react.useState(true);
2499
- const customComponents = useCustomComponents({
2500
- componentsProps: components,
2501
- disabled: Boolean(disabled),
2502
- readOnly: Boolean(props.readOnly),
2503
- setMenuIsEnabled,
2504
- dataTestId,
2505
- maxSelectedDisplayCount,
2506
- prefix,
2507
- hasError,
2508
- fieldSize,
2509
- getOptionLabelDescription,
2510
- getOptionPrefix,
2511
- });
2512
- const menuPlacement = "auto";
2513
- const openMenuHandler = async () => {
2514
- onMenuOpen?.();
2515
- if (menuIsEnabled) {
2516
- setMenuIsOpen(true);
2669
+ const serializeSchedule = (weekSchedule) => {
2670
+ return weekSchedule.schedule
2671
+ .filter(({ range, day, isAllDay }) => {
2672
+ const hasRange = range.timeFrom && range.timeTo;
2673
+ switch (weekSchedule.variant) {
2674
+ case exports.ScheduleVariant.WEEKDAYS:
2675
+ return day <= 5 && hasRange;
2676
+ case exports.ScheduleVariant.ALL_DAYS:
2677
+ return day <= 7 && hasRange;
2678
+ case exports.ScheduleVariant.CUSTOM:
2679
+ default:
2680
+ return hasRange || isAllDay;
2517
2681
  }
2518
- else {
2519
- setMenuIsEnabled(true);
2682
+ })
2683
+ .map(({ day, range, isAllDay }) => {
2684
+ if (isAllDay) {
2685
+ return `${day}#00:00-24:00`;
2520
2686
  }
2521
- };
2522
- const closeMenuHandler = () => {
2523
- setMenuIsOpen(false);
2524
- onMenuClose && onMenuClose();
2525
- };
2526
- return {
2527
- refContainer,
2528
- customStyles,
2529
- menuIsOpen,
2530
- customComponents,
2531
- menuPlacement,
2532
- openMenuHandler,
2533
- closeMenuHandler,
2534
- };
2687
+ return `${day}#${range.timeFrom}-${range.timeTo}`;
2688
+ })
2689
+ .join(",");
2535
2690
  };
2536
-
2537
2691
  /**
2538
- * CreatableSelects are input components used to choose a value from a set.
2692
+ * Checks if a list of schedule objects have the same ranges
2539
2693
  *
2540
- * @param {CreatableSelectProps} props - The props for the CreatableSelect component
2541
- * @returns {ReactElement} CreatableSelect component
2694
+ * @param {RawSchedule[]} schedule List of schedule objects
2695
+ * @returns {boolean} Whether the schedule is uniform
2542
2696
  */
2543
- const CreatableSelect = (props) => {
2544
- const { id, dataTestId = "creatableSelect", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, value, options, onChange, isLoading, classNamePrefix = "creatableSelect", onMenuScrollToBottom, onInputChange, isSearchable, isClearable = false, readOnly, openMenuOnClick = !disabled, openMenuOnFocus = !disabled, allowCreateWhileLoading, onCreateOption, } = props;
2545
- const { refContainer, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler } = useSelect(props);
2546
- const reactCreatableSelectProps = react.useMemo(() => ({
2547
- value,
2548
- menuPlacement,
2549
- maxMenuHeight,
2550
- onChange,
2551
- "aria-label": label,
2552
- "data-testid": dataTestId,
2553
- components: customComponents,
2554
- styles: customStyles,
2555
- tabSelectsValue: false,
2556
- blurInputOnSelect: !isMulti,
2557
- menuPortalTarget: props.menuPortalTarget || document.body,
2558
- isSearchable: disabled || readOnly ? false : isSearchable,
2559
- menuShouldBlockScroll: true,
2560
- menuShouldScrollIntoView: true,
2561
- openMenuOnFocus,
2562
- menuIsOpen: !readOnly ? menuIsOpen : false,
2563
- openMenuOnClick,
2564
- closeMenuOnSelect: false,
2565
- isMulti,
2566
- classNamePrefix,
2567
- isLoading,
2568
- isClearable,
2569
- id,
2570
- onMenuScrollToBottom,
2571
- onInputChange,
2572
- allowCreateWhileLoading,
2573
- onCreateOption,
2574
- isDisabled: Boolean(disabled),
2575
- }), [
2576
- allowCreateWhileLoading,
2577
- classNamePrefix,
2578
- customComponents,
2579
- customStyles,
2580
- dataTestId,
2581
- disabled,
2582
- id,
2583
- isClearable,
2584
- isLoading,
2585
- isMulti,
2586
- isSearchable,
2587
- label,
2588
- maxMenuHeight,
2589
- menuIsOpen,
2590
- menuPlacement,
2591
- onChange,
2592
- onCreateOption,
2593
- onInputChange,
2594
- onMenuScrollToBottom,
2595
- openMenuOnClick,
2596
- openMenuOnFocus,
2597
- props.menuPortalTarget,
2598
- readOnly,
2599
- value,
2600
- ]);
2601
- const renderAsDisabled = Boolean(props.disabled) || props.readOnly;
2602
- return (jsxRuntime.jsxs("div", { className: cvaSelect({ invalid: hasError, disabled: renderAsDisabled, className: props.className }), "data-testid": dataTestId, ref: refContainer, children: [prefix !== undefined ? (jsxRuntime.jsx("div", { className: cvaSelectPrefixSuffix({ kind: "prefix" }), "data-testid": dataTestId ? `${dataTestId}-prefix` : null, children: prefix })) : null, async ? (jsxRuntime.jsx(ReactAsyncCreatableSelect, { ...props, ...reactCreatableSelectProps, ...async, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, placeholder: renderAsDisabled ? null : props.placeholder })) : (jsxRuntime.jsx(ReactCreatableSelect, { ...props, ...reactCreatableSelectProps, hideSelectedOptions: false, isMulti: isMulti, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, options: options, placeholder: renderAsDisabled ? null : props.placeholder })), typeof props.disabled === "object" ? (jsxRuntime.jsx("div", { className: cvaSelectPrefixSuffix({ kind: "suffix" }), "data-testid": dataTestId ? `${dataTestId}-locked` : null, children: jsxRuntime.jsx(InputLockReasonTooltip, { ...props.disabled }) })) : null] }));
2697
+ const isUniform = (schedule) => {
2698
+ return schedule.every((day, _, collection) => collection[0]?.range?.timeFrom === day.range?.timeFrom && collection[0]?.range?.timeTo === day.range?.timeTo);
2699
+ };
2700
+ /**
2701
+ * Checks if a list of schedule objects are consecutive days
2702
+ *
2703
+ * @param {RawSchedule[]} schedule List of schedule objects
2704
+ * @returns {boolean} Whether the schedule has consecutive days
2705
+ */
2706
+ const hasConsecutiveDays = (schedule) => {
2707
+ const days = [1, 2, 3, 4, 5];
2708
+ return schedule.every(({ day }, index) => day === days[index]);
2603
2709
  };
2604
- CreatableSelect.displayName = "CreatableSelect";
2605
2710
 
2606
- // This is here to ensure the bundled react-components can expose the react-select for jest in external iris apps.
2607
- const ReactSyncSelect = ReactSelect.default || ReactSelect;
2711
+ const cvaSearch = cssClassVarianceUtilities.cvaMerge([
2712
+ "shadow-none",
2713
+ "component-search-border",
2714
+ "component-search-background",
2715
+ "hover:component-search-background",
2716
+ "hover:component-search-focus-hover",
2717
+ "transition-all",
2718
+ "duration-300",
2719
+ ], {
2720
+ variants: {
2721
+ border: { true: ["!component-search-borderless"], false: "" },
2722
+ widenOnFocus: {
2723
+ true: [
2724
+ "component-search-width",
2725
+ "component-search-widen",
2726
+ "hover:component-search-widen",
2727
+ "focus-within:w-full",
2728
+ "max-w-sm",
2729
+ ],
2730
+ false: "w-full",
2731
+ },
2732
+ },
2733
+ });
2734
+
2608
2735
  /**
2609
- * Selects are input components used to choose a value from a set.
2736
+ * The Search component is used to render a search input field.
2610
2737
  *
2611
- * @param {SelectProps} props - The props for the Select component
2612
- * @returns {ReactElement} Select component
2738
+ * @param {SearchProps} props - The props for the Search component
2613
2739
  */
2614
- const Select = (props) => {
2615
- const { id, dataTestId = "select", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, menuPosition = "absolute", value, options, onChange, isLoading, classNamePrefix = "select", onMenuScrollToBottom, onInputChange, isSearchable, isClearable = false, readOnly, fieldSize = "medium", openMenuOnClick = !disabled, openMenuOnFocus = false, hideSelectedOptions = false, } = props;
2616
- const { refContainer, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler } = useSelect(props);
2617
- const reactSelectProps = react.useMemo(() => ({
2618
- value,
2619
- menuPlacement,
2620
- maxMenuHeight,
2621
- onChange,
2622
- "aria-label": label,
2623
- "data-testid": dataTestId,
2624
- components: customComponents,
2625
- styles: customStyles,
2626
- tabSelectsValue: false,
2627
- blurInputOnSelect: false,
2628
- // This configuration allows for more flexible positioning control of the dropdown.
2629
- // Setting menuPortalTarget to 'null' specifies that the dropdown should be rendered within
2630
- // the parent element instead of 'document.body'.
2631
- menuPortalTarget: props.menuPortalTarget !== undefined ? props.menuPortalTarget : document.body,
2632
- isSearchable: disabled || readOnly ? false : isSearchable,
2633
- menuShouldBlockScroll: true,
2634
- menuShouldScrollIntoView: true,
2635
- openMenuOnFocus,
2636
- menuIsOpen: !readOnly ? menuIsOpen : false,
2637
- openMenuOnClick,
2638
- closeMenuOnSelect: !isMulti,
2639
- isMulti,
2640
- classNamePrefix,
2641
- isLoading,
2642
- isClearable,
2643
- id,
2644
- onMenuScrollToBottom,
2645
- onInputChange,
2646
- hideSelectedOptions,
2647
- isDisabled: Boolean(disabled),
2648
- }), [
2649
- classNamePrefix,
2650
- customComponents,
2651
- customStyles,
2652
- dataTestId,
2653
- disabled,
2654
- hideSelectedOptions,
2655
- id,
2656
- isClearable,
2657
- isLoading,
2658
- isMulti,
2659
- isSearchable,
2660
- label,
2661
- maxMenuHeight,
2662
- menuIsOpen,
2663
- menuPlacement,
2664
- onChange,
2665
- onInputChange,
2666
- onMenuScrollToBottom,
2667
- openMenuOnClick,
2668
- openMenuOnFocus,
2669
- props.menuPortalTarget,
2670
- readOnly,
2671
- value,
2672
- ]);
2673
- const renderAsDisabled = Boolean(props.disabled) || props.readOnly;
2674
- return (jsxRuntime.jsxs("div", { className: cvaSelect({
2675
- invalid: hasError,
2676
- fieldSize: fieldSize,
2677
- disabled: renderAsDisabled,
2678
- className: props.className,
2679
- }), "data-testid": dataTestId, ref: refContainer, children: [prefix !== undefined ? (jsxRuntime.jsx("div", { className: cvaSelectPrefixSuffix({ kind: "prefix" }), "data-testid": dataTestId ? `${dataTestId}-prefix` : null, children: prefix })) : null, async ? (jsxRuntime.jsx(ReactAsyncSelect, { ...props, ...reactSelectProps, ...async, menuPosition: menuPosition, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, placeholder: renderAsDisabled ? null : props.placeholder })) : (jsxRuntime.jsx(ReactSyncSelect, { ...props, ...reactSelectProps, isMulti: isMulti, menuPosition: menuPosition, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, options: options, placeholder: renderAsDisabled ? null : props.placeholder })), typeof props.disabled === "object" ? (jsxRuntime.jsx("div", { className: cvaSelectPrefixSuffix({ kind: "suffix" }), "data-testid": dataTestId ? `${dataTestId}-locked` : null, children: jsxRuntime.jsx(InputLockReasonTooltip, { ...props.disabled }) })) : null] }));
2740
+ const Search = ({ className, placeholder, value, widenInputOnFocus, hideBorderWhenNotInFocus = false, disabled = false, onKeyUp, onChange, onFocus, onBlur, name, onClear, dataTestId, autoComplete = "on", loading = false, inputClassName, iconName = "MagnifyingGlass", style, xMarkRef, ref, ...rest }) => {
2741
+ const { t } = useTranslation();
2742
+ return (jsxRuntime.jsx(TextBaseInput, { ...rest, autoComplete: autoComplete, className: cvaSearch({ className, border: hideBorderWhenNotInFocus, widenOnFocus: widenInputOnFocus }), dataTestId: dataTestId, disabled: disabled, inputClassName: inputClassName, name: name, onBlur: onBlur, onChange: onChange, onFocus: onFocus, onKeyUp: onKeyUp, placeholder: placeholder ?? t("search.placeholder"), prefix: loading ? (jsxRuntime.jsx(reactComponents.Spinner, { centering: "centered", size: rest.fieldSize ?? undefined })) : (jsxRuntime.jsx(reactComponents.Icon, { name: iconName, size: rest.fieldSize ?? undefined })), ref: ref, suffix:
2743
+ //only show the clear button if there is a value and the onClear function is provided
2744
+ onClear && value ? (jsxRuntime.jsx("button", { className: "flex", "data-testid": dataTestId ? `${dataTestId}_suffix_component` : null, onClick: () => {
2745
+ onClear();
2746
+ }, ref: xMarkRef, type: "button", children: jsxRuntime.jsx(reactComponents.Icon, { name: "XMark", size: "small" }) })) : undefined, value: value }));
2680
2747
  };
2681
- Select.displayName = "Select";
2748
+ Search.displayName = "Search";
2682
2749
 
2683
2750
  /**
2684
2751
  *
@@ -2765,7 +2832,7 @@ CreatableSelectField.displayName = "CreatableSelectField";
2765
2832
  * @param {SelectFieldProps} props - The props for the SelectField component
2766
2833
  */
2767
2834
  const SelectField = ({ ref, ...props }) => {
2768
- return (jsxRuntime.jsx(FormFieldSelectAdapter, { ...props, ref: ref, children: convertedProps => jsxRuntime.jsx(Select, { ...convertedProps }) }));
2835
+ return (jsxRuntime.jsx(FormFieldSelectAdapter, { ...props, ref: ref, children: convertedProps => jsxRuntime.jsx(BaseSelect, { ...convertedProps }) }));
2769
2836
  };
2770
2837
  SelectField.displayName = "SelectField";
2771
2838
 
@@ -3181,6 +3248,7 @@ setupLibraryTranslations();
3181
3248
  exports.ValueType = ReactSelect;
3182
3249
  exports.ActionButton = ActionButton;
3183
3250
  exports.BaseInput = BaseInput;
3251
+ exports.BaseSelect = BaseSelect;
3184
3252
  exports.Checkbox = Checkbox;
3185
3253
  exports.CheckboxField = CheckboxField;
3186
3254
  exports.ColorField = ColorField;
@@ -3196,6 +3264,7 @@ exports.EmailField = EmailField;
3196
3264
  exports.FormFieldSelectAdapter = FormFieldSelectAdapter;
3197
3265
  exports.FormGroup = FormGroup;
3198
3266
  exports.Label = Label;
3267
+ exports.MultiSelectField = MultiSelectField;
3199
3268
  exports.MultiSelectMenuItem = MultiSelectMenuItem;
3200
3269
  exports.NumberBaseInput = NumberBaseInput;
3201
3270
  exports.NumberField = NumberField;
@@ -3209,7 +3278,6 @@ exports.RadioGroup = RadioGroup;
3209
3278
  exports.RadioItem = RadioItem;
3210
3279
  exports.Schedule = Schedule;
3211
3280
  exports.Search = Search;
3212
- exports.Select = Select;
3213
3281
  exports.SelectField = SelectField;
3214
3282
  exports.SingleSelectMenuItem = SingleSelectMenuItem;
3215
3283
  exports.TextAreaBaseInput = TextAreaBaseInput;