UNPKG

nudge-components-library

Version:

A library of nudge UI components

114 lines (111 loc) 6.92 kB
import { jsxs, jsx, Fragment } from 'react/jsx-runtime'; import { useContext, useState, useRef, useEffect } from 'react'; import { FiChevronDown, FiCheck } from '../../node_modules/react-icons/fi/index.js'; import { ThemeContext } from '../../theme/ThemeContext.js'; import '../../styles/tokens.css.js'; import '../../styles/globals.css.js'; import styles from './DropdownMenu.module.css.js'; function DropdownMenu({ dropdownLabel, options, selected, defaultSelected, onChange, placeholder = "Select an option", disabled = false, id, ariaLabel, onFocus, onBlur, onCommit, nudgeVisible = true, nudgePosition = "bottom", renderNudge, }) { const theme = useContext(ThemeContext); const [isOpen, setIsOpen] = useState(false); const [internalSelected, setInternalSelected] = useState(defaultSelected || ""); const dropdownRef = useRef(null); const selectedValue = selected !== undefined ? selected : internalSelected; const selectedOption = options.find((opt) => opt.value === selectedValue); const toggleOpen = () => { if (!disabled) setIsOpen(!isOpen); }; const handleSelect = (value) => { if (!disabled) { setInternalSelected(value); onChange?.(value); onCommit?.(value); setIsOpen(false); } }; useEffect(() => { const handleClickOutside = (event) => { if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { setIsOpen(false); if (onBlur) { const dummyEvent = { target: dropdownRef.current, }; onBlur(dummyEvent); } onCommit?.(selectedValue); } }; document.addEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside); }, [dropdownRef, onBlur, onCommit, selectedValue]); useEffect(() => { const handleTouchOutside = (event) => { if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { setIsOpen(false); if (onBlur) { const dummyEvent = { target: dropdownRef.current, }; onBlur(dummyEvent); } onCommit?.(selectedValue); } }; document.addEventListener("touchstart", handleTouchOutside); return () => document.removeEventListener("touchstart", handleTouchOutside); }, [dropdownRef, onBlur, onCommit, selectedValue]); const handleTouchStart = (e) => { if (onFocus) { onFocus(e); } }; return (jsxs("div", { ref: dropdownRef, style: { ...theme.dropdown.wrapper, ...(disabled ? theme.dropdown.disabled : {}), }, children: [dropdownLabel && (jsx("div", { style: theme.dropdown.dropdownLabel, children: dropdownLabel })), jsxs("button", { id: id, "aria-label": ariaLabel || placeholder, style: { ...theme.dropdown.button, "--base-border": theme.dropdown.button.baseBorder, "--hover-border": theme.dropdown.hover.hoverBorder, }, onClick: toggleOpen, onFocus: onFocus, onBlur: (e) => { onBlur?.(e); onCommit?.(selectedValue); }, onTouchStart: handleTouchStart, className: styles.dropdownButton, children: [jsx("span", { children: selectedOption ? selectedOption.label : placeholder }), jsx(FiChevronDown, { style: { ...theme.dropdown.chevron, ...(isOpen ? theme.dropdown.chevronOpen : {}), } })] }), isOpen && (jsx("ul", { style: theme.dropdown.list, children: options.map((option) => { const isOptionSelected = option.value === selectedValue; let optionNudgeElement = null; if (nudgeVisible) { if (renderNudge) { optionNudgeElement = (jsx("div", { id: id ? `${id}-${option.value}-nudge` : undefined, style: theme.dropdown.nudgeText, children: renderNudge(option) })); } else if (option.nudgeText) { optionNudgeElement = (jsx("div", { id: id ? `${id}-${option.value}-nudge` : undefined, style: theme.dropdown.nudgeText, children: jsx("span", { children: option.nudgeText }) })); } } let optionContent; if (nudgePosition === "top") { optionContent = (jsxs(Fragment, { children: [optionNudgeElement, jsxs("div", { style: theme.dropdown.content, children: [jsx("span", { style: theme.dropdown.label, children: option.label }), isOptionSelected && (jsx(FiCheck, { style: theme.dropdown.checkIcon, strokeWidth: 2.5 }))] })] })); } else if (nudgePosition === "bottom") { optionContent = (jsxs(Fragment, { children: [jsxs("div", { style: theme.dropdown.content, children: [jsx("span", { style: theme.dropdown.label, children: option.label }), isOptionSelected && (jsx(FiCheck, { style: theme.dropdown.checkIcon, strokeWidth: 2.5 }))] }), optionNudgeElement] })); } else if (nudgePosition === "left" || nudgePosition === "right") { optionContent = (jsxs("div", { style: { display: "flex", alignItems: "center" }, children: [nudgePosition === "left" && optionNudgeElement, jsxs("div", { style: theme.dropdown.content, children: [jsx("span", { style: theme.dropdown.label, children: option.label }), isOptionSelected && (jsx(FiCheck, { style: theme.dropdown.checkIcon, strokeWidth: 2.5 }))] }), nudgePosition === "right" && optionNudgeElement] })); } else { optionContent = (jsxs(Fragment, { children: [jsxs("div", { style: theme.dropdown.content, children: [jsx("span", { style: theme.dropdown.label, children: option.label }), isOptionSelected && (jsx(FiCheck, { style: theme.dropdown.checkIcon, strokeWidth: 2.5 }))] }), optionNudgeElement] })); } return (jsx("li", { style: { ...theme.dropdown.option, "--item-hover-bg": theme.dropdown.optionHover.background, ...(isOptionSelected ? theme.dropdown.optionSelected : {}), }, onClick: () => handleSelect(option.value), className: styles.dropdownItem, children: optionContent }, option.value)); }) }))] })); } export { DropdownMenu }; //# sourceMappingURL=DropdownMenu.js.map