@trackunit/react-form-components 1.3.64 → 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
|
|
1996
|
-
const
|
|
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
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
.
|
|
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
|
|
2020
|
-
const
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
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 {
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
2168
|
-
|
|
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 {
|
|
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,
|
|
2182
|
-
const customStyles =
|
|
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
|
-
|
|
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,
|
|
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
|
|
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
|
-
|
|
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 (
|
|
2339
|
+
if (menuIsEnabled) {
|
|
2312
2340
|
setMenuIsOpen(true);
|
|
2313
2341
|
}
|
|
2314
2342
|
else {
|
|
2315
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
1977
|
-
const
|
|
1978
|
-
const childrenWidth = useRef([]);
|
|
1983
|
+
const [availableSpaceWidth, setAvailableSpaceWidth] = useState(0);
|
|
1984
|
+
const [childrenWidths, setChildrenWidths] = useState([]);
|
|
1979
1985
|
const itemsCount = items.length;
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
.
|
|
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
|
|
2001
|
-
const
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
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 {
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
2149
|
-
|
|
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 {
|
|
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,
|
|
2163
|
-
const customStyles =
|
|
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
|
-
|
|
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,
|
|
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
|
|
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
|
-
|
|
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 (
|
|
2320
|
+
if (menuIsEnabled) {
|
|
2293
2321
|
setMenuIsOpen(true);
|
|
2294
2322
|
}
|
|
2295
2323
|
else {
|
|
2296
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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.
|
|
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.
|
|
21
|
-
"@trackunit/react-components": "1.4.
|
|
22
|
-
"@trackunit/ui-icons": "1.3.
|
|
23
|
-
"@trackunit/shared-utils": "1.5.
|
|
24
|
-
"@trackunit/ui-design-tokens": "1.3.
|
|
25
|
-
"@trackunit/i18n-library-translation": "1.3.
|
|
20
|
+
"@trackunit/css-class-variance-utilities": "1.3.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
|
|
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 {
|
|
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,
|
|
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
|
-
|
|
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 {
|
|
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,
|
|
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,
|
|
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 {};
|