react-aim-menu
Version:
A React version of Amazon's jQuery-menu-aim plugin
255 lines (236 loc) • 9.82 kB
JavaScript
import {jsx as $jp1wC$jsx} from "react/jsx-runtime";
import $jp1wC$react, {useState as $jp1wC$useState, useContext as $jp1wC$useContext, useEffect as $jp1wC$useEffect, createContext as $jp1wC$createContext, forwardRef as $jp1wC$forwardRef, useRef as $jp1wC$useRef, useMemo as $jp1wC$useMemo} from "react";
function $03683a42a6c08b9c$export$567fc7097e064344() {
return '_' + Math.random().toString(36).substr(2, 9);
}
const $03683a42a6c08b9c$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 $03683a42a6c08b9c$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 $03683a42a6c08b9c$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 $03683a42a6c08b9c$export$20fc610e43966a58 = function(triangle, point) {
const { A: A , B: B , C: C } = triangle;
return $03683a42a6c08b9c$var$checkSameSide($03683a42a6c08b9c$var$toEdge(A, B), C, point) && $03683a42a6c08b9c$var$checkSameSide($03683a42a6c08b9c$var$toEdge(A, C), B, point) && $03683a42a6c08b9c$var$checkSameSide($03683a42a6c08b9c$var$toEdge(B, C), A, point);
};
const $03683a42a6c08b9c$var$checkSameSide = function(edge, point1, point2) {
return $03683a42a6c08b9c$var$getPolarity(edge, point1) === $03683a42a6c08b9c$var$getPolarity(edge, point2);
};
const $03683a42a6c08b9c$var$getPolarity = function(edge, point) {
const vectorA = $03683a42a6c08b9c$var$toVector(edge.v1, edge.v2);
const vectorB = $03683a42a6c08b9c$var$toVector(edge.v1, point);
const scalar = vectorA.x * vectorB.y - vectorA.y * vectorB.x;
return scalar >= 0 ? 1 : -1;
};
const $03683a42a6c08b9c$var$toEdge = function(pointA, pointB) {
return {
v1: {
...pointA
},
v2: {
...pointB
}
};
};
const $03683a42a6c08b9c$var$toVector = function(pointA, pointB) {
return {
x: pointB.x - pointA.x,
y: pointB.y - pointA.y
};
};
function $8198c3a472ced9dd$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 $8198c3a472ced9dd$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 $jp1wC$useMemo(()=>{
if (refA == null && refB == null) return null;
return (refValue)=>{
$8198c3a472ced9dd$var$setRef(refA, refValue);
$8198c3a472ced9dd$var$setRef(refB, refValue);
};
}, [
refA,
refB
]);
}
const $2bfe47a3fcaebb7f$var$state = {
pendingExpand: {
item: null,
timeoutId: null
},
mouseHistory: []
};
function $2bfe47a3fcaebb7f$var$clearPendingExpand() {
if ($2bfe47a3fcaebb7f$var$state.pendingExpand && $2bfe47a3fcaebb7f$var$state.pendingExpand.timeoutId) clearTimeout($2bfe47a3fcaebb7f$var$state.pendingExpand.timeoutId);
$2bfe47a3fcaebb7f$var$state.pendingExpand = null;
}
function $2bfe47a3fcaebb7f$var$checkAim(menuElem) {
if ($2bfe47a3fcaebb7f$var$state.mouseHistory.length < 2) return false;
const currentPosition = $2bfe47a3fcaebb7f$var$state.mouseHistory[$2bfe47a3fcaebb7f$var$state.mouseHistory.length - 1];
const prevPosition = $2bfe47a3fcaebb7f$var$state.mouseHistory[0];
const menuBox = $03683a42a6c08b9c$export$c32a249941905394(menuElem);
const triangle = $03683a42a6c08b9c$export$534bdd1067f4ef34(menuBox, prevPosition);
return $03683a42a6c08b9c$export$20fc610e43966a58(triangle, currentPosition);
}
const $2bfe47a3fcaebb7f$var$defaultState = {
};
const $2bfe47a3fcaebb7f$var$DEFAULT_HOVER_DELAY = 450;
const $2bfe47a3fcaebb7f$var$MOUSE_HISTORY_SIZE = 3;
const $2bfe47a3fcaebb7f$export$c7e742effb1c51e2 = /*#__PURE__*/ $jp1wC$createContext($2bfe47a3fcaebb7f$var$defaultState);
const $2bfe47a3fcaebb7f$var$Menu = /*#__PURE__*/ $jp1wC$forwardRef(function Menu({ hoverDelay: hoverDelay = $2bfe47a3fcaebb7f$var$DEFAULT_HOVER_DELAY , ...props }, ref) {
const menuRef = $jp1wC$useRef(null);
const forkedRef = $8198c3a472ced9dd$export$ebc1e1560c2dffa5(ref, menuRef);
const [expandedItem, setExpandedItem] = $jp1wC$useState(null);
function updateExpand() {
if (!$2bfe47a3fcaebb7f$var$state.pendingExpand || expandedItem === $2bfe47a3fcaebb7f$var$state.pendingExpand.item) return;
setExpandedItem($2bfe47a3fcaebb7f$var$state.pendingExpand.item);
$2bfe47a3fcaebb7f$var$state.mouseHistory = [];
$2bfe47a3fcaebb7f$var$clearPendingExpand();
}
function onItemEnter(item) {
$2bfe47a3fcaebb7f$var$clearPendingExpand();
$2bfe47a3fcaebb7f$var$state.pendingExpand = {
item: item
};
if (!expandedItem || !$2bfe47a3fcaebb7f$var$checkAim(menuRef.current)) return updateExpand();
$2bfe47a3fcaebb7f$var$state.pendingExpand.timeoutId = setTimeout(()=>updateExpand()
, hoverDelay);
}
function onItemLeave() {
$2bfe47a3fcaebb7f$var$state.pendingExpand = {
item: null,
timeoutId: setTimeout(()=>updateExpand()
, hoverDelay + 100)
};
}
function onMouseMove(event) {
props.onMouseMove && props.onMouseMove(event);
$2bfe47a3fcaebb7f$var$state.mouseHistory.push($03683a42a6c08b9c$export$642213d516a9b928(event.nativeEvent));
if ($2bfe47a3fcaebb7f$var$state.mouseHistory.length > $2bfe47a3fcaebb7f$var$MOUSE_HISTORY_SIZE) $2bfe47a3fcaebb7f$var$state.mouseHistory.shift();
}
function handleMenuLeave(event) {
props.onMouseLeave && props.onMouseLeave(event);
$2bfe47a3fcaebb7f$var$clearPendingExpand();
setExpandedItem(null);
}
return(/*#__PURE__*/ $jp1wC$jsx($2bfe47a3fcaebb7f$export$c7e742effb1c51e2.Provider, {
value: {
onItemEnter: onItemEnter,
onItemLeave: onItemLeave,
expandedItem: expandedItem
},
children: /*#__PURE__*/ $jp1wC$jsx("div", {
...props,
ref: forkedRef,
onMouseLeave: handleMenuLeave,
onMouseMove: onMouseMove,
children: props.children
})
}));
});
var $2bfe47a3fcaebb7f$export$2e2bcd8739ae039 = $2bfe47a3fcaebb7f$var$Menu;
const $d070a06810ab4d73$var$MenuItem = /*#__PURE__*/ $jp1wC$react.forwardRef(function MenuItem({ onHover: onHover , onLeave: onLeave , ...props }, ref) {
const [id, setId] = $jp1wC$useState(null);
const [expanded, setExpanded] = $jp1wC$useState(false);
const menu = $jp1wC$useContext($2bfe47a3fcaebb7f$export$c7e742effb1c51e2);
$jp1wC$useEffect(()=>{
setId($03683a42a6c08b9c$export$567fc7097e064344());
}, []);
$jp1wC$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__*/ $jp1wC$jsx("div", {
...props,
ref: ref,
onMouseEnter: handleMouseEnter,
onMouseLeave: handleMouseLeave,
children: props.children
}));
});
var $d070a06810ab4d73$export$2e2bcd8739ae039 = $d070a06810ab4d73$var$MenuItem;
export {$d070a06810ab4d73$export$2e2bcd8739ae039 as MenuItem, $2bfe47a3fcaebb7f$export$2e2bcd8739ae039 as Menu};
//# sourceMappingURL=module.js.map