@almadar/ui 5.62.0 → 5.63.1

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.
Files changed (35) hide show
  1. package/dist/avl/index.cjs +490 -147
  2. package/dist/avl/index.js +490 -147
  3. package/dist/components/core/atoms/Box.d.ts +2 -0
  4. package/dist/components/core/molecules/CalendarGrid.d.ts +9 -1
  5. package/dist/components/core/molecules/PositionedCanvas.d.ts +14 -1
  6. package/dist/components/core/molecules/ReplyTree.d.ts +13 -1
  7. package/dist/components/game/molecules/three/index.cjs +64 -0
  8. package/dist/components/game/molecules/three/index.js +64 -0
  9. package/dist/components/game/organisms/hooks/useCamera.d.ts +16 -0
  10. package/dist/components/index.cjs +490 -148
  11. package/dist/components/index.js +490 -148
  12. package/dist/components/marketing/organisms/CaseStudyOrganism.d.ts +10 -1
  13. package/dist/components/marketing/organisms/FeatureGridOrganism.d.ts +10 -1
  14. package/dist/components/marketing/organisms/HeroOrganism.d.ts +24 -1
  15. package/dist/components/marketing/organisms/PricingOrganism.d.ts +14 -1
  16. package/dist/components/marketing/organisms/ShowcaseOrganism.d.ts +14 -1
  17. package/dist/components/marketing/organisms/StatsOrganism.d.ts +6 -1
  18. package/dist/components/marketing/organisms/StepFlowOrganism.d.ts +9 -1
  19. package/dist/components/marketing/organisms/TeamOrganism.d.ts +10 -1
  20. package/dist/docs/index.cjs +64 -0
  21. package/dist/docs/index.d.cts +2 -0
  22. package/dist/docs/index.js +64 -0
  23. package/dist/hooks/index.cjs +148 -0
  24. package/dist/hooks/index.d.ts +2 -0
  25. package/dist/hooks/index.js +147 -1
  26. package/dist/hooks/useCanvasGestures.d.ts +44 -0
  27. package/dist/hooks/useTapReveal.d.ts +32 -0
  28. package/dist/marketing/index.cjs +59 -0
  29. package/dist/marketing/index.d.cts +2 -0
  30. package/dist/marketing/index.js +59 -0
  31. package/dist/providers/index.cjs +490 -147
  32. package/dist/providers/index.js +490 -147
  33. package/dist/runtime/index.cjs +490 -147
  34. package/dist/runtime/index.js +490 -147
  35. package/package.json +2 -2
package/dist/avl/index.js CHANGED
@@ -3362,12 +3362,60 @@ var init_useEventBus = __esm({
3362
3362
  useEventBus_default = useEventBus;
3363
3363
  }
3364
3364
  });
3365
+ function useTapReveal(options = {}) {
3366
+ const { onReveal, onDismiss, refs, enabled = true } = options;
3367
+ const [revealed, setRevealed] = useState(false);
3368
+ const onRevealRef = useRef(onReveal);
3369
+ const onDismissRef = useRef(onDismiss);
3370
+ onRevealRef.current = onReveal;
3371
+ onDismissRef.current = onDismiss;
3372
+ const reveal = useCallback(() => {
3373
+ setRevealed((wasRevealed) => {
3374
+ if (!wasRevealed) onRevealRef.current?.();
3375
+ return true;
3376
+ });
3377
+ }, []);
3378
+ const dismiss = useCallback(() => {
3379
+ setRevealed((wasRevealed) => {
3380
+ if (wasRevealed) onDismissRef.current?.();
3381
+ return false;
3382
+ });
3383
+ }, []);
3384
+ const onPointerDown = useCallback(
3385
+ (e) => {
3386
+ if (!enabled || e.pointerType === "mouse") return;
3387
+ if (revealed) dismiss();
3388
+ else reveal();
3389
+ },
3390
+ [enabled, revealed, reveal, dismiss]
3391
+ );
3392
+ useEffect(() => {
3393
+ if (!revealed || typeof document === "undefined") return;
3394
+ const onDocDown = (ev) => {
3395
+ const target = ev.target;
3396
+ if (!(target instanceof Node)) return;
3397
+ const inside = (refs ?? []).some((r2) => r2.current?.contains(target));
3398
+ if (!inside) dismiss();
3399
+ };
3400
+ const id = setTimeout(() => document.addEventListener("pointerdown", onDocDown), 0);
3401
+ return () => {
3402
+ clearTimeout(id);
3403
+ document.removeEventListener("pointerdown", onDocDown);
3404
+ };
3405
+ }, [revealed, refs, dismiss]);
3406
+ return { revealed, triggerProps: { onPointerDown }, reveal, dismiss };
3407
+ }
3408
+ var init_useTapReveal = __esm({
3409
+ "hooks/useTapReveal.ts"() {
3410
+ }
3411
+ });
3365
3412
  var paddingStyles, paddingXStyles, paddingYStyles, marginStyles, marginXStyles, marginYStyles, bgStyles, roundedStyles, shadowStyles, displayStyles, overflowStyles2, positionStyles, Box;
3366
3413
  var init_Box = __esm({
3367
3414
  "components/core/atoms/Box.tsx"() {
3368
3415
  "use client";
3369
3416
  init_cn();
3370
3417
  init_useEventBus();
3418
+ init_useTapReveal();
3371
3419
  paddingStyles = {
3372
3420
  none: "p-0",
3373
3421
  xs: "p-1",
@@ -3493,10 +3541,12 @@ var init_Box = __esm({
3493
3541
  action,
3494
3542
  actionPayload,
3495
3543
  hoverEvent,
3544
+ tapReveal = true,
3496
3545
  maxWidth,
3497
3546
  onClick,
3498
3547
  onMouseEnter,
3499
3548
  onMouseLeave,
3549
+ onPointerDown,
3500
3550
  ...rest
3501
3551
  }, ref) => {
3502
3552
  const eventBus = useEventBus();
@@ -3519,6 +3569,19 @@ var init_Box = __esm({
3519
3569
  }
3520
3570
  onMouseLeave?.(e);
3521
3571
  }, [hoverEvent, eventBus, onMouseLeave]);
3572
+ const { triggerProps } = useTapReveal({
3573
+ enabled: tapReveal && !!hoverEvent,
3574
+ onReveal: useCallback(() => {
3575
+ if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: true });
3576
+ }, [hoverEvent, eventBus]),
3577
+ onDismiss: useCallback(() => {
3578
+ if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: false });
3579
+ }, [hoverEvent, eventBus])
3580
+ });
3581
+ const handlePointerDown = useCallback((e) => {
3582
+ if (hoverEvent && tapReveal) triggerProps.onPointerDown(e);
3583
+ onPointerDown?.(e);
3584
+ }, [hoverEvent, tapReveal, triggerProps, onPointerDown]);
3522
3585
  const isClickable = action || onClick;
3523
3586
  return React93__default.createElement(
3524
3587
  Component2,
@@ -3546,6 +3609,7 @@ var init_Box = __esm({
3546
3609
  onClick: isClickable ? handleClick : void 0,
3547
3610
  onMouseEnter: hoverEvent || onMouseEnter ? handleMouseEnter : void 0,
3548
3611
  onMouseLeave: hoverEvent || onMouseLeave ? handleMouseLeave : void 0,
3612
+ onPointerDown: hoverEvent && tapReveal || onPointerDown ? handlePointerDown : void 0,
3549
3613
  style: maxWidth ? { maxWidth, ...rest.style } : rest.style,
3550
3614
  ...rest
3551
3615
  },
@@ -8621,6 +8685,11 @@ var init_TextHighlight = __esm({
8621
8685
  if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: false, annotationId });
8622
8686
  onMouseLeave?.();
8623
8687
  },
8688
+ onPointerDown: (e) => {
8689
+ if (e.pointerType === "mouse") return;
8690
+ if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: true, annotationId });
8691
+ onMouseEnter?.();
8692
+ },
8624
8693
  role: "button",
8625
8694
  tabIndex: 0,
8626
8695
  onKeyDown: (e) => {
@@ -8796,6 +8865,7 @@ var init_LawReferenceTooltip = __esm({
8796
8865
  init_Typography();
8797
8866
  init_Divider();
8798
8867
  init_cn();
8868
+ init_useTapReveal();
8799
8869
  positionStyles2 = {
8800
8870
  top: "bottom-full left-1/2 -translate-x-1/2 mb-2",
8801
8871
  bottom: "top-full left-1/2 -translate-x-1/2 mt-2",
@@ -8817,6 +8887,7 @@ var init_LawReferenceTooltip = __esm({
8817
8887
  const { t } = useTranslate();
8818
8888
  const [isVisible, setIsVisible] = React93__default.useState(false);
8819
8889
  const timeoutRef = React93__default.useRef(null);
8890
+ const triggerRef = React93__default.useRef(null);
8820
8891
  const handleMouseEnter = () => {
8821
8892
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
8822
8893
  timeoutRef.current = setTimeout(() => setIsVisible(true), 200);
@@ -8825,6 +8896,8 @@ var init_LawReferenceTooltip = __esm({
8825
8896
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
8826
8897
  setIsVisible(false);
8827
8898
  };
8899
+ const { revealed, triggerProps } = useTapReveal({ refs: [triggerRef] });
8900
+ const open = isVisible || revealed;
8828
8901
  React93__default.useEffect(() => {
8829
8902
  return () => {
8830
8903
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
@@ -8833,6 +8906,7 @@ var init_LawReferenceTooltip = __esm({
8833
8906
  return /* @__PURE__ */ jsxs(
8834
8907
  Box,
8835
8908
  {
8909
+ ref: triggerRef,
8836
8910
  as: "span",
8837
8911
  position: "relative",
8838
8912
  display: "inline-block",
@@ -8841,9 +8915,10 @@ var init_LawReferenceTooltip = __esm({
8841
8915
  onMouseLeave: handleMouseLeave,
8842
8916
  onFocus: handleMouseEnter,
8843
8917
  onBlur: handleMouseLeave,
8918
+ onPointerDown: triggerProps.onPointerDown,
8844
8919
  children: [
8845
8920
  children,
8846
- isVisible && /* @__PURE__ */ jsxs(
8921
+ open && /* @__PURE__ */ jsxs(
8847
8922
  Box,
8848
8923
  {
8849
8924
  padding: "sm",
@@ -14259,6 +14334,36 @@ function useCamera() {
14259
14334
  cameraRef.current.zoom = Math.max(0.5, Math.min(3, cameraRef.current.zoom * zoomDelta));
14260
14335
  drawFn?.();
14261
14336
  }, []);
14337
+ const handlePointerDown = useCallback((e) => {
14338
+ handleMouseDown(e);
14339
+ }, [handleMouseDown]);
14340
+ const handlePointerUp = useCallback(() => {
14341
+ handleMouseUp();
14342
+ }, [handleMouseUp]);
14343
+ const handlePointerMove = useCallback((e, drawFn) => {
14344
+ return handleMouseMove(e, drawFn);
14345
+ }, [handleMouseMove]);
14346
+ const panBy = useCallback((dx, dy, drawFn) => {
14347
+ cameraRef.current.x -= dx;
14348
+ cameraRef.current.y -= dy;
14349
+ targetCameraRef.current = null;
14350
+ drawFn?.();
14351
+ }, []);
14352
+ const zoomAtPoint = useCallback((factor, centerX, centerY, viewportSize, drawFn) => {
14353
+ const cam = cameraRef.current;
14354
+ const oldZoom = cam.zoom;
14355
+ const newZoom = Math.max(0.5, Math.min(3, oldZoom * factor));
14356
+ if (newZoom === oldZoom) {
14357
+ drawFn?.();
14358
+ return;
14359
+ }
14360
+ const inv = 1 / oldZoom - 1 / newZoom;
14361
+ cam.x += (centerX - viewportSize.width / 2) * inv;
14362
+ cam.y += (centerY - viewportSize.height / 2) * inv;
14363
+ cam.zoom = newZoom;
14364
+ targetCameraRef.current = null;
14365
+ drawFn?.();
14366
+ }, []);
14262
14367
  const screenToWorld = useCallback((clientX, clientY, canvas, viewportSize) => {
14263
14368
  const rect = canvas.getBoundingClientRect();
14264
14369
  const screenX = clientX - rect.left;
@@ -14290,6 +14395,11 @@ function useCamera() {
14290
14395
  handleMouseMove,
14291
14396
  handleMouseLeave,
14292
14397
  handleWheel,
14398
+ handlePointerDown,
14399
+ handlePointerUp,
14400
+ handlePointerMove,
14401
+ panBy,
14402
+ zoomAtPoint,
14293
14403
  screenToWorld,
14294
14404
  lerpToTarget
14295
14405
  };
@@ -14299,6 +14409,113 @@ var init_useCamera = __esm({
14299
14409
  "use client";
14300
14410
  }
14301
14411
  });
14412
+ function localPoint(canvas, clientX, clientY) {
14413
+ if (!canvas) return { x: clientX, y: clientY };
14414
+ const rect = canvas.getBoundingClientRect();
14415
+ return { x: clientX - rect.left, y: clientY - rect.top };
14416
+ }
14417
+ function useCanvasGestures(options) {
14418
+ const {
14419
+ canvasRef,
14420
+ enabled = true,
14421
+ wheelStep = 1.1,
14422
+ onPointerDown,
14423
+ onPointerMove,
14424
+ onPointerUp,
14425
+ onZoom,
14426
+ onPanDelta,
14427
+ onMultiTouchStart
14428
+ } = options;
14429
+ const pointers = useRef(/* @__PURE__ */ new Map());
14430
+ const pinch = useRef(null);
14431
+ const computePinch = useCallback(() => {
14432
+ const pts = [...pointers.current.values()];
14433
+ const dx = pts[1].x - pts[0].x;
14434
+ const dy = pts[1].y - pts[0].y;
14435
+ return {
14436
+ distance: Math.hypot(dx, dy) || 1,
14437
+ centroid: { x: (pts[0].x + pts[1].x) / 2, y: (pts[0].y + pts[1].y) / 2 }
14438
+ };
14439
+ }, []);
14440
+ const handlePointerDown = useCallback(
14441
+ (e) => {
14442
+ if (!enabled) return;
14443
+ e.currentTarget.setPointerCapture(e.pointerId);
14444
+ pointers.current.set(e.pointerId, localPoint(canvasRef.current, e.clientX, e.clientY));
14445
+ if (pointers.current.size === 2) {
14446
+ onMultiTouchStart?.();
14447
+ pinch.current = computePinch();
14448
+ } else if (pointers.current.size === 1) {
14449
+ onPointerDown?.(e);
14450
+ }
14451
+ },
14452
+ [enabled, canvasRef, onMultiTouchStart, computePinch, onPointerDown]
14453
+ );
14454
+ const handlePointerMove = useCallback(
14455
+ (e) => {
14456
+ if (!enabled) return;
14457
+ if (pointers.current.has(e.pointerId)) {
14458
+ pointers.current.set(e.pointerId, localPoint(canvasRef.current, e.clientX, e.clientY));
14459
+ }
14460
+ if (pointers.current.size >= 2 && pinch.current) {
14461
+ const next = computePinch();
14462
+ const prev = pinch.current;
14463
+ if (next.distance !== prev.distance) {
14464
+ onZoom?.(next.distance / prev.distance, next.centroid.x, next.centroid.y);
14465
+ }
14466
+ onPanDelta?.(next.centroid.x - prev.centroid.x, next.centroid.y - prev.centroid.y);
14467
+ pinch.current = next;
14468
+ return;
14469
+ }
14470
+ onPointerMove?.(e);
14471
+ },
14472
+ [enabled, canvasRef, computePinch, onZoom, onPanDelta, onPointerMove]
14473
+ );
14474
+ const endPointer = useCallback(
14475
+ (e, fireUp) => {
14476
+ const wasMulti = pointers.current.size >= 2;
14477
+ pointers.current.delete(e.pointerId);
14478
+ if (pointers.current.size < 2) pinch.current = null;
14479
+ if (wasMulti && pointers.current.size === 1) return;
14480
+ if (pointers.current.size === 0 && fireUp) onPointerUp?.(e);
14481
+ },
14482
+ [onPointerUp]
14483
+ );
14484
+ const handlePointerUp = useCallback(
14485
+ (e) => {
14486
+ if (!enabled) return;
14487
+ endPointer(e, true);
14488
+ },
14489
+ [enabled, endPointer]
14490
+ );
14491
+ const handlePointerCancel = useCallback(
14492
+ (e) => {
14493
+ if (!enabled) return;
14494
+ endPointer(e, false);
14495
+ },
14496
+ [enabled, endPointer]
14497
+ );
14498
+ const handleWheel = useCallback(
14499
+ (e) => {
14500
+ if (!enabled) return;
14501
+ e.preventDefault();
14502
+ const { x, y } = localPoint(canvasRef.current, e.clientX, e.clientY);
14503
+ onZoom?.(e.deltaY < 0 ? wheelStep : 1 / wheelStep, x, y);
14504
+ },
14505
+ [enabled, canvasRef, wheelStep, onZoom]
14506
+ );
14507
+ return {
14508
+ onPointerDown: handlePointerDown,
14509
+ onPointerMove: handlePointerMove,
14510
+ onPointerUp: handlePointerUp,
14511
+ onPointerCancel: handlePointerCancel,
14512
+ onWheel: handleWheel
14513
+ };
14514
+ }
14515
+ var init_useCanvasGestures = __esm({
14516
+ "hooks/useCanvasGestures.ts"() {
14517
+ }
14518
+ });
14302
14519
  function unitAtlasUrl(unit) {
14303
14520
  if (unit.spriteSheet) return unit.spriteSheet;
14304
14521
  const sprite = unit.sprite;
@@ -14677,11 +14894,12 @@ function IsometricCanvas({
14677
14894
  cameraRef,
14678
14895
  targetCameraRef,
14679
14896
  dragDistance,
14680
- handleMouseDown,
14681
- handleMouseUp,
14682
- handleMouseMove,
14683
14897
  handleMouseLeave,
14684
- handleWheel,
14898
+ handlePointerDown,
14899
+ handlePointerUp,
14900
+ handlePointerMove,
14901
+ panBy,
14902
+ zoomAtPoint,
14685
14903
  screenToWorld,
14686
14904
  lerpToTarget
14687
14905
  } = useCamera();
@@ -15116,11 +15334,16 @@ function IsometricCanvas({
15116
15334
  cancelAnimationFrame(rafIdRef.current);
15117
15335
  };
15118
15336
  }, [draw, units.length, validMoves.length, attackTargets.length, selectedUnitId, hasActiveEffects2, pendingCount, atlasPending, lerpToTarget, targetCameraRef]);
15119
- const handleMouseMoveWithCamera = useCallback((e) => {
15120
- if (enableCamera) {
15121
- const wasPanning = handleMouseMove(e, () => draw(animTimeRef.current));
15122
- if (wasPanning) return;
15123
- }
15337
+ const singlePointerActiveRef = useRef(false);
15338
+ const handleCanvasPointerDown = useCallback((e) => {
15339
+ singlePointerActiveRef.current = true;
15340
+ if (enableCamera) handlePointerDown(e);
15341
+ }, [enableCamera, handlePointerDown]);
15342
+ const handleCanvasPointerMove = useCallback((e) => {
15343
+ if (enableCamera) handlePointerMove(e, () => draw(animTimeRef.current));
15344
+ }, [enableCamera, handlePointerMove, draw]);
15345
+ const handleCanvasHover = useCallback((e) => {
15346
+ if (singlePointerActiveRef.current) return;
15124
15347
  if (!onTileHover && !tileHoverEvent || !canvasRef.current) return;
15125
15348
  const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
15126
15349
  const adjustedX = world.x - scaledTileWidth / 2;
@@ -15131,26 +15354,10 @@ function IsometricCanvas({
15131
15354
  if (tileHoverEvent) eventBus.emit(`UI:${tileHoverEvent}`, { x: isoPos.x, y: isoPos.y });
15132
15355
  onTileHover?.(isoPos.x, isoPos.y);
15133
15356
  }
15134
- }, [enableCamera, handleMouseMove, draw, onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
15135
- const handleMouseLeaveWithCamera = useCallback(() => {
15136
- handleMouseLeave();
15137
- if (tileLeaveEvent) eventBus.emit(`UI:${tileLeaveEvent}`, {});
15138
- onTileLeave?.();
15139
- }, [handleMouseLeave, onTileLeave, tileLeaveEvent, eventBus]);
15140
- const handleWheelWithCamera = useCallback((e) => {
15141
- if (enableCamera) {
15142
- handleWheel(e, () => draw(animTimeRef.current));
15143
- }
15144
- }, [enableCamera, handleWheel, draw]);
15145
- useEffect(() => {
15146
- const canvas = canvasRef.current;
15147
- if (!canvas) return;
15148
- canvas.addEventListener("wheel", handleWheelWithCamera, { passive: false });
15149
- return () => {
15150
- canvas.removeEventListener("wheel", handleWheelWithCamera);
15151
- };
15152
- }, [handleWheelWithCamera]);
15153
- const handleClick = useCallback((e) => {
15357
+ }, [onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
15358
+ const handleCanvasPointerUp = useCallback((e) => {
15359
+ singlePointerActiveRef.current = false;
15360
+ if (enableCamera) handlePointerUp();
15154
15361
  if (dragDistance() > 5) return;
15155
15362
  if (!canvasRef.current) return;
15156
15363
  const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
@@ -15168,7 +15375,32 @@ function IsometricCanvas({
15168
15375
  onTileClick?.(isoPos.x, isoPos.y);
15169
15376
  }
15170
15377
  }
15171
- }, [dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
15378
+ }, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
15379
+ const handleCanvasPointerLeave = useCallback(() => {
15380
+ handleMouseLeave();
15381
+ if (tileLeaveEvent) eventBus.emit(`UI:${tileLeaveEvent}`, {});
15382
+ onTileLeave?.();
15383
+ }, [handleMouseLeave, onTileLeave, tileLeaveEvent, eventBus]);
15384
+ const applyZoom = useCallback((factor, centerX, centerY) => {
15385
+ if (enableCamera) zoomAtPoint(factor, centerX, centerY, viewportSize, () => draw(animTimeRef.current));
15386
+ }, [enableCamera, zoomAtPoint, viewportSize, draw]);
15387
+ const applyPanDelta = useCallback((dx, dy) => {
15388
+ if (enableCamera) panBy(dx, dy, () => draw(animTimeRef.current));
15389
+ }, [enableCamera, panBy, draw]);
15390
+ const cancelSinglePointer = useCallback(() => {
15391
+ singlePointerActiveRef.current = false;
15392
+ if (enableCamera) handlePointerUp();
15393
+ }, [enableCamera, handlePointerUp]);
15394
+ const gestureHandlers = useCanvasGestures({
15395
+ canvasRef,
15396
+ enabled: enableCamera || !!onTileHover || !!tileHoverEvent || !!onTileClick || !!tileClickEvent || !!onUnitClick || !!unitClickEvent,
15397
+ onPointerDown: handleCanvasPointerDown,
15398
+ onPointerMove: handleCanvasPointerMove,
15399
+ onPointerUp: handleCanvasPointerUp,
15400
+ onZoom: applyZoom,
15401
+ onPanDelta: applyPanDelta,
15402
+ onMultiTouchStart: cancelSinglePointer
15403
+ });
15172
15404
  if (error) {
15173
15405
  return /* @__PURE__ */ jsx(ErrorState, { title: t("canvas.errorTitle"), message: error.message, className });
15174
15406
  }
@@ -15200,13 +15432,17 @@ function IsometricCanvas({
15200
15432
  {
15201
15433
  ref: canvasRef,
15202
15434
  "data-testid": "game-canvas",
15203
- onClick: handleClick,
15204
- onMouseDown: enableCamera ? handleMouseDown : void 0,
15205
- onMouseMove: handleMouseMoveWithCamera,
15206
- onMouseUp: enableCamera ? handleMouseUp : void 0,
15207
- onMouseLeave: handleMouseLeaveWithCamera,
15435
+ onPointerDown: gestureHandlers.onPointerDown,
15436
+ onPointerMove: (e) => {
15437
+ gestureHandlers.onPointerMove(e);
15438
+ handleCanvasHover(e);
15439
+ },
15440
+ onPointerUp: gestureHandlers.onPointerUp,
15441
+ onPointerCancel: gestureHandlers.onPointerCancel,
15442
+ onPointerLeave: handleCanvasPointerLeave,
15443
+ onWheel: gestureHandlers.onWheel,
15208
15444
  onContextMenu: (e) => e.preventDefault(),
15209
- className: "cursor-pointer",
15445
+ className: "cursor-pointer touch-none",
15210
15446
  style: {
15211
15447
  width: viewportSize.width,
15212
15448
  height: viewportSize.height
@@ -15260,6 +15496,7 @@ var init_IsometricCanvas = __esm({
15260
15496
  init_ErrorState();
15261
15497
  init_useImageCache();
15262
15498
  init_useCamera();
15499
+ init_useCanvasGestures();
15263
15500
  init_useUnitSpriteAtlas();
15264
15501
  init_verificationRegistry();
15265
15502
  init_isometric();
@@ -17546,6 +17783,10 @@ var init_StateMachineView = __esm({
17546
17783
  const handleMouseLeave2 = () => {
17547
17784
  onHover(null, 0, 0);
17548
17785
  };
17786
+ const handlePointerDown2 = (e) => {
17787
+ if (e.pointerType === "mouse") return;
17788
+ handleMouseEnter2();
17789
+ };
17549
17790
  return /* @__PURE__ */ jsxs(
17550
17791
  "g",
17551
17792
  {
@@ -17555,6 +17796,7 @@ var init_StateMachineView = __esm({
17555
17796
  onClick: () => onClick?.(bundle),
17556
17797
  onMouseEnter: handleMouseEnter2,
17557
17798
  onMouseLeave: handleMouseLeave2,
17799
+ onPointerDown: handlePointerDown2,
17558
17800
  style: { pointerEvents: "auto" },
17559
17801
  children: [
17560
17802
  /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx(
@@ -17672,6 +17914,10 @@ var init_StateMachineView = __esm({
17672
17914
  const handleMouseLeave = useCallback(() => {
17673
17915
  onHover(null, 0, 0);
17674
17916
  }, [onHover]);
17917
+ const handlePointerDown = useCallback((e) => {
17918
+ if (e.pointerType === "mouse") return;
17919
+ handleMouseEnter();
17920
+ }, [handleMouseEnter]);
17675
17921
  const uniqueMarkerId = `arrow-${bundle.id}`;
17676
17922
  const hasDetails = bundle.labels.some((l) => l.hasDetails);
17677
17923
  return /* @__PURE__ */ jsxs(
@@ -17683,6 +17929,7 @@ var init_StateMachineView = __esm({
17683
17929
  onClick: () => onClick?.(bundle),
17684
17930
  onMouseEnter: handleMouseEnter,
17685
17931
  onMouseLeave: handleMouseLeave,
17932
+ onPointerDown: handlePointerDown,
17686
17933
  style: { pointerEvents: "auto" },
17687
17934
  children: [
17688
17935
  /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx(
@@ -26181,10 +26428,84 @@ function SubMenu({
26181
26428
  );
26182
26429
  return typeof document !== "undefined" ? createPortal(panel, document.body) : panel;
26183
26430
  }
26431
+ function MenuItemRow({
26432
+ item,
26433
+ itemId,
26434
+ hasSubMenu,
26435
+ isDanger,
26436
+ direction,
26437
+ isSubMenuOpen,
26438
+ activeSubMenuRef,
26439
+ eventBus,
26440
+ onItemClick,
26441
+ openSubMenu
26442
+ }) {
26443
+ const rowRef = useRef(null);
26444
+ const { triggerProps } = useTapReveal({
26445
+ enabled: hasSubMenu,
26446
+ onReveal: () => openSubMenu(itemId, rowRef.current),
26447
+ refs: [rowRef]
26448
+ });
26449
+ return /* @__PURE__ */ jsxs(Box, { children: [
26450
+ /* @__PURE__ */ jsx(
26451
+ Box,
26452
+ {
26453
+ ref: rowRef,
26454
+ as: "button",
26455
+ onClick: () => onItemClick({ ...item, id: itemId }, itemId),
26456
+ "aria-disabled": item.disabled || void 0,
26457
+ onMouseEnter: (e) => {
26458
+ if (hasSubMenu) openSubMenu(itemId, e.currentTarget);
26459
+ },
26460
+ onPointerDown: hasSubMenu ? triggerProps.onPointerDown : void 0,
26461
+ "data-testid": item.event ? `action-${item.event}` : void 0,
26462
+ className: cn(
26463
+ "w-full flex items-center justify-between gap-3 px-4 py-2 text-start",
26464
+ "text-sm transition-colors",
26465
+ "hover:bg-muted",
26466
+ "focus:outline-none focus:bg-muted",
26467
+ "disabled:opacity-50 disabled:cursor-not-allowed",
26468
+ item.disabled && "cursor-not-allowed",
26469
+ isDanger && "text-error hover:bg-error/10"
26470
+ ),
26471
+ children: /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-3 flex-1 min-w-0", children: [
26472
+ item.icon && (typeof item.icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: item.icon, size: "sm", className: "flex-shrink-0" }) : /* @__PURE__ */ jsx(Icon, { icon: item.icon, size: "sm", className: "flex-shrink-0" })),
26473
+ /* @__PURE__ */ jsx(
26474
+ Typography,
26475
+ {
26476
+ variant: "small",
26477
+ className: cn("flex-1", isDanger && "text-red-600"),
26478
+ children: item.label
26479
+ }
26480
+ ),
26481
+ item.badge !== void 0 && /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", children: item.badge }),
26482
+ hasSubMenu && /* @__PURE__ */ jsx(
26483
+ Icon,
26484
+ {
26485
+ name: direction === "rtl" ? "chevron-left" : "chevron-right",
26486
+ size: "sm",
26487
+ className: "flex-shrink-0"
26488
+ }
26489
+ )
26490
+ ] })
26491
+ }
26492
+ ),
26493
+ hasSubMenu && isSubMenuOpen && item.subMenu && /* @__PURE__ */ jsx(
26494
+ SubMenu,
26495
+ {
26496
+ items: item.subMenu,
26497
+ itemRef: activeSubMenuRef,
26498
+ direction,
26499
+ eventBus
26500
+ }
26501
+ )
26502
+ ] });
26503
+ }
26184
26504
  var MENU_GAP, menuContainerStyles, Menu;
26185
26505
  var init_Menu = __esm({
26186
26506
  "components/core/molecules/Menu.tsx"() {
26187
26507
  "use client";
26508
+ init_useTapReveal();
26188
26509
  init_Box();
26189
26510
  init_Icon();
26190
26511
  init_Divider();
@@ -26239,6 +26560,10 @@ var init_Menu = __esm({
26239
26560
  setIsOpen(false);
26240
26561
  }
26241
26562
  };
26563
+ const openSubMenu = (itemId, el) => {
26564
+ setActiveSubMenu(itemId);
26565
+ setActiveSubMenuRef(el);
26566
+ };
26242
26567
  useEffect(() => {
26243
26568
  if (isOpen) {
26244
26569
  updatePosition();
@@ -26282,61 +26607,22 @@ var init_Menu = __esm({
26282
26607
  if (isDivider) {
26283
26608
  return /* @__PURE__ */ jsx(Divider, { className: "my-1" }, `divider-${index}`);
26284
26609
  }
26285
- return /* @__PURE__ */ jsxs(Box, { children: [
26286
- /* @__PURE__ */ jsx(
26287
- Box,
26288
- {
26289
- as: "button",
26290
- onClick: () => handleItemClick({ ...item, id: itemId }, itemId),
26291
- "aria-disabled": item.disabled || void 0,
26292
- onMouseEnter: (e) => {
26293
- if (hasSubMenu) {
26294
- setActiveSubMenu(itemId);
26295
- setActiveSubMenuRef(e.currentTarget);
26296
- }
26297
- },
26298
- "data-testid": item.event ? `action-${item.event}` : void 0,
26299
- className: cn(
26300
- "w-full flex items-center justify-between gap-3 px-4 py-2 text-start",
26301
- "text-sm transition-colors",
26302
- "hover:bg-muted",
26303
- "focus:outline-none focus:bg-muted",
26304
- "disabled:opacity-50 disabled:cursor-not-allowed",
26305
- item.disabled && "cursor-not-allowed",
26306
- isDanger && "text-error hover:bg-error/10"
26307
- ),
26308
- children: /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-3 flex-1 min-w-0", children: [
26309
- item.icon && (typeof item.icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: item.icon, size: "sm", className: "flex-shrink-0" }) : /* @__PURE__ */ jsx(Icon, { icon: item.icon, size: "sm", className: "flex-shrink-0" })),
26310
- /* @__PURE__ */ jsx(
26311
- Typography,
26312
- {
26313
- variant: "small",
26314
- className: cn("flex-1", isDanger && "text-red-600"),
26315
- children: item.label
26316
- }
26317
- ),
26318
- item.badge !== void 0 && /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", children: item.badge }),
26319
- hasSubMenu && /* @__PURE__ */ jsx(
26320
- Icon,
26321
- {
26322
- name: direction === "rtl" ? "chevron-left" : "chevron-right",
26323
- size: "sm",
26324
- className: "flex-shrink-0"
26325
- }
26326
- )
26327
- ] })
26328
- }
26329
- ),
26330
- hasSubMenu && activeSubMenu === itemId && item.subMenu && /* @__PURE__ */ jsx(
26331
- SubMenu,
26332
- {
26333
- items: item.subMenu,
26334
- itemRef: activeSubMenuRef,
26335
- direction,
26336
- eventBus
26337
- }
26338
- )
26339
- ] }, itemId);
26610
+ return /* @__PURE__ */ jsx(
26611
+ MenuItemRow,
26612
+ {
26613
+ item,
26614
+ itemId,
26615
+ hasSubMenu,
26616
+ isDanger,
26617
+ direction,
26618
+ isSubMenuOpen: activeSubMenu === itemId,
26619
+ activeSubMenuRef,
26620
+ eventBus,
26621
+ onItemClick: handleItemClick,
26622
+ openSubMenu
26623
+ },
26624
+ itemId
26625
+ );
26340
26626
  });
26341
26627
  const panel = isOpen && triggerRect ? /* @__PURE__ */ jsxs(
26342
26628
  "div",
@@ -28639,6 +28925,7 @@ var init_Popover = __esm({
28639
28925
  "use client";
28640
28926
  init_Typography();
28641
28927
  init_cn();
28928
+ init_useTapReveal();
28642
28929
  arrowClasses = {
28643
28930
  top: "top-full left-1/2 -translate-x-1/2 border-t-white border-l-transparent border-r-transparent border-b-transparent",
28644
28931
  bottom: "bottom-full left-1/2 -translate-x-1/2 border-b-white border-l-transparent border-r-transparent border-t-transparent",
@@ -28709,18 +28996,32 @@ var init_Popover = __esm({
28709
28996
  document.addEventListener("mousedown", handleClickOutside);
28710
28997
  return () => document.removeEventListener("mousedown", handleClickOutside);
28711
28998
  }, [isOpen, trigger]);
28712
- const triggerProps = trigger === "click" ? {
28999
+ const { triggerProps: tapTriggerProps } = useTapReveal({
29000
+ enabled: trigger === "hover",
29001
+ onReveal: handleOpen,
29002
+ onDismiss: handleClose,
29003
+ refs: [triggerRef, popoverRef]
29004
+ });
29005
+ const handlerProps = trigger === "click" ? {
28713
29006
  onClick: handleToggle
28714
29007
  } : {
28715
29008
  onMouseEnter: handleOpen,
28716
- onMouseLeave: handleClose
29009
+ onMouseLeave: handleClose,
29010
+ onPointerDown: tapTriggerProps.onPointerDown
28717
29011
  };
28718
29012
  const childElement = React93__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
29013
+ const childPointerDown = childElement.props.onPointerDown;
28719
29014
  const triggerElement = React93__default.cloneElement(
28720
29015
  childElement,
28721
29016
  {
28722
29017
  ref: triggerRef,
28723
- ...triggerProps
29018
+ ...handlerProps,
29019
+ ...trigger === "hover" ? {
29020
+ onPointerDown: (e) => {
29021
+ tapTriggerProps.onPointerDown(e);
29022
+ childPointerDown?.(e);
29023
+ }
29024
+ } : void 0
28724
29025
  }
28725
29026
  );
28726
29027
  const panel = isOpen && triggerRect ? /* @__PURE__ */ jsxs(
@@ -29251,6 +29552,7 @@ var init_Tooltip = __esm({
29251
29552
  "use client";
29252
29553
  init_Typography();
29253
29554
  init_cn();
29555
+ init_useTapReveal();
29254
29556
  TRIGGER_GAP2 = 8;
29255
29557
  arrowClasses2 = {
29256
29558
  top: "top-full left-1/2 -translate-x-1/2 border-t-primary border-l-transparent border-r-transparent border-b-transparent",
@@ -29295,6 +29597,11 @@ var init_Tooltip = __esm({
29295
29597
  setIsVisible(false);
29296
29598
  }, hideDelay);
29297
29599
  };
29600
+ const { triggerProps } = useTapReveal({
29601
+ onReveal: handleMouseEnter,
29602
+ onDismiss: handleMouseLeave,
29603
+ refs: [triggerRef, tooltipRef]
29604
+ });
29298
29605
  useLayoutEffect(() => {
29299
29606
  if (isVisible) {
29300
29607
  updatePosition();
@@ -29307,12 +29614,17 @@ var init_Tooltip = __esm({
29307
29614
  };
29308
29615
  }, []);
29309
29616
  const triggerElement = React93__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
29617
+ const childPointerDown = triggerElement.props.onPointerDown;
29310
29618
  const trigger = React93__default.cloneElement(triggerElement, {
29311
29619
  ref: triggerRef,
29312
29620
  onMouseEnter: handleMouseEnter,
29313
29621
  onMouseLeave: handleMouseLeave,
29314
29622
  onFocus: handleMouseEnter,
29315
- onBlur: handleMouseLeave
29623
+ onBlur: handleMouseLeave,
29624
+ onPointerDown: (e) => {
29625
+ triggerProps.onPointerDown(e);
29626
+ childPointerDown?.(e);
29627
+ }
29316
29628
  });
29317
29629
  const tooltipContent = isVisible && triggerRect ? /* @__PURE__ */ jsxs(
29318
29630
  "div",
@@ -32662,6 +32974,14 @@ var init_GraphView = __esm({
32662
32974
  },
32663
32975
  [onNodeClick]
32664
32976
  );
32977
+ const handleNodePointerDown = useCallback(
32978
+ (e, node) => {
32979
+ if (e.pointerType === "mouse") return;
32980
+ handleNodeMouseEnter(node);
32981
+ handleNodeClickInternal(node);
32982
+ },
32983
+ [handleNodeMouseEnter, handleNodeClickInternal]
32984
+ );
32665
32985
  if (nodes.length === 0) {
32666
32986
  return /* @__PURE__ */ jsx(Box, { className: cn("flex items-center justify-center", className), style: { width: w, height: h }, children: /* @__PURE__ */ jsx(Box, { className: "text-muted-foreground text-sm", children: t("display.noGraphData") }) });
32667
32987
  }
@@ -32721,6 +33041,7 @@ var init_GraphView = __esm({
32721
33041
  onMouseEnter: () => handleNodeMouseEnter(node),
32722
33042
  onMouseLeave: handleNodeMouseLeave,
32723
33043
  onClick: () => handleNodeClickInternal(node),
33044
+ onPointerDown: (e) => handleNodePointerDown(e, node),
32724
33045
  children: [
32725
33046
  /* @__PURE__ */ jsx(
32726
33047
  "circle",
@@ -32801,13 +33122,13 @@ var init_MapView = __esm({
32801
33122
  shadowSize: [41, 41]
32802
33123
  });
32803
33124
  L.Marker.prototype.options.icon = defaultIcon;
32804
- const { useEffect: useEffect87, useRef: useRef80, useCallback: useCallback130, useState: useState122 } = React93__default;
33125
+ const { useEffect: useEffect88, useRef: useRef82, useCallback: useCallback132, useState: useState123 } = React93__default;
32805
33126
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
32806
33127
  const { useEventBus: useEventBus4 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
32807
33128
  function MapUpdater({ centerLat, centerLng, zoom }) {
32808
33129
  const map = useMap();
32809
- const prevRef = useRef80({ centerLat, centerLng, zoom });
32810
- useEffect87(() => {
33130
+ const prevRef = useRef82({ centerLat, centerLng, zoom });
33131
+ useEffect88(() => {
32811
33132
  const prev = prevRef.current;
32812
33133
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
32813
33134
  map.setView([centerLat, centerLng], zoom);
@@ -32818,7 +33139,7 @@ var init_MapView = __esm({
32818
33139
  }
32819
33140
  function MapClickHandler({ onMapClick }) {
32820
33141
  const map = useMap();
32821
- useEffect87(() => {
33142
+ useEffect88(() => {
32822
33143
  if (!onMapClick) return;
32823
33144
  const handler = (e) => {
32824
33145
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -32846,8 +33167,8 @@ var init_MapView = __esm({
32846
33167
  showAttribution = true
32847
33168
  }) {
32848
33169
  const eventBus = useEventBus4();
32849
- const [clickedPosition, setClickedPosition] = useState122(null);
32850
- const handleMapClick = useCallback130((lat, lng) => {
33170
+ const [clickedPosition, setClickedPosition] = useState123(null);
33171
+ const handleMapClick = useCallback132((lat, lng) => {
32851
33172
  if (showClickedPin) {
32852
33173
  setClickedPosition({ lat, lng });
32853
33174
  }
@@ -32856,7 +33177,7 @@ var init_MapView = __esm({
32856
33177
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
32857
33178
  }
32858
33179
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
32859
- const handleMarkerClick = useCallback130((marker) => {
33180
+ const handleMarkerClick = useCallback132((marker) => {
32860
33181
  onMarkerClick?.(marker);
32861
33182
  if (markerClickEvent) {
32862
33183
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -33197,7 +33518,7 @@ var init_StarRating = __esm({
33197
33518
  "aria-valuenow": value,
33198
33519
  tabIndex: readOnly ? void 0 : 0,
33199
33520
  onKeyDown: handleKeyDown,
33200
- onMouseLeave: () => setHoverValue(null),
33521
+ onPointerLeave: () => setHoverValue(null),
33201
33522
  children: Array.from({ length: max }, (_, i) => {
33202
33523
  const fillLevel = Math.max(0, Math.min(1, displayValue - i));
33203
33524
  const isFull = fillLevel >= 1;
@@ -33207,7 +33528,7 @@ var init_StarRating = __esm({
33207
33528
  {
33208
33529
  className: "relative inline-block",
33209
33530
  onClick: () => handleStarClick(i, false),
33210
- onMouseMove: (e) => {
33531
+ onPointerMove: (e) => {
33211
33532
  if (readOnly) return;
33212
33533
  const rect = e.currentTarget.getBoundingClientRect();
33213
33534
  const isLeftHalf = e.clientX - rect.left < rect.width / 2;
@@ -37097,7 +37418,7 @@ var init_PositionedCanvas = __esm({
37097
37418
  {
37098
37419
  ref: containerRef,
37099
37420
  "data-testid": "positioned-canvas",
37100
- className: "relative bg-background border border-border rounded-container overflow-hidden",
37421
+ className: "relative bg-background border border-border rounded-container overflow-hidden touch-none",
37101
37422
  style: { width, height },
37102
37423
  onClick: handleContainerClick,
37103
37424
  children: items.map((item) => {
@@ -40857,6 +41178,7 @@ var init_GraphCanvas = __esm({
40857
41178
  init_ErrorState();
40858
41179
  init_EmptyState();
40859
41180
  init_useEventBus();
41181
+ init_useCanvasGestures();
40860
41182
  GROUP_COLORS2 = [
40861
41183
  "var(--color-primary)",
40862
41184
  "var(--color-success)",
@@ -40894,6 +41216,10 @@ var init_GraphCanvas = __esm({
40894
41216
  const animRef = useRef(0);
40895
41217
  const [zoom, setZoom] = useState(1);
40896
41218
  const [offset, setOffset] = useState({ x: 0, y: 0 });
41219
+ const zoomRef = useRef(zoom);
41220
+ zoomRef.current = zoom;
41221
+ const offsetRef = useRef(offset);
41222
+ offsetRef.current = offset;
40897
41223
  const [hoveredNode, setHoveredNode] = useState(null);
40898
41224
  const nodesRef = useRef([]);
40899
41225
  const [, forceUpdate] = useState(0);
@@ -41153,25 +41479,27 @@ var init_GraphCanvas = __esm({
41153
41479
  setZoom(1);
41154
41480
  setOffset({ x: 0, y: 0 });
41155
41481
  }, []);
41156
- const handleWheel = useCallback(
41157
- (e) => {
41158
- if (!interactive) return;
41159
- e.preventDefault();
41160
- const coords = toCoords(e);
41161
- if (!coords) return;
41162
- const oldZoom = zoom;
41163
- const factor = e.deltaY < 0 ? 1.1 : 1 / 1.1;
41164
- const newZoom = Math.max(0.3, Math.min(3, oldZoom * factor));
41165
- if (newZoom === oldZoom) return;
41166
- setOffset((o) => ({
41167
- x: coords.screenX - (coords.screenX - o.x) * (newZoom / oldZoom),
41168
- y: coords.screenY - (coords.screenY - o.y) * (newZoom / oldZoom)
41169
- }));
41170
- setZoom(newZoom);
41171
- },
41172
- [interactive, toCoords, zoom]
41173
- );
41174
- const handleMouseDown = useCallback(
41482
+ const applyZoom = useCallback((factor, cx, cy) => {
41483
+ if (!interactive) return;
41484
+ const oldZoom = zoomRef.current;
41485
+ const newZoom = Math.max(0.3, Math.min(3, oldZoom * factor));
41486
+ if (newZoom === oldZoom) return;
41487
+ const o = offsetRef.current;
41488
+ setOffset({
41489
+ x: cx - (cx - o.x) * (newZoom / oldZoom),
41490
+ y: cy - (cy - o.y) * (newZoom / oldZoom)
41491
+ });
41492
+ setZoom(newZoom);
41493
+ }, [interactive]);
41494
+ const applyPanDelta = useCallback((dx, dy) => {
41495
+ if (!interactive) return;
41496
+ setOffset((o) => ({ x: o.x + dx, y: o.y + dy }));
41497
+ }, [interactive]);
41498
+ const cancelSinglePointer = useCallback(() => {
41499
+ interactionRef.current.mode = "none";
41500
+ interactionRef.current.dragNodeId = null;
41501
+ }, []);
41502
+ const handlePointerDown = useCallback(
41175
41503
  (e) => {
41176
41504
  const coords = toCoords(e);
41177
41505
  if (!coords) return;
@@ -41193,7 +41521,7 @@ var init_GraphCanvas = __esm({
41193
41521
  },
41194
41522
  [toCoords, nodeAt, draggable, interactive, offset]
41195
41523
  );
41196
- const handleMouseMove = useCallback(
41524
+ const handlePointerMove = useCallback(
41197
41525
  (e) => {
41198
41526
  const state = interactionRef.current;
41199
41527
  if (state.mode === "panning") {
@@ -41222,7 +41550,7 @@ var init_GraphCanvas = __esm({
41222
41550
  },
41223
41551
  [toCoords, nodeAt]
41224
41552
  );
41225
- const handleMouseUp = useCallback(
41553
+ const handlePointerUp = useCallback(
41226
41554
  (e) => {
41227
41555
  const state = interactionRef.current;
41228
41556
  const moved = Math.abs(e.clientX - state.downPos.x) + Math.abs(e.clientY - state.downPos.y);
@@ -41239,11 +41567,19 @@ var init_GraphCanvas = __esm({
41239
41567
  },
41240
41568
  [toCoords, nodeAt, handleNodeClick]
41241
41569
  );
41242
- const handleMouseLeave = useCallback(() => {
41243
- interactionRef.current.mode = "none";
41244
- interactionRef.current.dragNodeId = null;
41570
+ const handlePointerLeave = useCallback(() => {
41245
41571
  setHoveredNode(null);
41246
41572
  }, []);
41573
+ const gestureHandlers = useCanvasGestures({
41574
+ canvasRef,
41575
+ enabled: interactive || draggable,
41576
+ onPointerDown: handlePointerDown,
41577
+ onPointerMove: handlePointerMove,
41578
+ onPointerUp: handlePointerUp,
41579
+ onZoom: applyZoom,
41580
+ onPanDelta: applyPanDelta,
41581
+ onMultiTouchStart: cancelSinglePointer
41582
+ });
41247
41583
  const handleDoubleClick = useCallback(
41248
41584
  (e) => {
41249
41585
  const coords = toCoords(e);
@@ -41312,13 +41648,14 @@ var init_GraphCanvas = __esm({
41312
41648
  ref: canvasRef,
41313
41649
  width: Math.round(logicalW * (typeof window !== "undefined" && window.devicePixelRatio || 1)),
41314
41650
  height: Math.round(height * (typeof window !== "undefined" && window.devicePixelRatio || 1)),
41315
- className: "w-full cursor-grab active:cursor-grabbing",
41651
+ className: "w-full cursor-grab active:cursor-grabbing touch-none",
41316
41652
  style: { height },
41317
- onWheel: handleWheel,
41318
- onMouseDown: handleMouseDown,
41319
- onMouseMove: handleMouseMove,
41320
- onMouseUp: handleMouseUp,
41321
- onMouseLeave: handleMouseLeave,
41653
+ onPointerDown: gestureHandlers.onPointerDown,
41654
+ onPointerMove: gestureHandlers.onPointerMove,
41655
+ onPointerUp: gestureHandlers.onPointerUp,
41656
+ onPointerCancel: gestureHandlers.onPointerCancel,
41657
+ onPointerLeave: handlePointerLeave,
41658
+ onWheel: gestureHandlers.onWheel,
41322
41659
  onDoubleClick: handleDoubleClick
41323
41660
  }
41324
41661
  ) }),
@@ -45790,6 +46127,9 @@ var init_GameCanvas3D2 = __esm({
45790
46127
  target: cameraTarget,
45791
46128
  enableDamping: true,
45792
46129
  dampingFactor: 0.05,
46130
+ enableZoom: true,
46131
+ enablePan: true,
46132
+ touches: { ONE: THREE3.TOUCH.ROTATE, TWO: THREE3.TOUCH.DOLLY_PAN },
45793
46133
  minDistance: 2,
45794
46134
  maxDistance: 100,
45795
46135
  maxPolarAngle: Math.PI / 2 - 0.1
@@ -51120,20 +51460,21 @@ var init_SplitPane = __esm({
51120
51460
  const [ratio, setRatio] = useState(initialRatio);
51121
51461
  const containerRef = useRef(null);
51122
51462
  const isDragging = useRef(false);
51123
- const handleMouseDown = useCallback(
51463
+ const handlePointerDown = useCallback(
51124
51464
  (e) => {
51125
51465
  if (!resizable) return;
51126
51466
  e.preventDefault();
51127
51467
  isDragging.current = true;
51128
- const handleMouseMove = (e2) => {
51468
+ e.currentTarget.setPointerCapture(e.pointerId);
51469
+ const handlePointerMove = (ev) => {
51129
51470
  if (!isDragging.current || !containerRef.current) return;
51130
51471
  const rect = containerRef.current.getBoundingClientRect();
51131
51472
  let newRatio;
51132
51473
  if (direction === "horizontal") {
51133
- const x = e2.clientX - rect.left;
51474
+ const x = ev.clientX - rect.left;
51134
51475
  newRatio = x / rect.width * 100;
51135
51476
  } else {
51136
- const y = e2.clientY - rect.top;
51477
+ const y = ev.clientY - rect.top;
51137
51478
  newRatio = y / rect.height * 100;
51138
51479
  }
51139
51480
  const minRatio = minSize / (direction === "horizontal" ? rect.width : rect.height) * 100;
@@ -51141,13 +51482,15 @@ var init_SplitPane = __esm({
51141
51482
  newRatio = Math.max(minRatio, Math.min(maxRatio, newRatio));
51142
51483
  setRatio(newRatio);
51143
51484
  };
51144
- const handleMouseUp = () => {
51485
+ const handlePointerUp = () => {
51145
51486
  isDragging.current = false;
51146
- document.removeEventListener("mousemove", handleMouseMove);
51147
- document.removeEventListener("mouseup", handleMouseUp);
51487
+ document.removeEventListener("pointermove", handlePointerMove);
51488
+ document.removeEventListener("pointerup", handlePointerUp);
51489
+ document.removeEventListener("pointercancel", handlePointerUp);
51148
51490
  };
51149
- document.addEventListener("mousemove", handleMouseMove);
51150
- document.addEventListener("mouseup", handleMouseUp);
51491
+ document.addEventListener("pointermove", handlePointerMove);
51492
+ document.addEventListener("pointerup", handlePointerUp);
51493
+ document.addEventListener("pointercancel", handlePointerUp);
51151
51494
  },
51152
51495
  [direction, minSize, resizable]
51153
51496
  );
@@ -51176,9 +51519,9 @@ var init_SplitPane = __esm({
51176
51519
  resizable && /* @__PURE__ */ jsx(
51177
51520
  "div",
51178
51521
  {
51179
- onMouseDown: handleMouseDown,
51522
+ onPointerDown: handlePointerDown,
51180
51523
  className: cn(
51181
- "flex-shrink-0 bg-border transition-colors",
51524
+ "flex-shrink-0 bg-border transition-colors touch-none",
51182
51525
  isHorizontal ? "w-1 cursor-col-resize hover:w-1.5 hover:bg-muted-foreground" : "h-1 cursor-row-resize hover:h-1.5 hover:bg-muted-foreground"
51183
51526
  )
51184
51527
  }