diff --git a/android/app/capacitor.build.gradle b/android/app/capacitor.build.gradle
index 7cf73370b..fe7e5d776 100644
--- a/android/app/capacitor.build.gradle
+++ b/android/app/capacitor.build.gradle
@@ -13,11 +13,12 @@ dependencies {
implementation project(':capacitor-clipboard')
implementation project(':capacitor-device')
implementation project(':capacitor-filesystem')
+ implementation project(':capacitor-keyboard')
implementation project(':capacitor-screen-orientation')
implementation project(':capacitor-splash-screen')
-
}
+
if (hasProperty('postBuildExtras')) {
postBuildExtras()
}
diff --git a/android/capacitor.settings.gradle b/android/capacitor.settings.gradle
index 9dd1d9112..7ca103cf7 100644
--- a/android/capacitor.settings.gradle
+++ b/android/capacitor.settings.gradle
@@ -14,6 +14,9 @@ project(':capacitor-device').projectDir = new File('../node_modules/@capacitor/d
include ':capacitor-filesystem'
project(':capacitor-filesystem').projectDir = new File('../node_modules/@capacitor/filesystem/android')
+include ':capacitor-keyboard'
+project(':capacitor-keyboard').projectDir = new File('../node_modules/@capacitor/keyboard/android')
+
include ':capacitor-screen-orientation'
project(':capacitor-screen-orientation').projectDir = new File('../node_modules/@capacitor/screen-orientation/android')
diff --git a/ios/App/Podfile b/ios/App/Podfile
index 388474730..9876b9ace 100644
--- a/ios/App/Podfile
+++ b/ios/App/Podfile
@@ -15,6 +15,7 @@ def capacitor_pods
pod 'CapacitorClipboard', :path => '../../node_modules/@capacitor/clipboard'
pod 'CapacitorDevice', :path => '../../node_modules/@capacitor/device'
pod 'CapacitorFilesystem', :path => '../../node_modules/@capacitor/filesystem'
+ pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard'
pod 'CapacitorScreenOrientation', :path => '../../node_modules/@capacitor/screen-orientation'
pod 'CapacitorSplashScreen', :path => '../../node_modules/@capacitor/splash-screen'
end
diff --git a/ios/App/Podfile.lock b/ios/App/Podfile.lock
index 5d67c18b0..d926ffb28 100644
--- a/ios/App/Podfile.lock
+++ b/ios/App/Podfile.lock
@@ -10,9 +10,11 @@ PODS:
- Capacitor
- CapacitorFilesystem (6.0.2):
- Capacitor
+ - CapacitorKeyboard (6.0.3):
+ - Capacitor
- CapacitorScreenOrientation (6.0.3):
- Capacitor
- - CapacitorSplashScreen (6.0.3):
+ - CapacitorSplashScreen (6.0.2):
- Capacitor
DEPENDENCIES:
@@ -22,6 +24,7 @@ DEPENDENCIES:
- "CapacitorCordova (from `../../node_modules/@capacitor/ios`)"
- "CapacitorDevice (from `../../node_modules/@capacitor/device`)"
- "CapacitorFilesystem (from `../../node_modules/@capacitor/filesystem`)"
+ - "CapacitorKeyboard (from `../../node_modules/@capacitor/keyboard`)"
- "CapacitorScreenOrientation (from `../../node_modules/@capacitor/screen-orientation`)"
- "CapacitorSplashScreen (from `../../node_modules/@capacitor/splash-screen`)"
@@ -38,6 +41,8 @@ EXTERNAL SOURCES:
:path: "../../node_modules/@capacitor/device"
CapacitorFilesystem:
:path: "../../node_modules/@capacitor/filesystem"
+ CapacitorKeyboard:
+ :path: "../../node_modules/@capacitor/keyboard"
CapacitorScreenOrientation:
:path: "../../node_modules/@capacitor/screen-orientation"
CapacitorSplashScreen:
@@ -50,9 +55,10 @@ SPEC CHECKSUMS:
CapacitorCordova: b33e7f4aa4ed105dd43283acdd940964374a87d9
CapacitorDevice: 1a215717f0b5061503b21a03508b0ec458a57d78
CapacitorFilesystem: c832a3f6d4870c3872688e782ae8e33665e6ecbf
+ CapacitorKeyboard: 460c6f9ec5e52c84f2742d5ce2e67bbc7ab0ebb0
CapacitorScreenOrientation: 3bb823f5d265190301cdc5d58a568a287d98972a
- CapacitorSplashScreen: 68893659d77b5f82d753b3a70475082845e3039c
+ CapacitorSplashScreen: 250df9ef8014fac5c7c1fd231f0f8b1d8f0b5624
-PODFILE CHECKSUM: 80366870d5c5081f271e0ddeab86b283217ebd9d
+PODFILE CHECKSUM: 0bfaa008b5f31bb57606a8c6259197a6af507ba4
-COCOAPODS: 1.16.1
+COCOAPODS: 1.16.2
diff --git a/package.json b/package.json
index 99a349d8f..9b4209a8e 100644
--- a/package.json
+++ b/package.json
@@ -42,6 +42,7 @@
"@capacitor/device": "^6.0.2",
"@capacitor/filesystem": "^6.0.1",
"@capacitor/ios": "^6.2.0",
+ "@capacitor/keyboard": "^6.0.3",
"@capacitor/screen-orientation": "^6.0.3",
"@capacitor/splash-screen": "^6.0.2",
"@dicebear/collection": "^9.0.1",
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)
+ })
-