UNPKG

@sitecore/sc-contenthub-blok

Version:

A UI library for [Sitecore Content Hub](https://doc.sitecore.com/ch/).

202 lines 10.7 kB
"use strict"; 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