Fix trackpad pinch-to-zoom on Safari macOS

This commit is contained in:
Danila Poyarkov 2026-03-01 22:07:47 +03:00
parent 13a95bf517
commit 5e209eca1c
11 changed files with 49 additions and 11 deletions

View file

@ -1,5 +1,11 @@
# Changelog
## 0.2.2 (2026-03-01)
### Bug Fixes
- Fix trackpad pinch-to-zoom on Safari macOS
## 0.2.1 (2026-03-01)
### UI

1
components.d.ts vendored
View file

@ -63,7 +63,6 @@ declare module 'vue' {
IconLucideLink: typeof import('~icons/lucide/link')['default']
IconLucideLoaderCircle: typeof import('~icons/lucide/loader-circle')['default']
IconLucideMessageCircle: typeof import('~icons/lucide/message-circle')['default']
IconLucidePanelLeft: typeof import('~icons/lucide/panel-left')['default']
IconLucidePlus: typeof import('~icons/lucide/plus')['default']
IconLucideRadius: typeof import('~icons/lucide/radius')['default']
IconLucideRotateCcw: typeof import('~icons/lucide/rotate-ccw')['default']

2
desktop/Cargo.lock generated
View file

@ -2466,7 +2466,7 @@ dependencies = [
[[package]]
name = "open_pencil"
version = "0.2.1"
version = "0.2.2"
dependencies = [
"font-kit",
"serde",

View file

@ -1,6 +1,6 @@
[package]
name = "open_pencil"
version = "0.2.1"
version = "0.2.2"
description = "A Tauri App"
authors = ["you"]
edition = "2021"

View file

@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "OpenPencil",
"version": "0.2.1",
"version": "0.2.2",
"identifier": "net.dannote.open-pencil",
"build": {
"beforeDevCommand": "bun run dev",

View file

@ -1,7 +1,7 @@
{
"name": "open-pencil-app",
"private": true,
"version": "0.2.1",
"version": "0.2.2",
"type": "module",
"workspaces": [
"packages/*"

View file

@ -1,6 +1,6 @@
{
"name": "@open-pencil/cli",
"version": "0.2.1",
"version": "0.2.2",
"type": "module",
"bin": {
"open-pencil": "./src/index.ts"

View file

@ -1,6 +1,6 @@
{
"name": "@open-pencil/core",
"version": "0.2.1",
"version": "0.2.2",
"type": "module",
"exports": {
".": {

View file

@ -1047,6 +1047,7 @@ export function useCanvasInput(
}
// Touch support for iOS/mobile: single-finger pan, two-finger pinch-zoom
const isTouchDevice = matchMedia('(pointer: coarse)').matches
let activeTouches: Touch[] = []
let pinchStartDist = 0
let pinchStartZoom = 0
@ -1058,6 +1059,7 @@ export function useCanvasInput(
}
function onTouchStart(e: TouchEvent) {
if (!isTouchDevice) return
e.preventDefault()
activeTouches = Array.from(e.touches)
const canvas = canvasRef.value
@ -1084,6 +1086,7 @@ export function useCanvasInput(
}
function onTouchMove(e: TouchEvent) {
if (!isTouchDevice) return
e.preventDefault()
activeTouches = Array.from(e.touches)
const canvas = canvasRef.value
@ -1122,6 +1125,7 @@ export function useCanvasInput(
}
function onTouchEnd(e: TouchEvent) {
if (!isTouchDevice) return
e.preventDefault()
activeTouches = Array.from(e.touches)
@ -1155,6 +1159,31 @@ export function useCanvasInput(
useEventListener(canvasRef, 'touchend', onTouchEnd, { passive: false })
useEventListener(canvasRef, 'touchcancel', onTouchEnd, { passive: false })
// Safari macOS: trackpad pinch-to-zoom uses gesture events, not wheel+ctrlKey
let gestureStartZoom = 1
useEventListener(canvasRef, 'gesturestart' as keyof HTMLElementEventMap, (e: Event) => {
e.preventDefault()
gestureStartZoom = store.state.zoom
}, { passive: false })
useEventListener(canvasRef, 'gesturechange' as keyof HTMLElementEventMap, (e: Event) => {
e.preventDefault()
const ge = e as GestureEvent
const canvas = canvasRef.value
if (!canvas) return
const rect = canvas.getBoundingClientRect()
const sx = (ge.clientX ?? rect.width / 2) - rect.left
const sy = (ge.clientY ?? rect.height / 2) - rect.top
const newZoom = Math.max(0.02, Math.min(256, gestureStartZoom * ge.scale))
const zoomRatio = newZoom / store.state.zoom
store.state.panX = sx - (sx - store.state.panX) * zoomRatio
store.state.panY = sy - (sy - store.state.panY) * zoomRatio
store.state.zoom = newZoom
store.requestRepaint()
}, { passive: false })
useEventListener(canvasRef, 'gestureend' as keyof HTMLElementEventMap, (e: Event) => {
e.preventDefault()
}, { passive: false })
return {
drag,
cursorOverride

7
src/global.d.ts vendored
View file

@ -1,3 +1,10 @@
interface GestureEvent extends UIEvent {
scale: number
rotation: number
clientX: number
clientY: number
}
interface FilePickerAcceptType {
description: string
accept: Record<string, string[]>

View file

@ -37,10 +37,7 @@ useEventListener(
{ passive: false }
)
// Prevent Safari's native pinch-zoom gesture on the page
useEventListener(document, 'gesturestart', (e: Event) => e.preventDefault(), { passive: false })
useEventListener(document, 'gesturechange', (e: Event) => e.preventDefault(), { passive: false })
useEventListener(document, 'gestureend', (e: Event) => e.preventDefault(), { passive: false })
const params = useUrlSearchParams('history')
const showChrome = !('no-chrome' in params)