diff --git a/src/lib/components/ui/ContextMenu.svelte b/src/lib/components/ui/ContextMenu.svelte
index 2c6d4e833..998aafebd 100644
--- a/src/lib/components/ui/ContextMenu.svelte
+++ b/src/lib/components/ui/ContextMenu.svelte
@@ -9,12 +9,14 @@
import { clickoutside } from "@svelte-put/clickoutside"
import { Appearance } from "$lib/enums"
import type { ContextItem } from "$lib/types"
- import { createEventDispatcher, tick } from "svelte"
+ import { createEventDispatcher, onDestroy, onMount, tick } from "svelte"
import { log } from "$lib/utils/Logger"
let visible: boolean = false
let coords: [number, number] = [0, 0]
let context: HTMLElement
+ let touchTimeout: number | undefined
+ let slotContainer: HTMLElement
export let items: ContextItem[] = []
export let hook: string = ""
@@ -25,38 +27,89 @@
close_context = undefined
}
- function calculatePos(evt: MouseEvent): [number, number] {
- if (context === undefined) return [evt.clientX, evt.clientY]
+ function calculatePos(evt: MouseEvent | TouchEvent): [number, number] {
+ if (!context) {
+ if (evt instanceof MouseEvent) {
+ return [evt.clientX, evt.clientY]
+ } else if (evt instanceof TouchEvent) {
+ const touch = evt.touches[0]
+ return [touch.clientX, touch.clientY]
+ }
+ return [0, 0]
+ }
+
const { width, height } = context.getBoundingClientRect()
- let offsetX = evt.pageX
- let offsetY = evt.pageY
- let screenWidth = evt.view!.innerWidth
- let screenHeight = evt.view!.innerHeight
- let overFlowX = screenWidth < width + offsetX
- let overFlowY = screenHeight < height + offsetY
- let topX = overFlowX ? Math.max(5, screenWidth - width - 5) : Math.max(5, offsetX)
- if (screenHeight - offsetY < height + 30) {
- let adjustedY = offsetY - height
- let topY = Math.max(5, adjustedY)
- return [topX, topY]
+
+ let offsetX: number, offsetY: number, screenWidth: number, screenHeight: number
+
+ if (evt instanceof MouseEvent) {
+ offsetX = evt.pageX
+ offsetY = evt.pageY
+ screenWidth = evt.view!.innerWidth
+ screenHeight = evt.view!.innerHeight
+ } else if (evt instanceof TouchEvent) {
+ const touch = evt.touches[0]
+ const targetElement = touch.target as HTMLElement
+
+ const doc = targetElement.ownerDocument!
+ const win = doc.defaultView!
+
+ offsetX = touch.pageX
+ offsetY = touch.pageY
+ screenWidth = win.innerWidth
+ screenHeight = win.innerHeight
} else {
- let topY = Math.max(5, overFlowY ? offsetY - height : offsetY)
- return [topX, topY]
+ return [0, 0]
}
+
+ // Calculate overflow
+ const overFlowX = screenWidth < width + offsetX
+ const overFlowY = screenHeight < height + offsetY
+
+ // Adjust X position
+ const topX = overFlowX ? Math.max(5, screenWidth - width - 5) : Math.max(5, offsetX)
+
+ // Adjust Y position
+ const topY = screenHeight - offsetY < height + 30 ? Math.max(5, offsetY - height) : Math.max(5, overFlowY ? offsetY - height : offsetY)
+
+ return [topX, topY]
}
- async function openContext(evt: MouseEvent) {
+ async function openContext(evt: MouseEvent | TouchEvent) {
if (close_context !== undefined) {
close_context()
}
close_context = () => (visible = false)
+
evt.preventDefault()
visible = true
- coords = [evt.clientX, evt.clientY]
+
+ if (evt instanceof MouseEvent) {
+ coords = [evt.clientX, evt.clientY]
+ } else if (evt instanceof TouchEvent) {
+ const touch = evt.touches[0]
+ coords = [touch.clientX, touch.clientY]
+ }
+
await tick()
coords = calculatePos(evt)
}
+ function handleTouchStart(evt: TouchEvent) {
+ document.body.style.userSelect = "none"
+
+ touchTimeout = window.setTimeout(() => {
+ openContext(evt)
+ }, 350)
+ }
+
+ function handleTouchEnd() {
+ if (touchTimeout !== undefined) {
+ clearTimeout(touchTimeout)
+ touchTimeout = undefined
+ }
+ }
+
function handleItemClick(e: MouseEvent, item: ContextItem) {
e.stopPropagation()
log.info(`Clicked ${item.text}`)
@@ -66,9 +119,22 @@
})
onClose(customEvent)
}
+
+ onMount(() => {
+ // Add event listeners for mobile
+ slotContainer.addEventListener("touchstart", handleTouchStart)
+ slotContainer.addEventListener("touchend", handleTouchEnd)
+ })
+
+ onDestroy(() => {
+ slotContainer.removeEventListener("touchstart", handleTouchStart)
+ slotContainer.removeEventListener("touchend", handleTouchEnd)
+ })
-