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

View file

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