@signalk/app-dock 0.3.0-beta.1 → 0.3.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/eslint.config.js +3 -1
- package/package.json +1 -1
- package/public/dock.js +60 -7
package/eslint.config.js
CHANGED
package/package.json
CHANGED
package/public/dock.js
CHANGED
|
@@ -399,9 +399,13 @@
|
|
|
399
399
|
}
|
|
400
400
|
|
|
401
401
|
// ─── Show / hide dock ────────────────────────────────────────────────────────
|
|
402
|
+
let dockShownAt = 0
|
|
403
|
+
const DOCK_CLICK_IGNORE_MS = 500
|
|
404
|
+
|
|
402
405
|
function showDock() {
|
|
403
406
|
if (dockVisible) return
|
|
404
407
|
dockVisible = true
|
|
408
|
+
dockShownAt = Date.now()
|
|
405
409
|
$dock.classList.add('visible')
|
|
406
410
|
$backdrop.classList.add('visible')
|
|
407
411
|
}
|
|
@@ -415,7 +419,17 @@
|
|
|
415
419
|
resetMagnification()
|
|
416
420
|
}
|
|
417
421
|
|
|
418
|
-
$backdrop.addEventListener('click',
|
|
422
|
+
$backdrop.addEventListener('click', (e) => {
|
|
423
|
+
// Windows touch synthesizes a click on whatever's under the finger after
|
|
424
|
+
// pointerdown. If that click lands on the just-shown backdrop, it would
|
|
425
|
+
// immediately close the dock. Ignore clicks within a short window after
|
|
426
|
+
// the dock opens.
|
|
427
|
+
if (Date.now() - dockShownAt < DOCK_CLICK_IGNORE_MS) {
|
|
428
|
+
e.stopPropagation()
|
|
429
|
+
return
|
|
430
|
+
}
|
|
431
|
+
hideDock()
|
|
432
|
+
})
|
|
419
433
|
|
|
420
434
|
// ─── Loading overlay helpers ──────────────────────────────────────────────────
|
|
421
435
|
function showLoading(label) {
|
|
@@ -474,28 +488,39 @@
|
|
|
474
488
|
// tap/click normally. A double-tap anywhere opens the dock. Side effect:
|
|
475
489
|
// double-tapping a button fires that button once before the dock opens —
|
|
476
490
|
// users are expected to aim double-taps at non-interactive regions.
|
|
477
|
-
const DOUBLE_TAP_MS =
|
|
478
|
-
const
|
|
479
|
-
const DOUBLE_TAP_SLOP = 24
|
|
491
|
+
const DOUBLE_TAP_MS = 450
|
|
492
|
+
const DOUBLE_TAP_SLOP = 40
|
|
480
493
|
|
|
481
494
|
let lastTapTime = 0
|
|
482
495
|
let lastTapX = 0
|
|
483
496
|
let lastTapY = 0
|
|
484
497
|
|
|
485
498
|
function triggerDock() {
|
|
499
|
+
if (DEBUG) console.log('[Dock] triggerDock called, dockVisible=', dockVisible)
|
|
486
500
|
if (dockVisible) return
|
|
487
501
|
showDock()
|
|
502
|
+
if (DEBUG) {
|
|
503
|
+
const r = $dock.getBoundingClientRect()
|
|
504
|
+
console.log('[Dock] after showDock: dock rect', r, 'classes', $dock.className)
|
|
505
|
+
}
|
|
488
506
|
if (navigator.vibrate) navigator.vibrate(8)
|
|
489
507
|
}
|
|
490
508
|
|
|
509
|
+
const DEBUG = new URLSearchParams(location.search).has('debugDock')
|
|
510
|
+
|
|
491
511
|
function handleTap(clientX, clientY) {
|
|
492
512
|
if (dockVisible) return
|
|
493
513
|
const now = Date.now()
|
|
494
514
|
const dx = clientX - lastTapX
|
|
495
515
|
const dy = clientY - lastTapY
|
|
496
|
-
const
|
|
516
|
+
const dist = Math.round(Math.sqrt(dx * dx + dy * dy))
|
|
517
|
+
const close = dist <= DOUBLE_TAP_SLOP
|
|
497
518
|
const gap = now - lastTapTime
|
|
498
|
-
|
|
519
|
+
const match = gap < DOUBLE_TAP_MS && close
|
|
520
|
+
if (DEBUG) {
|
|
521
|
+
console.log('[Dock] tap', { x: Math.round(clientX), y: Math.round(clientY), gap, dist, close, match })
|
|
522
|
+
}
|
|
523
|
+
if (match) {
|
|
499
524
|
lastTapTime = 0
|
|
500
525
|
triggerDock()
|
|
501
526
|
} else {
|
|
@@ -515,11 +540,39 @@
|
|
|
515
540
|
return { x: r.left, y: r.top }
|
|
516
541
|
}
|
|
517
542
|
|
|
543
|
+
// Dedupe: touchstart and pointerdown often both fire for the same gesture.
|
|
544
|
+
// We accept whichever arrives first and ignore the other if it's within
|
|
545
|
+
// 50 ms (the browser's synthesized-event coalescence window).
|
|
546
|
+
let lastEventAt = 0
|
|
547
|
+
const COALESCE_MS = 50
|
|
548
|
+
|
|
549
|
+
const onDown = (x, y) => {
|
|
550
|
+
const now = Date.now()
|
|
551
|
+
if (now - lastEventAt < COALESCE_MS) return
|
|
552
|
+
lastEventAt = now
|
|
553
|
+
handleTap(x, y)
|
|
554
|
+
}
|
|
555
|
+
|
|
518
556
|
doc.addEventListener(
|
|
519
557
|
'pointerdown',
|
|
520
558
|
(e) => {
|
|
521
559
|
const o = offset()
|
|
522
|
-
|
|
560
|
+
onDown(e.clientX + o.x, e.clientY + o.y)
|
|
561
|
+
},
|
|
562
|
+
{ passive: true, capture: true }
|
|
563
|
+
)
|
|
564
|
+
|
|
565
|
+
// Fallback for Windows touchscreens + some browsers where the root
|
|
566
|
+
// document does not receive pointerdown for finger input (observed on
|
|
567
|
+
// W11 with touch-action: none). touchstart is the universally-supported
|
|
568
|
+
// event for direct touch.
|
|
569
|
+
doc.addEventListener(
|
|
570
|
+
'touchstart',
|
|
571
|
+
(e) => {
|
|
572
|
+
if (!e.touches || e.touches.length === 0) return
|
|
573
|
+
const t = e.touches[0]
|
|
574
|
+
const o = offset()
|
|
575
|
+
onDown(t.clientX + o.x, t.clientY + o.y)
|
|
523
576
|
},
|
|
524
577
|
{ passive: true, capture: true }
|
|
525
578
|
)
|