UNPKG

react-aim-menu

Version:

A React version of Amazon's jQuery-menu-aim plugin

263 lines (243 loc) 10 kB
var $gati5$reactjsxruntime = require("react/jsx-runtime"); var $gati5$react = require("react"); function $parcel$export(e, n, v, s) { Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true}); } function $parcel$interopDefault(a) { return a && a.__esModule ? a.default : a; } $parcel$export(module.exports, "MenuItem", () => $d20f2444b9cc1ca0$export$2e2bcd8739ae039); $parcel$export(module.exports, "Menu", () => $d1df290c0e43fda8$export$2e2bcd8739ae039); function $847379c021b3641b$export$567fc7097e064344() { return '_' + Math.random().toString(36).substr(2, 9); } const $847379c021b3641b$export$642213d516a9b928 = function(mouseEvent) { let pos = { x: 0, y: 0 }; if (mouseEvent.pageX || mouseEvent.pageY) pos = { x: mouseEvent.pageX, y: mouseEvent.pageY }; else if (mouseEvent.clientX || mouseEvent.clientY) pos = { x: mouseEvent.clientX + document.body.scrollLeft + document.documentElement.scrollLeft, y: mouseEvent.clientY + document.body.scrollTop + document.documentElement.scrollTop }; return pos; }; const $847379c021b3641b$export$c32a249941905394 = function(elem) { const boundingBox = elem.getBoundingClientRect(); const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft; const scrollTop = window.pageYOffset || document.documentElement.scrollTop; return { topLeft: { x: boundingBox.left + scrollLeft, y: boundingBox.top + scrollTop }, topRight: { x: boundingBox.left + scrollLeft + boundingBox.width, y: boundingBox.top + scrollTop }, bottomLeft: { x: boundingBox.left + scrollLeft, y: boundingBox.top + scrollTop + boundingBox.height }, bottomRight: { x: boundingBox.left + scrollLeft + boundingBox.width, y: boundingBox.top + scrollTop + boundingBox.height } }; }; const $847379c021b3641b$export$534bdd1067f4ef34 = function(menuBox, point, direction = 'right') { if (direction === 'right') { const height = menuBox.bottomRight.y - menuBox.topRight.y; return { A: { x: point.x, y: point.y }, B: { x: menuBox.topRight.x, y: Math.min(0, menuBox.topRight.y - height) }, C: { x: menuBox.bottomRight.x, y: Math.max(window.innerHeight + height, menuBox.bottomRight.y + height) } }; } else if (direction === 'down') return { A: point, B: menuBox.topRight, C: menuBox.bottomRight }; }; const $847379c021b3641b$export$20fc610e43966a58 = function(triangle, point) { const { A: A , B: B , C: C } = triangle; return $847379c021b3641b$var$checkSameSide($847379c021b3641b$var$toEdge(A, B), C, point) && $847379c021b3641b$var$checkSameSide($847379c021b3641b$var$toEdge(A, C), B, point) && $847379c021b3641b$var$checkSameSide($847379c021b3641b$var$toEdge(B, C), A, point); }; const $847379c021b3641b$var$checkSameSide = function(edge, point1, point2) { return $847379c021b3641b$var$getPolarity(edge, point1) === $847379c021b3641b$var$getPolarity(edge, point2); }; const $847379c021b3641b$var$getPolarity = function(edge, point) { const vectorA = $847379c021b3641b$var$toVector(edge.v1, edge.v2); const vectorB = $847379c021b3641b$var$toVector(edge.v1, point); const scalar = vectorA.x * vectorB.y - vectorA.y * vectorB.x; return scalar >= 0 ? 1 : -1; }; const $847379c021b3641b$var$toEdge = function(pointA, pointB) { return { v1: { ...pointA }, v2: { ...pointB } }; }; const $847379c021b3641b$var$toVector = function(pointA, pointB) { return { x: pointB.x - pointA.x, y: pointB.y - pointA.y }; }; function $9bfb57088e8a5943$var$setRef(ref, value) { if (!ref) return; if (typeof ref === 'function') ref(value); else if (ref) ref.current = value; } /** * useForkRef * Joins refs together and returns a combination of the two as a new ref * * @param refA * @param refB */ function $9bfb57088e8a5943$export$ebc1e1560c2dffa5(refA, refB) { /** * This will create a new function if the ref props change and are defined. * This means react will call the old forkRef with `null` and the new forkRef * with the ref. Cleanup naturally emerges from this behavior */ return $gati5$react.useMemo(()=>{ if (refA == null && refB == null) return null; return (refValue)=>{ $9bfb57088e8a5943$var$setRef(refA, refValue); $9bfb57088e8a5943$var$setRef(refB, refValue); }; }, [ refA, refB ]); } const $d1df290c0e43fda8$var$state = { pendingExpand: { item: null, timeoutId: null }, mouseHistory: [] }; function $d1df290c0e43fda8$var$clearPendingExpand() { if ($d1df290c0e43fda8$var$state.pendingExpand && $d1df290c0e43fda8$var$state.pendingExpand.timeoutId) clearTimeout($d1df290c0e43fda8$var$state.pendingExpand.timeoutId); $d1df290c0e43fda8$var$state.pendingExpand = null; } function $d1df290c0e43fda8$var$checkAim(menuElem) { if ($d1df290c0e43fda8$var$state.mouseHistory.length < 2) return false; const currentPosition = $d1df290c0e43fda8$var$state.mouseHistory[$d1df290c0e43fda8$var$state.mouseHistory.length - 1]; const prevPosition = $d1df290c0e43fda8$var$state.mouseHistory[0]; const menuBox = $847379c021b3641b$export$c32a249941905394(menuElem); const triangle = $847379c021b3641b$export$534bdd1067f4ef34(menuBox, prevPosition); return $847379c021b3641b$export$20fc610e43966a58(triangle, currentPosition); } const $d1df290c0e43fda8$var$defaultState = { }; const $d1df290c0e43fda8$var$DEFAULT_HOVER_DELAY = 450; const $d1df290c0e43fda8$var$MOUSE_HISTORY_SIZE = 3; const $d1df290c0e43fda8$export$c7e742effb1c51e2 = /*#__PURE__*/ $gati5$react.createContext($d1df290c0e43fda8$var$defaultState); const $d1df290c0e43fda8$var$Menu = /*#__PURE__*/ $gati5$react.forwardRef(function Menu({ hoverDelay: hoverDelay = $d1df290c0e43fda8$var$DEFAULT_HOVER_DELAY , ...props }, ref) { const menuRef = $gati5$react.useRef(null); const forkedRef = $9bfb57088e8a5943$export$ebc1e1560c2dffa5(ref, menuRef); const [expandedItem, setExpandedItem] = $gati5$react.useState(null); function updateExpand() { if (!$d1df290c0e43fda8$var$state.pendingExpand || expandedItem === $d1df290c0e43fda8$var$state.pendingExpand.item) return; setExpandedItem($d1df290c0e43fda8$var$state.pendingExpand.item); $d1df290c0e43fda8$var$state.mouseHistory = []; $d1df290c0e43fda8$var$clearPendingExpand(); } function onItemEnter(item) { $d1df290c0e43fda8$var$clearPendingExpand(); $d1df290c0e43fda8$var$state.pendingExpand = { item: item }; if (!expandedItem || !$d1df290c0e43fda8$var$checkAim(menuRef.current)) return updateExpand(); $d1df290c0e43fda8$var$state.pendingExpand.timeoutId = setTimeout(()=>updateExpand() , hoverDelay); } function onItemLeave() { $d1df290c0e43fda8$var$state.pendingExpand = { item: null, timeoutId: setTimeout(()=>updateExpand() , hoverDelay + 100) }; } function onMouseMove(event) { props.onMouseMove && props.onMouseMove(event); $d1df290c0e43fda8$var$state.mouseHistory.push($847379c021b3641b$export$642213d516a9b928(event.nativeEvent)); if ($d1df290c0e43fda8$var$state.mouseHistory.length > $d1df290c0e43fda8$var$MOUSE_HISTORY_SIZE) $d1df290c0e43fda8$var$state.mouseHistory.shift(); } function handleMenuLeave(event) { props.onMouseLeave && props.onMouseLeave(event); $d1df290c0e43fda8$var$clearPendingExpand(); setExpandedItem(null); } return(/*#__PURE__*/ $gati5$reactjsxruntime.jsx($d1df290c0e43fda8$export$c7e742effb1c51e2.Provider, { value: { onItemEnter: onItemEnter, onItemLeave: onItemLeave, expandedItem: expandedItem }, children: /*#__PURE__*/ $gati5$reactjsxruntime.jsx("div", { ...props, ref: forkedRef, onMouseLeave: handleMenuLeave, onMouseMove: onMouseMove, children: props.children }) })); }); var $d1df290c0e43fda8$export$2e2bcd8739ae039 = $d1df290c0e43fda8$var$Menu; const $d20f2444b9cc1ca0$var$MenuItem = /*#__PURE__*/ ($parcel$interopDefault($gati5$react)).forwardRef(function MenuItem({ onHover: onHover , onLeave: onLeave , ...props }, ref) { const [id, setId] = $gati5$react.useState(null); const [expanded, setExpanded] = $gati5$react.useState(false); const menu = $gati5$react.useContext($d1df290c0e43fda8$export$c7e742effb1c51e2); $gati5$react.useEffect(()=>{ setId($847379c021b3641b$export$567fc7097e064344()); }, []); $gati5$react.useEffect(()=>{ if (menu.expandedItem && menu.expandedItem === id && !expanded) { setExpanded(true); onHover && onHover(); } if (menu.expandedItem !== id && expanded) { setExpanded(false); onLeave && onLeave(); } }, [ menu.expandedItem ]); function handleMouseEnter(event) { menu.onItemEnter(id); props.onMouseEnter && props.onMouseEnter(event); } function handleMouseLeave(event) { menu.onItemLeave(); props.onMouseLeave && props.onMouseLeave(event); } return(/*#__PURE__*/ $gati5$reactjsxruntime.jsx("div", { ...props, ref: ref, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: props.children })); }); var $d20f2444b9cc1ca0$export$2e2bcd8739ae039 = $d20f2444b9cc1ca0$var$MenuItem; //# sourceMappingURL=index.js.map