Files
notesnook/packages/editor/dist/components/menu/menu.js
thecodrr 7ae6590350 updates
2022-04-17 07:22:15 +05:00

235 lines
11 KiB
JavaScript

var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { useCallback, useRef, useEffect, useState, } from "react";
import { Box, Flex, Text } from "rebass";
import { getPosition } from "./useMenu";
// import { FlexScrollContainer } from "../scrollcontainer";
import MenuItem from "./menuitem";
// import { useMenuTrigger, useMenu, getPosition } from "../../hooks/useMenu";
import Modal from "react-modal";
// import { store as selectionStore } from "../../stores/selectionstore";
function useMenuFocus(items, onAction, onClose) {
var _a = useState(-1), focusIndex = _a[0], setFocusIndex = _a[1];
var _b = useState(false), isSubmenuOpen = _b[0], setIsSubmenuOpen = _b[1];
var moveItemIntoView = useCallback(function (index) {
var item = items[index];
if (!item)
return;
var element = document.getElementById(item.key);
if (!element)
return;
element.scrollIntoView({
behavior: "auto",
});
}, [items]);
var onKeyDown = useCallback(function (e) {
var isSeperator = function (i) { var _a, _b; return items && (((_a = items[i]) === null || _a === void 0 ? void 0 : _a.type) === "seperator" || ((_b = items[i]) === null || _b === void 0 ? void 0 : _b.isDisabled)); };
var moveDown = function (i) { return (i < items.length - 1 ? ++i : 0); };
var moveUp = function (i) { return (i > 0 ? --i : items.length - 1); };
var hasSubmenu = function (i) { var _a; return items && ((_a = items[i]) === null || _a === void 0 ? void 0 : _a.hasSubmenu); };
var openSubmenu = function (index) {
if (!hasSubmenu(index))
return;
setIsSubmenuOpen(true);
};
var closeSubmenu = function (index) {
if (!hasSubmenu(index))
return;
setIsSubmenuOpen(false);
};
setFocusIndex(function (i) {
var nextIndex = i;
switch (e.key) {
case "ArrowUp":
if (isSubmenuOpen)
break;
nextIndex = moveUp(i);
while (isSeperator(nextIndex)) {
nextIndex = moveUp(nextIndex);
}
break;
case "ArrowDown":
if (isSubmenuOpen)
break;
nextIndex = moveDown(i);
while (isSeperator(nextIndex)) {
nextIndex = moveDown(nextIndex);
}
break;
case "ArrowRight":
openSubmenu(i);
break;
case "ArrowLeft":
closeSubmenu(i);
break;
case "Enter":
onAction && onAction(e);
break;
case "Escape":
onClose && onClose(e);
break;
default:
break;
}
if (nextIndex !== i)
moveItemIntoView(nextIndex);
return nextIndex;
});
}, [items, isSubmenuOpen, moveItemIntoView, onAction]);
useEffect(function () {
window.addEventListener("keydown", onKeyDown);
return function () {
window.removeEventListener("keydown", onKeyDown);
};
}, [onKeyDown]);
return { focusIndex: focusIndex, setFocusIndex: setFocusIndex, isSubmenuOpen: isSubmenuOpen, setIsSubmenuOpen: setIsSubmenuOpen };
}
export function Menu(props) {
var _a;
var items = props.items, title = props.title, closeMenu = props.closeMenu, containerProps = __rest(props, ["items", "title", "closeMenu"]);
var hoverTimeout = useRef();
var onAction = useCallback(function (e, item) {
e.stopPropagation();
if (closeMenu)
closeMenu();
if (item.onClick) {
item.onClick();
}
}, [closeMenu]);
var _b = useMenuFocus(items, function (e) {
var item = items[focusIndex];
if (item)
onAction(e, item);
}, function () { return closeMenu(); }), focusIndex = _b.focusIndex, setFocusIndex = _b.setFocusIndex, isSubmenuOpen = _b.isSubmenuOpen, setIsSubmenuOpen = _b.setIsSubmenuOpen;
var subMenuRef = useRef(null);
useEffect(function () {
var item = items[focusIndex];
if (!item || !subMenuRef.current)
return;
var menuItemElement = document.getElementById(item.key);
if (!menuItemElement)
return;
if (!isSubmenuOpen) {
subMenuRef.current.style.visibility = "hidden";
return;
}
var _a = getPosition(subMenuRef.current, {
yOffset: menuItemElement.offsetHeight,
target: menuItemElement,
location: "right",
}), top = _a.top, left = _a.left;
subMenuRef.current.style.visibility = "visible";
subMenuRef.current.style.top = "".concat(top, "px");
subMenuRef.current.style.left = "".concat(left, "px");
}, [isSubmenuOpen, focusIndex, items]);
return (_jsxs(_Fragment, { children: [_jsx(MenuContainer, __assign({}, containerProps, { children: items.map(function (item, index) { return (_jsx(MenuItem, { item: item, onClick: function (e) {
var _a;
if ((_a = item.items) === null || _a === void 0 ? void 0 : _a.length) {
setFocusIndex(index);
setIsSubmenuOpen(true);
}
else
onAction(e, item);
}, isFocused: focusIndex === index, onMouseEnter: function () {
var _a;
if (item.isDisabled) {
setFocusIndex(-1);
return;
}
if (hoverTimeout.current)
clearTimeout(hoverTimeout.current);
setFocusIndex(index);
setIsSubmenuOpen(false);
if ((_a = item.items) === null || _a === void 0 ? void 0 : _a.length) {
hoverTimeout.current = setTimeout(function () {
setIsSubmenuOpen(true);
}, 500);
}
}, onMouseLeave: function () {
if (hoverTimeout.current)
clearTimeout(hoverTimeout.current);
} }, item.key)); }) })), isSubmenuOpen && (_jsx(Flex, __assign({ ref: subMenuRef, style: { visibility: "hidden" }, sx: {
position: "absolute",
} }, { children: _jsx(Menu, { items: ((_a = items[focusIndex]) === null || _a === void 0 ? void 0 : _a.items) || [], closeMenu: closeMenu }) })))] }));
}
function MenuContainer(props) {
var children = props.children, title = props.title, sx = props.sx, flexProps = __rest(props, ["children", "title", "sx"]);
return (_jsxs(Box, __assign({ className: "menuContainer", as: "ul", tabIndex: -1, sx: __assign({ bg: "background", py: 1, display: "flex", flexDirection: "column", position: "relative", listStyle: "none", padding: 0, margin: 0, borderRadius: "default", boxShadow: "menu", border: "1px solid var(--border)", width: 220 }, sx) }, flexProps, { children: [title && (_jsx(Text, __assign({ sx: {
fontFamily: "body",
fontSize: "subtitle",
color: "primary",
py: "8px",
px: 3,
borderBottom: "1px solid",
borderBottomColor: "border",
wordWrap: "break-word",
} }, { children: title }))), children] })));
}
export function MenuPresenter(props) {
var className = props.className, options = props.options, items = props.items, isOpen = props.isOpen, onClose = props.onClose, children = props.children, containerProps = __rest(props, ["className", "options", "items", "isOpen", "onClose", "children"]);
// const { isOpen, closeMenu } = useMenuTrigger();
// const { items, } = useMenu();
var position = options.position, type = options.type;
var isAutocomplete = type === "autocomplete";
var contentRef = useRef();
useEffect(function () {
if (!contentRef.current || !position)
return;
var menu = contentRef.current;
var menuPosition = getPosition(menu, position);
menu.style.top = menuPosition.top + "px";
menu.style.left = menuPosition.left + "px";
}, [position]);
return (_jsx(Modal, __assign({ contentRef: function (ref) { return (contentRef.current = ref); }, className: className || "menuContainer", role: "menu", isOpen: isOpen, appElement: document.body, shouldCloseOnEsc: true, shouldReturnFocusAfterClose: true, shouldCloseOnOverlayClick: true, shouldFocusAfterRender: !isAutocomplete, ariaHideApp: !isAutocomplete, preventScroll: !isAutocomplete, onRequestClose: onClose, portalClassName: className || "menuPresenter", onAfterOpen: function (obj) {
if (!obj || !position)
return;
var menu = obj.contentEl;
var menuPosition = getPosition(menu, position);
menu.style.top = menuPosition.top + "px";
menu.style.left = menuPosition.left + "px";
}, overlayElement: function (props, contentEl) {
return (_jsx(Box, __assign({}, props, { style: __assign(__assign({}, props.style), { position: isAutocomplete ? "initial" : "fixed", zIndex: 1000, backgroundColor: isAutocomplete ? "transparent" : "unset" }) }, { children: contentEl })));
}, contentElement: function (props, children) { return (_jsx(Box, __assign({}, props, { style: {}, sx: {
top: 0,
left: 0,
right: 0,
bottom: 0,
display: "flex",
width: "fit-content",
height: "fit-content",
position: "absolute",
backgroundColor: undefined,
padding: 0,
zIndex: 0,
outline: 0,
isolation: "isolate",
} }, { children: children }))); }, style: {
content: {},
overlay: {
zIndex: 999,
background: "transparent",
},
} }, { children: props.children ? (props.children) : (_jsx(Menu, __assign({ items: items, closeMenu: onClose }, containerProps))) })));
}