@hitachivantara/uikit-react-core
Version:
Core React components for the NEXT Design System.
288 lines (287 loc) • 10.5 kB
JavaScript
"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;