@trackunit/react-form-components 1.3.65 → 1.3.66

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
@@ -1171,7 +1171,6 @@ const NumberField = ({ label, id, tip, helpText, errorMessage, helpAddon, isInva
1171
1171
  const error = React.useMemo(() => {
1172
1172
  // for the case when a custom error message is provided
1173
1173
  if (errorMessage) {
1174
- setRenderAsInvalid(Boolean(errorMessage));
1175
1174
  return errorMessage;
1176
1175
  }
1177
1176
  else if (errorType) {
@@ -1179,6 +1178,11 @@ const NumberField = ({ label, id, tip, helpText, errorMessage, helpAddon, isInva
1179
1178
  }
1180
1179
  return errorMessage;
1181
1180
  }, [errorMessage, errorType, rest.max, rest.min, t]);
1181
+ React.useEffect(() => {
1182
+ if (errorMessage) {
1183
+ setRenderAsInvalid(Boolean(errorMessage));
1184
+ }
1185
+ }, [errorMessage]);
1182
1186
  const handleBlur = React.useCallback(event => {
1183
1187
  const newValue = event.target.value;
1184
1188
  setInnerValue(newValue.toString());
@@ -1452,7 +1456,6 @@ const PhoneField = ({ label, id, tip, helpText, isInvalid, errorMessage, value,
1452
1456
  const error = React.useMemo(() => {
1453
1457
  // for the case when a custom error message is provided
1454
1458
  if (errorMessage) {
1455
- setRenderAsInvalid(Boolean(errorMessage));
1456
1459
  return errorMessage;
1457
1460
  }
1458
1461
  else if (errorType) {
@@ -1460,6 +1463,9 @@ const PhoneField = ({ label, id, tip, helpText, isInvalid, errorMessage, value,
1460
1463
  }
1461
1464
  return errorMessage;
1462
1465
  }, [errorMessage, errorType, t]);
1466
+ React.useEffect(() => {
1467
+ setRenderAsInvalid(Boolean(errorMessage));
1468
+ }, [errorMessage]);
1463
1469
  const handleBlur = React.useCallback(event => {
1464
1470
  const newValue = event.target.value;
1465
1471
  setInnerValue(newValue);
@@ -1990,54 +1996,72 @@ const TagWithWidth = ({ onWidthKnown, children, ...rest }) => {
1990
1996
  * @returns {ReactElement} TagsContainer
1991
1997
  */
1992
1998
  const TagsContainer = ({ items, width = "100%", itemsGap = 5, postFix, disabled }) => {
1999
+ const containerRef = React.useRef(null);
1993
2000
  const [isReady, setIsReady] = React.useState(false);
1994
2001
  const [counterWidth, setCounterWidth] = React.useState(0);
1995
- const containerRef = React.useRef(null);
1996
- const availableWidth = React.useRef(undefined);
1997
- const childrenWidth = React.useRef([]);
2002
+ const [availableSpaceWidth, setAvailableSpaceWidth] = React.useState(0);
2003
+ const [childrenWidths, setChildrenWidths] = React.useState([]);
1998
2004
  const itemsCount = items.length;
1999
- React.useLayoutEffect(() => {
2000
- availableWidth.current = containerRef.current?.offsetWidth || 0;
2001
- }, [containerRef]);
2002
- const onWidthKnownHandler = ({ width: reportedWidth }) => {
2003
- childrenWidth.current.push({ width: reportedWidth + itemsGap });
2004
- if (childrenWidth.current.length === itemsCount) {
2005
- setIsReady(true);
2006
- }
2007
- };
2008
- const requiredSpace = childrenWidth.current.reduce((previous, current) => {
2009
- return previous + current.width;
2010
- }, 0);
2011
- let counter = 0;
2012
- const availableSpace = (availableWidth.current || 0) - counterWidth;
2013
- const renderedElements = items
2014
- .concat({ text: "", onClick: () => null, disabled: false }) // reserved element for a potential counter
2015
- .map((item, index) => {
2016
- const spaceNeeded = childrenWidth.current.slice(0, index + 1).reduce((previous, current) => {
2005
+ const dimensions = reactComponents.useResize();
2006
+ const { width: windowWidth } = reactComponents.useDebounce(dimensions, 100);
2007
+ React.useEffect(() => {
2008
+ const containerWidth = containerRef.current?.offsetWidth || 0;
2009
+ setAvailableSpaceWidth(containerWidth);
2010
+ }, [windowWidth]);
2011
+ const onWidthKnownHandler = React.useCallback(({ width: reportedWidth }) => {
2012
+ setChildrenWidths(prev => {
2013
+ const next = [...prev, { width: reportedWidth + itemsGap }];
2014
+ if (next.length === itemsCount) {
2015
+ setIsReady(true);
2016
+ }
2017
+ return next;
2018
+ });
2019
+ }, [itemsCount, itemsGap]);
2020
+ const renderedElements = React.useMemo(() => {
2021
+ const requiredSpace = childrenWidths.reduce((previous, current) => {
2017
2022
  return previous + current.width;
2018
2023
  }, 0);
2019
- const isLast = index === items.length;
2020
- const counterRequired = requiredSpace > availableSpace && counter !== 0;
2021
- if (isLast && counterRequired) {
2022
- return (jsxRuntime.jsx(TagWithWidth, { color: "white", disabled: disabled, onWidthKnown: ({ width: reportedWidth }) => setCounterWidth(reportedWidth), children: jsxRuntime.jsxs("div", { className: cvaSelectCounter(), "data-testid": "select-counter", children: ["+", counter] }) }, item.text + index));
2023
- }
2024
- if (isLast) {
2025
- return null;
2026
- }
2027
- const itemCanFit = spaceNeeded <= availableSpace;
2028
- if (itemCanFit) {
2029
- return (jsxRuntime.jsx(TagWithWidth, { className: "inline-flex shrink-0", color: item.disabled ? "unknown" : "primary", dataTestId: `${item.text}-tag`, disabled: disabled, onClose: e => {
2030
- e.stopPropagation();
2031
- item.onClick();
2032
- }, onWidthKnown: onWidthKnownHandler, children: item.text }, item.text + index));
2033
- }
2034
- const fromTheItems = item.text !== "";
2035
- if (fromTheItems) {
2036
- counter = counter + 1;
2037
- }
2038
- return null;
2039
- })
2040
- .filter(element => element !== null);
2024
+ const availableSpace = availableSpaceWidth - counterWidth;
2025
+ const { elements } = items
2026
+ .concat({ text: "", onClick: () => null, disabled: false })
2027
+ .reduce((acc, item, index) => {
2028
+ const spaceNeeded = childrenWidths.slice(0, index + 1).reduce((previous, current) => {
2029
+ return previous + current.width;
2030
+ }, 0);
2031
+ const isLast = index === items.length;
2032
+ const counterRequired = requiredSpace > availableSpace && acc.counter !== 0;
2033
+ if (isLast && counterRequired) {
2034
+ return {
2035
+ ...acc,
2036
+ elements: [
2037
+ ...acc.elements,
2038
+ jsxRuntime.jsx(TagWithWidth, { color: "white", disabled: disabled, onWidthKnown: ({ width: reportedWidth }) => setCounterWidth(reportedWidth), children: jsxRuntime.jsxs("div", { className: cvaSelectCounter(), "data-testid": "select-counter", children: ["+", acc.counter] }) }, item.text + index),
2039
+ ],
2040
+ };
2041
+ }
2042
+ if (isLast) {
2043
+ return acc;
2044
+ }
2045
+ const itemCanFit = spaceNeeded <= availableSpace;
2046
+ if (itemCanFit) {
2047
+ return {
2048
+ ...acc,
2049
+ elements: [
2050
+ ...acc.elements,
2051
+ jsxRuntime.jsx(TagWithWidth, { className: "inline-flex shrink-0", color: item.disabled ? "unknown" : "primary", dataTestId: `${item.text}-tag`, disabled: disabled, onClose: e => {
2052
+ e.stopPropagation();
2053
+ item.onClick();
2054
+ }, onWidthKnown: onWidthKnownHandler, children: item.text }, item.text + index),
2055
+ ],
2056
+ };
2057
+ }
2058
+ return {
2059
+ elements: acc.elements,
2060
+ counter: item.text !== "" ? acc.counter + 1 : acc.counter,
2061
+ };
2062
+ }, { elements: [], counter: 0 });
2063
+ return elements;
2064
+ }, [items, availableSpaceWidth, counterWidth, disabled, onWidthKnownHandler, childrenWidths]);
2041
2065
  return (jsxRuntime.jsxs("div", { className: cvaSelectDynamicTagContainer({ visible: isReady }), ref: containerRef, style: {
2042
2066
  width: `${width}`,
2043
2067
  }, children: [renderedElements, postFix] }));
@@ -2052,15 +2076,13 @@ const TagsContainer = ({ items, width = "100%", itemsGap = 5, postFix, disabled
2052
2076
  * @param {Partial<SelectComponents<Option, IsMulti, Group>> | undefined} componentsProps a custom component prop that you can to override defaults
2053
2077
  * @param {boolean} disabled decide to override disabled variant
2054
2078
  * @param {boolean} menuIsOpen menu is open state
2055
- * @param {RefObject<boolean>} refMenuIsEnabled a flag to block menu from open
2056
2079
  * @param {string} dataTestId a test id
2057
2080
  * @param {number} maxSelectedDisplayCount a number of max display count
2058
- * @param {ReactElement} dropdownIcon an custom dropdown icon
2059
2081
  * @param {boolean} hasError decide to override hasError variant
2060
- * @param {ReactElement} prefix a prefix element
2082
+ * @param {ReactNode} prefix a prefix element
2061
2083
  * @returns {Partial<SelectComponents<Option, boolean, GroupBase<Option>>> | undefined} components object to override react-select default components
2062
2084
  */
2063
- const useCustomComponents = ({ componentsProps, disabled, readOnly, refMenuIsEnabled, dataTestId, maxSelectedDisplayCount, dropdownIcon, prefix, hasError, fieldSize, getOptionLabelDescription, }) => {
2085
+ const useCustomComponents = ({ componentsProps, disabled, readOnly, setMenuIsEnabled, dataTestId, maxSelectedDisplayCount, prefix, hasError, fieldSize, getOptionLabelDescription, }) => {
2064
2086
  const [t] = useTranslation();
2065
2087
  // perhaps it should not be wrap in memo (causing some issues with opening and closing on mobiles)
2066
2088
  const customComponents = React.useMemo(() => {
@@ -2082,7 +2104,7 @@ const useCustomComponents = ({ componentsProps, disabled, readOnly, refMenuIsEna
2082
2104
  onClick: disabled
2083
2105
  ? undefined
2084
2106
  : (e) => {
2085
- refMenuIsEnabled.current = false;
2107
+ setMenuIsEnabled(false);
2086
2108
  tagProps.removeProps.onClick && tagProps.removeProps.onClick(e);
2087
2109
  },
2088
2110
  disabled: disabled,
@@ -2092,7 +2114,7 @@ const useCustomComponents = ({ componentsProps, disabled, readOnly, refMenuIsEna
2092
2114
  ? tags.slice(0, maxSelectedDisplayCount).map(({ props: tagProps }) => {
2093
2115
  return (jsxRuntime.jsx(reactComponents.Tag, { className: "inline-flex shrink-0", color: disabled ? "unknown" : "primary", dataTestId: tagProps.children ? `${tagProps.children.toString()}-tag` : undefined, onClose: e => {
2094
2116
  e.stopPropagation();
2095
- refMenuIsEnabled.current = false;
2117
+ setMenuIsEnabled(false);
2096
2118
  tagProps.removeProps.onClick && tagProps.removeProps.onClick(e);
2097
2119
  }, children: tagProps.children }, tagProps.children?.toString()));
2098
2120
  })
@@ -2105,7 +2127,7 @@ const useCustomComponents = ({ componentsProps, disabled, readOnly, refMenuIsEna
2105
2127
  },
2106
2128
  DropdownIndicator: props => {
2107
2129
  const icon = props.selectProps.menuIsOpen ? (jsxRuntime.jsx(reactComponents.Icon, { name: "ChevronUp", size: "medium" })) : (jsxRuntime.jsx(reactComponents.Icon, { name: "ChevronDown", size: "medium" }));
2108
- return props.selectProps.isLoading || props.selectProps.isDisabled || readOnly ? null : (jsxRuntime.jsx(ReactSelect.components.DropdownIndicator, { ...props, children: jsxRuntime.jsx("div", { className: cvaSelectIcon(), children: dropdownIcon ?? icon }) }));
2130
+ return props.selectProps.isLoading || props.selectProps.isDisabled || readOnly ? null : (jsxRuntime.jsx(ReactSelect.components.DropdownIndicator, { ...props, children: jsxRuntime.jsx("div", { className: cvaSelectIcon(), children: icon }) }));
2109
2131
  },
2110
2132
  IndicatorSeparator: () => null,
2111
2133
  ClearIndicator: props => {
@@ -2164,22 +2186,32 @@ const useCustomComponents = ({ componentsProps, disabled, readOnly, refMenuIsEna
2164
2186
  },
2165
2187
  ...componentsProps,
2166
2188
  };
2167
- // eslint-disable-next-line react-hooks/exhaustive-deps
2168
- }, [componentsProps, disabled, maxSelectedDisplayCount, readOnly]); // do not add dropdownIcon (it will cause issue with opening/closing list for selects with custom icon)
2189
+ }, [
2190
+ componentsProps,
2191
+ disabled,
2192
+ fieldSize,
2193
+ getOptionLabelDescription,
2194
+ hasError,
2195
+ maxSelectedDisplayCount,
2196
+ prefix,
2197
+ readOnly,
2198
+ setMenuIsEnabled,
2199
+ t,
2200
+ dataTestId,
2201
+ ]);
2169
2202
  return customComponents;
2170
2203
  };
2171
2204
 
2172
2205
  /**
2173
2206
  * @template IsMulti
2174
2207
  * @template Group
2175
- * @param {React.RefObject<HTMLDivElement>} refContainer react ref to container element
2176
- * @param {React.RefObject<HTMLDivElement>} refPrefix react ref to prefix element
2208
+ * @param {RefObject<HTMLDivElement | null>} refContainer react ref to container element
2177
2209
  * @param {number | undefined} maxSelectedDisplayCount a number of max display count
2178
2210
  * @param {StylesConfig<Option, IsMulti, Group> | undefined} styles a optional object to override styles of react-select
2179
2211
  * @returns {StylesConfig<Option, boolean>} styles to override in select
2180
2212
  */
2181
- const useCustomStyles = ({ refContainer, refPrefix, maxSelectedDisplayCount, styles, disabled, fieldSize, }) => {
2182
- const customStyles = React__namespace.useMemo(() => {
2213
+ const useCustomStyles = ({ refContainer, maxSelectedDisplayCount, styles, disabled, fieldSize, }) => {
2214
+ const customStyles = React.useMemo(() => {
2183
2215
  return {
2184
2216
  control: base => {
2185
2217
  return {
@@ -2268,8 +2300,7 @@ const useCustomStyles = ({ refContainer, refPrefix, maxSelectedDisplayCount, sty
2268
2300
  },
2269
2301
  ...styles,
2270
2302
  };
2271
- // eslint-disable-next-line react-hooks/exhaustive-deps
2272
- }, [refContainer, refPrefix, disabled]);
2303
+ }, [refContainer, disabled, fieldSize, maxSelectedDisplayCount, styles]);
2273
2304
  return { customStyles };
2274
2305
  };
2275
2306
 
@@ -2279,27 +2310,24 @@ const useCustomStyles = ({ refContainer, refPrefix, maxSelectedDisplayCount, sty
2279
2310
  * @param {SelectProps} props - The props for the Select component
2280
2311
  * @returns {UseSelectProps} Select component
2281
2312
  */
2282
- const useSelect = ({ id, className, dataTestId = "select", prefix, async, dropdownIcon, maxMenuHeight = 200, label, hasError, disabled, isMulti, components, value, options, onChange, isLoading, classNamePrefix = "", onMenuOpen, onMenuClose, maxSelectedDisplayCount = undefined, isClearable = false, isSearchable = true, onMenuScrollToBottom, styles, filterOption, onInputChange, getOptionLabelDescription, fieldSize = "medium", ...props }) => {
2313
+ const useSelect = ({ id, className, dataTestId = "select", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, components, value, options, onChange, isLoading, classNamePrefix = "", onMenuOpen, onMenuClose, maxSelectedDisplayCount = undefined, isClearable = false, isSearchable = true, onMenuScrollToBottom, styles, filterOption, onInputChange, getOptionLabelDescription, fieldSize = "medium", ...props }) => {
2283
2314
  const refContainer = React.useRef(document.createElement("div"));
2284
- const refPrefix = React.useRef(document.createElement("div"));
2285
2315
  const { customStyles } = useCustomStyles({
2286
2316
  refContainer,
2287
- refPrefix,
2288
2317
  maxSelectedDisplayCount,
2289
2318
  styles,
2290
2319
  disabled: Boolean(disabled),
2291
2320
  fieldSize,
2292
2321
  });
2293
2322
  const [menuIsOpen, setMenuIsOpen] = React.useState(props.menuIsOpen ?? false);
2294
- const refMenuIsEnabled = React.useRef(true);
2323
+ const [menuIsEnabled, setMenuIsEnabled] = React.useState(true);
2295
2324
  const customComponents = useCustomComponents({
2296
2325
  componentsProps: components,
2297
2326
  disabled: Boolean(disabled),
2298
2327
  readOnly: Boolean(props.readOnly),
2299
- refMenuIsEnabled,
2328
+ setMenuIsEnabled,
2300
2329
  dataTestId,
2301
2330
  maxSelectedDisplayCount,
2302
- dropdownIcon,
2303
2331
  prefix,
2304
2332
  hasError,
2305
2333
  fieldSize,
@@ -2308,11 +2336,11 @@ const useSelect = ({ id, className, dataTestId = "select", prefix, async, dropdo
2308
2336
  const menuPlacement = "auto";
2309
2337
  const openMenuHandler = async () => {
2310
2338
  onMenuOpen?.();
2311
- if (refMenuIsEnabled.current) {
2339
+ if (menuIsEnabled) {
2312
2340
  setMenuIsOpen(true);
2313
2341
  }
2314
2342
  else {
2315
- refMenuIsEnabled.current = true;
2343
+ setMenuIsEnabled(true);
2316
2344
  }
2317
2345
  };
2318
2346
  const closeMenuHandler = () => {
@@ -2321,7 +2349,6 @@ const useSelect = ({ id, className, dataTestId = "select", prefix, async, dropdo
2321
2349
  };
2322
2350
  return {
2323
2351
  refContainer,
2324
- refPrefix,
2325
2352
  customStyles,
2326
2353
  menuIsOpen,
2327
2354
  customComponents,
@@ -2339,7 +2366,7 @@ const useSelect = ({ id, className, dataTestId = "select", prefix, async, dropdo
2339
2366
  */
2340
2367
  const CreatableSelect = (props) => {
2341
2368
  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;
2342
- const { refContainer, refPrefix, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler, } = useSelect(props);
2369
+ const { refContainer, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler } = useSelect(props);
2343
2370
  const reactCreatableSelectProps = React.useMemo(() => ({
2344
2371
  value,
2345
2372
  menuPlacement,
@@ -2396,7 +2423,7 @@ const CreatableSelect = (props) => {
2396
2423
  value,
2397
2424
  ]);
2398
2425
  const renderAsDisabled = Boolean(props.disabled) || props.readOnly;
2399
- 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, ref: refPrefix, 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] }));
2426
+ 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] }));
2400
2427
  };
2401
2428
  CreatableSelect.displayName = "CreatableSelect";
2402
2429
 
@@ -2411,7 +2438,7 @@ const ReactSyncSelect = ReactSelect.default || ReactSelect;
2411
2438
  */
2412
2439
  const Select = (props) => {
2413
2440
  const { id, dataTestId = "select", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, menuPosition = "absolute", value, options, onChange, isLoading, classNamePrefix = "select", onMenuScrollToBottom, onInputChange, isSearchable, isClearable = false, readOnly, fieldSize = "medium", openMenuOnClick = !disabled, openMenuOnFocus = !disabled, hideSelectedOptions = false, } = props;
2414
- const { refContainer, refPrefix, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler, } = useSelect(props);
2441
+ const { refContainer, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler } = useSelect(props);
2415
2442
  const reactSelectProps = React.useMemo(() => ({
2416
2443
  value,
2417
2444
  menuPlacement,
@@ -2474,7 +2501,7 @@ const Select = (props) => {
2474
2501
  fieldSize: fieldSize,
2475
2502
  disabled: renderAsDisabled,
2476
2503
  className: props.className,
2477
- }), "data-testid": dataTestId, ref: refContainer, children: [prefix !== undefined ? (jsxRuntime.jsx("div", { className: cvaSelectPrefixSuffix({ kind: "prefix" }), "data-testid": dataTestId ? `${dataTestId}-prefix` : null, ref: refPrefix, 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] }));
2504
+ }), "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] }));
2478
2505
  };
2479
2506
  Select.displayName = "Select";
2480
2507
 
package/index.esm.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { useNamespaceTranslation, registerTranslations, NamespaceTrans } from '@trackunit/i18n-library-translation';
3
- import { IconButton, Icon, Tooltip, useGeometry, useIsTextTruncated, Heading, Text, Spinner, MenuItem, Tag, useIsFirstRender } from '@trackunit/react-components';
3
+ import { IconButton, Icon, Tooltip, useGeometry, useIsTextTruncated, Heading, Text, Spinner, MenuItem, Tag, useResize, useDebounce, useIsFirstRender } from '@trackunit/react-components';
4
4
  import { useCopyToClipboard } from 'usehooks-ts';
5
5
  import { cvaMerge } from '@trackunit/css-class-variance-utilities';
6
6
  import { themeSpacing } from '@trackunit/ui-design-tokens';
7
7
  import * as React from 'react';
8
- import { forwardRef, useRef, useImperativeHandle, useMemo, useState, useCallback, cloneElement, useEffect, useContext, useLayoutEffect } from 'react';
8
+ import { forwardRef, useRef, useImperativeHandle, useMemo, useState, useCallback, useEffect, cloneElement, useContext, useLayoutEffect } from 'react';
9
9
  import { titleCase } from 'string-ts';
10
10
  import { uuidv4, nonNullable } from '@trackunit/shared-utils';
11
11
  import { Temporal } from '@js-temporal/polyfill';
@@ -1152,7 +1152,6 @@ const NumberField = ({ label, id, tip, helpText, errorMessage, helpAddon, isInva
1152
1152
  const error = useMemo(() => {
1153
1153
  // for the case when a custom error message is provided
1154
1154
  if (errorMessage) {
1155
- setRenderAsInvalid(Boolean(errorMessage));
1156
1155
  return errorMessage;
1157
1156
  }
1158
1157
  else if (errorType) {
@@ -1160,6 +1159,11 @@ const NumberField = ({ label, id, tip, helpText, errorMessage, helpAddon, isInva
1160
1159
  }
1161
1160
  return errorMessage;
1162
1161
  }, [errorMessage, errorType, rest.max, rest.min, t]);
1162
+ useEffect(() => {
1163
+ if (errorMessage) {
1164
+ setRenderAsInvalid(Boolean(errorMessage));
1165
+ }
1166
+ }, [errorMessage]);
1163
1167
  const handleBlur = useCallback(event => {
1164
1168
  const newValue = event.target.value;
1165
1169
  setInnerValue(newValue.toString());
@@ -1433,7 +1437,6 @@ const PhoneField = ({ label, id, tip, helpText, isInvalid, errorMessage, value,
1433
1437
  const error = useMemo(() => {
1434
1438
  // for the case when a custom error message is provided
1435
1439
  if (errorMessage) {
1436
- setRenderAsInvalid(Boolean(errorMessage));
1437
1440
  return errorMessage;
1438
1441
  }
1439
1442
  else if (errorType) {
@@ -1441,6 +1444,9 @@ const PhoneField = ({ label, id, tip, helpText, isInvalid, errorMessage, value,
1441
1444
  }
1442
1445
  return errorMessage;
1443
1446
  }, [errorMessage, errorType, t]);
1447
+ useEffect(() => {
1448
+ setRenderAsInvalid(Boolean(errorMessage));
1449
+ }, [errorMessage]);
1444
1450
  const handleBlur = useCallback(event => {
1445
1451
  const newValue = event.target.value;
1446
1452
  setInnerValue(newValue);
@@ -1971,54 +1977,72 @@ const TagWithWidth = ({ onWidthKnown, children, ...rest }) => {
1971
1977
  * @returns {ReactElement} TagsContainer
1972
1978
  */
1973
1979
  const TagsContainer = ({ items, width = "100%", itemsGap = 5, postFix, disabled }) => {
1980
+ const containerRef = useRef(null);
1974
1981
  const [isReady, setIsReady] = useState(false);
1975
1982
  const [counterWidth, setCounterWidth] = useState(0);
1976
- const containerRef = useRef(null);
1977
- const availableWidth = useRef(undefined);
1978
- const childrenWidth = useRef([]);
1983
+ const [availableSpaceWidth, setAvailableSpaceWidth] = useState(0);
1984
+ const [childrenWidths, setChildrenWidths] = useState([]);
1979
1985
  const itemsCount = items.length;
1980
- useLayoutEffect(() => {
1981
- availableWidth.current = containerRef.current?.offsetWidth || 0;
1982
- }, [containerRef]);
1983
- const onWidthKnownHandler = ({ width: reportedWidth }) => {
1984
- childrenWidth.current.push({ width: reportedWidth + itemsGap });
1985
- if (childrenWidth.current.length === itemsCount) {
1986
- setIsReady(true);
1987
- }
1988
- };
1989
- const requiredSpace = childrenWidth.current.reduce((previous, current) => {
1990
- return previous + current.width;
1991
- }, 0);
1992
- let counter = 0;
1993
- const availableSpace = (availableWidth.current || 0) - counterWidth;
1994
- const renderedElements = items
1995
- .concat({ text: "", onClick: () => null, disabled: false }) // reserved element for a potential counter
1996
- .map((item, index) => {
1997
- const spaceNeeded = childrenWidth.current.slice(0, index + 1).reduce((previous, current) => {
1986
+ const dimensions = useResize();
1987
+ const { width: windowWidth } = useDebounce(dimensions, 100);
1988
+ useEffect(() => {
1989
+ const containerWidth = containerRef.current?.offsetWidth || 0;
1990
+ setAvailableSpaceWidth(containerWidth);
1991
+ }, [windowWidth]);
1992
+ const onWidthKnownHandler = useCallback(({ width: reportedWidth }) => {
1993
+ setChildrenWidths(prev => {
1994
+ const next = [...prev, { width: reportedWidth + itemsGap }];
1995
+ if (next.length === itemsCount) {
1996
+ setIsReady(true);
1997
+ }
1998
+ return next;
1999
+ });
2000
+ }, [itemsCount, itemsGap]);
2001
+ const renderedElements = useMemo(() => {
2002
+ const requiredSpace = childrenWidths.reduce((previous, current) => {
1998
2003
  return previous + current.width;
1999
2004
  }, 0);
2000
- const isLast = index === items.length;
2001
- const counterRequired = requiredSpace > availableSpace && counter !== 0;
2002
- if (isLast && counterRequired) {
2003
- return (jsx(TagWithWidth, { color: "white", disabled: disabled, onWidthKnown: ({ width: reportedWidth }) => setCounterWidth(reportedWidth), children: jsxs("div", { className: cvaSelectCounter(), "data-testid": "select-counter", children: ["+", counter] }) }, item.text + index));
2004
- }
2005
- if (isLast) {
2006
- return null;
2007
- }
2008
- const itemCanFit = spaceNeeded <= availableSpace;
2009
- if (itemCanFit) {
2010
- return (jsx(TagWithWidth, { className: "inline-flex shrink-0", color: item.disabled ? "unknown" : "primary", dataTestId: `${item.text}-tag`, disabled: disabled, onClose: e => {
2011
- e.stopPropagation();
2012
- item.onClick();
2013
- }, onWidthKnown: onWidthKnownHandler, children: item.text }, item.text + index));
2014
- }
2015
- const fromTheItems = item.text !== "";
2016
- if (fromTheItems) {
2017
- counter = counter + 1;
2018
- }
2019
- return null;
2020
- })
2021
- .filter(element => element !== null);
2005
+ const availableSpace = availableSpaceWidth - counterWidth;
2006
+ const { elements } = items
2007
+ .concat({ text: "", onClick: () => null, disabled: false })
2008
+ .reduce((acc, item, index) => {
2009
+ const spaceNeeded = childrenWidths.slice(0, index + 1).reduce((previous, current) => {
2010
+ return previous + current.width;
2011
+ }, 0);
2012
+ const isLast = index === items.length;
2013
+ const counterRequired = requiredSpace > availableSpace && acc.counter !== 0;
2014
+ if (isLast && counterRequired) {
2015
+ return {
2016
+ ...acc,
2017
+ elements: [
2018
+ ...acc.elements,
2019
+ jsx(TagWithWidth, { color: "white", disabled: disabled, onWidthKnown: ({ width: reportedWidth }) => setCounterWidth(reportedWidth), children: jsxs("div", { className: cvaSelectCounter(), "data-testid": "select-counter", children: ["+", acc.counter] }) }, item.text + index),
2020
+ ],
2021
+ };
2022
+ }
2023
+ if (isLast) {
2024
+ return acc;
2025
+ }
2026
+ const itemCanFit = spaceNeeded <= availableSpace;
2027
+ if (itemCanFit) {
2028
+ return {
2029
+ ...acc,
2030
+ elements: [
2031
+ ...acc.elements,
2032
+ jsx(TagWithWidth, { className: "inline-flex shrink-0", color: item.disabled ? "unknown" : "primary", dataTestId: `${item.text}-tag`, disabled: disabled, onClose: e => {
2033
+ e.stopPropagation();
2034
+ item.onClick();
2035
+ }, onWidthKnown: onWidthKnownHandler, children: item.text }, item.text + index),
2036
+ ],
2037
+ };
2038
+ }
2039
+ return {
2040
+ elements: acc.elements,
2041
+ counter: item.text !== "" ? acc.counter + 1 : acc.counter,
2042
+ };
2043
+ }, { elements: [], counter: 0 });
2044
+ return elements;
2045
+ }, [items, availableSpaceWidth, counterWidth, disabled, onWidthKnownHandler, childrenWidths]);
2022
2046
  return (jsxs("div", { className: cvaSelectDynamicTagContainer({ visible: isReady }), ref: containerRef, style: {
2023
2047
  width: `${width}`,
2024
2048
  }, children: [renderedElements, postFix] }));
@@ -2033,15 +2057,13 @@ const TagsContainer = ({ items, width = "100%", itemsGap = 5, postFix, disabled
2033
2057
  * @param {Partial<SelectComponents<Option, IsMulti, Group>> | undefined} componentsProps a custom component prop that you can to override defaults
2034
2058
  * @param {boolean} disabled decide to override disabled variant
2035
2059
  * @param {boolean} menuIsOpen menu is open state
2036
- * @param {RefObject<boolean>} refMenuIsEnabled a flag to block menu from open
2037
2060
  * @param {string} dataTestId a test id
2038
2061
  * @param {number} maxSelectedDisplayCount a number of max display count
2039
- * @param {ReactElement} dropdownIcon an custom dropdown icon
2040
2062
  * @param {boolean} hasError decide to override hasError variant
2041
- * @param {ReactElement} prefix a prefix element
2063
+ * @param {ReactNode} prefix a prefix element
2042
2064
  * @returns {Partial<SelectComponents<Option, boolean, GroupBase<Option>>> | undefined} components object to override react-select default components
2043
2065
  */
2044
- const useCustomComponents = ({ componentsProps, disabled, readOnly, refMenuIsEnabled, dataTestId, maxSelectedDisplayCount, dropdownIcon, prefix, hasError, fieldSize, getOptionLabelDescription, }) => {
2066
+ const useCustomComponents = ({ componentsProps, disabled, readOnly, setMenuIsEnabled, dataTestId, maxSelectedDisplayCount, prefix, hasError, fieldSize, getOptionLabelDescription, }) => {
2045
2067
  const [t] = useTranslation();
2046
2068
  // perhaps it should not be wrap in memo (causing some issues with opening and closing on mobiles)
2047
2069
  const customComponents = useMemo(() => {
@@ -2063,7 +2085,7 @@ const useCustomComponents = ({ componentsProps, disabled, readOnly, refMenuIsEna
2063
2085
  onClick: disabled
2064
2086
  ? undefined
2065
2087
  : (e) => {
2066
- refMenuIsEnabled.current = false;
2088
+ setMenuIsEnabled(false);
2067
2089
  tagProps.removeProps.onClick && tagProps.removeProps.onClick(e);
2068
2090
  },
2069
2091
  disabled: disabled,
@@ -2073,7 +2095,7 @@ const useCustomComponents = ({ componentsProps, disabled, readOnly, refMenuIsEna
2073
2095
  ? tags.slice(0, maxSelectedDisplayCount).map(({ props: tagProps }) => {
2074
2096
  return (jsx(Tag, { className: "inline-flex shrink-0", color: disabled ? "unknown" : "primary", dataTestId: tagProps.children ? `${tagProps.children.toString()}-tag` : undefined, onClose: e => {
2075
2097
  e.stopPropagation();
2076
- refMenuIsEnabled.current = false;
2098
+ setMenuIsEnabled(false);
2077
2099
  tagProps.removeProps.onClick && tagProps.removeProps.onClick(e);
2078
2100
  }, children: tagProps.children }, tagProps.children?.toString()));
2079
2101
  })
@@ -2086,7 +2108,7 @@ const useCustomComponents = ({ componentsProps, disabled, readOnly, refMenuIsEna
2086
2108
  },
2087
2109
  DropdownIndicator: props => {
2088
2110
  const icon = props.selectProps.menuIsOpen ? (jsx(Icon, { name: "ChevronUp", size: "medium" })) : (jsx(Icon, { name: "ChevronDown", size: "medium" }));
2089
- return props.selectProps.isLoading || props.selectProps.isDisabled || readOnly ? null : (jsx(components.DropdownIndicator, { ...props, children: jsx("div", { className: cvaSelectIcon(), children: dropdownIcon ?? icon }) }));
2111
+ return props.selectProps.isLoading || props.selectProps.isDisabled || readOnly ? null : (jsx(components.DropdownIndicator, { ...props, children: jsx("div", { className: cvaSelectIcon(), children: icon }) }));
2090
2112
  },
2091
2113
  IndicatorSeparator: () => null,
2092
2114
  ClearIndicator: props => {
@@ -2145,22 +2167,32 @@ const useCustomComponents = ({ componentsProps, disabled, readOnly, refMenuIsEna
2145
2167
  },
2146
2168
  ...componentsProps,
2147
2169
  };
2148
- // eslint-disable-next-line react-hooks/exhaustive-deps
2149
- }, [componentsProps, disabled, maxSelectedDisplayCount, readOnly]); // do not add dropdownIcon (it will cause issue with opening/closing list for selects with custom icon)
2170
+ }, [
2171
+ componentsProps,
2172
+ disabled,
2173
+ fieldSize,
2174
+ getOptionLabelDescription,
2175
+ hasError,
2176
+ maxSelectedDisplayCount,
2177
+ prefix,
2178
+ readOnly,
2179
+ setMenuIsEnabled,
2180
+ t,
2181
+ dataTestId,
2182
+ ]);
2150
2183
  return customComponents;
2151
2184
  };
2152
2185
 
2153
2186
  /**
2154
2187
  * @template IsMulti
2155
2188
  * @template Group
2156
- * @param {React.RefObject<HTMLDivElement>} refContainer react ref to container element
2157
- * @param {React.RefObject<HTMLDivElement>} refPrefix react ref to prefix element
2189
+ * @param {RefObject<HTMLDivElement | null>} refContainer react ref to container element
2158
2190
  * @param {number | undefined} maxSelectedDisplayCount a number of max display count
2159
2191
  * @param {StylesConfig<Option, IsMulti, Group> | undefined} styles a optional object to override styles of react-select
2160
2192
  * @returns {StylesConfig<Option, boolean>} styles to override in select
2161
2193
  */
2162
- const useCustomStyles = ({ refContainer, refPrefix, maxSelectedDisplayCount, styles, disabled, fieldSize, }) => {
2163
- const customStyles = React.useMemo(() => {
2194
+ const useCustomStyles = ({ refContainer, maxSelectedDisplayCount, styles, disabled, fieldSize, }) => {
2195
+ const customStyles = useMemo(() => {
2164
2196
  return {
2165
2197
  control: base => {
2166
2198
  return {
@@ -2249,8 +2281,7 @@ const useCustomStyles = ({ refContainer, refPrefix, maxSelectedDisplayCount, sty
2249
2281
  },
2250
2282
  ...styles,
2251
2283
  };
2252
- // eslint-disable-next-line react-hooks/exhaustive-deps
2253
- }, [refContainer, refPrefix, disabled]);
2284
+ }, [refContainer, disabled, fieldSize, maxSelectedDisplayCount, styles]);
2254
2285
  return { customStyles };
2255
2286
  };
2256
2287
 
@@ -2260,27 +2291,24 @@ const useCustomStyles = ({ refContainer, refPrefix, maxSelectedDisplayCount, sty
2260
2291
  * @param {SelectProps} props - The props for the Select component
2261
2292
  * @returns {UseSelectProps} Select component
2262
2293
  */
2263
- const useSelect = ({ id, className, dataTestId = "select", prefix, async, dropdownIcon, maxMenuHeight = 200, label, hasError, disabled, isMulti, components, value, options, onChange, isLoading, classNamePrefix = "", onMenuOpen, onMenuClose, maxSelectedDisplayCount = undefined, isClearable = false, isSearchable = true, onMenuScrollToBottom, styles, filterOption, onInputChange, getOptionLabelDescription, fieldSize = "medium", ...props }) => {
2294
+ const useSelect = ({ id, className, dataTestId = "select", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, components, value, options, onChange, isLoading, classNamePrefix = "", onMenuOpen, onMenuClose, maxSelectedDisplayCount = undefined, isClearable = false, isSearchable = true, onMenuScrollToBottom, styles, filterOption, onInputChange, getOptionLabelDescription, fieldSize = "medium", ...props }) => {
2264
2295
  const refContainer = useRef(document.createElement("div"));
2265
- const refPrefix = useRef(document.createElement("div"));
2266
2296
  const { customStyles } = useCustomStyles({
2267
2297
  refContainer,
2268
- refPrefix,
2269
2298
  maxSelectedDisplayCount,
2270
2299
  styles,
2271
2300
  disabled: Boolean(disabled),
2272
2301
  fieldSize,
2273
2302
  });
2274
2303
  const [menuIsOpen, setMenuIsOpen] = useState(props.menuIsOpen ?? false);
2275
- const refMenuIsEnabled = useRef(true);
2304
+ const [menuIsEnabled, setMenuIsEnabled] = useState(true);
2276
2305
  const customComponents = useCustomComponents({
2277
2306
  componentsProps: components,
2278
2307
  disabled: Boolean(disabled),
2279
2308
  readOnly: Boolean(props.readOnly),
2280
- refMenuIsEnabled,
2309
+ setMenuIsEnabled,
2281
2310
  dataTestId,
2282
2311
  maxSelectedDisplayCount,
2283
- dropdownIcon,
2284
2312
  prefix,
2285
2313
  hasError,
2286
2314
  fieldSize,
@@ -2289,11 +2317,11 @@ const useSelect = ({ id, className, dataTestId = "select", prefix, async, dropdo
2289
2317
  const menuPlacement = "auto";
2290
2318
  const openMenuHandler = async () => {
2291
2319
  onMenuOpen?.();
2292
- if (refMenuIsEnabled.current) {
2320
+ if (menuIsEnabled) {
2293
2321
  setMenuIsOpen(true);
2294
2322
  }
2295
2323
  else {
2296
- refMenuIsEnabled.current = true;
2324
+ setMenuIsEnabled(true);
2297
2325
  }
2298
2326
  };
2299
2327
  const closeMenuHandler = () => {
@@ -2302,7 +2330,6 @@ const useSelect = ({ id, className, dataTestId = "select", prefix, async, dropdo
2302
2330
  };
2303
2331
  return {
2304
2332
  refContainer,
2305
- refPrefix,
2306
2333
  customStyles,
2307
2334
  menuIsOpen,
2308
2335
  customComponents,
@@ -2320,7 +2347,7 @@ const useSelect = ({ id, className, dataTestId = "select", prefix, async, dropdo
2320
2347
  */
2321
2348
  const CreatableSelect = (props) => {
2322
2349
  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;
2323
- const { refContainer, refPrefix, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler, } = useSelect(props);
2350
+ const { refContainer, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler } = useSelect(props);
2324
2351
  const reactCreatableSelectProps = useMemo(() => ({
2325
2352
  value,
2326
2353
  menuPlacement,
@@ -2377,7 +2404,7 @@ const CreatableSelect = (props) => {
2377
2404
  value,
2378
2405
  ]);
2379
2406
  const renderAsDisabled = Boolean(props.disabled) || props.readOnly;
2380
- return (jsxs("div", { className: cvaSelect({ invalid: hasError, disabled: renderAsDisabled, className: props.className }), "data-testid": dataTestId, ref: refContainer, children: [prefix !== undefined ? (jsx("div", { className: cvaSelectPrefixSuffix({ kind: "prefix" }), "data-testid": dataTestId ? `${dataTestId}-prefix` : null, ref: refPrefix, children: prefix })) : null, async ? (jsx(ReactAsyncCreatableSelect, { ...props, ...reactCreatableSelectProps, ...async, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, placeholder: renderAsDisabled ? null : props.placeholder })) : (jsx(ReactCreatableSelect, { ...props, ...reactCreatableSelectProps, hideSelectedOptions: false, isMulti: isMulti, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, options: options, placeholder: renderAsDisabled ? null : props.placeholder })), typeof props.disabled === "object" ? (jsx("div", { className: cvaSelectPrefixSuffix({ kind: "suffix" }), "data-testid": dataTestId ? `${dataTestId}-locked` : null, children: jsx(InputLockReasonTooltip, { ...props.disabled }) })) : null] }));
2407
+ return (jsxs("div", { className: cvaSelect({ invalid: hasError, disabled: renderAsDisabled, className: props.className }), "data-testid": dataTestId, ref: refContainer, children: [prefix !== undefined ? (jsx("div", { className: cvaSelectPrefixSuffix({ kind: "prefix" }), "data-testid": dataTestId ? `${dataTestId}-prefix` : null, children: prefix })) : null, async ? (jsx(ReactAsyncCreatableSelect, { ...props, ...reactCreatableSelectProps, ...async, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, placeholder: renderAsDisabled ? null : props.placeholder })) : (jsx(ReactCreatableSelect, { ...props, ...reactCreatableSelectProps, hideSelectedOptions: false, isMulti: isMulti, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, options: options, placeholder: renderAsDisabled ? null : props.placeholder })), typeof props.disabled === "object" ? (jsx("div", { className: cvaSelectPrefixSuffix({ kind: "suffix" }), "data-testid": dataTestId ? `${dataTestId}-locked` : null, children: jsx(InputLockReasonTooltip, { ...props.disabled }) })) : null] }));
2381
2408
  };
2382
2409
  CreatableSelect.displayName = "CreatableSelect";
2383
2410
 
@@ -2392,7 +2419,7 @@ const ReactSyncSelect = ReactSelect.default || ReactSelect;
2392
2419
  */
2393
2420
  const Select = (props) => {
2394
2421
  const { id, dataTestId = "select", prefix, async, maxMenuHeight = 200, label, hasError, disabled, isMulti, menuPosition = "absolute", value, options, onChange, isLoading, classNamePrefix = "select", onMenuScrollToBottom, onInputChange, isSearchable, isClearable = false, readOnly, fieldSize = "medium", openMenuOnClick = !disabled, openMenuOnFocus = !disabled, hideSelectedOptions = false, } = props;
2395
- const { refContainer, refPrefix, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler, } = useSelect(props);
2422
+ const { refContainer, customStyles, menuIsOpen, customComponents, menuPlacement, openMenuHandler, closeMenuHandler } = useSelect(props);
2396
2423
  const reactSelectProps = useMemo(() => ({
2397
2424
  value,
2398
2425
  menuPlacement,
@@ -2455,7 +2482,7 @@ const Select = (props) => {
2455
2482
  fieldSize: fieldSize,
2456
2483
  disabled: renderAsDisabled,
2457
2484
  className: props.className,
2458
- }), "data-testid": dataTestId, ref: refContainer, children: [prefix !== undefined ? (jsx("div", { className: cvaSelectPrefixSuffix({ kind: "prefix" }), "data-testid": dataTestId ? `${dataTestId}-prefix` : null, ref: refPrefix, children: prefix })) : null, async ? (jsx(ReactAsyncSelect, { ...props, ...reactSelectProps, ...async, menuPosition: menuPosition, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, placeholder: renderAsDisabled ? null : props.placeholder })) : (jsx(ReactSyncSelect, { ...props, ...reactSelectProps, isMulti: isMulti, menuPosition: menuPosition, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, options: options, placeholder: renderAsDisabled ? null : props.placeholder })), typeof props.disabled === "object" ? (jsx("div", { className: cvaSelectPrefixSuffix({ kind: "suffix" }), "data-testid": dataTestId ? `${dataTestId}-locked` : null, children: jsx(InputLockReasonTooltip, { ...props.disabled }) })) : null] }));
2485
+ }), "data-testid": dataTestId, ref: refContainer, children: [prefix !== undefined ? (jsx("div", { className: cvaSelectPrefixSuffix({ kind: "prefix" }), "data-testid": dataTestId ? `${dataTestId}-prefix` : null, children: prefix })) : null, async ? (jsx(ReactAsyncSelect, { ...props, ...reactSelectProps, ...async, menuPosition: menuPosition, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, placeholder: renderAsDisabled ? null : props.placeholder })) : (jsx(ReactSyncSelect, { ...props, ...reactSelectProps, isMulti: isMulti, menuPosition: menuPosition, onMenuClose: closeMenuHandler, onMenuOpen: openMenuHandler, options: options, placeholder: renderAsDisabled ? null : props.placeholder })), typeof props.disabled === "object" ? (jsx("div", { className: cvaSelectPrefixSuffix({ kind: "suffix" }), "data-testid": dataTestId ? `${dataTestId}-locked` : null, children: jsx(InputLockReasonTooltip, { ...props.disabled }) })) : null] }));
2459
2486
  };
2460
2487
  Select.displayName = "Select";
2461
2488
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/react-form-components",
3
- "version": "1.3.65",
3
+ "version": "1.3.66",
4
4
  "repository": "https://github.com/Trackunit/manager",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "engines": {
@@ -17,12 +17,12 @@
17
17
  "zod": "3.22.4",
18
18
  "react-hook-form": "7.53.1",
19
19
  "tailwind-merge": "^2.0.0",
20
- "@trackunit/css-class-variance-utilities": "1.3.46",
21
- "@trackunit/react-components": "1.4.56",
22
- "@trackunit/ui-icons": "1.3.46",
23
- "@trackunit/shared-utils": "1.5.46",
24
- "@trackunit/ui-design-tokens": "1.3.46",
25
- "@trackunit/i18n-library-translation": "1.3.51",
20
+ "@trackunit/css-class-variance-utilities": "1.3.47",
21
+ "@trackunit/react-components": "1.4.57",
22
+ "@trackunit/ui-icons": "1.3.47",
23
+ "@trackunit/shared-utils": "1.5.47",
24
+ "@trackunit/ui-design-tokens": "1.3.47",
25
+ "@trackunit/i18n-library-translation": "1.3.52",
26
26
  "string-ts": "^2.0.0"
27
27
  },
28
28
  "module": "./index.esm.js",
@@ -1,4 +1,4 @@
1
- import { ReactNode, RefObject } from "react";
1
+ import { ReactNode } from "react";
2
2
  import { GroupBase } from "react-select";
3
3
  import { SelectComponents } from "react-select/dist/declarations/src/components";
4
4
  import { FormComponentSizes } from "../../types";
@@ -11,22 +11,19 @@ import { FormComponentSizes } from "../../types";
11
11
  * @param {Partial<SelectComponents<Option, IsMulti, Group>> | undefined} componentsProps a custom component prop that you can to override defaults
12
12
  * @param {boolean} disabled decide to override disabled variant
13
13
  * @param {boolean} menuIsOpen menu is open state
14
- * @param {RefObject<boolean>} refMenuIsEnabled a flag to block menu from open
15
14
  * @param {string} dataTestId a test id
16
15
  * @param {number} maxSelectedDisplayCount a number of max display count
17
- * @param {ReactElement} dropdownIcon an custom dropdown icon
18
16
  * @param {boolean} hasError decide to override hasError variant
19
- * @param {ReactElement} prefix a prefix element
17
+ * @param {ReactNode} prefix a prefix element
20
18
  * @returns {Partial<SelectComponents<Option, boolean, GroupBase<Option>>> | undefined} components object to override react-select default components
21
19
  */
22
- export declare const useCustomComponents: <Option, IsMulti extends boolean = false, Group extends GroupBase<Option> = GroupBase<Option>>({ componentsProps, disabled, readOnly, refMenuIsEnabled, dataTestId, maxSelectedDisplayCount, dropdownIcon, prefix, hasError, fieldSize, getOptionLabelDescription, }: {
20
+ export declare const useCustomComponents: <Option, IsMulti extends boolean = false, Group extends GroupBase<Option> = GroupBase<Option>>({ componentsProps, disabled, readOnly, setMenuIsEnabled, dataTestId, maxSelectedDisplayCount, prefix, hasError, fieldSize, getOptionLabelDescription, }: {
23
21
  componentsProps: Partial<SelectComponents<Option, IsMulti, Group>> | undefined;
24
22
  disabled: boolean;
25
23
  readOnly: boolean;
26
- refMenuIsEnabled: RefObject<boolean>;
24
+ setMenuIsEnabled: (menuIsEnabled: boolean) => void;
27
25
  dataTestId: string;
28
26
  maxSelectedDisplayCount: number | undefined;
29
- dropdownIcon?: ReactNode;
30
27
  prefix?: ReactNode;
31
28
  hasError?: boolean;
32
29
  fieldSize?: FormComponentSizes;
@@ -4,15 +4,13 @@ import { FormComponentSizes } from "../../types";
4
4
  /**
5
5
  * @template IsMulti
6
6
  * @template Group
7
- * @param {React.RefObject<HTMLDivElement>} refContainer react ref to container element
8
- * @param {React.RefObject<HTMLDivElement>} refPrefix react ref to prefix element
7
+ * @param {RefObject<HTMLDivElement | null>} refContainer react ref to container element
9
8
  * @param {number | undefined} maxSelectedDisplayCount a number of max display count
10
9
  * @param {StylesConfig<Option, IsMulti, Group> | undefined} styles a optional object to override styles of react-select
11
10
  * @returns {StylesConfig<Option, boolean>} styles to override in select
12
11
  */
13
- export declare const useCustomStyles: <Option, IsMulti extends boolean = false, Group extends GroupBase<Option> = GroupBase<Option>>({ refContainer, refPrefix, maxSelectedDisplayCount, styles, disabled, fieldSize, }: {
12
+ export declare const useCustomStyles: <Option, IsMulti extends boolean = false, Group extends GroupBase<Option> = GroupBase<Option>>({ refContainer, maxSelectedDisplayCount, styles, disabled, fieldSize, }: {
14
13
  refContainer: RefObject<HTMLDivElement | null>;
15
- refPrefix: RefObject<HTMLDivElement | null>;
16
14
  maxSelectedDisplayCount: number | undefined;
17
15
  styles: StylesConfig<Option, IsMulti, Group> | undefined;
18
16
  disabled: boolean | undefined;
@@ -50,13 +50,6 @@ export type SelectProps<Option, IsAsync extends boolean, IsMulti extends boolean
50
50
  * @memberof SelectProps
51
51
  */
52
52
  async?: AsyncSelect<Option, GroupType>;
53
- /**
54
- * A custom icon to be used as a dropdown indicator
55
- * This is typically used during style customization
56
- *
57
- * @memberof SelectProps
58
- */
59
- dropdownIcon?: ReactNode;
60
53
  /**
61
54
  * A label to be used as a aria-label
62
55
  * This is typically used for accessibility
@@ -140,7 +133,6 @@ interface UseSelectProps<Option, IsMulti extends boolean = false, Group extends
140
133
  customStyles: StylesConfig<Option, IsMulti, Group>;
141
134
  customComponents: Partial<SelectComponents<Option, IsMulti, Group>>;
142
135
  refContainer: React.RefObject<HTMLDivElement>;
143
- refPrefix: React.RefObject<HTMLDivElement>;
144
136
  menuIsOpen: boolean;
145
137
  menuPlacement: MenuPlacement;
146
138
  openMenuHandler: () => Promise<void>;
@@ -152,5 +144,5 @@ interface UseSelectProps<Option, IsMulti extends boolean = false, Group extends
152
144
  * @param {SelectProps} props - The props for the Select component
153
145
  * @returns {UseSelectProps} Select component
154
146
  */
155
- export declare const useSelect: <Option, IsAsync extends boolean = false, IsMulti extends boolean = false, Group extends GroupBase<Option> = GroupBase<Option>>({ id, className, dataTestId, prefix, async, dropdownIcon, maxMenuHeight, label, hasError, disabled, isMulti, components, value, options, onChange, isLoading, classNamePrefix, onMenuOpen, onMenuClose, maxSelectedDisplayCount, isClearable, isSearchable, onMenuScrollToBottom, styles, filterOption, onInputChange, getOptionLabelDescription, fieldSize, ...props }: SelectProps<Option, IsAsync, IsMulti, Group>) => UseSelectProps<Option, IsMulti, Group>;
147
+ export declare const useSelect: <Option, IsAsync extends boolean = false, IsMulti extends boolean = false, Group extends GroupBase<Option> = GroupBase<Option>>({ id, className, dataTestId, prefix, async, maxMenuHeight, label, hasError, disabled, isMulti, components, value, options, onChange, isLoading, classNamePrefix, onMenuOpen, onMenuClose, maxSelectedDisplayCount, isClearable, isSearchable, onMenuScrollToBottom, styles, filterOption, onInputChange, getOptionLabelDescription, fieldSize, ...props }: SelectProps<Option, IsAsync, IsMulti, Group>) => UseSelectProps<Option, IsMulti, Group>;
156
148
  export {};