infinity-ui-elements 1.8.2 → 1.8.4
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/dist/components/Dropdown/DropdownMenu.d.ts +3 -2
- package/dist/components/Dropdown/DropdownMenu.d.ts.map +1 -1
- package/dist/components/Modal/Modal.d.ts +1 -1
- package/dist/components/Modal/Modal.d.ts.map +1 -1
- package/dist/components/SearchableDropdown/SearchableDropdown.d.ts +4 -1
- package/dist/components/SearchableDropdown/SearchableDropdown.d.ts.map +1 -1
- package/dist/components/SearchableDropdown/SearchableDropdown.stories.d.ts +6 -0
- package/dist/components/SearchableDropdown/SearchableDropdown.stories.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.esm.js +52 -15
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +51 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1889,10 +1889,10 @@ const DropdownMenu = React__namespace.forwardRef(({ items = [], customContent, s
|
|
|
1889
1889
|
if (isEmpty || items.length === 0) {
|
|
1890
1890
|
return (jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-8 px-6 text-center", children: [emptyIcon || (jsxRuntime.jsx(lucideReact.Search, { className: "w-12 h-12 text-surface-ink-neutral-muted mb-4" })), jsxRuntime.jsx(Text, { as: "h3", variant: "body", size: "small", weight: "semibold", className: "text-surface-ink-neutral-normal mb-2", children: emptyTitle }), jsxRuntime.jsx(Text, { as: "p", variant: "body", size: "small", weight: "regular", className: "text-surface-ink-neutral-muted mb-3", children: emptyDescription }), emptyLinkText && (jsxRuntime.jsx(Link, { type: "anchor", color: "primary", size: "small", onClick: onEmptyLinkClick, children: emptyLinkText }))] }));
|
|
1891
1891
|
}
|
|
1892
|
-
return (jsxRuntime.jsxs("div", { className: "py-3 px-3 max-h-[400px] overflow-y-auto", children: [sectionHeading && (jsxRuntime.jsx(Text, { as: "div", variant: "body", size: "small", weight: "medium", className: "text-surface-ink-neutral-muted px-3 py-2 mb-1", children: sectionHeading })), jsxRuntime.jsx("div", { className: "flex flex-col gap-1", children: items.map((item, index) => (jsxRuntime.jsx(ListItem, { title: item.
|
|
1892
|
+
return (jsxRuntime.jsxs("div", { className: "py-3 px-3 max-h-[400px] overflow-y-auto", children: [sectionHeading && (jsxRuntime.jsx(Text, { as: "div", variant: "body", size: "small", weight: "medium", className: "text-surface-ink-neutral-muted px-3 py-2 mb-1", children: sectionHeading })), jsxRuntime.jsx("div", { className: "flex flex-col gap-1", children: items.map((item, index) => (jsxRuntime.jsx(ListItem, { title: item.label, description: item.description, leadingIcon: item.leadingIcon, trailingIcon: item.trailingIcon, showChevron: showChevron, isDisabled: item.isDisabled, isSelected: index === focusedIndex, variant: item.variant, onClick: () => {
|
|
1893
1893
|
item.onClick?.();
|
|
1894
1894
|
onClose?.();
|
|
1895
|
-
}, containerClassName: cn(index === focusedIndex && "bg-action-fill-primary-faded") }, item.
|
|
1895
|
+
}, containerClassName: cn(index === focusedIndex && "bg-action-fill-primary-faded") }, item.value))) })] }));
|
|
1896
1896
|
};
|
|
1897
1897
|
const widthClass = width === "full" ? "w-full" : width === "auto" ? "w-auto" : "";
|
|
1898
1898
|
const footerVisible = showFooter ?? !disableFooter;
|
|
@@ -2234,7 +2234,7 @@ const Modal = React__namespace.forwardRef(({ isOpen, onClose, title, description
|
|
|
2234
2234
|
};
|
|
2235
2235
|
// Handle escape key
|
|
2236
2236
|
React__namespace.useEffect(() => {
|
|
2237
|
-
if (!isOpen || !closeOnEscape)
|
|
2237
|
+
if (!isOpen || !closeOnEscape || !onClose)
|
|
2238
2238
|
return;
|
|
2239
2239
|
const handleEscape = (e) => {
|
|
2240
2240
|
if (e.key === "Escape") {
|
|
@@ -2258,7 +2258,7 @@ const Modal = React__namespace.forwardRef(({ isOpen, onClose, title, description
|
|
|
2258
2258
|
}, [isOpen]);
|
|
2259
2259
|
// Handle overlay click
|
|
2260
2260
|
const handleOverlayClick = (e) => {
|
|
2261
|
-
if (closeOnOverlayClick && e.target === e.currentTarget) {
|
|
2261
|
+
if (closeOnOverlayClick && e.target === e.currentTarget && onClose) {
|
|
2262
2262
|
onClose();
|
|
2263
2263
|
}
|
|
2264
2264
|
};
|
|
@@ -2266,7 +2266,7 @@ const Modal = React__namespace.forwardRef(({ isOpen, onClose, title, description
|
|
|
2266
2266
|
if (!isOpen)
|
|
2267
2267
|
return null;
|
|
2268
2268
|
const hasHeader = title || description;
|
|
2269
|
-
return (jsxRuntime.jsxs("div", { className: cn("fixed inset-0 z-50 flex items-center justify-center p-4", className), role: "dialog", "aria-modal": "true", "aria-label": ariaLabel || title, "aria-describedby": ariaDescribedBy, children: [jsxRuntime.jsx("div", { className: cn("absolute inset-0 bg-black/50 backdrop-blur-sm transition-opacity", overlayClassName), onClick: handleOverlayClick, "aria-hidden": "true" }), jsxRuntime.jsxs("div", { ref: contentRef, className: cn("relative w-full bg-white rounded-large shadow-xl transition-all", "flex flex-col max-h-[90vh]", sizeConfig[size], contentClassName), children: [hasHeader && (jsxRuntime.jsxs("div", { className: cn("flex items-start justify-between gap-4 px-6 pt-6", !description && "pb-4", description && "pb-2", headerClassName), children: [jsxRuntime.jsxs("div", { className: "flex-1", children: [title && (jsxRuntime.jsx(Text, { as: "h2", variant: "body", size: "large", weight: "semibold", color: "default", children: title })), description && (jsxRuntime.jsx(Text, { as: "p", variant: "body", size: "small", weight: "regular", color: "subtle", className: "mt-1", children: description }))] }), showCloseButton && (jsxRuntime.jsx(
|
|
2269
|
+
return (jsxRuntime.jsxs("div", { className: cn("fixed inset-0 z-50 flex items-center justify-center p-4", className), role: "dialog", "aria-modal": "true", "aria-label": ariaLabel || title, "aria-describedby": ariaDescribedBy, children: [jsxRuntime.jsx("div", { className: cn("absolute inset-0 bg-black/50 backdrop-blur-sm transition-opacity", overlayClassName), onClick: handleOverlayClick, "aria-hidden": "true" }), jsxRuntime.jsxs("div", { ref: contentRef, className: cn("relative w-full bg-white rounded-large shadow-xl transition-all", "flex flex-col max-h-[90vh]", sizeConfig[size], contentClassName), children: [hasHeader && (jsxRuntime.jsxs("div", { className: cn("flex items-start justify-between gap-4 px-6 pt-6", !description && "pb-4", description && "pb-2", headerClassName), children: [jsxRuntime.jsxs("div", { className: "flex-1", children: [title && (jsxRuntime.jsx(Text, { as: "h2", variant: "body", size: "large", weight: "semibold", color: "default", children: title })), description && (jsxRuntime.jsx(Text, { as: "p", variant: "body", size: "small", weight: "regular", color: "subtle", className: "mt-1", children: description }))] }), showCloseButton && onClose && (jsxRuntime.jsx(IconButton, { icon: "close", onClick: onClose, color: "neutral", size: "small", "aria-label": "Close modal", className: "shrink-0" }))] })), !hasHeader && showCloseButton && onClose && (jsxRuntime.jsx("div", { className: "absolute top-4 right-4 z-10", children: jsxRuntime.jsx(IconButton, { icon: "close", onClick: onClose, color: "neutral", size: "small", "aria-label": "Close modal" }) })), jsxRuntime.jsx("div", { className: cn("flex-1 overflow-y-auto px-6", hasHeader ? "py-4" : "pt-6 pb-4", !footer && "pb-6", bodyClassName), children: children }), footer && (jsxRuntime.jsxs("div", { className: "flex flex-col", children: [jsxRuntime.jsx(Divider, { thickness: "thin", variant: "muted" }), jsxRuntime.jsx("div", { className: cn("flex items-center justify-end gap-3 px-6 py-4", footerClassName), children: footer })] }))] })] }));
|
|
2270
2270
|
});
|
|
2271
2271
|
Modal.displayName = "Modal";
|
|
2272
2272
|
|
|
@@ -2906,10 +2906,10 @@ TextField.displayName = "TextField";
|
|
|
2906
2906
|
|
|
2907
2907
|
const defaultFilter = (item, query) => {
|
|
2908
2908
|
const searchQuery = query.toLowerCase();
|
|
2909
|
-
return (item.
|
|
2909
|
+
return (item.label.toLowerCase().includes(searchQuery) ||
|
|
2910
2910
|
(item.description?.toLowerCase().includes(searchQuery) ?? false));
|
|
2911
2911
|
};
|
|
2912
|
-
const SearchableDropdown = React__namespace.forwardRef(({ className, items = [], sectionHeading, isLoading = false, emptyTitle = "No Search Results Found", emptyDescription = "Add description of what the user can search for here.", emptyLinkText = "Link to support site", onEmptyLinkClick, primaryButtonText
|
|
2912
|
+
const SearchableDropdown = React__namespace.forwardRef(({ className, items = [], sectionHeading, isLoading = false, emptyTitle = "No Search Results Found", emptyDescription = "Add description of what the user can search for here.", emptyLinkText = "Link to support site", onEmptyLinkClick, primaryButtonText, secondaryButtonText, onPrimaryClick, onSecondaryClick, dropdownWidth = "full", showChevron = false, emptyIcon, disableFooter = false, footerLayout = "horizontal", onSearchChange, onItemSelect, filterFunction = defaultFilter, searchValue: controlledSearchValue, defaultSearchValue = "", dropdownClassName, minSearchLength = 0, showOnFocus = true, showAddNew = false, containerClassName, ...textFieldProps }, ref) => {
|
|
2913
2913
|
const [uncontrolledSearchValue, setUncontrolledSearchValue] = React__namespace.useState(defaultSearchValue);
|
|
2914
2914
|
const [isOpen, setIsOpen] = React__namespace.useState(false);
|
|
2915
2915
|
const [focusedIndex, setFocusedIndex] = React__namespace.useState(-1);
|
|
@@ -2958,7 +2958,7 @@ const SearchableDropdown = React__namespace.forwardRef(({ className, items = [],
|
|
|
2958
2958
|
const handleItemSelect = (item) => {
|
|
2959
2959
|
onItemSelect?.(item);
|
|
2960
2960
|
if (controlledSearchValue === undefined) {
|
|
2961
|
-
setUncontrolledSearchValue(item.
|
|
2961
|
+
setUncontrolledSearchValue(item.label);
|
|
2962
2962
|
}
|
|
2963
2963
|
setIsOpen(false);
|
|
2964
2964
|
inputRef.current?.focus();
|
|
@@ -2969,6 +2969,40 @@ const SearchableDropdown = React__namespace.forwardRef(({ className, items = [],
|
|
|
2969
2969
|
return items;
|
|
2970
2970
|
return items.filter((item) => filterFunction(item, searchValue));
|
|
2971
2971
|
}, [items, searchValue, filterFunction]);
|
|
2972
|
+
// Add "Add New" option if showAddNew is true and no items match
|
|
2973
|
+
const itemsWithAddNew = React__namespace.useMemo(() => {
|
|
2974
|
+
if (!showAddNew || !searchValue || filteredItems.length > 0) {
|
|
2975
|
+
return filteredItems;
|
|
2976
|
+
}
|
|
2977
|
+
const addNewItem = {
|
|
2978
|
+
value: searchValue,
|
|
2979
|
+
label: `+ Add ${searchValue}`,
|
|
2980
|
+
variant: "primary",
|
|
2981
|
+
onClick: () => {
|
|
2982
|
+
const newItem = {
|
|
2983
|
+
value: searchValue,
|
|
2984
|
+
label: searchValue,
|
|
2985
|
+
};
|
|
2986
|
+
onItemSelect?.(newItem);
|
|
2987
|
+
if (controlledSearchValue === undefined) {
|
|
2988
|
+
setUncontrolledSearchValue(searchValue);
|
|
2989
|
+
}
|
|
2990
|
+
setIsOpen(false);
|
|
2991
|
+
inputRef.current?.focus();
|
|
2992
|
+
},
|
|
2993
|
+
};
|
|
2994
|
+
return [addNewItem];
|
|
2995
|
+
}, [
|
|
2996
|
+
showAddNew,
|
|
2997
|
+
searchValue,
|
|
2998
|
+
filteredItems,
|
|
2999
|
+
onItemSelect,
|
|
3000
|
+
controlledSearchValue,
|
|
3001
|
+
]);
|
|
3002
|
+
// Reset focused index when items change
|
|
3003
|
+
React__namespace.useEffect(() => {
|
|
3004
|
+
setFocusedIndex(-1);
|
|
3005
|
+
}, [itemsWithAddNew.length]);
|
|
2972
3006
|
// Close dropdown when clicking outside
|
|
2973
3007
|
React__namespace.useEffect(() => {
|
|
2974
3008
|
const handleClickOutside = (event) => {
|
|
@@ -2998,7 +3032,7 @@ const SearchableDropdown = React__namespace.forwardRef(({ className, items = [],
|
|
|
2998
3032
|
switch (e.key) {
|
|
2999
3033
|
case "ArrowDown":
|
|
3000
3034
|
e.preventDefault();
|
|
3001
|
-
setFocusedIndex((prev) => prev <
|
|
3035
|
+
setFocusedIndex((prev) => prev < itemsWithAddNew.length - 1 ? prev + 1 : prev);
|
|
3002
3036
|
break;
|
|
3003
3037
|
case "ArrowUp":
|
|
3004
3038
|
e.preventDefault();
|
|
@@ -3006,8 +3040,8 @@ const SearchableDropdown = React__namespace.forwardRef(({ className, items = [],
|
|
|
3006
3040
|
break;
|
|
3007
3041
|
case "Enter":
|
|
3008
3042
|
e.preventDefault();
|
|
3009
|
-
if (focusedIndex >= 0 &&
|
|
3010
|
-
handleItemSelect(
|
|
3043
|
+
if (focusedIndex >= 0 && itemsWithAddNew[focusedIndex]) {
|
|
3044
|
+
handleItemSelect(itemsWithAddNew[focusedIndex]);
|
|
3011
3045
|
}
|
|
3012
3046
|
break;
|
|
3013
3047
|
case "Escape":
|
|
@@ -3018,9 +3052,10 @@ const SearchableDropdown = React__namespace.forwardRef(({ className, items = [],
|
|
|
3018
3052
|
}
|
|
3019
3053
|
};
|
|
3020
3054
|
// Update items with onClick handlers that call handleItemSelect
|
|
3021
|
-
|
|
3055
|
+
// Only add onClick if it doesn't already exist (for Add New items)
|
|
3056
|
+
const itemsWithHandlers = itemsWithAddNew.map((item) => ({
|
|
3022
3057
|
...item,
|
|
3023
|
-
onClick: () => handleItemSelect(item),
|
|
3058
|
+
onClick: item.onClick || (() => handleItemSelect(item)),
|
|
3024
3059
|
}));
|
|
3025
3060
|
const showDropdown = isOpen && searchValue.length >= minSearchLength;
|
|
3026
3061
|
const dropdownMenu = showDropdown && (jsxRuntime.jsx("div", { ref: menuRef, style: {
|
|
@@ -3029,7 +3064,9 @@ const SearchableDropdown = React__namespace.forwardRef(({ className, items = [],
|
|
|
3029
3064
|
left: `${position.left}px`,
|
|
3030
3065
|
width: dropdownWidth === "full" ? `${position.width}px` : "auto",
|
|
3031
3066
|
zIndex: 9999,
|
|
3032
|
-
}, children: jsxRuntime.jsx(DropdownMenu, { items: itemsWithHandlers, sectionHeading: sectionHeading, isLoading: isLoading, isEmpty:
|
|
3067
|
+
}, children: jsxRuntime.jsx(DropdownMenu, { items: itemsWithHandlers, sectionHeading: sectionHeading, isLoading: isLoading, isEmpty: itemsWithAddNew.length === 0 && !showAddNew, emptyTitle: emptyTitle, emptyDescription: emptyDescription, emptyLinkText: emptyLinkText, onEmptyLinkClick: onEmptyLinkClick, primaryButtonText: primaryButtonText, secondaryButtonText: secondaryButtonText, onPrimaryClick: onPrimaryClick, onSecondaryClick: onSecondaryClick, showChevron: showChevron, emptyIcon: emptyIcon, disableFooter: disableFooter, showFooter: (primaryButtonText || secondaryButtonText) && !disableFooter
|
|
3068
|
+
? true
|
|
3069
|
+
: false, footerLayout: footerLayout, onClose: () => setIsOpen(false), focusedIndex: focusedIndex, className: dropdownClassName, width: dropdownWidth === "full" ? "full" : "auto" }) }));
|
|
3033
3070
|
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { ref: dropdownRef, className: cn("relative", containerClassName), children: jsxRuntime.jsx(TextField, { ref: inputRef, value: searchValue, onChange: handleSearchChange, onFocus: handleFocus, onKeyDown: handleKeyDown, containerClassName: "mb-0", ...textFieldProps }) }), typeof document !== "undefined" &&
|
|
3034
3071
|
dropdownMenu &&
|
|
3035
3072
|
reactDom.createPortal(dropdownMenu, document.body)] }));
|