Merge branch 'fix/menu-position' into 'develop'

fix: Prevent menu from overflowing off screen

Co-authored-by: Lhcfl <Lhcfl@outlook.com>

See merge request firefish/firefish!10885
This commit is contained in:
naskya 2024-05-21 14:38:19 +00:00
commit 0cdf8dbcda
4 changed files with 31 additions and 3 deletions

View file

@ -12,7 +12,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { nextTick, onMounted, ref } from "vue"; import { nextTick, onMounted, ref, watch } from "vue";
import MkMenu from "./MkMenu.vue"; import MkMenu from "./MkMenu.vue";
import type { MenuItem } from "@/types/menu"; import type { MenuItem } from "@/types/menu";
@ -35,7 +35,13 @@ const align = "left";
function setPosition() { function setPosition() {
const rootRect = props.rootElement.getBoundingClientRect(); const rootRect = props.rootElement.getBoundingClientRect();
const rect = props.targetElement.getBoundingClientRect(); const rect = props.targetElement.getBoundingClientRect();
const left = props.targetElement.offsetWidth; let left = props.targetElement.offsetWidth;
if (rootRect.x + left > window.innerWidth - rect.width) {
left = -rect.width;
}
if (rect.x + left < 0) {
left = -rect.x;
}
const top = rect.top - rootRect.top - 8; const top = rect.top - rootRect.top - 8;
el.value!.style.left = `${left}px`; el.value!.style.left = `${left}px`;
el.value!.style.top = `${top}px`; el.value!.style.top = `${top}px`;
@ -56,6 +62,15 @@ onMounted(() => {
}); });
}); });
watch(
() => props.items,
() => {
nextTick(() => {
setPosition();
});
},
);
defineExpose({ defineExpose({
checkHit: (ev: MouseEvent) => { checkHit: (ev: MouseEvent) => {
return ev.target === el.value || el.value?.contains(ev.target as Node); return ev.target === el.value || el.value?.contains(ev.target as Node);

View file

@ -250,7 +250,7 @@ const align = () => {
if (props.anchor.x === "center") { if (props.anchor.x === "center") {
left = x + props.src.offsetWidth / 2 - width / 2; left = x + props.src.offsetWidth / 2 - width / 2;
} else if (props.anchor.x === "left") { } else if (props.anchor.x === "left") {
// TODO left = x + props.src.offsetWidth - width;
} else if (props.anchor.x === "right") { } else if (props.anchor.x === "right") {
left = x + props.src.offsetWidth; left = x + props.src.offsetWidth;
} }
@ -317,6 +317,9 @@ const align = () => {
top = MARGIN; top = MARGIN;
} }
if (left > window.innerWidth - width - MARGIN) {
left = window.innerWidth - width - MARGIN;
}
if (left < 0) { if (left < 0) {
left = 0; left = 0;
} }

View file

@ -5,6 +5,7 @@
:z-priority="'high'" :z-priority="'high'"
:src="src" :src="src"
:transparent-bg="true" :transparent-bg="true"
:anchor
tabindex="-1" tabindex="-1"
@click="modal?.close()" @click="modal?.close()"
@closed="emit('closed')" @closed="emit('closed')"
@ -36,6 +37,10 @@ defineProps<{
width?: number; width?: number;
viaKeyboard?: boolean; viaKeyboard?: boolean;
src?: HTMLElement | null; src?: HTMLElement | null;
anchor?: {
x: "left" | "center" | "right";
y: "top" | "center" | "bottom";
};
noReturnFocus?; noReturnFocus?;
}>(); }>();

View file

@ -916,6 +916,10 @@ export function popupMenu(
width?: number; width?: number;
viaKeyboard?: boolean; viaKeyboard?: boolean;
noReturnFocus?: boolean; noReturnFocus?: boolean;
anchor?: {
x: "left" | "center" | "right";
y: "top" | "center" | "bottom";
};
}, },
) { ) {
return new Promise<void>((resolve, _reject) => { return new Promise<void>((resolve, _reject) => {
@ -929,6 +933,7 @@ export function popupMenu(
{ {
items, items,
src, src,
anchor: options?.anchor,
width: options?.width, width: options?.width,
align: options?.align, align: options?.align,
viaKeyboard: options?.viaKeyboard, viaKeyboard: options?.viaKeyboard,