UNPKG

@yamada-ui/react

Version:

React UI components of the Yamada, by the Yamada, for the Yamada built with React and Emotion

487 lines (483 loc) • 16.1 kB
"use client"; const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs'); const require_context = require('../../utils/context.cjs'); const require_dom = require('../../utils/dom.cjs'); const require_effect = require('../../utils/effect.cjs'); const require_ref = require('../../utils/ref.cjs'); const require_utils_index = require('../../utils/index.cjs'); const require_hooks_use_controllable_state_index = require('../../hooks/use-controllable-state/index.cjs'); const require_hooks_use_descendants_index = require('../../hooks/use-descendants/index.cjs'); const require_use_disclosure = require('../../hooks/use-disclosure/use-disclosure.cjs'); let react = require("react"); react = require_rolldown_runtime.__toESM(react); //#region src/components/menu/use-menu.ts const { DescendantsContext: MenuDescendantsContext, useDescendant: useMenuDescendant, useDescendantRegister: useMenuDescendantRegister, useDescendants: useMenuDescendants } = require_hooks_use_descendants_index.createDescendants(); const [MenuContext, useMenuContext] = require_context.createContext({ name: "MenuContext" }); const [MenuGroupContext, useMenuGroupContext] = require_context.createContext({ name: "MenuGroupContext" }); const [MainMenuContext, useMainMenuContext] = require_context.createContext({ name: "MainMenuContext", strict: false }); const [MenuOptionGroupContext, useMenuOptionGroupContext] = require_context.createContext({ name: "MenuOptionGroupContext" }); const useMenu = ({ closeOnSelect, defaultOpen, disabled = false, open: openProp, subMenuDirection = "end", onClose: onCloseProp, onOpen: onOpenProp, onSelect: onSelectProp } = {}) => { const triggerId = (0, react.useId)(); const contentId = (0, react.useId)(); const descendants = useMenuDescendants(); const updateRef = (0, react.useRef)(require_utils_index.utils_exports.noop); const onCloseRef = (0, react.useRef)(require_utils_index.utils_exports.noop); const contentRef = (0, react.useRef)(null); const { open, onClose, onOpen } = require_use_disclosure.useDisclosure({ defaultOpen, open: openProp, onClose: onCloseProp, onOpen: onOpenProp }); const onCloseSubMenu = (0, react.useCallback)(() => onCloseRef.current(), []); const onActiveDescendant = (0, react.useCallback)((descendant, options = { preventScroll: true }) => { if (!contentRef.current || !descendant || disabled) return; contentRef.current.setAttribute("aria-activedescendant", descendant.id); descendants.active(descendant, options); }, [descendants, disabled]); const { mainCloseOnSelect, subMenu, getSubMenuProps, onMainSelect } = useSubMenu({ descendants, disabled, open, subMenuDirection, onActiveDescendant, onClose, onOpen }); closeOnSelect ??= mainCloseOnSelect ?? true; const onSelect = (0, react.useCallback)((value, closeOnSelectProp = closeOnSelect) => { if (disabled) return; onSelectProp?.(value); onMainSelect?.(value, closeOnSelectProp); if (!closeOnSelectProp) return; onClose(); }, [ closeOnSelect, disabled, onClose, onMainSelect, onSelectProp ]); const onClick = (0, react.useCallback)((ev) => { if (disabled) return; ev.preventDefault(); if (!open) onOpen(); else onClose(); }, [ disabled, onClose, onOpen, open ]); const onContextMenu = (0, react.useCallback)((ev) => { if (disabled) return; ev.preventDefault(); onOpen(); updateRef.current(); }, [disabled, onOpen]); const onKeyDown = (0, react.useCallback)((ev) => { if (disabled) return; require_dom.runKeyAction(ev, { ArrowDown: () => { onOpen(); setTimeout(() => { onActiveDescendant(descendants.enabledFirstValue()); }); }, ArrowUp: () => { onOpen(); setTimeout(() => { onActiveDescendant(descendants.enabledLastValue()); }); }, Enter: () => { onOpen(); setTimeout(() => { onActiveDescendant(descendants.enabledFirstValue()); }); }, Space: () => { onOpen(); setTimeout(() => { onActiveDescendant(descendants.enabledFirstValue()); }); } }); }, [ descendants, disabled, onActiveDescendant, onOpen ]); const getTriggerProps = (0, react.useCallback)((props = {}) => ({ ...getSubMenuProps({ id: triggerId, "aria-controls": open ? contentId : void 0, "aria-disabled": (0, require_utils_index.utils_exports.ariaAttr)(disabled), "aria-expanded": open, "aria-haspopup": "menu", "data-trigger": (0, require_utils_index.utils_exports.dataAttr)(true), role: "button", tabIndex: disabled ? -1 : 0, ...props, onClick: (0, require_utils_index.utils_exports.handlerAll)(props.onClick, onClick), onKeyDown: (0, require_utils_index.utils_exports.handlerAll)(props.onKeyDown, onKeyDown) }) }), [ contentId, disabled, getSubMenuProps, onClick, onKeyDown, open, triggerId ]); const getContextTriggerProps = (0, react.useCallback)((props = {}) => ({ id: triggerId, "aria-controls": open ? contentId : void 0, "aria-disabled": (0, require_utils_index.utils_exports.ariaAttr)(disabled), "aria-expanded": open, "aria-haspopup": "menu", "data-trigger": (0, require_utils_index.utils_exports.dataAttr)(true), role: "application", ...props, onContextMenu: (0, require_utils_index.utils_exports.handlerAll)(props.onContextMenu, onContextMenu) }), [ contentId, disabled, onContextMenu, open, triggerId ]); const getContentProps = (0, react.useCallback)(({ ref, "aria-labelledby": ariaLabelledby,...props } = {}) => ({ id: contentId, "aria-labelledby": (0, require_utils_index.utils_exports.cx)(ariaLabelledby, triggerId), role: "menu", ...props, ref: require_ref.mergeRefs(ref, contentRef) }), [contentId, triggerId]); const getSeparatorProps = (0, react.useCallback)((props) => ({ role: "separator", ...props }), []); return { closeOnSelect, descendants, open, subMenu, subMenuDirection, updateRef, getContentProps, getContextTriggerProps, getSeparatorProps, getTriggerProps, onActiveDescendant, onClose, onCloseRef, onCloseSubMenu, onOpen, onSelect }; }; const useSubMenu = ({ descendants, disabled = false, open, subMenuDirection = "end", onActiveDescendant, onClose, onOpen }) => { const uuid = (0, react.useId)(); const { closeOnSelect: mainCloseOnSelect, descendants: mainDescendants, onActiveDescendant: onActiveMainDescendant, onCloseRef, onSelect: onMainSelect } = useMainMenuContext() ?? {}; const subMenu = !!mainDescendants && !!onActiveMainDescendant; const createRegister = useMenuDescendantRegister(mainDescendants); const triggerRef = (0, react.useRef)(null); const dataDisabled = (0, react.useCallback)((node) => { node ??= triggerRef.current; if (!node) return false; return (0, require_utils_index.utils_exports.isTruthyDataAttr)(node.getAttribute("data-disabled")); }, []); const ariaDisabled = (0, react.useCallback)((node) => { node ??= triggerRef.current; if (!node) return false; return (0, require_utils_index.utils_exports.isTruthyDataAttr)(node.getAttribute("aria-disabled")); }, []); const onClick = (0, react.useCallback)((ev) => { if (!subMenu) return; ev.defaultPrevented = disabled || dataDisabled() || ariaDisabled(); }, [ ariaDisabled, dataDisabled, disabled, subMenu ]); const onMouseEnter = (0, react.useCallback)(() => { if (!subMenu || disabled || dataDisabled() || ariaDisabled()) return; onOpen(); }, [ ariaDisabled, dataDisabled, disabled, onOpen, subMenu ]); const onMouseMove = (0, react.useCallback)((ev) => { if (!subMenu || disabled || dataDisabled() || ariaDisabled()) return; onActiveMainDescendant(descendants.value(triggerRef.current)); ev.defaultPrevented = true; }, [ ariaDisabled, dataDisabled, descendants, disabled, onActiveMainDescendant, subMenu ]); const onKeyDown = (0, react.useCallback)((ev) => { if (!subMenu || disabled) return; const currentDescendant = open ? descendants : mainDescendants; const onActiveCurrentDescendant = open ? onActiveDescendant : onActiveMainDescendant; require_dom.runKeyAction(ev, { ArrowDown: () => { onActiveCurrentDescendant(currentDescendant.enabledNextValue(triggerRef.current)); ev.defaultPrevented = true; }, ArrowUp: () => { onActiveCurrentDescendant(currentDescendant.enabledPrevValue(triggerRef.current)); ev.defaultPrevented = true; }, End: () => { onActiveCurrentDescendant(currentDescendant.enabledLastValue()); ev.defaultPrevented = true; }, Home: () => { onActiveCurrentDescendant(currentDescendant.enabledFirstValue()); ev.defaultPrevented = true; }, [subMenuDirection === "end" ? "ArrowRight" : "ArrowLeft"]: () => { onOpen(); setTimeout(() => { onActiveDescendant(descendants.enabledFirstValue()); }); ev.defaultPrevented = true; } }); }, [ subMenu, disabled, open, descendants, mainDescendants, onActiveDescendant, onActiveMainDescendant, subMenuDirection, onOpen ]); require_ref.assignRef(onCloseRef, onClose); return { mainCloseOnSelect, subMenu, getSubMenuProps: (0, react.useCallback)(({ id = uuid, ref,...props } = {}) => { const getDisabled = (node) => disabled || dataDisabled(node) || ariaDisabled(node); const register = createRegister({ id, disabled: getDisabled }); return { role: subMenu ? "menuitem" : "button", ...props, ref: require_ref.mergeRefs(ref, triggerRef, register), onClick: (0, require_utils_index.utils_exports.handlerAll)(onClick, props.onClick), onKeyDown: (0, require_utils_index.utils_exports.handlerAll)(onKeyDown, props.onKeyDown), onMouseEnter: (0, require_utils_index.utils_exports.handlerAll)(onMouseEnter, props.onMouseEnter), onMouseMove: (0, require_utils_index.utils_exports.handlerAll)(onMouseMove, props.onMouseMove) }; }, [ uuid, subMenu, createRegister, onClick, onKeyDown, onMouseEnter, onMouseMove, disabled, dataDisabled, ariaDisabled ]), onMainSelect }; }; const useMenuGroup = ({ "aria-labelledby": ariaLabelledbyProp,...rest }) => { const labelId = (0, react.useId)(); return { getGroupProps: (0, react.useCallback)(({ "aria-labelledby": ariaLabelledby,...props } = {}) => ({ "aria-labelledby": (0, require_utils_index.utils_exports.cx)(ariaLabelledbyProp, ariaLabelledby, labelId), role: "group", ...rest, ...props }), [ ariaLabelledbyProp, labelId, rest ]), getLabelProps: (0, react.useCallback)((props) => ({ id: labelId, role: "presentation", ...props }), [labelId]) }; }; const useMenuItem = ({ id, "aria-disabled": ariaDisabled, "data-disabled": dataDisabled, "data-trigger": dataTrigger, closeOnSelect, disabled = false, value,...rest }) => { const trigger = (0, require_utils_index.utils_exports.isTruthyDataAttr)(dataTrigger); const { subMenu, subMenuDirection, onActiveDescendant, onClose, onCloseSubMenu, onSelect } = useMenuContext(); const uuid = (0, react.useId)(); const itemRef = (0, react.useRef)(null); const subMenuTrigger = subMenu && trigger; id ??= uuid; const { descendants, register } = useMenuDescendant({ id, disabled: disabled || subMenuTrigger }); const onActive = (0, react.useCallback)(() => { if (disabled) return; onActiveDescendant(descendants.value(itemRef.current)); }, [ descendants, disabled, onActiveDescendant ]); const onKeyDown = (0, react.useCallback)((ev) => { require_dom.runKeyAction(ev, { ArrowDown: () => { onActiveDescendant(descendants.enabledNextValue(itemRef.current)); }, ArrowUp: () => { onActiveDescendant(descendants.enabledPrevValue(itemRef.current)); }, End: () => { onActiveDescendant(descendants.enabledLastValue()); }, Enter: () => onSelect(value, closeOnSelect), Home: () => { onActiveDescendant(descendants.enabledFirstValue()); }, Space: () => onSelect(value, closeOnSelect), [subMenuDirection === "end" ? "ArrowLeft" : "ArrowRight"]: () => { if (!subMenu) return; onClose(); descendants.firstValue()?.node.focus(); } }); }, [ closeOnSelect, descendants, onActiveDescendant, onClose, onSelect, subMenu, subMenuDirection, value ]); return { subMenuTrigger, getItemProps: (0, react.useCallback)(({ ref,...props } = {}) => ({ id, "aria-disabled": ariaDisabled ?? (0, require_utils_index.utils_exports.ariaAttr)(disabled), "data-disabled": dataDisabled ?? (0, require_utils_index.utils_exports.dataAttr)(disabled), role: "menuitem", tabIndex: -1, ...rest, ...props, ref: require_ref.mergeRefs(ref, rest.ref, itemRef, register), onClick: (0, require_utils_index.utils_exports.handlerAll)(props.onClick, rest.onClick, () => onSelect(value, closeOnSelect)), onFocus: (0, require_utils_index.utils_exports.handlerAll)(props.onFocus, rest.onFocus, onActive), onKeyDown: (0, require_utils_index.utils_exports.handlerAll)(props.onKeyDown, rest.onKeyDown, onKeyDown), onMouseMove: (0, require_utils_index.utils_exports.handlerAll)(props.onMouseMove, rest.onMouseMove, () => { onCloseSubMenu(); onActive(); }) }), [ id, ariaDisabled, disabled, dataDisabled, rest, register, onActive, onKeyDown, onSelect, value, closeOnSelect, onCloseSubMenu ]) }; }; const useMenuOptionGroup = ({ type = "checkbox", defaultValue = type === "checkbox" ? [] : "", value: valueProp, onChange: onChangeProp }) => { const [value, setValue] = require_hooks_use_controllable_state_index.useControllableState({ defaultValue, value: valueProp, onChange: onChangeProp }); const radio = type === "radio"; const onChange = (0, react.useCallback)((selectedValue) => { setValue((prev) => { if (radio && (0, require_utils_index.utils_exports.isString)(prev)) return selectedValue; else if (!radio && (0, require_utils_index.utils_exports.isArray)(prev)) return prev.includes(selectedValue) ? prev.filter((value$1) => value$1 !== selectedValue) : prev.concat(selectedValue); else return prev; }); }, [radio, setValue]); require_effect.useUpdateEffect(() => { setValue(valueProp); }, [valueProp]); return { type, value, onChange }; }; const useMenuOptionItem = ({ disabled, value,...rest }) => { const { type, value: selectedValue, onChange } = useMenuOptionGroupContext(); const { getItemProps } = useMenuItem({ disabled, value, ...rest }); const radio = type === "radio" && (0, require_utils_index.utils_exports.isString)(selectedValue); const checkbox = type === "checkbox" && (0, require_utils_index.utils_exports.isArray)(selectedValue); const selected = radio ? value === selectedValue : checkbox ? selectedValue.includes(value) : false; return { type, selected, getIndicatorProps: (0, react.useCallback)(({ style,...props } = {}) => ({ style: { opacity: selected ? 1 : 0, ...style }, ...props }), [selected]), getOptionItemProps: (0, react.useCallback)((props = {}) => getItemProps({ role: radio ? "menuitemradio" : "menuitemcheckbox", ...props, onClick: (0, require_utils_index.utils_exports.handlerAll)(props.onClick, () => !disabled ? onChange?.(value) : require_utils_index.utils_exports.noop) }), [ disabled, getItemProps, onChange, radio, value ]) }; }; //#endregion exports.MainMenuContext = MainMenuContext; exports.MenuContext = MenuContext; exports.MenuDescendantsContext = MenuDescendantsContext; exports.MenuGroupContext = MenuGroupContext; exports.MenuOptionGroupContext = MenuOptionGroupContext; exports.useMainMenuContext = useMainMenuContext; exports.useMenu = useMenu; exports.useMenuContext = useMenuContext; exports.useMenuDescendant = useMenuDescendant; exports.useMenuDescendants = useMenuDescendants; exports.useMenuGroup = useMenuGroup; exports.useMenuGroupContext = useMenuGroupContext; exports.useMenuItem = useMenuItem; exports.useMenuOptionGroup = useMenuOptionGroup; exports.useMenuOptionGroupContext = useMenuOptionGroupContext; exports.useMenuOptionItem = useMenuOptionItem; exports.useSubMenu = useSubMenu; //# sourceMappingURL=use-menu.cjs.map