@sitecore/sc-contenthub-blok
Version:
A UI library for [Sitecore Content Hub](https://doc.sitecore.com/ch/).
202 lines • 10.7 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getPopoverOrigin = void 0;
exports.BlokButtonSelect = BlokButtonSelect;
const jsx_runtime_1 = require("react/jsx-runtime");
const css_1 = require("@emotion/css");
const react_1 = require("react");
const useIsMounted_1 = __importDefault(require("../../customHooks/useIsMounted"));
const Foundations_1 = require("../../Foundations");
const utils_1 = require("../../Foundations/utils");
const utils_2 = require("../../Foundations/utils");
const BlokButton_1 = require("../BlokButton/BlokButton");
const BlokIcon_1 = require("../BlokIcon/BlokIcon");
const BlokIconButton_1 = require("../BlokIconButton/BlokIconButton");
const BlokSearchBox_1 = require("../BlokSearchBox/BlokSearchBox");
const BlokTooltip_1 = require("../BlokTooltip/BlokTooltip");
const CoreComponents_1 = require("../CoreComponents");
const classes = {
dropdownItemIcon: (0, css_1.css)({
color: Foundations_1.blackAlpha[600],
}),
iconLabel: (0, css_1.css)({
marginLeft: "8px",
verticalAlign: "middle",
maxWidth: "100%",
overflow: "hidden",
textOverflow: "ellipsis",
}),
dropdownItemIconMenu: (0, css_1.css)({
marginRight: utils_1.isLTR ? "24px" : 0,
marginLeft: utils_1.isRTL ? "24px" : 0,
color: Foundations_1.blackAlpha[600],
}),
hidden: (0, css_1.css)({
display: "none",
}),
lightText: (0, css_1.css)({ color: Foundations_1.blackAlpha["500"] }),
chevronIcon: (0, css_1.css)({
svg: {
padding: "0.125rem",
marginInlineStart: "-0.375rem",
marginInlineEnd: "-0.375rem",
},
}),
};
const menuListProps = { component: "div" };
const getPopoverOrigin = (element, type) => {
if (!element) {
return type === "anchor"
? { vertical: "bottom", horizontal: "center" }
: { vertical: "top", horizontal: "right" };
}
const { right, left } = element.getBoundingClientRect();
const { innerWidth: viewportWidth } = window;
const spaceOnRight = viewportWidth - right;
const spaceOnLeft = left;
const horizontal = spaceOnRight > spaceOnLeft ? "left" : "right";
const vertical = type === "anchor" ? "bottom" : "top";
return { horizontal, vertical };
};
exports.getPopoverOrigin = getPopoverOrigin;
const style = {
zIndex: 2001 /* Z-index of AppointmentToolTip is 2000 so this needs to be larger */,
};
function BlokButtonSelect({ id, options = (0, utils_2.getEmptyImmutableArray)(), onChange: onChange_, value, labelMapper = (item) => item, valueMapper = (item) => item, returnValue, placeholder = "Select an option", emptyValueSelectable = false, className, isReadOnly, searchBoxMinAmountOfItems = 8, showIconAndText = false, hideItemIcons = false, maxHeight = 250, itemsToDisable = (0, utils_2.getEmptyImmutableArray)(), showEmptyDropdown = false, noneLabel = "None", noResultsText = "No results found", variant, colorScheme, size, clearMessage = "Clear", searchMessage = "Search", }) {
const [anchorEl, setAnchorEl] = (0, react_1.useState)(null);
const isOpen = Boolean(anchorEl);
const [filteredOptions, setFilteredOptions] = (0, react_1.useState)(options);
const [searchFilter, setSearchFilter] = (0, react_1.useState)("");
const searchBoxRef = (0, react_1.useCallback)((node) => {
if (node) {
node.focus();
}
}, []);
const isMountedRef = (0, useIsMounted_1.default)();
// When clicking the clear button on the searchbox clear search value and set the list back to the original values.
const onClearSearch = (0, react_1.useCallback)(() => {
setFilteredOptions(options);
setSearchFilter("");
}, [options]);
/**
* Open the operation's dropdown.
* @param event - the mouse event
*/
const handleClick = (0, react_1.useCallback)((event) => {
event.stopPropagation();
event.preventDefault();
setAnchorEl(event.currentTarget);
}, []);
/**
* Close the menu.
*/
const handleClose = (0, react_1.useCallback)(() => {
setAnchorEl(null);
setSearchFilter("");
}, []);
// When selecting a value in the dropdown.
const onChange = (0, react_1.useCallback)(async (newValue) => {
if ((0, utils_2.isFunction)(onChange_)) {
if (newValue) {
if ((0, utils_2.isFunction)(returnValue)) {
await onChange_(returnValue(newValue));
}
else {
await onChange_(newValue);
}
}
if (newValue == null) {
if (emptyValueSelectable) {
await onChange_(newValue);
}
}
}
handleClose();
}, [onChange_, handleClose, returnValue, emptyValueSelectable]);
// When clicking the enter key in the search box select the first value in the list and close the menu.
const onEnterPress = (0, react_1.useCallback)(async () => {
if (filteredOptions.length) {
// Grab the first value in the filtered options list.
const valueToSelect = filteredOptions[0];
if ((0, utils_2.isFunction)(returnValue)) {
await onChange_(returnValue(valueToSelect));
}
else {
await onChange_(valueToSelect);
}
if (isMountedRef.current) {
// Restore the filtered options to the options.
setFilteredOptions(options);
handleClose();
}
}
}, [
filteredOptions,
handleClose,
isMountedRef,
onChange_,
options,
returnValue,
]);
(0, react_1.useEffect)(() => {
if (!options.length) {
return;
}
if (searchFilter !== "") {
setFilteredOptions(options.filter((option) => labelMapper(option)
.toLocaleLowerCase()
.includes(searchFilter.toLocaleLowerCase())));
}
else {
setFilteredOptions(options);
}
}, [options, searchFilter, labelMapper]);
const selectedValue = (value && valueMapper(value)) || "";
const filteredItems = (0, react_1.useMemo)(() => {
return filteredOptions?.map((option, index) => {
return (option && ((0, jsx_runtime_1.jsxs)(CoreComponents_1.MenuItem, { onKeyDown: (e) => {
if (e.key === "Escape") {
setSearchFilter("");
handleClose();
}
}, disabled: itemsToDisable.some((item) => valueMapper(option) === valueMapper(item)), onClick: () => onChange(option), selected: valueMapper(option) === selectedValue, children: [Object.prototype.hasOwnProperty.call(option, "icon") &&
!hideItemIcons && ((0, jsx_runtime_1.jsx)(CoreComponents_1.ListItemIcon, { children: (0, jsx_runtime_1.jsx)(BlokIcon_1.BlokIcon, { icon: option.icon }) })), (0, jsx_runtime_1.jsx)(CoreComponents_1.ListItemText, { primary: labelMapper(option) })] }, `${valueMapper(option)}-${index}`)));
});
}, [
filteredOptions,
valueMapper,
itemsToDisable,
selectedValue,
hideItemIcons,
labelMapper,
handleClose,
onChange,
]);
const searchBox = (0, react_1.useMemo)(() => options.length > searchBoxMinAmountOfItems && ((0, jsx_runtime_1.jsx)(BlokSearchBox_1.BlokSearchBox, { onSearch: setSearchFilter, onClearSearch: onClearSearch, value: searchFilter, ref: searchBoxRef, onEnterPress: onEnterPress, isInsideDropdown: true, hasGutterBottom: false, clearMessage: clearMessage, searchMessage: searchMessage })), [
clearMessage,
onClearSearch,
onEnterPress,
options.length,
searchBoxMinAmountOfItems,
searchBoxRef,
searchFilter,
searchMessage,
]);
if (!options.length && !showEmptyDropdown) {
return null;
}
const dropdownMenuId = `button-select-menu-${id}`;
const icon = value?.icon;
const labelToDisplay = value
? (labelMapper(value) ?? placeholder)
: placeholder;
return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: isReadOnly ? ((0, jsx_runtime_1.jsx)("div", { "data-testid": id, children: (0, jsx_runtime_1.jsx)(CoreComponents_1.Typography, { variant: "body1", children: typeof value === "object"
? labelMapper(value)
: (value ?? "") }) })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [!showIconAndText && icon ? ((0, jsx_runtime_1.jsx)(BlokTooltip_1.BlokTooltip, { title: labelToDisplay ?? "", children: (0, jsx_runtime_1.jsx)(BlokIconButton_1.BlokIconButton, { id: id, onClick: handleClick, className: className, variant: variant, colorScheme: colorScheme, size: size, children: (0, jsx_runtime_1.jsx)(BlokIcon_1.BlokIcon, { icon: icon }) }) })) : ((0, jsx_runtime_1.jsx)(BlokButton_1.BlokButton, { id: id, onClick: handleClick, startIcon: icon ? (0, jsx_runtime_1.jsx)(BlokIcon_1.BlokIcon, { icon: icon }) : undefined, endIcon: (0, jsx_runtime_1.jsx)(BlokIcon_1.BlokIcon, { icon: "chevron-down", classes: [classes.chevronIcon] }), className: className, variant: variant, colorScheme: colorScheme, size: size, children: labelToDisplay })), (0, jsx_runtime_1.jsxs)(CoreComponents_1.Menu, { keepMounted: true, anchorOrigin: (0, exports.getPopoverOrigin)(anchorEl, "anchor"), id: dropdownMenuId, anchorEl: anchorEl, open: isOpen, onClose: handleClose, MenuListProps: menuListProps, onKeyDown: (e) => e.stopPropagation(), variant: "menu", style: style, transformOrigin: (0, exports.getPopoverOrigin)(anchorEl, "transform"), autoFocus: options.length < searchBoxMinAmountOfItems, slotProps: { paper: { style: { maxHeight, overflow: "auto" } } }, children: [isOpen && searchBox, value === null && ((0, jsx_runtime_1.jsx)(CoreComponents_1.MenuItem, { value: undefined, className: classes.hidden, children: (0, jsx_runtime_1.jsx)("em", { className: classes.lightText, children: placeholder }) })), emptyValueSelectable && searchFilter === "" && (
// We need to set the value to null so that it is picked up correctly.
(0, jsx_runtime_1.jsx)(CoreComponents_1.MenuItem, { value: null, children: (0, jsx_runtime_1.jsx)("em", { children: noneLabel }) })), !filteredOptions.length && noResultsText, filteredItems] })] })) }));
}
//# sourceMappingURL=BlokButtonSelect.js.map