UNPKG

@razorpay/blade

Version:

The Design System that powers Razorpay

179 lines (174 loc) 6.34 kB
import _slicedToArray from '@babel/runtime/helpers/slicedToArray'; import React__default from 'react'; import { useFloatingTree, useFloatingNodeId, useFloatingParentNodeId, useListItem, useFloating, offset, flip, shift, size, autoUpdate, useHover, safePolygon, useClick, useRole, useDismiss, useListNavigation, useInteractions, useTransitionStyles } from '@floating-ui/react'; import { useControllableState } from '../../utils/useControllable.js'; import { OVERLAY_OFFSET, OVERLAY_TRANSITION_OFFSET } from '../BaseMenu/tokens.js'; import '../../utils/index.js'; import useTheme from '../BladeProvider/useTheme.js'; import { makeSize } from '../../utils/makeSize/makeSize.js'; var MenuContext = /*#__PURE__*/React__default.createContext({ getItemProps: function getItemProps() { return {}; }, // eslint-disable-next-line @typescript-eslint/no-empty-function setHasFocusInside: function setHasFocusInside() {}, isOpen: false }); var useMenu = function useMenu() { var contextValue = React__default.useContext(MenuContext); return contextValue; }; var useFloatingMenuSetup = function useFloatingMenuSetup(_ref) { var elementsRef = _ref.elementsRef, openInteraction = _ref.openInteraction, onOpenChange = _ref.onOpenChange, isOpen = _ref.isOpen; var _useControllableState = useControllableState({ value: isOpen, defaultValue: false, onChange: function onChange(isOpen) { return onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange({ isOpen: isOpen }); } }), _useControllableState2 = _slicedToArray(_useControllableState, 2), isControllableOpen = _useControllableState2[0], setIsControllableOpen = _useControllableState2[1]; var _React$useState = React__default.useState(null), _React$useState2 = _slicedToArray(_React$useState, 2), activeIndex = _React$useState2[0], setActiveIndex = _React$useState2[1]; var tree = useFloatingTree(); var nodeId = useFloatingNodeId(); var parentId = useFloatingParentNodeId(); var item = useListItem(); var _useTheme = useTheme(), theme = _useTheme.theme; var isNested = parentId != null; var _useFloating = useFloating({ nodeId: nodeId, open: isControllableOpen, onOpenChange: function onOpenChange(_isOpen) { return setIsControllableOpen(function () { return _isOpen; }); }, placement: isNested ? 'right-start' : 'bottom-start', middleware: [offset({ mainAxis: isNested ? 12 : OVERLAY_OFFSET, alignmentAxis: isNested ? -16 : 0 }), flip(), shift(), size({ apply: function apply(_ref2) { var availableHeight = _ref2.availableHeight, elements = _ref2.elements; elements.floating.style.maxHeight = "".concat(availableHeight, "px"); } })], whileElementsMounted: autoUpdate }), floatingStyles = _useFloating.floatingStyles, refs = _useFloating.refs, context = _useFloating.context; var hover = useHover(context, { enabled: isNested || openInteraction === 'hover', delay: { open: 75 }, handleClose: safePolygon({ blockPointerEvents: true }) }); var click = useClick(context, { event: 'mousedown', toggle: !isNested, ignoreMouse: isNested }); var role = useRole(context, { role: 'menu' }); var dismiss = useDismiss(context, { bubbles: true }); var listNavigation = useListNavigation(context, { listRef: elementsRef, activeIndex: activeIndex, nested: isNested, onNavigate: setActiveIndex, focusItemOnHover: false }); var _useInteractions = useInteractions([hover, click, role, dismiss, listNavigation]), getReferenceProps = _useInteractions.getReferenceProps, getFloatingProps = _useInteractions.getFloatingProps, getItemProps = _useInteractions.getItemProps; var _useTransitionStyles = useTransitionStyles(context, { duration: theme.motion.duration.quick, initial: function initial(_ref3) { var side = _ref3.side; var transitionOffset = makeSize(OVERLAY_TRANSITION_OFFSET); var transformMap = { top: "translateY(".concat(transitionOffset, ")"), right: "translateX(-".concat(transitionOffset, ")"), left: "translateX(".concat(transitionOffset, ")"), bottom: "translateY(-".concat(transitionOffset, ")") }; return { transform: transformMap[side !== null && side !== void 0 ? side : 'bottom'], opacity: 0 }; } }), isMounted = _useTransitionStyles.isMounted, floatingTransitionStyles = _useTransitionStyles.styles; // Event emitter allows you to communicate across tree components. // This effect closes all menus when an item gets clicked anywhere // in the tree. React__default.useEffect(function () { if (!tree) return; var handleTreeClick = function handleTreeClick() { setIsControllableOpen(function () { return false; }); }; var onSubMenuOpen = function onSubMenuOpen(event) { if (event.nodeId !== nodeId && event.parentId === parentId) { setIsControllableOpen(function () { return false; }); } }; tree.events.on('click', handleTreeClick); tree.events.on('menuopen', onSubMenuOpen); // eslint-disable-next-line consistent-return return function () { // Cleanup tree.events.off('click', handleTreeClick); tree.events.off('menuopen', onSubMenuOpen); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [tree, nodeId, parentId]); React__default.useEffect(function () { if (isOpen && tree) { tree.events.emit('menuopen', { parentId: parentId, nodeId: nodeId }); } }, [tree, isOpen, nodeId, parentId]); return { getReferenceProps: getReferenceProps, getFloatingProps: getFloatingProps, getItemProps: getItemProps, item: item, context: context, nodeId: nodeId, isOpen: isControllableOpen, floatingStyles: floatingStyles, refs: refs, isNested: isNested, isMounted: isMounted, floatingTransitionStyles: floatingTransitionStyles }; }; export { MenuContext, useFloatingMenuSetup, useMenu }; //# sourceMappingURL=useMenu.js.map