fix(context-menu): render submenu based on viewport constraints #577

This commit is contained in:
Eric Y Liu 2021-04-02 13:23:01 -07:00
commit 6dbbe7a2f0
2 changed files with 27 additions and 3 deletions

View file

@ -26,6 +26,7 @@
const position = writable([x, y]);
const currentIndex = writable(-1);
const hasPopup = writable(false);
const menuOffsetX = writable(0);
const ctx = getContext("ContextMenu");
let options = [];
@ -44,6 +45,7 @@
}
setContext("ContextMenu", {
menuOffsetX,
currentIndex,
position,
close,
@ -77,9 +79,19 @@
<svelte:window
on:contextmenu|preventDefault="{(e) => {
if (level > 1) return;
if (open || x === 0) x = e.x;
const { height, width } = ref.getBoundingClientRect();
if (open || x === 0) {
if (window.innerWidth - width < e.x) {
x = e.x - width;
} else {
x = e.x;
}
}
if (open || y === 0) {
const { height } = ref.getBoundingClientRect();
menuOffsetX.set(e.x);
if (window.innerHeight - height < e.y) {
y = e.y - height;

View file

@ -70,11 +70,16 @@
let role = "menuitem";
let submenuOpen = false;
let submenuPosition = [0, 0];
let menuOffsetX = 0;
const unsubPosition = ctx.position.subscribe((position) => {
rootMenuPosition = position;
});
const unsubMenuOffsetX = ctx.menuOffsetX.subscribe((_menuOffsetX) => {
menuOffsetX = _menuOffsetX;
});
function handleClick(opts = {}) {
if (disabled) return ctx.close();
if (subOptions) return;
@ -112,6 +117,7 @@
return () => {
unsubPosition();
unsubMenuOffsetX();
if (unsubCurrentIds) unsubCurrentIds();
if (unsubCurrentId) unsubCurrentId();
if (typeof timeoutHover === "number") clearTimeout(timeoutHover);
@ -124,7 +130,13 @@
$: ctx.setPopup(submenuOpen);
$: if (submenuOpen) {
const { width, y } = ref.getBoundingClientRect();
submenuPosition = [rootMenuPosition[0] + width, y];
let x = rootMenuPosition[0] + width;
if (window.innerWidth - menuOffsetX < width) {
x = rootMenuPosition[0] - width;
}
submenuPosition = [x, y];
}
$: {
if (isSelectable) {