UNPKG

@hitachivantara/uikit-react-core

Version:

Core React components for the NEXT Design System.

288 lines (287 loc) 10.5 kB
"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const jsxRuntime = require("react/jsx-runtime"); const React = require("react"); const reactPopper = require("react-popper"); const utils = require("@mui/material/utils"); const core = require("@popperjs/core"); const uikitReactUtils = require("@hitachivantara/uikit-react-utils"); const useControlled = require("../hooks/useControlled.cjs"); const useUniqueId = require("../hooks/useUniqueId.cjs"); const icons = require("../icons.cjs"); const focusableElementFinder = require("../utils/focusableElementFinder.cjs"); const keyboardUtils = require("../utils/keyboardUtils.cjs"); const setId = require("../utils/setId.cjs"); const BaseDropdown_styles = require("./BaseDropdown.styles.cjs"); const BaseDropdownPanel = require("./BaseDropdownPanel.cjs"); const context = require("./context.cjs"); const Typography = require("../Typography/Typography.cjs"); const BaseDropdown = React.forwardRef(function BaseDropdown2(props, ref) { const { id: idProp, className, classes: classesProp, children, role, placeholder, component, headerComponent: HeaderComponentProp, adornment, expanded, dropdownHeaderProps, defaultExpanded, disabled, readOnly, required, disablePortal, "aria-expanded": ariaExpandedProp, "aria-label": ariaLabelProp, "aria-labelledby": ariaLabelledByProp, dropdownHeaderRef: dropdownHeaderRefProp, onToggle, onClickOutside, ...others } = props; const { classes, cx } = BaseDropdown_styles.useClasses(classesProp); const { popperPlacement, popperElement, referenceElement, setReferenceElement } = context.useBaseDropdownContext(); const [isOpen, setIsOpen] = useControlled.useControlled(expanded, Boolean(defaultExpanded)); const headerRef = utils.useForkRef( setReferenceElement, dropdownHeaderRefProp, dropdownHeaderProps?.ref ); const customHeaderRef = utils.useForkRef(ref, headerRef); const ariaRole = role || (component == null ? "combobox" : void 0); const ariaExpanded = ariaExpandedProp ?? (ariaRole ? !!isOpen : void 0); const id = useUniqueId.useUniqueId(idProp); const containerId = setId.setId(id, "children-container"); const headerControlArias = { "aria-required": required ?? void 0, "aria-readonly": readOnly ?? void 0, "aria-disabled": disabled ?? void 0, "aria-expanded": ariaExpanded, "aria-owns": isOpen ? containerId : void 0, "aria-controls": isOpen ? containerId : void 0 }; const headerAriaLabels = { "aria-label": ariaLabelProp, "aria-labelledby": ariaLabelledByProp }; const handleToggle = React.useCallback( (event) => { if (event && !keyboardUtils.isKey(event, "Tab")) { event.preventDefault(); } const notControlKey = !!event?.code && !keyboardUtils.isOneOfKeys(event, ["Tab", "Enter", "Esc", "ArrowDown", "Space"]); const ignoredCombinations = keyboardUtils.isKey(event, "Esc") && !isOpen || keyboardUtils.isKey(event, "ArrowDown") && isOpen || keyboardUtils.isKey(event, "Tab") && !isOpen; if (disabled || notControlKey || ignoredCombinations) return; const newOpen = !isOpen; setIsOpen(() => { if (!newOpen) { referenceElement?.focus({ preventScroll: true }); } return newOpen; }); onToggle?.(event, newOpen); }, [isOpen, disabled, setIsOpen, onToggle, referenceElement] ); const defaultHeaderElement = /* @__PURE__ */ jsxRuntime.jsxs( "div", { id: setId.setId(id, "header"), "data-popper-placement": popperPlacement, className: cx(classes.header, { [classes.headerOpen]: isOpen, [classes.headerOpenUp]: isOpen && popperPlacement?.includes("top"), [classes.headerOpenDown]: isOpen && popperPlacement?.includes("bottom"), [classes.headerReadOnly]: readOnly, [classes.headerDisabled]: disabled }), role: ariaRole === "combobox" ? "textbox" : void 0, ...headerAriaLabels, style: disabled || readOnly ? { pointerEvents: "none" } : void 0, tabIndex: disabled ? -1 : 0, ref: headerRef, ...dropdownHeaderProps, children: [ /* @__PURE__ */ jsxRuntime.jsx( "div", { className: cx(classes.selection, { [classes.selectionDisabled]: disabled }), children: placeholder && typeof placeholder === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Typography.HvTypography, { noWrap: true, className: classes.placeholder, children: placeholder }) : placeholder } ), /* @__PURE__ */ jsxRuntime.jsx("div", { className: classes.arrowContainer, children: adornment || /* @__PURE__ */ jsxRuntime.jsx( icons.HvIcon, { name: "CaretDown", size: "xs", rotate: isOpen, className: classes.arrow } ) }) ] } ); const headerElement = component && React.isValidElement(component) ? React.cloneElement(component, { ref: headerRef, ...headerControlArias }) : defaultHeaderElement; const handleContainerKeyDown = (event) => { if (keyboardUtils.isKey(event, "Esc")) { handleToggle(event); } if (keyboardUtils.isKey(event, "Tab") && !event.shiftKey) { const focusList = focusableElementFinder.getFirstAndLastFocus(popperElement); if (document.activeElement === focusList?.last) { event.preventDefault(); focusList?.first?.focus(); } } }; const handleOutside = (event) => { const isButtonClick = referenceElement?.contains(event.target); if (!isButtonClick) { onClickOutside?.(event); setIsOpen(false); onToggle?.(event, false); } }; const hasCustomHeader = !!HeaderComponentProp; const HeaderComponent = HeaderComponentProp || "div"; const RootComponent = HeaderComponentProp ? React.Fragment : "div"; return /* @__PURE__ */ jsxRuntime.jsxs(RootComponent, { ...!hasCustomHeader && { className: classes.root }, children: [ /* @__PURE__ */ jsxRuntime.jsx( HeaderComponent, { ref: hasCustomHeader ? customHeaderRef : ref, id, disabled: hasCustomHeader && disabled, className: cx(className, { [classes.anchor]: !hasCustomHeader, [classes.rootDisabled]: disabled }), ...!readOnly && { onKeyDown: handleToggle, onClick: handleToggle }, ...(ariaRole || hasCustomHeader) && { role: hasCustomHeader ? void 0 : ariaRole, ...headerAriaLabels, ...headerControlArias }, tabIndex: hasCustomHeader ? void 0 : -1, ...others, children: headerElement } ), isOpen && /* @__PURE__ */ jsxRuntime.jsx( BaseDropdownPanel.BaseDropdownPanel, { classes, containerId, onClickAway: handleOutside, disablePortal, onContainerKeyDown: handleContainerKeyDown, children } ) ] }); }); const HvBaseDropdown = React.forwardRef( function HvBaseDropdown2(props, ref) { const { popperProps = {}, variableWidth, placement: placementProp = "right", onContainerCreation, ...others } = uikitReactUtils.useDefaultProps("HvBaseDropdown", props); const placement = `bottom-${placementProp === "right" ? "start" : "end"}`; const { modifiers: popperPropsModifiers, ...otherPopperProps } = popperProps; const [referenceElement, setReferenceElement] = React.useState(null); const [popperElement, setPopperElement] = React.useState( null ); const onFirstUpdate = React.useCallback(() => { onContainerCreation?.(popperElement); }, [onContainerCreation, popperElement]); const modifiers = React.useMemo( () => [ { name: "variableWidth", enabled: !variableWidth, phase: "beforeWrite", requires: ["computeStyles"], fn: ({ state }) => { state.styles.popper.width = `${state.rects.reference.width}px`; }, effect: ({ state }) => { state.elements.popper.style.width = `${state.elements.reference.offsetWidth}px`; } }, { name: "maxSize", enabled: true, phase: "main", requiresIfExists: ["offset", "preventOverflow", "flip"], fn: ({ state, name, options }) => { const overflow = core.detectOverflow(state, options); const x = state.modifiersData.preventOverflow?.x || 0; const y = state.modifiersData.preventOverflow?.y || 0; const popperWidth = state.rects.popper.width; const popperHeight = state.rects.popper.height; const basePlacement = state.placement.split("-")[0]; const widthProp = basePlacement === "left" ? "left" : "right"; const heightProp = basePlacement === "top" ? "top" : "bottom"; state.modifiersData[name] = { width: popperWidth - overflow[widthProp] - x, height: popperHeight - overflow[heightProp] - y }; } }, { name: "applyMaxSize", enabled: true, phase: "beforeWrite", requires: ["maxSize"], fn: ({ state }) => { const { width, height } = state.modifiersData.maxSize; state.styles.popper.maxWidth = `${width}px`; state.styles.popper.maxHeight = `${height}px`; } }, ...popperPropsModifiers || [] ], [popperPropsModifiers, variableWidth] ); const popper = reactPopper.usePopper(referenceElement, popperElement, { placement, modifiers, onFirstUpdate, ...otherPopperProps }); const value = React.useMemo( () => ({ popperPlacement: popper?.attributes.popper?.["data-popper-placement"] ?? "bottom", popper, popperElement, setPopperElement, referenceElement, setReferenceElement }), [popper, popperElement, referenceElement] ); return /* @__PURE__ */ jsxRuntime.jsx(context.BaseDropdownContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx(BaseDropdown, { ref, ...others }) }); } ); exports.baseDropdownClasses = BaseDropdown_styles.staticClasses; exports.HvBaseDropdown = HvBaseDropdown;