@marianmeres/stuic 3.119.0 → 3.120.0

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.
@@ -135,8 +135,24 @@
135
135
 
136
136
  $effect(() => () => clearTimeout(_previewSettleTimer));
137
137
 
138
- // Drag guard for area clicks (prevent click after drag/pan)
139
- let _wasDragged = false;
138
+ // ---- Tap vs drag discrimination for area activation ----
139
+ // Areas activate via pointer events (pointerdown/pointerup), not a synthesized
140
+ // `click`. On touch the synthesized click is dropped whenever the gesture involves
141
+ // any movement/scroll — unreliable in general, worst on inner SVG shapes (iOS
142
+ // Safari) — which made small, closely-spaced area taps a no-op on mobile. A tap is
143
+ // a pointerup landing within TAP_SLOP_PX of its pointerdown. (Mirrors Book.svelte.)
144
+ const TAP_SLOP_PX = 10;
145
+ let _tapDownX = 0;
146
+ let _tapDownY = 0;
147
+
148
+ function handleTapDown(e: PointerEvent) {
149
+ _tapDownX = e.clientX;
150
+ _tapDownY = e.clientY;
151
+ }
152
+
153
+ function isTap(e: PointerEvent): boolean {
154
+ return Math.hypot(e.clientX - _tapDownX, e.clientY - _tapDownY) <= TAP_SLOP_PX;
155
+ }
140
156
 
141
157
  const BUTTON_CLS = "stuic-assets-preview-control pointer-events-auto p-0!";
142
158
 
@@ -279,7 +295,6 @@
279
295
 
280
296
  // Pan/drag handlers
281
297
  function panStart(e: MouseEvent | TouchEvent) {
282
- _wasDragged = false;
283
298
  // Detect two-finger pinch gesture
284
299
  if ("touches" in e && e.touches.length === 2) {
285
300
  if (noZoom) return;
@@ -336,11 +351,6 @@
336
351
  const newPanX = startPanX + (clientX - startMouseX);
337
352
  const newPanY = startPanY + (clientY - startMouseY);
338
353
 
339
- // Track drag for area click guard
340
- if (Math.abs(clientX - startMouseX) > 3 || Math.abs(clientY - startMouseY) > 3) {
341
- _wasDragged = true;
342
- }
343
-
344
354
  if (clampPan) {
345
355
  const clamped = getClampedPan(newPanX, newPanY);
346
356
  panX = clamped.x;
@@ -389,10 +399,6 @@
389
399
  }
390
400
 
391
401
  isPanning = false;
392
- // Reset _wasDragged after a microtask so onclick handlers can check it first
393
- requestAnimationFrame(() => {
394
- _wasDragged = false;
395
- });
396
402
  }
397
403
 
398
404
  async function slideToIndex(targetIdx: number, direction: "next" | "prev") {
@@ -565,6 +571,7 @@
565
571
  use:interactable
566
572
  bind:this={containerEl}
567
573
  class="w-full h-full overflow-hidden flex items-center justify-center relative"
574
+ style:touch-action="none"
568
575
  >
569
576
  <img
570
577
  use:pannable
@@ -600,7 +607,6 @@
600
607
  style:transform-origin="center center"
601
608
  >
602
609
  {#each previewAsset.areas as area, i (`${area.id}-${i}`)}
603
- <!-- svelte-ignore a11y_click_events_have_key_events -->
604
610
  <!-- svelte-ignore a11y_no_static_element_interactions -->
605
611
  <rect
606
612
  x={area.x}
@@ -608,8 +614,9 @@
608
614
  width={area.w}
609
615
  height={area.h}
610
616
  class="stuic-assets-preview-area"
611
- onclick={(e: MouseEvent) => {
612
- if (_wasDragged) return;
617
+ onpointerdown={handleTapDown}
618
+ onpointerup={(e: PointerEvent) => {
619
+ if (!isTap(e)) return;
613
620
  e.stopPropagation();
614
621
  onAreaClick({ area, asset: previewAsset });
615
622
  }}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marianmeres/stuic",
3
- "version": "3.119.0",
3
+ "version": "3.120.0",
4
4
  "packageManager": "pnpm@11.5.0",
5
5
  "scripts": {
6
6
  "dev": "vite dev",