@cloudparse/up-miniapps-sdk 0.2.7 → 0.5.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/dist/index.cjs CHANGED
@@ -43,9 +43,11 @@ __export(src_exports, {
43
43
  MapMenuItem: () => MapMenuItem,
44
44
  MapMenuTitle: () => MapMenuTitle,
45
45
  MiniAppSDK: () => MiniAppSDK,
46
+ MockLocationContext: () => MockLocationContext,
46
47
  RouteLayer: () => RouteLayer,
47
48
  SDKMapProvider: () => SDKMapProvider,
48
49
  SDKProvider: () => SDKProvider,
50
+ SwipeCarousel: () => SwipeCarousel,
49
51
  UIEvent: () => UIEvent,
50
52
  default: () => src_default,
51
53
  handleClearRoute: () => handleClearRoute,
@@ -54,14 +56,21 @@ __export(src_exports, {
54
56
  renderMap: () => renderMap,
55
57
  sdk: () => sdk,
56
58
  useIsMocked: () => useIsMocked,
59
+ useJourney: () => useJourney,
57
60
  useLiveRouting: () => useLiveRouting,
58
61
  useMapControls: () => useMapControls,
62
+ useMockLocation: () => useMockLocation,
59
63
  useRoute: () => useRoute,
60
64
  useTrimmedRoute: () => useTrimmedRoute,
61
65
  useUserLocation: () => useUserLocation
62
66
  });
63
67
  module.exports = __toCommonJS(src_exports);
64
68
 
69
+ // src/components/Map/MockLocationContext.tsx
70
+ var import_react = require("react");
71
+ var MockLocationContext = (0, import_react.createContext)(null);
72
+ var useMockLocation = () => (0, import_react.useContext)(MockLocationContext);
73
+
65
74
  // src/lib/utils.ts
66
75
  var import_clsx = require("clsx");
67
76
  var import_tailwind_merge = require("tailwind-merge");
@@ -388,7 +397,7 @@ var SheetDescription = React2.forwardRef(({ className, ...props }, ref) => /* @_
388
397
  SheetDescription.displayName = SheetPrimitive.Description.displayName;
389
398
 
390
399
  // src/components/Map/components/MapDrawer.tsx
391
- var import_react = require("react");
400
+ var import_react2 = require("react");
392
401
  var import_jsx_runtime3 = require("react/jsx-runtime");
393
402
  var resolveHeightToPixels = (height, containerHeight) => {
394
403
  if (typeof height === "number") {
@@ -399,7 +408,9 @@ var resolveHeightToPixels = (height, containerHeight) => {
399
408
  }
400
409
  return parseFloat(height);
401
410
  };
402
- var MapDrawer = (0, import_react.forwardRef)(
411
+ var CONTENT_EDGE_PULL_THRESHOLD_PX = 24;
412
+ var HANDLE_BAR_HEIGHT_PX = 32;
413
+ var MapDrawer = (0, import_react2.forwardRef)(
403
414
  ({
404
415
  menuItems,
405
416
  state,
@@ -415,16 +426,21 @@ var MapDrawer = (0, import_react.forwardRef)(
415
426
  clampedDragOffset,
416
427
  drawerPeekHeight,
417
428
  drawerFullHeight,
429
+ drawerAutoMaxHeight,
418
430
  containerHeight,
419
431
  menuContent,
420
432
  enableTouchDrag = false,
433
+ handleVisible = true,
434
+ onAutoContentHeightChange,
421
435
  showScrollToTopButton = true,
422
436
  scrollToTopThreshold = 300,
423
437
  safeAreaInsets = { bottom: 0, left: 0, right: 0, top: 0 }
424
438
  }, ref) => {
425
- const scrollContainerRef = (0, import_react.useRef)(null);
426
- const containerRef = (0, import_react.useRef)(null);
427
- (0, import_react.useImperativeHandle)(
439
+ const scrollContainerRef = (0, import_react2.useRef)(null);
440
+ const containerRef = (0, import_react2.useRef)(null);
441
+ const handleBarRef = (0, import_react2.useRef)(null);
442
+ const contentAreaRef = (0, import_react2.useRef)(null);
443
+ (0, import_react2.useImperativeHandle)(
428
444
  ref,
429
445
  () => scrollContainerRef.current
430
446
  );
@@ -436,17 +452,42 @@ var MapDrawer = (0, import_react.forwardRef)(
436
452
  onChangeState("peek");
437
453
  } else if (state === "peek") {
438
454
  onChangeState("full");
455
+ } else if (state === "auto") {
456
+ onChangeState("closed");
439
457
  } else {
440
458
  onChangeState("peek");
441
459
  }
442
460
  }
443
461
  };
444
- const [showScrollTop, setShowScrollTop] = (0, import_react.useState)(false);
462
+ const handleHandleClickRef = (0, import_react2.useRef)(handleHandleClick);
463
+ handleHandleClickRef.current = handleHandleClick;
464
+ const [autoContentPx, setAutoContentPx] = (0, import_react2.useState)(0);
465
+ (0, import_react2.useEffect)(() => {
466
+ if (state !== "auto") return;
467
+ const scrollEl = scrollContainerRef.current;
468
+ const contentAreaEl = contentAreaRef.current;
469
+ if (!scrollEl || !contentAreaEl) return;
470
+ const handleHeight = handleVisible ? handleBarRef.current?.offsetHeight ?? 0 : 0;
471
+ const contentEl = scrollEl.firstElementChild;
472
+ const measure = () => {
473
+ const contentAreaStyle = window.getComputedStyle(contentAreaEl);
474
+ const verticalPadding = parseFloat(contentAreaStyle.paddingTop || "0") + parseFloat(contentAreaStyle.paddingBottom || "0");
475
+ const contentHeight = contentEl?.scrollHeight ?? scrollEl.scrollHeight;
476
+ const px = handleHeight + verticalPadding + contentHeight;
477
+ setAutoContentPx(px);
478
+ onAutoContentHeightChange?.(px);
479
+ };
480
+ measure();
481
+ const ro = new ResizeObserver(measure);
482
+ ro.observe(contentEl ?? scrollEl);
483
+ return () => ro.disconnect();
484
+ }, [state, handleVisible, onAutoContentHeightChange]);
485
+ const [showScrollTop, setShowScrollTop] = (0, import_react2.useState)(false);
445
486
  const handleScroll = (e) => {
446
487
  const scrollTop = e.currentTarget.scrollTop;
447
488
  setShowScrollTop(state !== "closed" && scrollTop > scrollToTopThreshold);
448
489
  };
449
- (0, import_react.useEffect)(() => {
490
+ (0, import_react2.useEffect)(() => {
450
491
  if (state === "closed") {
451
492
  setShowScrollTop(false);
452
493
  } else {
@@ -454,22 +495,28 @@ var MapDrawer = (0, import_react.forwardRef)(
454
495
  setShowScrollTop(scrollTop > scrollToTopThreshold);
455
496
  }
456
497
  }, [state, scrollToTopThreshold]);
457
- const isDraggingSheet = (0, import_react.useRef)(false);
458
- const hasDeterminedDirection = (0, import_react.useRef)(false);
459
- const isTouchOnContent = (0, import_react.useRef)(false);
460
- const stateRef = (0, import_react.useRef)(state);
461
- const touchStartYRef = (0, import_react.useRef)(touchStartY);
462
- const currentTouchYRef = (0, import_react.useRef)(currentTouchY);
463
- (0, import_react.useEffect)(() => {
498
+ const isDraggingSheet = (0, import_react2.useRef)(false);
499
+ const hasDeterminedDirection = (0, import_react2.useRef)(false);
500
+ const isTouchOnContent = (0, import_react2.useRef)(false);
501
+ const isTouchOnHandle = (0, import_react2.useRef)(false);
502
+ const suppressNextClickRef = (0, import_react2.useRef)(false);
503
+ const contentAtTopSinceY = (0, import_react2.useRef)(null);
504
+ const contentAtBottomSinceY = (0, import_react2.useRef)(null);
505
+ const dragStartYRef = (0, import_react2.useRef)(null);
506
+ const dragBaseHeightPxRef = (0, import_react2.useRef)(0);
507
+ const stateRef = (0, import_react2.useRef)(state);
508
+ const touchStartYRef = (0, import_react2.useRef)(touchStartY);
509
+ const currentTouchYRef = (0, import_react2.useRef)(currentTouchY);
510
+ (0, import_react2.useEffect)(() => {
464
511
  stateRef.current = state;
465
512
  }, [state]);
466
- (0, import_react.useEffect)(() => {
513
+ (0, import_react2.useEffect)(() => {
467
514
  touchStartYRef.current = touchStartY;
468
515
  }, [touchStartY]);
469
- (0, import_react.useEffect)(() => {
516
+ (0, import_react2.useEffect)(() => {
470
517
  currentTouchYRef.current = currentTouchY;
471
518
  }, [currentTouchY]);
472
- (0, import_react.useEffect)(() => {
519
+ (0, import_react2.useEffect)(() => {
473
520
  const container = containerRef.current;
474
521
  if (!container || side !== "bottom" || !enableTouchDrag) return;
475
522
  const handleNativeTouchStart = (e) => {
@@ -478,8 +525,12 @@ var MapDrawer = (0, import_react.forwardRef)(
478
525
  setCurrentTouchY(clientY);
479
526
  isDraggingSheet.current = false;
480
527
  hasDeterminedDirection.current = false;
528
+ contentAtTopSinceY.current = null;
529
+ contentAtBottomSinceY.current = null;
530
+ dragStartYRef.current = null;
481
531
  const target = e.target;
482
532
  isTouchOnContent.current = scrollContainerRef.current ? scrollContainerRef.current.contains(target) : false;
533
+ isTouchOnHandle.current = handleBarRef.current ? handleBarRef.current.contains(target) : false;
483
534
  };
484
535
  const handleNativeTouchMove = (e) => {
485
536
  const startY = touchStartYRef.current;
@@ -491,39 +542,86 @@ var MapDrawer = (0, import_react.forwardRef)(
491
542
  const scrollHeight = scrollContainerRef.current ? scrollContainerRef.current.scrollHeight : 0;
492
543
  const isAtBottom = scrollTop + clientHeight >= scrollHeight - 1;
493
544
  const currentState = stateRef.current;
545
+ const containerHForHeights = containerHeight || container.parentElement?.getBoundingClientRect().height || window.innerHeight;
546
+ const fullPxNow = resolveHeightToPixels(
547
+ drawerFullHeight || "85%",
548
+ containerHForHeights
549
+ );
550
+ const peekPxNow = resolveHeightToPixels(
551
+ drawerPeekHeight || "15%",
552
+ containerHForHeights
553
+ );
554
+ const closedPxNow = (handleVisible ? HANDLE_BAR_HEIGHT_PX : 0) + (currentState === "closed" ? safeAreaInsets.bottom : 0);
555
+ const autoMaxPxNow = resolveHeightToPixels(
556
+ drawerAutoMaxHeight || "100%",
557
+ containerHForHeights
558
+ );
559
+ const autoPxNow = Math.min(autoMaxPxNow, autoContentPx);
560
+ const baselineHeightPxForState = (s) => {
561
+ if (s === "full") return fullPxNow;
562
+ if (s === "peek") return peekPxNow;
563
+ if (s === "auto") return autoPxNow;
564
+ return closedPxNow;
565
+ };
566
+ const commitDrag = () => {
567
+ isDraggingSheet.current = true;
568
+ dragStartYRef.current = currentY;
569
+ dragBaseHeightPxRef.current = baselineHeightPxForState(currentState);
570
+ };
571
+ if (scrollTop <= 0) {
572
+ if (contentAtTopSinceY.current === null) {
573
+ contentAtTopSinceY.current = currentY;
574
+ }
575
+ } else {
576
+ contentAtTopSinceY.current = null;
577
+ }
578
+ if (isAtBottom) {
579
+ if (contentAtBottomSinceY.current === null) {
580
+ contentAtBottomSinceY.current = currentY;
581
+ }
582
+ } else {
583
+ contentAtBottomSinceY.current = null;
584
+ }
585
+ const pullPastTop = contentAtTopSinceY.current !== null ? currentY - contentAtTopSinceY.current : 0;
586
+ const pullPastBottom = contentAtBottomSinceY.current !== null ? contentAtBottomSinceY.current - currentY : 0;
494
587
  if (!hasDeterminedDirection.current) {
495
588
  if (!isTouchOnContent.current) {
496
- isDraggingSheet.current = true;
589
+ if (Math.abs(deltaY) < CONTENT_EDGE_PULL_THRESHOLD_PX) {
590
+ return;
591
+ }
592
+ commitDrag();
497
593
  hasDeterminedDirection.current = true;
498
594
  } else if (currentState !== "full") {
499
- if (deltaY > 0 && isAtBottom) {
500
- isDraggingSheet.current = true;
595
+ if (deltaY > 0 && isAtBottom && pullPastBottom >= CONTENT_EDGE_PULL_THRESHOLD_PX) {
596
+ commitDrag();
501
597
  hasDeterminedDirection.current = true;
502
- } else if (deltaY < 0 && scrollTop <= 0) {
503
- isDraggingSheet.current = true;
598
+ } else if (deltaY < 0 && scrollTop <= 0 && pullPastTop >= CONTENT_EDGE_PULL_THRESHOLD_PX) {
599
+ commitDrag();
504
600
  hasDeterminedDirection.current = true;
601
+ } else if (deltaY > 0 && isAtBottom || deltaY < 0 && scrollTop <= 0) {
602
+ return;
505
603
  } else {
506
604
  isDraggingSheet.current = false;
507
605
  hasDeterminedDirection.current = true;
508
606
  }
509
607
  } else {
510
- if (deltaY < 0 && scrollTop <= 0) {
511
- isDraggingSheet.current = true;
608
+ if (deltaY < 0 && scrollTop <= 0 && pullPastTop >= CONTENT_EDGE_PULL_THRESHOLD_PX) {
609
+ commitDrag();
512
610
  hasDeterminedDirection.current = true;
611
+ } else if (deltaY < 0 && scrollTop <= 0) {
612
+ return;
513
613
  } else {
514
614
  isDraggingSheet.current = false;
515
615
  hasDeterminedDirection.current = true;
516
616
  }
517
617
  }
518
618
  } else if (!isDraggingSheet.current && isTouchOnContent.current) {
519
- if (deltaY < 0 && scrollTop <= 0) {
520
- isDraggingSheet.current = true;
521
- setTouchStartY(currentY);
619
+ if (deltaY < 0 && scrollTop <= 0 && pullPastTop >= CONTENT_EDGE_PULL_THRESHOLD_PX) {
620
+ commitDrag();
522
621
  return;
523
622
  }
524
- if (deltaY > 0 && isAtBottom && currentState !== "full") {
525
- isDraggingSheet.current = true;
526
- setTouchStartY(currentY);
623
+ if (deltaY > 0 && isAtBottom && currentState !== "full" && pullPastBottom >= CONTENT_EDGE_PULL_THRESHOLD_PX) {
624
+ commitDrag();
527
625
  return;
528
626
  }
529
627
  }
@@ -533,33 +631,25 @@ var MapDrawer = (0, import_react.forwardRef)(
533
631
  }
534
632
  const parentContainer = container.parentElement;
535
633
  if (parentContainer) {
536
- const containerH2 = containerHeight || parentContainer.getBoundingClientRect().height;
537
- const fullPx2 = resolveHeightToPixels(
538
- drawerFullHeight || "85%",
539
- containerH2
540
- );
541
- const peekPx2 = resolveHeightToPixels(
542
- drawerPeekHeight || "15%",
543
- containerH2
544
- );
545
- const closedPx = 32 + (currentState === "closed" ? safeAreaInsets.bottom : 0);
546
- const dragOffset = currentY - startY;
634
+ const dragOffset = currentY - (dragStartYRef.current ?? currentY);
547
635
  let localClamped = dragOffset;
548
636
  if (currentState === "full") {
549
637
  localClamped = Math.max(
550
638
  0,
551
- Math.min(fullPx2 - closedPx, dragOffset)
639
+ Math.min(fullPxNow - closedPxNow, dragOffset)
552
640
  );
553
641
  } else if (currentState === "peek") {
554
642
  localClamped = Math.max(
555
- -(fullPx2 - peekPx2),
556
- Math.min(peekPx2 - closedPx, dragOffset)
643
+ -(fullPxNow - peekPxNow),
644
+ Math.min(peekPxNow - closedPxNow, dragOffset)
557
645
  );
558
646
  } else if (currentState === "closed") {
559
647
  localClamped = Math.min(
560
648
  0,
561
- Math.max(-(fullPx2 - closedPx), dragOffset)
649
+ Math.max(-(fullPxNow - closedPxNow), dragOffset)
562
650
  );
651
+ } else if (currentState === "auto") {
652
+ localClamped = Math.max(0, dragOffset);
563
653
  }
564
654
  parentContainer.style.setProperty(
565
655
  "--drag-offset",
@@ -579,6 +669,13 @@ var MapDrawer = (0, import_react.forwardRef)(
579
669
  return;
580
670
  }
581
671
  if (!isDraggingSheet.current) {
672
+ if (isTouchOnHandle.current) {
673
+ handleHandleClickRef.current();
674
+ suppressNextClickRef.current = true;
675
+ setTimeout(() => {
676
+ suppressNextClickRef.current = false;
677
+ }, 500);
678
+ }
582
679
  setTouchStartY(null);
583
680
  setCurrentTouchY(null);
584
681
  if (parentContainer) {
@@ -587,7 +684,8 @@ var MapDrawer = (0, import_react.forwardRef)(
587
684
  return;
588
685
  }
589
686
  const touchEndY = e.changedTouches[0].clientY;
590
- const dragDistance = Math.abs(touchEndY - startY);
687
+ const dragStartY = dragStartYRef.current ?? startY;
688
+ const dragDistance = Math.abs(touchEndY - dragStartY);
591
689
  if (dragDistance < 10) {
592
690
  setTouchStartY(null);
593
691
  setCurrentTouchY(null);
@@ -597,9 +695,6 @@ var MapDrawer = (0, import_react.forwardRef)(
597
695
  return;
598
696
  }
599
697
  const containerH2 = containerHeight || (parentContainer ? parentContainer.getBoundingClientRect().height : window.innerHeight);
600
- const containerTop = parentContainer ? parentContainer.getBoundingClientRect().top : 0;
601
- const touchYInContainer = touchEndY - containerTop;
602
- const drawerHeightFromBottom = containerH2 - touchYInContainer;
603
698
  const fullPx2 = resolveHeightToPixels(
604
699
  drawerFullHeight || "85%",
605
700
  containerH2
@@ -609,18 +704,30 @@ var MapDrawer = (0, import_react.forwardRef)(
609
704
  containerH2
610
705
  );
611
706
  const currentState = stateRef.current;
612
- const closedPx = 32 + (currentState === "closed" ? safeAreaInsets.bottom : 0);
613
- const distToFull = Math.abs(drawerHeightFromBottom - fullPx2);
614
- const distToPeek = Math.abs(drawerHeightFromBottom - peekPx2);
707
+ const closedPx = (handleVisible ? HANDLE_BAR_HEIGHT_PX : 0) + (currentState === "closed" ? safeAreaInsets.bottom : 0);
708
+ const dragDelta = touchEndY - dragStartY;
709
+ const drawerHeightFromBottom = dragBaseHeightPxRef.current - dragDelta;
615
710
  const distToClosed = Math.abs(drawerHeightFromBottom - closedPx);
616
- const minDist = Math.min(distToFull, distToPeek, distToClosed);
617
- let targetState = "closed";
618
- if (minDist === distToFull) {
619
- targetState = "full";
620
- } else if (minDist === distToPeek) {
621
- targetState = "peek";
711
+ let targetState;
712
+ if (currentState === "auto") {
713
+ const autoMaxPx2 = resolveHeightToPixels(
714
+ drawerAutoMaxHeight || "100%",
715
+ containerH2
716
+ );
717
+ const autoPx2 = Math.min(autoMaxPx2, autoContentPx);
718
+ const distToAuto = Math.abs(drawerHeightFromBottom - autoPx2);
719
+ targetState = distToAuto <= distToClosed ? "auto" : "closed";
622
720
  } else {
623
- targetState = "closed";
721
+ const distToFull = Math.abs(drawerHeightFromBottom - fullPx2);
722
+ const distToPeek = Math.abs(drawerHeightFromBottom - peekPx2);
723
+ const minDist = Math.min(distToFull, distToPeek, distToClosed);
724
+ if (minDist === distToFull) {
725
+ targetState = "full";
726
+ } else if (minDist === distToPeek) {
727
+ targetState = "peek";
728
+ } else {
729
+ targetState = "closed";
730
+ }
624
731
  }
625
732
  setTouchStartY(null);
626
733
  setCurrentTouchY(null);
@@ -651,17 +758,26 @@ var MapDrawer = (0, import_react.forwardRef)(
651
758
  containerHeight,
652
759
  drawerFullHeight,
653
760
  drawerPeekHeight,
761
+ drawerAutoMaxHeight,
654
762
  safeAreaInsets,
655
763
  onChangeState,
656
764
  setTouchStartY,
657
- setCurrentTouchY
765
+ setCurrentTouchY,
766
+ autoContentPx,
767
+ handleVisible
658
768
  ]);
659
- const isBackdropActive = state === "full";
769
+ const isBackdropActive = state === "full" || state === "auto";
660
770
  const backdropStyles = isBackdropActive ? "opacity-100 pointer-events-auto" : "opacity-0 pointer-events-none";
661
771
  const containerH = containerHeight || window.innerHeight;
662
772
  const fullPx = resolveHeightToPixels(drawerFullHeight || "85%", containerH);
663
773
  const peekPx = resolveHeightToPixels(drawerPeekHeight || "15%", containerH);
774
+ const autoMaxPx = resolveHeightToPixels(
775
+ drawerAutoMaxHeight || "100%",
776
+ containerH
777
+ );
664
778
  const shiftPx = fullPx - peekPx;
779
+ const autoPx = Math.min(autoMaxPx, autoContentPx);
780
+ const autoShiftPx = Math.max(fullPx - autoPx, 0);
665
781
  const getBottomDrawerTransform = () => {
666
782
  if (state === "full") {
667
783
  return "translateY(var(--drag-offset, 0px))";
@@ -669,7 +785,10 @@ var MapDrawer = (0, import_react.forwardRef)(
669
785
  if (state === "peek") {
670
786
  return `translateY(calc(${shiftPx}px + var(--drag-offset, 0px)))`;
671
787
  }
672
- const closedVisibleHeight = 32;
788
+ if (state === "auto") {
789
+ return `translateY(calc(${autoShiftPx}px + var(--drag-offset, 0px)))`;
790
+ }
791
+ const closedVisibleHeight = handleVisible ? HANDLE_BAR_HEIGHT_PX : 0;
673
792
  const closedShiftPx = fullPx - closedVisibleHeight;
674
793
  return `translateY(calc(${closedShiftPx}px + var(--drag-offset, 0px)))`;
675
794
  };
@@ -803,17 +922,34 @@ var MapDrawer = (0, import_react.forwardRef)(
803
922
  ref: containerRef,
804
923
  style: {
805
924
  bottom: "0px",
806
- height: typeof drawerFullHeight === "number" ? `${drawerFullHeight}px` : drawerFullHeight || "85%",
925
+ // Box height must stay exactly fullPx for "closed"/"peek"/
926
+ // "full" — every other transform calc in this component
927
+ // assumes the box IS fullPx tall. Only "auto" grows it (up to
928
+ // autoMaxPx) when content needs more room than fullPx offers;
929
+ // getBottomDrawerTransform()'s auto branch is derived to match
930
+ // (shift = max(fullPx - autoPx, 0), so a taller box needs zero
931
+ // extra shift to fully reveal itself).
932
+ height: `${state === "auto" ? Math.max(fullPx, autoPx) : fullPx}px`,
807
933
  marginBottom: state === "closed" ? `${safeAreaInsets.bottom}px` : "0px",
808
934
  transform: getBottomDrawerTransform(),
809
- transition: isDragging ? "none" : "transform 300ms ease-out, margin-bottom 250ms ease-in-out"
935
+ // `height` is animated too (not just transform/margin-bottom):
936
+ // entering/leaving "auto" with content taller than fullPx
937
+ // changes the box's actual CSS height, and without this it
938
+ // would snap instantly while transform eases in over 300ms —
939
+ // a visible pop of content before the slide animation catches
940
+ // up.
941
+ transition: isDragging ? "none" : "transform 300ms ease-out, height 300ms ease-out, margin-bottom 250ms ease-in-out"
810
942
  },
811
943
  children: [
812
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
944
+ handleVisible && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
813
945
  "div",
814
946
  {
815
947
  className: "w-full h-8 flex flex-col items-center justify-center cursor-pointer hover:bg-white/5 rounded-t-2xl transition-colors border-b border-white/5",
816
- onClick: handleHandleClick,
948
+ onClick: () => {
949
+ if (suppressNextClickRef.current) return;
950
+ handleHandleClick();
951
+ },
952
+ ref: handleBarRef,
817
953
  children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "w-12 h-1 bg-white/25 rounded-full" })
818
954
  }
819
955
  ),
@@ -821,6 +957,7 @@ var MapDrawer = (0, import_react.forwardRef)(
821
957
  "div",
822
958
  {
823
959
  className: "flex-1 flex flex-col overflow-hidden px-4 pb-4 pt-2 transition-[margin-top] duration-250 ease-in-out relative",
960
+ ref: contentAreaRef,
824
961
  style: {
825
962
  marginTop: state === "closed" ? `${safeAreaInsets.bottom}px` : "0px"
826
963
  },
@@ -1209,7 +1346,8 @@ var MapRightControls = ({
1209
1346
  customRecenterButton,
1210
1347
  customCompassButton,
1211
1348
  drawerPeekHeight,
1212
- insets = { bottom: 0, left: 0, right: 0, top: 0 }
1349
+ insets = { bottom: 0, left: 0, right: 0, top: 0 },
1350
+ bottomOffset = 0
1213
1351
  }) => {
1214
1352
  const aboveControls = customControls.filter(
1215
1353
  (c) => c.position === "above-recenter"
@@ -1221,7 +1359,7 @@ var MapRightControls = ({
1221
1359
  const closedHeightOffset = "32px";
1222
1360
  const activeEtaHeight = etaData ? etaBarHeight : drawerState === "closed" ? insets.bottom : 0;
1223
1361
  const peekStyle = typeof drawerPeekHeight === "number" ? `${drawerPeekHeight}px` : drawerPeekHeight || "15%";
1224
- const controlsBottom = side === "bottom" ? drawerState === "closed" ? `calc(${closedHeightOffset} + 1rem + ${activeEtaHeight}px - var(--drag-offset, 0px))` : `calc(${peekStyle} + 1rem + ${etaData ? etaBarHeight : 0}px - var(--drag-offset, 0px))` : `calc(1rem + ${insets.bottom}px)`;
1362
+ const controlsBottom = side === "bottom" ? drawerState === "closed" ? `calc(${closedHeightOffset} + 1rem + ${activeEtaHeight}px + ${bottomOffset}px - var(--drag-offset, 0px))` : `calc(${peekStyle} + 1rem + ${etaData ? etaBarHeight : 0}px + ${bottomOffset}px - var(--drag-offset, 0px))` : `calc(1rem + ${insets.bottom}px + ${bottomOffset}px)`;
1225
1363
  const isControlsVisible = side !== "bottom" || drawerState !== "full";
1226
1364
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1227
1365
  "div",
@@ -1349,28 +1487,32 @@ var MapRightControls = ({
1349
1487
  };
1350
1488
 
1351
1489
  // src/components/Map/MapContext.tsx
1352
- var import_react2 = require("react");
1490
+ var import_react3 = require("react");
1353
1491
  var import_jsx_runtime7 = require("react/jsx-runtime");
1354
- var MapControlsContext = (0, import_react2.createContext)(
1492
+ var MapControlsContext = (0, import_react3.createContext)(
1355
1493
  null
1356
1494
  );
1357
1495
  var SDKMapProvider = ({
1358
1496
  children
1359
1497
  }) => {
1360
- const [isFollowing, setIsFollowing] = (0, import_react2.useState)(true);
1361
- const [bearing, setBearingState] = (0, import_react2.useState)(0);
1362
- const [pitch, setPitchState] = (0, import_react2.useState)(0);
1363
- const [drawerState, setDrawerStateInternal] = (0, import_react2.useState)("closed");
1364
- const drawerContentRef = (0, import_react2.useRef)(null);
1365
- const setDrawerState = (0, import_react2.useCallback)((val) => {
1498
+ const [isFollowing, setIsFollowing] = (0, import_react3.useState)(true);
1499
+ const [bearing, setBearingState] = (0, import_react3.useState)(0);
1500
+ const [pitch, setPitchState] = (0, import_react3.useState)(0);
1501
+ const [drawerState, setDrawerStateInternal] = (0, import_react3.useState)("closed");
1502
+ const drawerContentRef = (0, import_react3.useRef)(null);
1503
+ const setDrawerState = (0, import_react3.useCallback)((val) => {
1366
1504
  setDrawerStateInternal(val);
1367
1505
  }, []);
1368
- const [hasControls, setHasControlsState] = (0, import_react2.useState)(false);
1369
- const setHasControls = (0, import_react2.useCallback)((val) => {
1506
+ const [drawerHandleVisible, setDrawerHandleVisibleState] = (0, import_react3.useState)(true);
1507
+ const setDrawerHandleVisible = (0, import_react3.useCallback)((val) => {
1508
+ setDrawerHandleVisibleState((prev) => prev === val ? prev : val);
1509
+ }, []);
1510
+ const [hasControls, setHasControlsState] = (0, import_react3.useState)(false);
1511
+ const setHasControls = (0, import_react3.useCallback)((val) => {
1370
1512
  setHasControlsState((prev) => prev === val ? prev : val);
1371
1513
  }, []);
1372
- const [etaData, setEtaDataState] = (0, import_react2.useState)(void 0);
1373
- const setEtaData = (0, import_react2.useCallback)((newData) => {
1514
+ const [etaData, setEtaDataState] = (0, import_react3.useState)(void 0);
1515
+ const setEtaData = (0, import_react3.useCallback)((newData) => {
1374
1516
  setEtaDataState((prev) => {
1375
1517
  if (!prev && !newData) return prev;
1376
1518
  if (!prev || !newData) return newData;
@@ -1380,60 +1522,79 @@ var SDKMapProvider = ({
1380
1522
  return newData;
1381
1523
  });
1382
1524
  }, []);
1383
- const [insets, setInsetsState] = (0, import_react2.useState)({
1525
+ const [insets, setInsetsState] = (0, import_react3.useState)({
1384
1526
  bottom: 0,
1385
1527
  left: 0,
1386
1528
  right: 0,
1387
1529
  top: 0
1388
1530
  });
1389
- const setInsets = (0, import_react2.useCallback)((newInsets) => {
1531
+ const setInsets = (0, import_react3.useCallback)((newInsets) => {
1390
1532
  setInsetsState((prev) => ({ ...prev, ...newInsets }));
1391
1533
  }, []);
1392
- const centerCallbackRef = (0, import_react2.useRef)(null);
1393
- const resetBearingCallbackRef = (0, import_react2.useRef)(null);
1394
- const centerOnUser = (0, import_react2.useCallback)((params) => {
1534
+ const centerCallbackRef = (0, import_react3.useRef)(null);
1535
+ const resetBearingCallbackRef = (0, import_react3.useRef)(null);
1536
+ const flyToCallbackRef = (0, import_react3.useRef)(null);
1537
+ const centerOnUser = (0, import_react3.useCallback)((params) => {
1395
1538
  if (centerCallbackRef.current) {
1396
1539
  centerCallbackRef.current(params);
1397
1540
  }
1398
1541
  }, []);
1399
- const resetBearing = (0, import_react2.useCallback)((params) => {
1542
+ const resetBearing = (0, import_react3.useCallback)((params) => {
1400
1543
  if (resetBearingCallbackRef.current) {
1401
1544
  resetBearingCallbackRef.current(params);
1402
1545
  }
1403
1546
  }, []);
1404
- const _registerCenterCallback = (0, import_react2.useCallback)(
1547
+ const flyTo = (0, import_react3.useCallback)(
1548
+ (coords, params) => {
1549
+ if (flyToCallbackRef.current) {
1550
+ flyToCallbackRef.current(coords, params);
1551
+ }
1552
+ },
1553
+ []
1554
+ );
1555
+ const _registerCenterCallback = (0, import_react3.useCallback)(
1405
1556
  (cb) => {
1406
1557
  centerCallbackRef.current = cb;
1407
1558
  },
1408
1559
  []
1409
1560
  );
1410
- const _registerResetBearingCallback = (0, import_react2.useCallback)(
1561
+ const _registerResetBearingCallback = (0, import_react3.useCallback)(
1411
1562
  (cb) => {
1412
1563
  resetBearingCallbackRef.current = cb;
1413
1564
  },
1414
1565
  []
1415
1566
  );
1416
- const setBearing = (0, import_react2.useCallback)((b) => {
1567
+ const _registerFlyToCallback = (0, import_react3.useCallback)(
1568
+ (cb) => {
1569
+ flyToCallbackRef.current = cb;
1570
+ },
1571
+ []
1572
+ );
1573
+ const setBearing = (0, import_react3.useCallback)((b) => {
1417
1574
  setBearingState(b);
1418
1575
  }, []);
1419
- const setPitch = (0, import_react2.useCallback)((p) => {
1576
+ const setPitch = (0, import_react3.useCallback)((p) => {
1420
1577
  setPitchState(p);
1421
1578
  }, []);
1422
- const contextValue = (0, import_react2.useMemo)(
1579
+ const contextValue = (0, import_react3.useMemo)(
1423
1580
  () => ({
1424
1581
  _registerCenterCallback,
1582
+ _registerFlyToCallback,
1425
1583
  _registerResetBearingCallback,
1426
1584
  bearing,
1427
1585
  centerOnUser,
1428
1586
  drawerContentRef,
1587
+ drawerHandleVisible,
1429
1588
  drawerState,
1430
1589
  etaData,
1590
+ flyTo,
1431
1591
  hasControls,
1432
1592
  insets,
1433
1593
  isFollowing,
1434
1594
  pitch,
1435
1595
  resetBearing,
1436
1596
  setBearing,
1597
+ setDrawerHandleVisible,
1437
1598
  setDrawerState,
1438
1599
  setEtaData,
1439
1600
  setHasControls,
@@ -1443,16 +1604,20 @@ var SDKMapProvider = ({
1443
1604
  }),
1444
1605
  [
1445
1606
  _registerCenterCallback,
1607
+ _registerFlyToCallback,
1446
1608
  _registerResetBearingCallback,
1447
1609
  bearing,
1448
1610
  centerOnUser,
1611
+ drawerHandleVisible,
1449
1612
  drawerState,
1450
1613
  etaData,
1614
+ flyTo,
1451
1615
  hasControls,
1452
1616
  isFollowing,
1453
1617
  pitch,
1454
1618
  resetBearing,
1455
1619
  setBearing,
1620
+ setDrawerHandleVisible,
1456
1621
  setDrawerState,
1457
1622
  setEtaData,
1458
1623
  setHasControls,
@@ -1464,7 +1629,7 @@ var SDKMapProvider = ({
1464
1629
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MapControlsContext.Provider, { value: contextValue, children });
1465
1630
  };
1466
1631
  var useMapControls = () => {
1467
- const context = (0, import_react2.useContext)(MapControlsContext);
1632
+ const context = (0, import_react3.useContext)(MapControlsContext);
1468
1633
  if (!context) {
1469
1634
  throw new Error("useMapControls must be used within a MapControlsProvider");
1470
1635
  }
@@ -1472,7 +1637,7 @@ var useMapControls = () => {
1472
1637
  };
1473
1638
 
1474
1639
  // src/components/Map/components/MapControls.tsx
1475
- var import_react3 = require("react");
1640
+ var import_react4 = require("react");
1476
1641
  var import_jsx_runtime8 = require("react/jsx-runtime");
1477
1642
  var resolveHeightToPixels2 = (height, containerHeight) => {
1478
1643
  if (typeof height === "number") {
@@ -1499,17 +1664,19 @@ var MapControls = ({
1499
1664
  customCompassButton,
1500
1665
  drawerPeekHeight,
1501
1666
  drawerFullHeight,
1667
+ drawerAutoMaxHeight,
1502
1668
  drawerContentRef,
1503
1669
  menuContent,
1504
1670
  children,
1505
1671
  enableTouchDrag = false,
1506
1672
  showScrollToTopButton = true,
1507
1673
  scrollToTopThreshold = 300,
1674
+ controlsBottomOffset = 0,
1508
1675
  isInternal = false
1509
1676
  }) => {
1510
- const mapContext = (0, import_react3.useContext)(MapControlsContext);
1677
+ const mapContext = (0, import_react4.useContext)(MapControlsContext);
1511
1678
  const contextRef = mapContext?.drawerContentRef;
1512
- const mergedRef = (0, import_react3.useCallback)(
1679
+ const mergedRef = (0, import_react4.useCallback)(
1513
1680
  (node) => {
1514
1681
  if (drawerContentRef) {
1515
1682
  if (typeof drawerContentRef === "function") {
@@ -1524,11 +1691,11 @@ var MapControls = ({
1524
1691
  },
1525
1692
  [drawerContentRef, contextRef]
1526
1693
  );
1527
- const [localDrawerState, setLocalDrawerState] = (0, import_react3.useState)(
1694
+ const [localDrawerState, setLocalDrawerState] = (0, import_react4.useState)(
1528
1695
  defaultState ?? "closed"
1529
1696
  );
1530
1697
  const drawerState = mapContext ? mapContext.drawerState : localDrawerState;
1531
- const setDrawerState = (0, import_react3.useCallback)(
1698
+ const setDrawerState = (0, import_react4.useCallback)(
1532
1699
  (state) => {
1533
1700
  if (mapContext) {
1534
1701
  mapContext.setDrawerState(state);
@@ -1538,15 +1705,15 @@ var MapControls = ({
1538
1705
  },
1539
1706
  [mapContext]
1540
1707
  );
1541
- (0, import_react3.useEffect)(() => {
1708
+ (0, import_react4.useEffect)(() => {
1542
1709
  if (defaultState && mapContext) {
1543
1710
  mapContext.setDrawerState(defaultState);
1544
1711
  }
1545
1712
  }, []);
1546
- const [side, setSide] = (0, import_react3.useState)("left");
1547
- const containerRef = (0, import_react3.useRef)(null);
1548
- const [mapHeight, setMapHeight] = (0, import_react3.useState)(600);
1549
- (0, import_react3.useEffect)(() => {
1713
+ const [side, setSide] = (0, import_react4.useState)("left");
1714
+ const containerRef = (0, import_react4.useRef)(null);
1715
+ const [mapHeight, setMapHeight] = (0, import_react4.useState)(600);
1716
+ (0, import_react4.useEffect)(() => {
1550
1717
  const parent = containerRef.current?.parentElement;
1551
1718
  if (!parent) return;
1552
1719
  const updateHeight = () => {
@@ -1560,7 +1727,7 @@ var MapControls = ({
1560
1727
  };
1561
1728
  }, []);
1562
1729
  const setHasControls = mapContext?.setHasControls;
1563
- (0, import_react3.useEffect)(() => {
1730
+ (0, import_react4.useEffect)(() => {
1564
1731
  if (setHasControls && !isInternal) {
1565
1732
  setHasControls(true);
1566
1733
  return () => setHasControls(false);
@@ -1584,9 +1751,10 @@ var MapControls = ({
1584
1751
  };
1585
1752
  const mapPitch = mapContext ? mapContext.pitch : 0;
1586
1753
  const resolvedEtaData = etaData !== void 0 ? etaData : mapContext?.etaData;
1587
- const [touchStartY, setTouchStartY] = (0, import_react3.useState)(null);
1588
- const [currentTouchY, setCurrentTouchY] = (0, import_react3.useState)(null);
1589
- (0, import_react3.useEffect)(() => {
1754
+ const [touchStartY, setTouchStartY] = (0, import_react4.useState)(null);
1755
+ const [currentTouchY, setCurrentTouchY] = (0, import_react4.useState)(null);
1756
+ const [autoContentPx, setAutoContentPx] = (0, import_react4.useState)(0);
1757
+ (0, import_react4.useEffect)(() => {
1590
1758
  if (typeof window === "undefined") return;
1591
1759
  const checkLayout = () => {
1592
1760
  if (drawerSide) {
@@ -1607,8 +1775,14 @@ var MapControls = ({
1607
1775
  const dragOffset = isDragging ? currentTouchY - touchStartY : 0;
1608
1776
  const fullPx = resolveHeightToPixels2(drawerFullHeight || "85%", mapHeight);
1609
1777
  const peekPx = resolveHeightToPixels2(drawerPeekHeight || "15%", mapHeight);
1778
+ const autoMaxPx = resolveHeightToPixels2(
1779
+ drawerAutoMaxHeight || "100%",
1780
+ mapHeight
1781
+ );
1782
+ const autoPx = Math.min(autoMaxPx, autoContentPx);
1610
1783
  const bottomInset = mapContext?.insets.bottom || 0;
1611
- const closedPx = 32 + (drawerState === "closed" ? bottomInset : 0);
1784
+ const handleVisible = mapContext ? mapContext.drawerHandleVisible : true;
1785
+ const closedPx = (handleVisible ? 32 : 0) + (drawerState === "closed" ? bottomInset : 0);
1612
1786
  let clampedDragOffset = dragOffset;
1613
1787
  if (drawerState === "full") {
1614
1788
  clampedDragOffset = Math.max(0, Math.min(fullPx - closedPx, dragOffset));
@@ -1621,12 +1795,16 @@ var MapControls = ({
1621
1795
  );
1622
1796
  } else if (drawerState === "closed") {
1623
1797
  clampedDragOffset = Math.min(0, Math.max(-(fullPx - closedPx), dragOffset));
1798
+ } else if (drawerState === "auto") {
1799
+ clampedDragOffset = Math.max(0, dragOffset);
1624
1800
  }
1625
- let baseHeight = 32;
1801
+ let baseHeight = handleVisible ? 32 : 0;
1626
1802
  if (drawerState === "peek") {
1627
1803
  baseHeight = peekPx;
1628
1804
  } else if (drawerState === "full") {
1629
1805
  baseHeight = fullPx;
1806
+ } else if (drawerState === "auto") {
1807
+ baseHeight = autoPx;
1630
1808
  }
1631
1809
  const currentDrawerHeight = baseHeight - clampedDragOffset;
1632
1810
  const startFadeHeight = peekPx + 20;
@@ -1656,14 +1834,17 @@ var MapControls = ({
1656
1834
  clampedDragOffset,
1657
1835
  containerHeight: mapHeight,
1658
1836
  currentTouchY,
1837
+ drawerAutoMaxHeight,
1659
1838
  drawerFullHeight,
1660
1839
  drawerPeekHeight,
1661
1840
  enableTouchDrag,
1662
1841
  etaBarHeight,
1663
1842
  etaData: resolvedEtaData,
1843
+ handleVisible,
1664
1844
  isDragging,
1665
1845
  menuContent: children || menuContent,
1666
1846
  menuItems,
1847
+ onAutoContentHeightChange: setAutoContentPx,
1667
1848
  onChangeState: setDrawerState,
1668
1849
  ref: mergedRef,
1669
1850
  safeAreaInsets: mapContext?.insets,
@@ -1679,6 +1860,7 @@ var MapControls = ({
1679
1860
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1680
1861
  MapRightControls,
1681
1862
  {
1863
+ bottomOffset: controlsBottomOffset,
1682
1864
  clampedDragOffset,
1683
1865
  customCompassButton,
1684
1866
  customControls,
@@ -1716,7 +1898,7 @@ var MapControls = ({
1716
1898
  };
1717
1899
 
1718
1900
  // src/components/Map/components/MapMenu.tsx
1719
- var import_react4 = require("react");
1901
+ var import_react5 = require("react");
1720
1902
  var import_jsx_runtime9 = require("react/jsx-runtime");
1721
1903
  var MapMenu = ({ children }) => {
1722
1904
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex flex-col gap-1.5", children });
@@ -1730,7 +1912,7 @@ var MapMenuItem = ({
1730
1912
  disabled = false,
1731
1913
  children
1732
1914
  }) => {
1733
- const context = (0, import_react4.useContext)(MapControlsContext);
1915
+ const context = (0, import_react5.useContext)(MapControlsContext);
1734
1916
  const handleClick = (e) => {
1735
1917
  if (disabled) return;
1736
1918
  if (onPress) onPress();
@@ -1812,25 +1994,25 @@ var GlobalEvent = /* @__PURE__ */ ((GlobalEvent2) => {
1812
1994
  })(GlobalEvent || {});
1813
1995
 
1814
1996
  // src/components/Map/hooks/useUserLocation.ts
1815
- var import_react5 = require("react");
1997
+ var import_react6 = require("react");
1816
1998
  var LERP_FACTOR = 0.12;
1817
1999
  var useUserLocation = () => {
1818
- const [locationState, setLocationState] = (0, import_react5.useState)({
2000
+ const [locationState, setLocationState] = (0, import_react6.useState)({
1819
2001
  accuracy: null,
1820
2002
  coords: null,
1821
2003
  heading: null
1822
2004
  });
1823
- const targetRef = (0, import_react5.useRef)({
2005
+ const targetRef = (0, import_react6.useRef)({
1824
2006
  accuracy: null,
1825
2007
  coords: null,
1826
2008
  heading: null
1827
2009
  });
1828
- const currentRef = (0, import_react5.useRef)({
2010
+ const currentRef = (0, import_react6.useRef)({
1829
2011
  accuracy: null,
1830
2012
  coords: null,
1831
2013
  heading: null
1832
2014
  });
1833
- const mapPayload = (0, import_react5.useCallback)((payload) => {
2015
+ const mapPayload = (0, import_react6.useCallback)((payload) => {
1834
2016
  const coords = payload.location?.coords || payload.coords;
1835
2017
  const headingData = payload.heading || payload.coords;
1836
2018
  const newCoords = coords ? [coords.longitude, coords.latitude] : null;
@@ -1848,7 +2030,7 @@ var useUserLocation = () => {
1848
2030
  heading
1849
2031
  };
1850
2032
  }, []);
1851
- (0, import_react5.useEffect)(() => {
2033
+ (0, import_react6.useEffect)(() => {
1852
2034
  let rafId;
1853
2035
  const animate = () => {
1854
2036
  let changed = false;
@@ -1927,7 +2109,7 @@ var useUserLocation = () => {
1927
2109
  };
1928
2110
 
1929
2111
  // src/components/Map/hooks/useLiveRouting.ts
1930
- var import_react6 = require("react");
2112
+ var import_react7 = require("react");
1931
2113
  var useLiveRouting = ({
1932
2114
  origin: manualOrigin,
1933
2115
  destination,
@@ -1936,18 +2118,19 @@ var useLiveRouting = ({
1936
2118
  enabled = true,
1937
2119
  initialMode = "preview"
1938
2120
  }) => {
1939
- const [route, setRoute] = (0, import_react6.useState)(null);
1940
- const [totalDistance, setTotalDistance] = (0, import_react6.useState)(null);
1941
- const [isCalculating, setIsCalculating] = (0, import_react6.useState)(false);
1942
- const [error, setError] = (0, import_react6.useState)(null);
1943
- const [mode, setMode] = (0, import_react6.useState)(initialMode);
2121
+ const [route, setRoute] = (0, import_react7.useState)(null);
2122
+ const [totalDistance, setTotalDistance] = (0, import_react7.useState)(null);
2123
+ const [isCalculating, setIsCalculating] = (0, import_react7.useState)(false);
2124
+ const [error, setError] = (0, import_react7.useState)(null);
2125
+ const [mode, setMode] = (0, import_react7.useState)(initialMode);
1944
2126
  const userLocationState = useUserLocation();
1945
2127
  const calculationOrigin = manualOrigin || userLocationState.coords;
1946
2128
  const trackingLocation = userLocationState.coords || manualOrigin;
1947
- const lastCalcOrigin = (0, import_react6.useRef)(null);
1948
- const lastCalcDest = (0, import_react6.useRef)(null);
1949
- const isRequestInProgress = (0, import_react6.useRef)(false);
1950
- const getDistance = (0, import_react6.useCallback)(
2129
+ const lastCalcOrigin = (0, import_react7.useRef)(null);
2130
+ const lastCalcDest = (0, import_react7.useRef)(null);
2131
+ const isRequestInProgress = (0, import_react7.useRef)(false);
2132
+ const lastResetDestKey = (0, import_react7.useRef)(null);
2133
+ const getDistance = (0, import_react7.useCallback)(
1951
2134
  (p1, p2) => {
1952
2135
  const R = 6371e3;
1953
2136
  const \u03C61 = p1[1] * Math.PI / 180;
@@ -1960,7 +2143,7 @@ var useLiveRouting = ({
1960
2143
  },
1961
2144
  []
1962
2145
  );
1963
- const currentDistanceMeters = (0, import_react6.useMemo)(() => {
2146
+ const currentDistanceMeters = (0, import_react7.useMemo)(() => {
1964
2147
  if (!trackingLocation || !route || route.geometry.coordinates.length < 2) {
1965
2148
  if (trackingLocation && destination) {
1966
2149
  return getDistance(trackingLocation, destination);
@@ -1987,7 +2170,7 @@ var useLiveRouting = ({
1987
2170
  }
1988
2171
  return dist;
1989
2172
  }, [trackingLocation, route, destination, getDistance]);
1990
- const calculate = (0, import_react6.useCallback)(
2173
+ const calculate = (0, import_react7.useCallback)(
1991
2174
  async (origin, dest, isNewDest) => {
1992
2175
  if (isRequestInProgress.current) return;
1993
2176
  isRequestInProgress.current = true;
@@ -2022,17 +2205,29 @@ var useLiveRouting = ({
2022
2205
  },
2023
2206
  [profile, getDistance]
2024
2207
  );
2025
- (0, import_react6.useEffect)(() => {
2208
+ (0, import_react7.useEffect)(() => {
2209
+ if (initialMode === "navigation") {
2210
+ setMode("navigation");
2211
+ }
2212
+ }, [initialMode]);
2213
+ (0, import_react7.useEffect)(() => {
2026
2214
  if (!enabled || !destination || !calculationOrigin) {
2027
2215
  if (!enabled || !destination) {
2028
2216
  setRoute(null);
2029
2217
  setTotalDistance(null);
2030
2218
  lastCalcOrigin.current = null;
2031
2219
  lastCalcDest.current = null;
2220
+ lastResetDestKey.current = null;
2221
+ setMode(initialMode);
2032
2222
  }
2033
2223
  return;
2034
2224
  }
2035
2225
  const destChanged = !lastCalcDest.current || lastCalcDest.current[0] !== destination[0] || lastCalcDest.current[1] !== destination[1];
2226
+ const destKey = `${destination[0]},${destination[1]}`;
2227
+ if (lastResetDestKey.current !== destKey) {
2228
+ lastResetDestKey.current = destKey;
2229
+ setMode(initialMode);
2230
+ }
2036
2231
  if (destChanged) {
2037
2232
  calculate(calculationOrigin, destination, true);
2038
2233
  } else if (lastCalcOrigin.current) {
@@ -2049,6 +2244,7 @@ var useLiveRouting = ({
2049
2244
  trackingLocation,
2050
2245
  destination,
2051
2246
  enabled,
2247
+ initialMode,
2052
2248
  recalculateThreshold,
2053
2249
  calculate,
2054
2250
  getDistance
@@ -2065,10 +2261,10 @@ var useLiveRouting = ({
2065
2261
  };
2066
2262
  };
2067
2263
  var useRoute = (origin, destination, profile = "driving") => {
2068
- const [route, setRoute] = (0, import_react6.useState)(null);
2069
- const [isCalculating, setIsCalculating] = (0, import_react6.useState)(false);
2070
- const [error, setError] = (0, import_react6.useState)(null);
2071
- (0, import_react6.useEffect)(() => {
2264
+ const [route, setRoute] = (0, import_react7.useState)(null);
2265
+ const [isCalculating, setIsCalculating] = (0, import_react7.useState)(false);
2266
+ const [error, setError] = (0, import_react7.useState)(null);
2267
+ (0, import_react7.useEffect)(() => {
2072
2268
  if (!origin || !destination) {
2073
2269
  setRoute(null);
2074
2270
  return;
@@ -2094,10 +2290,103 @@ var useRoute = (origin, destination, profile = "driving") => {
2094
2290
  return { error, isCalculating, route };
2095
2291
  };
2096
2292
 
2293
+ // src/components/Map/hooks/useJourney.ts
2294
+ var import_react8 = require("react");
2295
+ var useJourney = (options = {}) => {
2296
+ const { navigation, onAbort, onModeChange } = options;
2297
+ const [progNav, setProgNav] = (0, import_react8.useState)(null);
2298
+ const [isAborted, setIsAborted] = (0, import_react8.useState)(false);
2299
+ (0, import_react8.useEffect)(() => {
2300
+ const unsubCreate = sdk.on("SDK_NAVIGATION_CREATE", (payload) => {
2301
+ setIsAborted(false);
2302
+ setProgNav(payload);
2303
+ });
2304
+ const unsubStart = sdk.on("SDK_NAVIGATION_START", () => {
2305
+ setIsAborted(false);
2306
+ setProgNav((prev) => prev ? { ...prev, mode: "navigation" } : null);
2307
+ });
2308
+ const unsubAbort = sdk.on("SDK_NAVIGATION_ABORT", () => {
2309
+ setIsAborted(true);
2310
+ setProgNav(null);
2311
+ });
2312
+ return () => {
2313
+ unsubCreate();
2314
+ unsubStart();
2315
+ unsubAbort();
2316
+ };
2317
+ }, []);
2318
+ const effectiveOptions = progNav || navigation;
2319
+ const internalNav = useLiveRouting({
2320
+ destination: effectiveOptions?.destination || null,
2321
+ enabled: !isAborted && !!effectiveOptions?.destination,
2322
+ initialMode: effectiveOptions?.mode || "preview",
2323
+ origin: effectiveOptions?.origin,
2324
+ profile: effectiveOptions?.profile || "driving",
2325
+ recalculateThreshold: effectiveOptions?.recalculateThreshold || 50
2326
+ });
2327
+ const prevDest = (0, import_react8.useRef)(null);
2328
+ const currentDest = effectiveOptions?.destination;
2329
+ (0, import_react8.useEffect)(() => {
2330
+ if (currentDest && (!prevDest.current || prevDest.current[0] !== currentDest[0] || prevDest.current[1] !== currentDest[1])) {
2331
+ setIsAborted(false);
2332
+ }
2333
+ prevDest.current = currentDest;
2334
+ }, [currentDest]);
2335
+ const onModeChangeRef = (0, import_react8.useRef)(onModeChange);
2336
+ onModeChangeRef.current = onModeChange;
2337
+ (0, import_react8.useEffect)(() => {
2338
+ onModeChangeRef.current?.(internalNav.mode);
2339
+ }, [internalNav.mode]);
2340
+ const isActive = !isAborted && !!effectiveOptions?.destination;
2341
+ const distanceRemainingMeters = isActive ? internalNav.currentDistanceMeters : null;
2342
+ const totalDistanceMeters = isActive ? internalNav.totalDistance : null;
2343
+ const routeDurationSeconds = internalNav.route?.durationSeconds ?? null;
2344
+ const remainingMeters = distanceRemainingMeters ?? 0;
2345
+ const distanceRemainingKm = remainingMeters / 1e3;
2346
+ const etaMinutes = (() => {
2347
+ if (!routeDurationSeconds || !totalDistanceMeters || !distanceRemainingMeters)
2348
+ return 0;
2349
+ const ratio = distanceRemainingMeters / totalDistanceMeters;
2350
+ return Math.ceil(routeDurationSeconds * ratio / 60);
2351
+ })();
2352
+ const progress = totalDistanceMeters && totalDistanceMeters > 0 ? Math.min(
2353
+ 100,
2354
+ Math.max(
2355
+ 0,
2356
+ (totalDistanceMeters - remainingMeters) / totalDistanceMeters * 100
2357
+ )
2358
+ ) : 0;
2359
+ const cancel = (0, import_react8.useCallback)(() => {
2360
+ setIsAborted(true);
2361
+ setProgNav(null);
2362
+ sdk.navigation.abort();
2363
+ if (onAbort) onAbort();
2364
+ }, [onAbort]);
2365
+ const start = (0, import_react8.useCallback)(() => {
2366
+ sdk.navigation.start();
2367
+ internalNav.start();
2368
+ }, [internalNav.start]);
2369
+ return {
2370
+ cancel,
2371
+ distanceRemainingKm,
2372
+ distanceRemainingMeters,
2373
+ error: isActive ? internalNav.error : null,
2374
+ etaMinutes,
2375
+ isActive,
2376
+ isCalculating: isActive ? internalNav.isCalculating : false,
2377
+ mode: isActive ? internalNav.mode : "preview",
2378
+ progress,
2379
+ recalculate: internalNav.recalculate,
2380
+ route: isActive ? internalNav.route : null,
2381
+ start,
2382
+ totalDistanceMeters
2383
+ };
2384
+ };
2385
+
2097
2386
  // src/components/Map/hooks/useTrimmedRoute.ts
2098
- var import_react7 = require("react");
2387
+ var import_react9 = require("react");
2099
2388
  var useTrimmedRoute = (route, userLocation) => {
2100
- return (0, import_react7.useMemo)(() => {
2389
+ return (0, import_react9.useMemo)(() => {
2101
2390
  if (!route || !userLocation || route.coordinates.length < 2) return route;
2102
2391
  const coords = route.coordinates;
2103
2392
  let minDistance = Infinity;
@@ -2169,14 +2458,76 @@ var RouteLayer = ({
2169
2458
  };
2170
2459
 
2171
2460
  // src/components/Map/Map.tsx
2172
- var import_react_maplibre5 = require("@vis.gl/react-maplibre");
2173
- var import_react9 = __toESM(require("react"), 1);
2461
+ var import_react_maplibre6 = require("@vis.gl/react-maplibre");
2462
+ var import_react12 = __toESM(require("react"), 1);
2174
2463
  var import_maplibre_gl = require("maplibre-gl/dist/maplibre-gl.css");
2175
2464
 
2176
- // src/components/Map/layers/POILayers.tsx
2465
+ // src/components/Map/utils/geoCircle.ts
2466
+ var EARTH_RADIUS_METERS = 6371e3;
2467
+ var buildGeoCircle = (center, radiusMeters, points = 64) => {
2468
+ const [lng, lat] = center;
2469
+ const latRad = lat * Math.PI / 180;
2470
+ const coordinates = [];
2471
+ for (let i = 0; i <= points; i++) {
2472
+ const angle = i / points * 2 * Math.PI;
2473
+ const dLat = radiusMeters * Math.cos(angle) / EARTH_RADIUS_METERS * (180 / Math.PI);
2474
+ const dLng = radiusMeters * Math.sin(angle) / (EARTH_RADIUS_METERS * Math.cos(latRad)) * (180 / Math.PI);
2475
+ coordinates.push([lng + dLng, lat + dLat]);
2476
+ }
2477
+ return {
2478
+ geometry: {
2479
+ coordinates: [coordinates],
2480
+ type: "Polygon"
2481
+ },
2482
+ properties: {},
2483
+ type: "Feature"
2484
+ };
2485
+ };
2486
+
2487
+ // src/components/Map/layers/MockRadiusLayer.tsx
2177
2488
  var import_react_maplibre2 = require("@vis.gl/react-maplibre");
2178
- var import_react8 = require("react");
2489
+ var import_react10 = require("react");
2179
2490
  var import_jsx_runtime11 = require("react/jsx-runtime");
2491
+ var MockRadiusLayer = ({
2492
+ center,
2493
+ radiusMeters,
2494
+ color = "#39ff88"
2495
+ }) => {
2496
+ const data = (0, import_react10.useMemo)(
2497
+ () => buildGeoCircle(center, radiusMeters),
2498
+ [center, radiusMeters]
2499
+ );
2500
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_maplibre2.Source, { data, id: "sdk-mock-radius-source", type: "geojson", children: [
2501
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2502
+ import_react_maplibre2.Layer,
2503
+ {
2504
+ id: "sdk-mock-radius-fill",
2505
+ paint: {
2506
+ "fill-color": color,
2507
+ "fill-opacity": 0.12
2508
+ },
2509
+ type: "fill"
2510
+ }
2511
+ ),
2512
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2513
+ import_react_maplibre2.Layer,
2514
+ {
2515
+ id: "sdk-mock-radius-outline",
2516
+ paint: {
2517
+ "line-color": color,
2518
+ "line-dasharray": [2, 2],
2519
+ "line-width": 2
2520
+ },
2521
+ type: "line"
2522
+ }
2523
+ )
2524
+ ] });
2525
+ };
2526
+
2527
+ // src/components/Map/layers/POILayers.tsx
2528
+ var import_react_maplibre3 = require("@vis.gl/react-maplibre");
2529
+ var import_react11 = require("react");
2530
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2180
2531
  function createEmojiIcon(emoji, size = 64) {
2181
2532
  const canvas = document.createElement("canvas");
2182
2533
  canvas.width = size;
@@ -2189,13 +2540,13 @@ function createEmojiIcon(emoji, size = 64) {
2189
2540
  return ctx.getImageData(0, 0, size, size);
2190
2541
  }
2191
2542
  var POILayers = ({ pois }) => {
2192
- const [loadedImages, setLoadedImages] = (0, import_react8.useState)(0);
2193
- const { current: map } = (0, import_react_maplibre2.useMap)();
2194
- const glPois = (0, import_react8.useMemo)(
2543
+ const [loadedImages, setLoadedImages] = (0, import_react11.useState)(0);
2544
+ const { current: map } = (0, import_react_maplibre3.useMap)();
2545
+ const glPois = (0, import_react11.useMemo)(
2195
2546
  () => pois.filter((p) => !p.displayMode || p.displayMode === "gl"),
2196
2547
  [pois]
2197
2548
  );
2198
- (0, import_react8.useEffect)(() => {
2549
+ (0, import_react11.useEffect)(() => {
2199
2550
  if (!map) return;
2200
2551
  const glMap = map.getMap();
2201
2552
  const defaults = [
@@ -2235,7 +2586,7 @@ var POILayers = ({ pois }) => {
2235
2586
  setLoadedImages((prev) => prev + updates);
2236
2587
  }
2237
2588
  }, [map, glPois]);
2238
- const geojson = (0, import_react8.useMemo)(
2589
+ const geojson = (0, import_react11.useMemo)(
2239
2590
  () => ({
2240
2591
  features: glPois.map((poi) => ({
2241
2592
  geometry: {
@@ -2253,8 +2604,8 @@ var POILayers = ({ pois }) => {
2253
2604
  }),
2254
2605
  [glPois]
2255
2606
  );
2256
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_maplibre2.Source, { data: geojson, id: "sdk-pois", type: "geojson", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2257
- import_react_maplibre2.Layer,
2607
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_maplibre3.Source, { data: geojson, id: "sdk-pois", type: "geojson", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2608
+ import_react_maplibre3.Layer,
2258
2609
  {
2259
2610
  id: "sdk-poi-layer",
2260
2611
  layout: {
@@ -2289,13 +2640,13 @@ var POILayers = ({ pois }) => {
2289
2640
  };
2290
2641
 
2291
2642
  // src/components/Map/layers/POIMarkers.tsx
2292
- var import_react_maplibre3 = require("@vis.gl/react-maplibre");
2293
- var import_jsx_runtime12 = require("react/jsx-runtime");
2643
+ var import_react_maplibre4 = require("@vis.gl/react-maplibre");
2644
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2294
2645
  var POIMarkers = ({ pois, onClick }) => {
2295
2646
  const markerPois = pois.filter((p) => p.displayMode === "marker");
2296
2647
  if (markerPois.length === 0) return null;
2297
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_jsx_runtime12.Fragment, { children: markerPois.map((poi) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2298
- import_react_maplibre3.Marker,
2648
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_jsx_runtime13.Fragment, { children: markerPois.map((poi) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2649
+ import_react_maplibre4.Marker,
2299
2650
  {
2300
2651
  anchor: "bottom",
2301
2652
  latitude: poi.latitude,
@@ -2304,7 +2655,7 @@ var POIMarkers = ({ pois, onClick }) => {
2304
2655
  e.originalEvent.stopPropagation();
2305
2656
  if (onClick) onClick(poi);
2306
2657
  },
2307
- children: poi.markerComponent ? poi.markerComponent : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2658
+ children: poi.markerComponent ? poi.markerComponent : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2308
2659
  "div",
2309
2660
  {
2310
2661
  style: {
@@ -2313,7 +2664,7 @@ var POIMarkers = ({ pois, onClick }) => {
2313
2664
  transform: "transition-transform duration-200 hover:scale-110"
2314
2665
  },
2315
2666
  children: [
2316
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2667
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2317
2668
  "div",
2318
2669
  {
2319
2670
  style: {
@@ -2326,7 +2677,7 @@ var POIMarkers = ({ pois, onClick }) => {
2326
2677
  justifyContent: "center",
2327
2678
  width: "32px"
2328
2679
  },
2329
- children: poi.emoji ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { fontSize: "16px" }, children: poi.emoji }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2680
+ children: poi.emoji ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontSize: "16px" }, children: poi.emoji }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2330
2681
  "div",
2331
2682
  {
2332
2683
  style: {
@@ -2339,7 +2690,7 @@ var POIMarkers = ({ pois, onClick }) => {
2339
2690
  )
2340
2691
  }
2341
2692
  ),
2342
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2693
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2343
2694
  "div",
2344
2695
  {
2345
2696
  style: {
@@ -2361,20 +2712,20 @@ var POIMarkers = ({ pois, onClick }) => {
2361
2712
  };
2362
2713
 
2363
2714
  // src/components/Map/layers/UserLocationLayer.tsx
2364
- var import_react_maplibre4 = require("@vis.gl/react-maplibre");
2365
- var import_jsx_runtime13 = require("react/jsx-runtime");
2715
+ var import_react_maplibre5 = require("@vis.gl/react-maplibre");
2716
+ var import_jsx_runtime14 = require("react/jsx-runtime");
2366
2717
  var UserLocationLayer = ({
2367
2718
  forcedLocation,
2368
2719
  heading
2369
2720
  }) => {
2370
2721
  if (!forcedLocation) return null;
2371
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2372
- import_react_maplibre4.Marker,
2722
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2723
+ import_react_maplibre5.Marker,
2373
2724
  {
2374
2725
  anchor: "center",
2375
2726
  latitude: forcedLocation[1],
2376
2727
  longitude: forcedLocation[0],
2377
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2728
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2378
2729
  "div",
2379
2730
  {
2380
2731
  style: {
@@ -2384,7 +2735,7 @@ var UserLocationLayer = ({
2384
2735
  position: "relative"
2385
2736
  },
2386
2737
  children: [
2387
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2738
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2388
2739
  "div",
2389
2740
  {
2390
2741
  style: {
@@ -2397,7 +2748,7 @@ var UserLocationLayer = ({
2397
2748
  }
2398
2749
  }
2399
2750
  ),
2400
- heading !== void 0 && heading !== null && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2751
+ heading !== void 0 && heading !== null && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2401
2752
  "div",
2402
2753
  {
2403
2754
  style: {
@@ -2407,13 +2758,13 @@ var UserLocationLayer = ({
2407
2758
  width: "60px",
2408
2759
  zIndex: 0
2409
2760
  },
2410
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2761
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2411
2762
  "svg",
2412
2763
  {
2413
2764
  style: { height: "100%", width: "100%" },
2414
2765
  viewBox: "0 0 100 100",
2415
2766
  children: [
2416
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2767
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2417
2768
  "radialGradient",
2418
2769
  {
2419
2770
  cx: "50%",
@@ -2423,7 +2774,7 @@ var UserLocationLayer = ({
2423
2774
  id: "grad1",
2424
2775
  r: "50%",
2425
2776
  children: [
2426
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2777
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2427
2778
  "stop",
2428
2779
  {
2429
2780
  offset: "0%",
@@ -2433,7 +2784,7 @@ var UserLocationLayer = ({
2433
2784
  }
2434
2785
  }
2435
2786
  ),
2436
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2787
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2437
2788
  "stop",
2438
2789
  {
2439
2790
  offset: "100%",
@@ -2446,7 +2797,7 @@ var UserLocationLayer = ({
2446
2797
  ]
2447
2798
  }
2448
2799
  ) }),
2449
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2800
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2450
2801
  "path",
2451
2802
  {
2452
2803
  d: "M 50 50 L 35 0 A 50 50 0 0 1 65 0 Z",
@@ -2458,7 +2809,7 @@ var UserLocationLayer = ({
2458
2809
  )
2459
2810
  }
2460
2811
  ),
2461
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2812
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2462
2813
  "div",
2463
2814
  {
2464
2815
  style: {
@@ -2472,7 +2823,7 @@ var UserLocationLayer = ({
2472
2823
  width: "20px",
2473
2824
  zIndex: 1
2474
2825
  },
2475
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2826
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2476
2827
  "div",
2477
2828
  {
2478
2829
  style: {
@@ -2486,7 +2837,7 @@ var UserLocationLayer = ({
2486
2837
  )
2487
2838
  }
2488
2839
  ),
2489
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("style", { children: `@keyframes pulse { 0% { transform: scale(0.95); opacity: 0.7; } 70% { transform: scale(1.5); opacity: 0; } 100% { transform: scale(0.95); opacity: 0; } }` })
2840
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("style", { children: `@keyframes pulse { 0% { transform: scale(0.95); opacity: 0.7; } 70% { transform: scale(1.5); opacity: 0; } 100% { transform: scale(0.95); opacity: 0; } }` })
2490
2841
  ]
2491
2842
  }
2492
2843
  )
@@ -2495,7 +2846,7 @@ var UserLocationLayer = ({
2495
2846
  };
2496
2847
 
2497
2848
  // src/components/Map/Map.tsx
2498
- var import_jsx_runtime14 = require("react/jsx-runtime");
2849
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2499
2850
  var MapInternal = ({
2500
2851
  initialViewState = {
2501
2852
  latitude: 45.90583599233422,
@@ -2514,6 +2865,7 @@ var MapInternal = ({
2514
2865
  onLoad,
2515
2866
  showUserLocation = true,
2516
2867
  followUser: initialFollowUser = false,
2868
+ lockToUser = false,
2517
2869
  showUserLocationButton = true,
2518
2870
  renderUserLocation,
2519
2871
  pois = [],
@@ -2532,67 +2884,44 @@ var MapInternal = ({
2532
2884
  controlProps = {},
2533
2885
  enableTouchDrag = false
2534
2886
  }) => {
2535
- const mapControls = (0, import_react9.useContext)(MapControlsContext);
2536
- const mapRef = (0, import_react9.useRef)(null);
2887
+ const mapControls = (0, import_react12.useContext)(MapControlsContext);
2888
+ const mockLocation = (0, import_react12.useContext)(MockLocationContext);
2889
+ const mapRef = (0, import_react12.useRef)(null);
2537
2890
  const userLocationState = useUserLocation();
2538
- const [progNav, setProgNav] = (0, import_react9.useState)(null);
2539
- const [isAborted, setIsAborted] = (0, import_react9.useState)(false);
2540
- (0, import_react9.useEffect)(() => {
2541
- const unsubCreate = sdk.on("SDK_NAVIGATION_CREATE", (payload) => {
2542
- setIsAborted(false);
2543
- setProgNav(payload);
2544
- });
2545
- const unsubStart = sdk.on("SDK_NAVIGATION_START", () => {
2546
- setIsAborted(false);
2547
- setProgNav((prev) => prev ? { ...prev, mode: "navigation" } : null);
2548
- });
2549
- const unsubAbort = sdk.on("SDK_NAVIGATION_ABORT", () => {
2550
- setIsAborted(true);
2551
- setProgNav(null);
2552
- });
2553
- return () => {
2554
- unsubCreate();
2555
- unsubStart();
2556
- unsubAbort();
2557
- };
2558
- }, []);
2559
- const effectiveNavOptions = progNav || navigation;
2560
- const internalNav = useLiveRouting({
2561
- destination: effectiveNavOptions?.destination || null,
2562
- enabled: !!effectiveNavOptions?.destination,
2563
- initialMode: effectiveNavOptions?.mode || "preview",
2564
- origin: effectiveNavOptions?.origin,
2565
- profile: effectiveNavOptions?.profile || "driving",
2566
- recalculateThreshold: effectiveNavOptions?.recalculateThreshold || 50
2891
+ const journey = useJourney({
2892
+ navigation,
2893
+ onModeChange: navigation ? onNavigationModeChange : void 0
2567
2894
  });
2568
- (0, import_react9.useEffect)(() => {
2569
- if (onNavigationModeChange && navigation) {
2570
- onNavigationModeChange(internalNav.mode);
2571
- }
2572
- }, [internalNav.mode, onNavigationModeChange, navigation]);
2573
- const prevDest = (0, import_react9.useRef)(null);
2574
- const currentDest = effectiveNavOptions?.destination;
2575
- (0, import_react9.useEffect)(() => {
2576
- if (currentDest) {
2577
- if (!prevDest.current || prevDest.current[0] !== currentDest[0] || prevDest.current[1] !== currentDest[1]) {
2578
- setIsAborted(false);
2579
- }
2580
- }
2581
- prevDest.current = currentDest;
2582
- }, [currentDest]);
2583
- const navigationData = !isAborted ? effectiveNavOptions ? internalNav : externalNavigationData : void 0;
2584
- const route = !isAborted ? effectiveNavOptions ? internalNav.route?.geometry : externalRoute : void 0;
2585
- const showNavigationUI = !isAborted && effectiveNavOptions?.showUI !== false && (effectiveNavOptions ? !!effectiveNavOptions.destination : externalShowNavigationUI);
2895
+ const hasIntegratedNav = journey.isActive;
2896
+ const navigationData = hasIntegratedNav ? {
2897
+ currentDistanceMeters: journey.distanceRemainingMeters,
2898
+ mode: journey.mode,
2899
+ route: journey.route,
2900
+ start: journey.start,
2901
+ totalDistance: journey.totalDistanceMeters
2902
+ } : externalNavigationData;
2903
+ const route = hasIntegratedNav ? journey.route?.geometry : externalRoute;
2904
+ const showNavigationUI = hasIntegratedNav ? externalShowNavigationUI !== false && navigation?.showUI !== false : externalShowNavigationUI;
2586
2905
  const mode = navigationData?.mode || "preview";
2587
2906
  const resolvedInitialFollow = mapControls ? mapControls.isFollowing : initialFollowUser;
2588
- const isFollowingRef = (0, import_react9.useRef)(resolvedInitialFollow);
2589
- const isFlyingRef = (0, import_react9.useRef)(false);
2590
- const [localIsFollowingUI, setLocalIsFollowingUI] = (0, import_react9.useState)(
2907
+ const isFollowingRef = (0, import_react12.useRef)(resolvedInitialFollow);
2908
+ const isFlyingRef = (0, import_react12.useRef)(false);
2909
+ const flyingGenerationRef = (0, import_react12.useRef)(0);
2910
+ const lockFlying = (0, import_react12.useCallback)(() => {
2911
+ isFlyingRef.current = true;
2912
+ return ++flyingGenerationRef.current;
2913
+ }, []);
2914
+ const releaseFlyingIfCurrent = (0, import_react12.useCallback)((flightId) => {
2915
+ if (flyingGenerationRef.current === flightId) {
2916
+ isFlyingRef.current = false;
2917
+ }
2918
+ }, []);
2919
+ const [localIsFollowingUI, setLocalIsFollowingUI] = (0, import_react12.useState)(
2591
2920
  resolvedInitialFollow
2592
2921
  );
2593
2922
  const isFollowingUI = mapControls ? mapControls.isFollowing : localIsFollowingUI;
2594
2923
  const setIsFollowingCtx = mapControls?.setIsFollowing;
2595
- const setFollowMode = (0, import_react9.useCallback)(
2924
+ const setFollowMode = (0, import_react12.useCallback)(
2596
2925
  (follow) => {
2597
2926
  isFollowingRef.current = follow;
2598
2927
  setLocalIsFollowingUI(follow);
@@ -2602,7 +2931,7 @@ var MapInternal = ({
2602
2931
  },
2603
2932
  [setIsFollowingCtx]
2604
2933
  );
2605
- (0, import_react9.useEffect)(() => {
2934
+ (0, import_react12.useEffect)(() => {
2606
2935
  if (mapControls && mapControls.isFollowing !== isFollowingRef.current) {
2607
2936
  isFollowingRef.current = mapControls.isFollowing;
2608
2937
  }
@@ -2611,13 +2940,13 @@ var MapInternal = ({
2611
2940
  if (pois.length > 0 && !mergedInteractiveLayerIds.includes("sdk-poi-layer")) {
2612
2941
  mergedInteractiveLayerIds.push("sdk-poi-layer");
2613
2942
  }
2614
- const prevInitialFollow = (0, import_react9.useRef)(initialFollowUser);
2615
- (0, import_react9.useEffect)(() => {
2943
+ const prevInitialFollow = (0, import_react12.useRef)(initialFollowUser);
2944
+ (0, import_react12.useEffect)(() => {
2616
2945
  if (initialFollowUser !== prevInitialFollow.current) {
2617
2946
  setFollowMode(initialFollowUser);
2618
2947
  prevInitialFollow.current = initialFollowUser;
2619
2948
  if (initialFollowUser && userLocationState.coords && mapRef.current) {
2620
- isFlyingRef.current = true;
2949
+ const flightId = lockFlying();
2621
2950
  mapRef.current.flyTo({
2622
2951
  center: userLocationState.coords,
2623
2952
  duration: 1e3,
@@ -2625,14 +2954,20 @@ var MapInternal = ({
2625
2954
  zoom: Math.max(mapRef.current.getZoom(), 16)
2626
2955
  });
2627
2956
  setTimeout(() => {
2628
- isFlyingRef.current = false;
2957
+ releaseFlyingIfCurrent(flightId);
2629
2958
  }, 1050);
2630
2959
  }
2631
2960
  }
2632
- }, [initialFollowUser, setFollowMode, userLocationState.coords]);
2633
- const lastAutoLockedRouteRef = (0, import_react9.useRef)(null);
2634
- const lastModeRef = (0, import_react9.useRef)(null);
2635
- (0, import_react9.useEffect)(() => {
2961
+ }, [
2962
+ initialFollowUser,
2963
+ setFollowMode,
2964
+ userLocationState.coords,
2965
+ lockFlying,
2966
+ releaseFlyingIfCurrent
2967
+ ]);
2968
+ const lastAutoLockedRouteRef = (0, import_react12.useRef)(null);
2969
+ const lastModeRef = (0, import_react12.useRef)(null);
2970
+ (0, import_react12.useEffect)(() => {
2636
2971
  if (!route || !mapRef.current) {
2637
2972
  if (!route) lastAutoLockedRouteRef.current = null;
2638
2973
  return;
@@ -2640,9 +2975,11 @@ var MapInternal = ({
2640
2975
  const isNewRoute = route !== lastAutoLockedRouteRef.current;
2641
2976
  const modeChanged = lastModeRef.current !== mode;
2642
2977
  if (mode === "navigation") {
2643
- setFollowMode(true);
2978
+ if (modeChanged || isNewRoute) {
2979
+ setFollowMode(true);
2980
+ }
2644
2981
  if ((modeChanged || isNewRoute) && userLocationState.coords && mapRef.current) {
2645
- isFlyingRef.current = true;
2982
+ const flightId = lockFlying();
2646
2983
  mapRef.current.flyTo({
2647
2984
  center: userLocationState.coords,
2648
2985
  duration: 1e3,
@@ -2651,7 +2988,7 @@ var MapInternal = ({
2651
2988
  // Zoomed in on user for active guidance
2652
2989
  });
2653
2990
  setTimeout(() => {
2654
- isFlyingRef.current = false;
2991
+ releaseFlyingIfCurrent(flightId);
2655
2992
  }, 1050);
2656
2993
  }
2657
2994
  } else if (mode === "preview" && isNewRoute) {
@@ -2678,8 +3015,15 @@ var MapInternal = ({
2678
3015
  }
2679
3016
  lastAutoLockedRouteRef.current = route;
2680
3017
  lastModeRef.current = mode;
2681
- }, [route, mode, setFollowMode, userLocationState.coords]);
2682
- (0, import_react9.useEffect)(() => {
3018
+ }, [
3019
+ route,
3020
+ mode,
3021
+ setFollowMode,
3022
+ userLocationState.coords,
3023
+ lockFlying,
3024
+ releaseFlyingIfCurrent
3025
+ ]);
3026
+ (0, import_react12.useEffect)(() => {
2683
3027
  if (isFollowingRef.current && !isFlyingRef.current && userLocationState.coords && mapRef.current) {
2684
3028
  mapRef.current.easeTo({
2685
3029
  center: userLocationState.coords,
@@ -2708,15 +3052,13 @@ var MapInternal = ({
2708
3052
  100,
2709
3053
  Math.max(0, (totalDist - remainingMeters) / totalDist * 100)
2710
3054
  ) : 0;
2711
- const showEtaData = navigationData && route ? {
3055
+ const showEtaData = showNavigationUI && navigationData && route ? {
2712
3056
  distanceRemainingKm: kmRemaining,
2713
3057
  etaMins,
2714
3058
  label: mode === "navigation" ? "Walking Guidance Active" : "Route Preview",
2715
3059
  mode,
2716
3060
  onAbort: () => {
2717
- setIsAborted(true);
2718
- setProgNav(null);
2719
- sdk.navigation.abort();
3061
+ journey.cancel();
2720
3062
  if (onNavigationAbort) {
2721
3063
  onNavigationAbort();
2722
3064
  }
@@ -2725,52 +3067,23 @@ var MapInternal = ({
2725
3067
  progress: progressValue
2726
3068
  } : void 0;
2727
3069
  const setEtaDataCtx = mapControls?.setEtaData;
2728
- (0, import_react9.useEffect)(() => {
3070
+ (0, import_react12.useEffect)(() => {
2729
3071
  if (setEtaDataCtx) {
2730
3072
  setEtaDataCtx(showEtaData);
2731
3073
  }
2732
3074
  }, [showEtaData, setEtaDataCtx]);
2733
3075
  const setDrawerStateCtx = mapControls?.setDrawerState;
2734
- (0, import_react9.useEffect)(() => {
3076
+ (0, import_react12.useEffect)(() => {
2735
3077
  if (setDrawerStateCtx && propDrawerState !== void 0) {
2736
3078
  setDrawerStateCtx(propDrawerState);
2737
3079
  }
2738
3080
  }, [propDrawerState, setDrawerStateCtx]);
2739
- const defaultMenuItems = (0, import_react9.useMemo)(
2740
- () => [
2741
- {
2742
- icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2743
- "svg",
2744
- {
2745
- className: "w-5 h-5",
2746
- fill: "none",
2747
- stroke: "currentColor",
2748
- strokeWidth: "2",
2749
- viewBox: "0 0 24 24",
2750
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2751
- "path",
2752
- {
2753
- d: "M12 11c0 3.517-1.009 6.799-2.753 9.571m-3.44-2.04l.054-.09A13.916 13.916 0 008 11a4 4 0 118 0c0 1.017-.07 2.019-.203 3m-2.118 6.844A21.88 21.88 0 0015.171 17m3.839 1.132c.645-2.266.99-4.659.99-7.132A8 8 0 008 4.07M3 15.364c.64-1.319 1-2.8 1-4.364 0-1.457.39-2.823 1.07-4",
2754
- strokeLinecap: "round",
2755
- strokeLinejoin: "round"
2756
- }
2757
- )
2758
- }
2759
- ),
2760
- id: "walking",
2761
- label: "Walking Mode",
2762
- onPress: () => {
2763
- }
2764
- }
2765
- ],
2766
- []
2767
- );
2768
- const resolvedMenuItems = menuItems || defaultMenuItems;
2769
- const { mapLibreChildren, menuContentFromChildren } = (0, import_react9.useMemo)(() => {
3081
+ const resolvedMenuItems = menuItems ?? [];
3082
+ const { mapLibreChildren, menuContentFromChildren } = (0, import_react12.useMemo)(() => {
2770
3083
  const mapLibreChildren2 = [];
2771
3084
  const extractedMenuItems = [];
2772
- import_react9.default.Children.forEach(children, (child) => {
2773
- if (import_react9.default.isValidElement(child)) {
3085
+ import_react12.default.Children.forEach(children, (child) => {
3086
+ if (import_react12.default.isValidElement(child)) {
2774
3087
  const type = child.type;
2775
3088
  const displayName = type?.displayName || type?.name;
2776
3089
  const isMenu = type === MapMenu || displayName === "MapMenu";
@@ -2781,7 +3094,7 @@ var MapInternal = ({
2781
3094
  "MapMenuFooter"
2782
3095
  ].includes(displayName);
2783
3096
  if (isMenu) {
2784
- import_react9.default.Children.forEach(
3097
+ import_react12.default.Children.forEach(
2785
3098
  child.props.children,
2786
3099
  (nestedChild) => {
2787
3100
  if (nestedChild) {
@@ -2798,10 +3111,14 @@ var MapInternal = ({
2798
3111
  mapLibreChildren2.push(child);
2799
3112
  }
2800
3113
  });
2801
- const menuContentFromChildren2 = extractedMenuItems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(MapMenu, { children: extractedMenuItems }) : null;
3114
+ const menuContentFromChildren2 = extractedMenuItems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MapMenu, { children: extractedMenuItems }) : null;
2802
3115
  return { mapLibreChildren: mapLibreChildren2, menuContentFromChildren: menuContentFromChildren2 };
2803
3116
  }, [children]);
2804
3117
  const handleMapClick = (e) => {
3118
+ if (mockLocation?.isPlacingLocation) {
3119
+ mockLocation.placeLocation([e.lngLat.lng, e.lngLat.lat]);
3120
+ return;
3121
+ }
2805
3122
  const clickedFeatures = e.features || [];
2806
3123
  if (onPoiClick) {
2807
3124
  const poiFeature = clickedFeatures.find(
@@ -2822,26 +3139,52 @@ var MapInternal = ({
2822
3139
  }
2823
3140
  if (onClick) onClick(e);
2824
3141
  };
2825
- const handleCenterOnUser = (0, import_react9.useCallback)(
3142
+ const handleCenterOnUser = (0, import_react12.useCallback)(
2826
3143
  (payload) => {
2827
3144
  if (userLocationState.coords && mapRef.current) {
2828
3145
  setFollowMode(true);
2829
- isFlyingRef.current = true;
3146
+ const flightId = lockFlying();
2830
3147
  mapRef.current.flyTo({
2831
3148
  center: userLocationState.coords,
2832
3149
  duration: 1e3,
2833
3150
  essential: true,
2834
3151
  pitch: payload?.pitch || 0,
2835
- zoom: Math.max(mapRef.current.getZoom(), 16)
3152
+ zoom: Math.max(mapRef.current.getZoom(), 16),
3153
+ ...payload?.bearing !== void 0 ? { bearing: payload.bearing } : {}
2836
3154
  });
2837
3155
  setTimeout(() => {
2838
- isFlyingRef.current = false;
3156
+ releaseFlyingIfCurrent(flightId);
2839
3157
  }, 1050);
2840
3158
  }
2841
3159
  },
2842
- [userLocationState.coords, setFollowMode]
3160
+ [
3161
+ userLocationState.coords,
3162
+ setFollowMode,
3163
+ lockFlying,
3164
+ releaseFlyingIfCurrent
3165
+ ]
3166
+ );
3167
+ const handleFlyTo = (0, import_react12.useCallback)(
3168
+ (coords, params) => {
3169
+ const map = mapRef.current;
3170
+ if (!map) return;
3171
+ setFollowMode(false);
3172
+ const flightId = lockFlying();
3173
+ map.flyTo({
3174
+ center: coords,
3175
+ essential: true,
3176
+ pitch: params?.pitch ?? 0,
3177
+ zoom: params?.zoom ?? map.getZoom(),
3178
+ // Omit entirely (rather than defaulting to a fixed number) when
3179
+ // not given, so MapLibre computes its own distance-based duration.
3180
+ ...params?.duration !== void 0 ? { duration: params.duration } : {},
3181
+ ...params?.bearing !== void 0 ? { bearing: params.bearing } : {}
3182
+ });
3183
+ map.once("moveend", () => releaseFlyingIfCurrent(flightId));
3184
+ },
3185
+ [setFollowMode, lockFlying, releaseFlyingIfCurrent]
2843
3186
  );
2844
- const handleResetBearing = (0, import_react9.useCallback)((params) => {
3187
+ const handleResetBearing = (0, import_react12.useCallback)((params) => {
2845
3188
  if (mapRef.current) {
2846
3189
  mapRef.current.easeTo({
2847
3190
  bearing: 0,
@@ -2851,35 +3194,36 @@ var MapInternal = ({
2851
3194
  });
2852
3195
  }
2853
3196
  }, []);
2854
- (0, import_react9.useEffect)(() => {
3197
+ (0, import_react12.useEffect)(() => {
2855
3198
  if (mapControls) {
2856
3199
  mapControls._registerCenterCallback(handleCenterOnUser);
2857
3200
  mapControls._registerResetBearingCallback(handleResetBearing);
3201
+ mapControls._registerFlyToCallback(handleFlyTo);
2858
3202
  }
2859
- }, [mapControls, handleCenterOnUser, handleResetBearing]);
2860
- const handleMove = (0, import_react9.useCallback)(() => {
3203
+ }, [mapControls, handleCenterOnUser, handleResetBearing, handleFlyTo]);
3204
+ const handleMove = (0, import_react12.useCallback)(() => {
2861
3205
  if (mapRef.current && mapControls) {
2862
3206
  mapControls.setBearing(mapRef.current.getBearing());
2863
3207
  mapControls.setPitch(mapRef.current.getPitch());
2864
3208
  }
2865
3209
  }, [mapControls]);
2866
3210
  const handleUserInteraction = () => {
3211
+ if (lockToUser) return;
2867
3212
  if (isFollowingRef.current) {
2868
- console.log("[SDK:Map] Manual interaction detected. Halting tracking.");
2869
3213
  setFollowMode(false);
2870
3214
  if (mapRef.current) {
2871
3215
  mapRef.current.stop();
2872
3216
  }
2873
3217
  }
2874
3218
  };
2875
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
3219
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2876
3220
  "div",
2877
3221
  {
2878
- className: `w-full h-full overflow-hidden relative ${className}`,
3222
+ className: `w-full h-full overflow-hidden relative ${mockLocation?.isPlacingLocation ? "cursor-crosshair" : ""} ${className}`,
2879
3223
  style,
2880
3224
  children: [
2881
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2882
- import_react_maplibre5.Map,
3225
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
3226
+ import_react_maplibre6.Map,
2883
3227
  {
2884
3228
  attributionControl: false,
2885
3229
  initialViewState,
@@ -2900,6 +3244,7 @@ var MapInternal = ({
2900
3244
  },
2901
3245
  onMouseDown: handleUserInteraction,
2902
3246
  onMove: handleMove,
3247
+ onRotateStart: handleUserInteraction,
2903
3248
  onTouchStart: handleUserInteraction,
2904
3249
  onWheel: handleUserInteraction,
2905
3250
  ref: mapRef,
@@ -2907,23 +3252,30 @@ var MapInternal = ({
2907
3252
  showUserLocation && userLocationState.coords && (renderUserLocation ? renderUserLocation({
2908
3253
  coords: userLocationState.coords,
2909
3254
  heading: userLocationState.heading
2910
- }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3255
+ }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2911
3256
  UserLocationLayer,
2912
3257
  {
2913
3258
  forcedLocation: userLocationState.coords,
2914
3259
  heading: userLocationState.heading
2915
3260
  }
2916
3261
  )),
2917
- displayRoute && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(RouteLayer, { geometry: displayRoute }),
2918
- pois.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
2919
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(POILayers, { pois }),
2920
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(POIMarkers, { onClick: onPoiClick, pois })
3262
+ mockLocation && mockLocation.radiusMeters > 0 && userLocationState.coords && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3263
+ MockRadiusLayer,
3264
+ {
3265
+ center: userLocationState.coords,
3266
+ radiusMeters: mockLocation.radiusMeters
3267
+ }
3268
+ ),
3269
+ displayRoute && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(RouteLayer, { geometry: displayRoute }),
3270
+ pois.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
3271
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(POILayers, { pois }),
3272
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(POIMarkers, { onClick: onPoiClick, pois })
2921
3273
  ] }),
2922
3274
  mapLibreChildren
2923
3275
  ]
2924
3276
  }
2925
3277
  ),
2926
- showControls && mapControls && !mapControls.hasControls && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3278
+ showControls && mapControls && !mapControls.hasControls && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2927
3279
  MapControls,
2928
3280
  {
2929
3281
  drawerContentRef,
@@ -2943,18 +3295,18 @@ var MapInternal = ({
2943
3295
  var SDKMapProviderWrapper = ({
2944
3296
  children
2945
3297
  }) => {
2946
- const context = (0, import_react9.useContext)(MapControlsContext);
3298
+ const context = (0, import_react12.useContext)(MapControlsContext);
2947
3299
  if (context) {
2948
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children });
3300
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
2949
3301
  }
2950
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SDKMapProvider, { children });
3302
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SDKMapProvider, { children });
2951
3303
  };
2952
3304
  var Map2 = (props) => {
2953
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SDKMapProviderWrapper, { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_maplibre5.MapProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(MapInternal, { ...props }) }) });
3305
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SDKMapProviderWrapper, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_maplibre6.MapProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MapInternal, { ...props }) }) });
2954
3306
  };
2955
3307
 
2956
3308
  // src/components/MapWrapper.tsx
2957
- var import_react10 = __toESM(require("react"), 1);
3309
+ var import_react13 = __toESM(require("react"), 1);
2958
3310
  var import_client = require("react-dom/client");
2959
3311
  function renderMap(containerId, props = {}) {
2960
3312
  const container = document.getElementById(containerId);
@@ -2962,7 +3314,7 @@ function renderMap(containerId, props = {}) {
2962
3314
  throw new Error(`Container with id "${containerId}" not found.`);
2963
3315
  }
2964
3316
  const root = (0, import_client.createRoot)(container);
2965
- root.render(import_react10.default.createElement(Map2, props));
3317
+ root.render(import_react13.default.createElement(Map2, props));
2966
3318
  return root;
2967
3319
  }
2968
3320
 
@@ -3147,7 +3499,7 @@ var RoutingService = {
3147
3499
  };
3148
3500
 
3149
3501
  // package.json
3150
- var version = "0.2.7";
3502
+ var version = "0.5.2";
3151
3503
 
3152
3504
  // src/sdk.ts
3153
3505
  function deepFreeze(obj) {
@@ -3350,8 +3702,11 @@ var MiniAppSDK = class {
3350
3702
  getFidelityHistory: (params) => this.bridge.send("GET_FIDELITY_HISTORY", params),
3351
3703
  /**
3352
3704
  * Triggers the native fidelity history view.
3705
+ * @param options.isDark Theme to render the native view in. Pass the
3706
+ * mini-app's current theme explicitly — the native history screen is a
3707
+ * standalone view and does not read it from `updateContext`.
3353
3708
  */
3354
- showHistory: () => this.bridge.send("SHOW_FIDELITY_HISTORY"),
3709
+ showHistory: (options) => this.bridge.send("SHOW_FIDELITY_HISTORY", options),
3355
3710
  /**
3356
3711
  * Authorize spending fidelity points (FPoints) via Two-Phase Authorization.
3357
3712
  * @param intentUuid UUID generated by your backend for the transaction.
@@ -3486,8 +3841,8 @@ var MiniAppSDK = class {
3486
3841
  var sdk = deepFreeze(new MiniAppSDK());
3487
3842
 
3488
3843
  // src/components/BridgeMocker.tsx
3489
- var import_react11 = require("react");
3490
- var import_jsx_runtime15 = require("react/jsx-runtime");
3844
+ var import_react14 = require("react");
3845
+ var import_jsx_runtime16 = require("react/jsx-runtime");
3491
3846
  var getBearing = (p1, p2) => {
3492
3847
  const lat1 = p1[1] * Math.PI / 180;
3493
3848
  const lat2 = p2[1] * Math.PI / 180;
@@ -3506,16 +3861,19 @@ var BridgeMocker = ({
3506
3861
  mockJWTToken,
3507
3862
  children
3508
3863
  }) => {
3509
- const [autoMove, setAutoMove] = (0, import_react11.useState)(isMoving);
3510
- const [location, setLocation] = (0, import_react11.useState)(initialLocation);
3511
- const [heading, setHeading] = (0, import_react11.useState)(0);
3512
- const [speedMultiplier, setSpeedMultiplier] = (0, import_react11.useState)(simulationSpeed);
3513
- const [isReady, setIsReady] = (0, import_react11.useState)(false);
3514
- const [isMinimized, setIsMinimized] = (0, import_react11.useState)(true);
3515
- const streamIntervalRef = (0, import_react11.useRef)(null);
3516
- const pathIndexRef = (0, import_react11.useRef)(0);
3517
- const activeConfigRef = (0, import_react11.useRef)(null);
3518
- const stateRef = (0, import_react11.useRef)({
3864
+ const [autoMove, setAutoMove] = (0, import_react14.useState)(isMoving);
3865
+ const [location, setLocation] = (0, import_react14.useState)(initialLocation);
3866
+ const [heading, setHeading] = (0, import_react14.useState)(0);
3867
+ const [speedMultiplier, setSpeedMultiplier] = (0, import_react14.useState)(simulationSpeed);
3868
+ const [isReady, setIsReady] = (0, import_react14.useState)(false);
3869
+ const [isMinimized, setIsMinimized] = (0, import_react14.useState)(true);
3870
+ const [radiusMeters, setRadiusMeters] = (0, import_react14.useState)(0);
3871
+ const [radiusUnit, setRadiusUnit] = (0, import_react14.useState)("m");
3872
+ const [isPlacingLocation, setIsPlacingLocation] = (0, import_react14.useState)(false);
3873
+ const streamIntervalRef = (0, import_react14.useRef)(null);
3874
+ const pathIndexRef = (0, import_react14.useRef)(0);
3875
+ const activeConfigRef = (0, import_react14.useRef)(null);
3876
+ const stateRef = (0, import_react14.useRef)({
3519
3877
  autoMove,
3520
3878
  heading,
3521
3879
  location,
@@ -3527,36 +3885,51 @@ var BridgeMocker = ({
3527
3885
  simulationPath,
3528
3886
  speedMultiplier
3529
3887
  });
3530
- const pushLocationUpdate = (0, import_react11.useCallback)(() => {
3531
- const currentState = stateRef.current;
3532
- const payload = {
3533
- accelerometer: null,
3534
- heading: {
3535
- accuracy: 3,
3536
- magneticHeading: currentState.heading,
3537
- trueHeading: currentState.heading
3538
- },
3539
- location: {
3540
- coords: {
3541
- accuracy: 10,
3542
- altitude: 0,
3543
- altitudeAccuracy: null,
3544
- heading: currentState.heading,
3545
- latitude: currentState.location[1],
3546
- longitude: currentState.location[0],
3547
- speed: currentState.autoMove ? 1.5 * currentState.speedMultiplier : 0
3888
+ const pushLocationUpdateFor = (0, import_react14.useCallback)(
3889
+ (coords, headingDeg) => {
3890
+ const currentState = stateRef.current;
3891
+ const payload = {
3892
+ accelerometer: null,
3893
+ heading: {
3894
+ accuracy: 3,
3895
+ magneticHeading: headingDeg,
3896
+ trueHeading: headingDeg
3897
+ },
3898
+ location: {
3899
+ coords: {
3900
+ accuracy: 10,
3901
+ altitude: 0,
3902
+ altitudeAccuracy: null,
3903
+ heading: headingDeg,
3904
+ latitude: coords[1],
3905
+ longitude: coords[0],
3906
+ speed: currentState.autoMove ? 1.5 * currentState.speedMultiplier : 0
3907
+ },
3908
+ timestamp: Date.now()
3548
3909
  },
3549
3910
  timestamp: Date.now()
3550
- },
3551
- timestamp: Date.now()
3552
- };
3553
- window.__MiniAppBridge?.onNativeMessage({
3554
- eventName: "LOCATION_STREAM_UPDATE" /* LOCATION_STREAM_UPDATE */,
3555
- payload,
3556
- type: "EVENT"
3557
- });
3558
- }, []);
3559
- (0, import_react11.useEffect)(() => {
3911
+ };
3912
+ window.__MiniAppBridge?.onNativeMessage({
3913
+ eventName: "LOCATION_STREAM_UPDATE" /* LOCATION_STREAM_UPDATE */,
3914
+ payload,
3915
+ type: "EVENT"
3916
+ });
3917
+ },
3918
+ []
3919
+ );
3920
+ const pushLocationUpdate = (0, import_react14.useCallback)(() => {
3921
+ const currentState = stateRef.current;
3922
+ pushLocationUpdateFor(currentState.location, currentState.heading);
3923
+ }, [pushLocationUpdateFor]);
3924
+ const placeLocation = (0, import_react14.useCallback)(
3925
+ (coords) => {
3926
+ setLocation(coords);
3927
+ setIsPlacingLocation(false);
3928
+ pushLocationUpdateFor(coords, stateRef.current.heading);
3929
+ },
3930
+ [pushLocationUpdateFor]
3931
+ );
3932
+ (0, import_react14.useEffect)(() => {
3560
3933
  stateRef.current = {
3561
3934
  autoMove,
3562
3935
  heading,
@@ -3577,19 +3950,19 @@ var BridgeMocker = ({
3577
3950
  speedMultiplier,
3578
3951
  mockJWTToken
3579
3952
  ]);
3580
- (0, import_react11.useEffect)(() => {
3953
+ (0, import_react14.useEffect)(() => {
3581
3954
  setAutoMove(isMoving);
3582
3955
  }, [isMoving]);
3583
- (0, import_react11.useEffect)(() => {
3956
+ (0, import_react14.useEffect)(() => {
3584
3957
  setSpeedMultiplier(simulationSpeed);
3585
3958
  }, [simulationSpeed]);
3586
- (0, import_react11.useEffect)(() => {
3959
+ (0, import_react14.useEffect)(() => {
3587
3960
  if (simulationPath && simulationPath.length > 0) {
3588
3961
  pathIndexRef.current = 0;
3589
3962
  setLocation(simulationPath[0]);
3590
3963
  }
3591
3964
  }, [simulationPath]);
3592
- (0, import_react11.useEffect)(() => {
3965
+ (0, import_react14.useEffect)(() => {
3593
3966
  if (streamIntervalRef.current && activeConfigRef.current) {
3594
3967
  sdk.bridge.send(
3595
3968
  "START_LOCATION_STREAM",
@@ -3597,7 +3970,7 @@ var BridgeMocker = ({
3597
3970
  );
3598
3971
  }
3599
3972
  }, [speedMultiplier]);
3600
- (0, import_react11.useEffect)(() => {
3973
+ (0, import_react14.useEffect)(() => {
3601
3974
  const bridge = sdk.bridge;
3602
3975
  const originalSend = bridge.send.bind(bridge);
3603
3976
  const stopStream = () => {
@@ -3803,10 +4176,19 @@ var BridgeMocker = ({
3803
4176
  bridge.send = originalSend;
3804
4177
  };
3805
4178
  }, [appId]);
4179
+ const radiusInMeters = radiusUnit === "km" ? radiusMeters * 1e3 : radiusMeters;
4180
+ const mockLocationContextValue = (0, import_react14.useMemo)(
4181
+ () => ({
4182
+ isPlacingLocation,
4183
+ placeLocation,
4184
+ radiusMeters: radiusInMeters
4185
+ }),
4186
+ [isPlacingLocation, placeLocation, radiusInMeters]
4187
+ );
3806
4188
  if (!isReady) return null;
3807
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "relative w-full h-full", children: [
3808
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "w-full h-full", children }),
3809
- isMinimized ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4189
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "relative w-full h-full", children: [
4190
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "w-full h-full", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(MockLocationContext.Provider, { value: mockLocationContextValue, children }) }),
4191
+ isMinimized ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3810
4192
  Button,
3811
4193
  {
3812
4194
  className: "fixed bottom-4 right-4 w-8 h-8 rounded-full bg-slate-900/60 backdrop-blur-sm border border-slate-700/50 flex items-center justify-center text-slate-400 hover:text-blue-400 hover:bg-slate-900/80 z-[9999] transition-all shadow-lg group p-0!",
@@ -3814,7 +4196,7 @@ var BridgeMocker = ({
3814
4196
  title: "Open Simulation Controls",
3815
4197
  type: "button",
3816
4198
  variant: "ghost",
3817
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
4199
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
3818
4200
  "svg",
3819
4201
  {
3820
4202
  className: "group-hover:scale-110 transition-transform",
@@ -3828,34 +4210,34 @@ var BridgeMocker = ({
3828
4210
  width: "14",
3829
4211
  xmlns: "http://www.w3.org/2000/svg",
3830
4212
  children: [
3831
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M21 4H3" }),
3832
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M10 8H3" }),
3833
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M21 12H3" }),
3834
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M10 16H3" }),
3835
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M21 20H3" }),
3836
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("circle", { cx: "14", cy: "8", r: "2" }),
3837
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("circle", { cx: "14", cy: "16", r: "2" })
4213
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M21 4H3" }),
4214
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M10 8H3" }),
4215
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M21 12H3" }),
4216
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M10 16H3" }),
4217
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M21 20H3" }),
4218
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "14", cy: "8", r: "2" }),
4219
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "14", cy: "16", r: "2" })
3838
4220
  ]
3839
4221
  }
3840
4222
  )
3841
4223
  }
3842
- ) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
4224
+ ) : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
3843
4225
  "div",
3844
4226
  {
3845
4227
  className: "fixed bottom-4 right-4 bg-slate-900 text-slate-300 font-mono text-xs rounded-xl shadow-2xl border border-slate-700 pointer-events-auto flex flex-col w-80 overflow-hidden animate-in slide-in-from-right duration-300",
3846
4228
  style: { zIndex: 9998 },
3847
4229
  children: [
3848
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
4230
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
3849
4231
  "div",
3850
4232
  {
3851
4233
  className: "flex justify-between items-center p-3 border-b border-slate-800 cursor-pointer bg-slate-800/50 hover:bg-slate-800 transition-colors",
3852
4234
  onClick: () => setIsMinimized(true),
3853
4235
  children: [
3854
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "font-bold text-slate-100 flex items-center gap-2", children: [
3855
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-lg", children: "\u{1F6E0}\uFE0F" }),
4236
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "font-bold text-slate-100 flex items-center gap-2", children: [
4237
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-lg", children: "\u{1F6E0}\uFE0F" }),
3856
4238
  " Simulation Controls"
3857
4239
  ] }),
3858
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4240
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3859
4241
  Button,
3860
4242
  {
3861
4243
  className: "text-slate-500 hover:text-white p-0 h-auto hover:bg-transparent cursor-pointer",
@@ -3867,10 +4249,10 @@ var BridgeMocker = ({
3867
4249
  ]
3868
4250
  }
3869
4251
  ),
3870
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "p-4 flex flex-col gap-3", children: [
3871
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex justify-between items-center", children: [
3872
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer", children: [
3873
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4252
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "p-4 flex flex-col gap-3", children: [
4253
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex justify-between items-center", children: [
4254
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer", children: [
4255
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3874
4256
  "input",
3875
4257
  {
3876
4258
  checked: autoMove,
@@ -3879,20 +4261,20 @@ var BridgeMocker = ({
3879
4261
  type: "checkbox"
3880
4262
  }
3881
4263
  ),
3882
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "text-slate-200 font-bold", children: [
4264
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "text-slate-200 font-bold", children: [
3883
4265
  "Auto-Move ",
3884
4266
  simulationPath ? "(Path)" : "(Random)"
3885
4267
  ] })
3886
4268
  ] }),
3887
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-2", children: [
3888
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-[10px] text-slate-500", children: "Speed:" }),
3889
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4269
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-2", children: [
4270
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-[10px] text-slate-500", children: "Speed:" }),
4271
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3890
4272
  "select",
3891
4273
  {
3892
4274
  className: "bg-slate-800 border border-slate-700 rounded px-1 py-0.5 text-white focus:outline-none focus:border-blue-500 text-[10px]",
3893
4275
  onChange: (e) => setSpeedMultiplier(Number(e.target.value)),
3894
4276
  value: speedMultiplier,
3895
- children: [1, 2, 5, 10, 50, 100, 250].map((s) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("option", { value: s, children: [
4277
+ children: [1, 2, 5, 10, 50, 100, 250].map((s) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("option", { value: s, children: [
3896
4278
  s,
3897
4279
  "x"
3898
4280
  ] }, s))
@@ -3900,10 +4282,10 @@ var BridgeMocker = ({
3900
4282
  )
3901
4283
  ] })
3902
4284
  ] }),
3903
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
3904
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-1", children: [
3905
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-[10px] text-slate-500 text-left", children: "Lng" }),
3906
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4285
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
4286
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-col gap-1", children: [
4287
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-[10px] text-slate-500 text-left", children: "Lng" }),
4288
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3907
4289
  "input",
3908
4290
  {
3909
4291
  className: "bg-slate-800 border border-slate-700 rounded px-2 py-1 text-white focus:outline-none focus:border-blue-500",
@@ -3918,9 +4300,9 @@ var BridgeMocker = ({
3918
4300
  }
3919
4301
  )
3920
4302
  ] }),
3921
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-1", children: [
3922
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-[10px] text-slate-500 text-left", children: "Lat" }),
3923
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4303
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-col gap-1", children: [
4304
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-[10px] text-slate-500 text-left", children: "Lat" }),
4305
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3924
4306
  "input",
3925
4307
  {
3926
4308
  className: "bg-slate-800 border border-slate-700 rounded px-2 py-1 text-white focus:outline-none focus:border-blue-500",
@@ -3935,9 +4317,9 @@ var BridgeMocker = ({
3935
4317
  }
3936
4318
  )
3937
4319
  ] }),
3938
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-1 col-span-2", children: [
3939
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-[10px] text-slate-500", children: "Heading (Degrees)" }),
3940
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4320
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-col gap-1 col-span-2", children: [
4321
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-[10px] text-slate-500", children: "Heading (Degrees)" }),
4322
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3941
4323
  "input",
3942
4324
  {
3943
4325
  className: "w-full accent-blue-500",
@@ -3951,11 +4333,63 @@ var BridgeMocker = ({
3951
4333
  value: heading
3952
4334
  }
3953
4335
  ),
3954
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "text-right text-slate-400", children: [
4336
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "text-right text-slate-400", children: [
3955
4337
  heading,
3956
4338
  "\xB0"
3957
4339
  ] })
3958
4340
  ] })
4341
+ ] }),
4342
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4343
+ Button,
4344
+ {
4345
+ className: `w-full rounded px-2 py-1.5 text-[10px] font-bold border cursor-pointer ${isPlacingLocation ? "bg-blue-500/20 border-blue-500 text-blue-300" : "bg-slate-800 border-slate-700 text-slate-200 hover:bg-slate-700"}`,
4346
+ onClick: () => setIsPlacingLocation((prev) => !prev),
4347
+ type: "button",
4348
+ variant: "ghost",
4349
+ children: isPlacingLocation ? "\u{1F4CD} Click the map to drop location\u2026" : "\u{1F4CD} Drop location on map"
4350
+ }
4351
+ ),
4352
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-col gap-1 border-t border-slate-800 pt-3", children: [
4353
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex justify-between items-center", children: [
4354
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-[10px] text-slate-500", children: "Scan Radius" }),
4355
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-1", children: [
4356
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4357
+ "input",
4358
+ {
4359
+ className: "w-16 bg-slate-800 border border-slate-700 rounded px-1.5 py-0.5 text-white text-[10px] focus:outline-none focus:border-blue-500",
4360
+ min: "0",
4361
+ onChange: (e) => setRadiusMeters(Math.max(0, Number(e.target.value) || 0)),
4362
+ type: "number",
4363
+ value: radiusMeters
4364
+ }
4365
+ ),
4366
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
4367
+ "select",
4368
+ {
4369
+ className: "bg-slate-800 border border-slate-700 rounded px-1 py-0.5 text-white text-[10px] focus:outline-none focus:border-blue-500",
4370
+ onChange: (e) => setRadiusUnit(e.target.value),
4371
+ value: radiusUnit,
4372
+ children: [
4373
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "m", children: "m" }),
4374
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "km", children: "km" })
4375
+ ]
4376
+ }
4377
+ )
4378
+ ] })
4379
+ ] }),
4380
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4381
+ "input",
4382
+ {
4383
+ className: "w-full accent-blue-500",
4384
+ max: radiusUnit === "km" ? 10 : 500,
4385
+ min: "0",
4386
+ onChange: (e) => setRadiusMeters(Number(e.target.value)),
4387
+ step: radiusUnit === "km" ? 0.1 : 5,
4388
+ type: "range",
4389
+ value: radiusMeters
4390
+ }
4391
+ ),
4392
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "text-right text-slate-400", children: radiusMeters === 0 ? "hidden" : `${radiusMeters}${radiusUnit} radius around user` })
3959
4393
  ] })
3960
4394
  ] })
3961
4395
  ]
@@ -3965,20 +4399,20 @@ var BridgeMocker = ({
3965
4399
  };
3966
4400
 
3967
4401
  // src/components/DebugConsole.tsx
3968
- var import_react12 = require("react");
3969
- var import_jsx_runtime16 = require("react/jsx-runtime");
4402
+ var import_react15 = require("react");
4403
+ var import_jsx_runtime17 = require("react/jsx-runtime");
3970
4404
  var DebugConsole = ({
3971
4405
  isOpen: initialOpen = false,
3972
4406
  onClose
3973
4407
  }) => {
3974
- const [showConsole, setShowConsole] = (0, import_react12.useState)(initialOpen);
3975
- const [logs, setLogs] = (0, import_react12.useState)([]);
3976
- const scrollRef = (0, import_react12.useRef)(null);
3977
- (0, import_react12.useEffect)(() => {
4408
+ const [showConsole, setShowConsole] = (0, import_react15.useState)(initialOpen);
4409
+ const [logs, setLogs] = (0, import_react15.useState)([]);
4410
+ const scrollRef = (0, import_react15.useRef)(null);
4411
+ (0, import_react15.useEffect)(() => {
3978
4412
  setShowConsole(initialOpen);
3979
4413
  }, [initialOpen]);
3980
4414
  const clearLogs = () => setLogs([]);
3981
- const addLog = (0, import_react12.useCallback)((label, data) => {
4415
+ const addLog = (0, import_react15.useCallback)((label, data) => {
3982
4416
  if (label.includes("LOCATION_STREAM_UPDATE" /* LOCATION_STREAM_UPDATE */)) return;
3983
4417
  const entry = {
3984
4418
  content: typeof data === "string" ? data : JSON.stringify(data, null, 2),
@@ -3988,7 +4422,7 @@ var DebugConsole = ({
3988
4422
  };
3989
4423
  setLogs((prev) => [entry, ...prev].slice(0, 100));
3990
4424
  }, []);
3991
- (0, import_react12.useEffect)(() => {
4425
+ (0, import_react15.useEffect)(() => {
3992
4426
  if (typeof window === "undefined") return;
3993
4427
  const bridge = sdk.bridge;
3994
4428
  const originalSend = bridge.send.bind(bridge);
@@ -4010,7 +4444,7 @@ var DebugConsole = ({
4010
4444
  };
4011
4445
  }, [addLog]);
4012
4446
  if (!showConsole) {
4013
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4447
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4014
4448
  Button,
4015
4449
  {
4016
4450
  className: "fixed bottom-4 left-4 w-8 h-8 rounded-full bg-slate-900/60 backdrop-blur-sm border border-slate-700/50 flex items-center justify-center text-slate-400 hover:text-emerald-400 hover:bg-slate-900/80 transition-all z-[9998] shadow-lg group p-0!",
@@ -4018,7 +4452,7 @@ var DebugConsole = ({
4018
4452
  title: "Open Debug Console",
4019
4453
  type: "button",
4020
4454
  variant: "ghost",
4021
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
4455
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
4022
4456
  "svg",
4023
4457
  {
4024
4458
  className: "group-hover:scale-110 transition-transform",
@@ -4032,31 +4466,31 @@ var DebugConsole = ({
4032
4466
  width: "14",
4033
4467
  xmlns: "http://www.w3.org/2000/svg",
4034
4468
  children: [
4035
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "m8 2 1.88 1.88" }),
4036
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M14.12 3.88 16 2" }),
4037
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M9 7.13v-1a3.003 3.003 0 1 1 6 0v1" }),
4038
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6" }),
4039
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M12 20v-9" }),
4040
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M6.53 9C4.6 8.8 3 7.1 3 5" }),
4041
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M6 13H2" }),
4042
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M3 21c0-2.1 1.7-3.9 3.8-4" }),
4043
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M20.97 5c0 2.1-1.6 3.8-3.5 4" }),
4044
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M22 13h-4" }),
4045
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M17.2 17c2.1.1 3.8 1.9 3.8 4" })
4469
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "m8 2 1.88 1.88" }),
4470
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M14.12 3.88 16 2" }),
4471
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M9 7.13v-1a3.003 3.003 0 1 1 6 0v1" }),
4472
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6" }),
4473
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M12 20v-9" }),
4474
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M6.53 9C4.6 8.8 3 7.1 3 5" }),
4475
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M6 13H2" }),
4476
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M3 21c0-2.1 1.7-3.9 3.8-4" }),
4477
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M20.97 5c0 2.1-1.6 3.8-3.5 4" }),
4478
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M22 13h-4" }),
4479
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M17.2 17c2.1.1 3.8 1.9 3.8 4" })
4046
4480
  ]
4047
4481
  }
4048
4482
  )
4049
4483
  }
4050
4484
  );
4051
4485
  }
4052
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "fixed inset-x-0 bottom-0 w-full bg-[#0a080f] border-t border-slate-800 z-[9998] p-4 shadow-2xl flex flex-col animate-in slide-in-from-bottom duration-300", children: [
4053
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [
4054
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "text-[10px] font-bold uppercase tracking-widest text-slate-400 flex items-center gap-2", children: [
4055
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "w-2 h-2 rounded-full bg-emerald-500 animate-pulse" }),
4486
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "fixed inset-x-0 bottom-0 w-full bg-[#0a080f] border-t border-slate-800 z-[9998] p-4 shadow-2xl flex flex-col animate-in slide-in-from-bottom duration-300", children: [
4487
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [
4488
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "text-[10px] font-bold uppercase tracking-widest text-slate-400 flex items-center gap-2", children: [
4489
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-2 h-2 rounded-full bg-emerald-500 animate-pulse" }),
4056
4490
  "UP SDK Debug Console"
4057
4491
  ] }),
4058
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex gap-4", children: [
4059
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4492
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex gap-4", children: [
4493
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4060
4494
  Button,
4061
4495
  {
4062
4496
  className: "text-[10px] text-slate-500 font-bold uppercase hover:text-slate-300 hover:bg-transparent transition-colors p-0 h-auto cursor-pointer",
@@ -4066,7 +4500,7 @@ var DebugConsole = ({
4066
4500
  children: "Clear"
4067
4501
  }
4068
4502
  ),
4069
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4503
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4070
4504
  Button,
4071
4505
  {
4072
4506
  className: "text-[10px] text-pink-500 font-bold uppercase hover:text-pink-400 hover:bg-transparent transition-colors p-0 h-auto cursor-pointer",
@@ -4081,21 +4515,21 @@ var DebugConsole = ({
4081
4515
  )
4082
4516
  ] })
4083
4517
  ] }),
4084
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4518
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4085
4519
  "div",
4086
4520
  {
4087
4521
  className: "bg-black/80 rounded-xl p-3 font-mono text-[10px] text-emerald-400 min-h-[120px] max-h-[240px] overflow-y-auto border border-slate-900 custom-scrollbar",
4088
4522
  ref: scrollRef,
4089
- children: logs.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "text-slate-600 italic text-center py-8", children: "No logs yet. Interacting with the SDK will show events here." }) : logs.map((log) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
4523
+ children: logs.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "text-slate-600 italic text-center py-8", children: "No logs yet. Interacting with the SDK will show events here." }) : logs.map((log) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
4090
4524
  "div",
4091
4525
  {
4092
4526
  className: "mb-3 pb-3 border-b border-slate-900/50 last:border-0 last:mb-0 last:pb-0",
4093
4527
  children: [
4094
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex gap-2 text-slate-500 mb-1 items-center", children: [
4095
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-[8px]", children: log.time }),
4096
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "font-bold text-white uppercase text-[8px] bg-slate-800 px-1.5 py-0.5 rounded leading-none", children: log.label })
4528
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex gap-2 text-slate-500 mb-1 items-center", children: [
4529
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-[8px]", children: log.time }),
4530
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "font-bold text-white uppercase text-[8px] bg-slate-800 px-1.5 py-0.5 rounded leading-none", children: log.label })
4097
4531
  ] }),
4098
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("pre", { className: "whitespace-pre-wrap break-all opacity-90", children: log.content })
4532
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("pre", { className: "whitespace-pre-wrap break-all opacity-90", children: log.content })
4099
4533
  ]
4100
4534
  },
4101
4535
  log.id
@@ -4106,25 +4540,249 @@ var DebugConsole = ({
4106
4540
  };
4107
4541
 
4108
4542
  // src/components/SDKProvider.tsx
4109
- var import_react13 = require("react");
4110
- var import_jsx_runtime17 = require("react/jsx-runtime");
4111
- var SDKContext = (0, import_react13.createContext)({ isMocked: false });
4112
- var useIsMocked = () => (0, import_react13.useContext)(SDKContext).isMocked;
4543
+ var import_react16 = require("react");
4544
+ var import_jsx_runtime18 = require("react/jsx-runtime");
4545
+ var SDKContext = (0, import_react16.createContext)({ isMocked: false });
4546
+ var useIsMocked = () => (0, import_react16.useContext)(SDKContext).isMocked;
4113
4547
  var SDKProvider = ({
4114
4548
  children,
4115
4549
  debug = false,
4116
4550
  ...mockerProps
4117
4551
  }) => {
4118
4552
  const isMocked = typeof window !== "undefined" && !(window.__UP_REACT_NATIVE_APP__ === true || !!window.ReactNativeWebView);
4119
- const value = (0, import_react13.useMemo)(() => ({ isMocked }), [isMocked]);
4120
- const content = /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
4553
+ const value = (0, import_react16.useMemo)(() => ({ isMocked }), [isMocked]);
4554
+ const content = /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4121
4555
  children,
4122
- (debug || isMocked) && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DebugConsole, {})
4556
+ (debug || isMocked) && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DebugConsole, {})
4123
4557
  ] });
4124
4558
  if (isMocked) {
4125
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SDKContext.Provider, { value, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(BridgeMocker, { ...mockerProps, children: content }) });
4559
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SDKContext.Provider, { value, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(BridgeMocker, { ...mockerProps, children: content }) });
4126
4560
  }
4127
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SDKContext.Provider, { value, children: content });
4561
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SDKContext.Provider, { value, children: content });
4562
+ };
4563
+
4564
+ // src/components/SwipeCarousel.tsx
4565
+ var import_react17 = require("react");
4566
+ var import_jsx_runtime19 = require("react/jsx-runtime");
4567
+ var DIRECTION_LOCK_THRESHOLD_PX = 8;
4568
+ var SWIPE_DISTANCE_THRESHOLD_PX = 40;
4569
+ var SWIPE_VELOCITY_THRESHOLD = 0.4;
4570
+ var EDGE_RESISTANCE = 0.35;
4571
+ var SNAP_EASING = "cubic-bezier(0.16, 1, 0.3, 1)";
4572
+ var SNAP_DURATION_MS = 300;
4573
+ var VERTICAL_DEAD_ZONE_PX = 15;
4574
+ var DEFAULT_VERTICAL_DISMISS_THRESHOLD_PX = 200;
4575
+ var DEFAULT_VERTICAL_DISMISS_VELOCITY = 0.5;
4576
+ var DEFAULT_OVERSCAN = 2;
4577
+ var DEFAULT_VISIBLE_OVERSCAN = 1;
4578
+ var DEFAULT_SCROLL_ROOT_SELECTOR = "[data-swipe-scroll-root]";
4579
+ var SNAP_TRANSITION = `transform ${SNAP_DURATION_MS}ms ${SNAP_EASING}`;
4580
+ var SwipeCarousel = ({
4581
+ items,
4582
+ activeId,
4583
+ onActiveChange,
4584
+ peek = 1.1,
4585
+ gap = 10,
4586
+ className,
4587
+ itemClassName,
4588
+ axisPriority = "horizontal",
4589
+ verticalDrag,
4590
+ overscan = DEFAULT_OVERSCAN,
4591
+ visibleOverscan = DEFAULT_VISIBLE_OVERSCAN
4592
+ }) => {
4593
+ const containerRef = (0, import_react17.useRef)(null);
4594
+ const [containerWidth, setContainerWidth] = (0, import_react17.useState)(0);
4595
+ const [dragX, setDragX] = (0, import_react17.useState)(0);
4596
+ const [dragY, setDragY] = (0, import_react17.useState)(0);
4597
+ const [isDraggingX, setIsDraggingX] = (0, import_react17.useState)(false);
4598
+ const [isDraggingY, setIsDraggingY] = (0, import_react17.useState)(false);
4599
+ const touchStateRef = (0, import_react17.useRef)(null);
4600
+ const [internalIndex, setInternalIndex] = (0, import_react17.useState)(
4601
+ () => Math.max(
4602
+ 0,
4603
+ items.findIndex((item) => item.id === activeId)
4604
+ )
4605
+ );
4606
+ const prevActiveIdRef = (0, import_react17.useRef)(activeId);
4607
+ (0, import_react17.useEffect)(() => {
4608
+ if (activeId !== prevActiveIdRef.current) {
4609
+ const idx = items.findIndex((item) => item.id === activeId);
4610
+ if (idx !== -1) setInternalIndex(idx);
4611
+ prevActiveIdRef.current = activeId;
4612
+ }
4613
+ }, [activeId, items]);
4614
+ const activeIndex = Math.min(
4615
+ Math.max(internalIndex, 0),
4616
+ Math.max(items.length - 1, 0)
4617
+ );
4618
+ (0, import_react17.useLayoutEffect)(() => {
4619
+ const el = containerRef.current;
4620
+ if (!el) return;
4621
+ const update = () => setContainerWidth(el.clientWidth);
4622
+ update();
4623
+ const observer = new ResizeObserver(update);
4624
+ observer.observe(el);
4625
+ return () => observer.disconnect();
4626
+ }, []);
4627
+ const slideWidth = containerWidth / peek;
4628
+ const step = slideWidth + gap;
4629
+ const baseOffset = (containerWidth - slideWidth) / 2;
4630
+ const translateX = baseOffset - activeIndex * step + dragX;
4631
+ const commitIndex = (nextIndex) => {
4632
+ setInternalIndex(nextIndex);
4633
+ const nextItem = items[nextIndex];
4634
+ if (nextItem && nextItem.id !== activeId) onActiveChange(nextItem.id);
4635
+ };
4636
+ const handleTouchStart = (e) => {
4637
+ const touch = e.targetTouches[0];
4638
+ if (!touch) return;
4639
+ let verticalAllowed = false;
4640
+ if (verticalDrag) {
4641
+ const selector = verticalDrag.scrollRootSelector ?? DEFAULT_SCROLL_ROOT_SELECTOR;
4642
+ const scrollRoot = e.target.closest(
4643
+ selector
4644
+ );
4645
+ verticalAllowed = !scrollRoot || scrollRoot.scrollTop <= 2;
4646
+ }
4647
+ touchStateRef.current = {
4648
+ lastT: e.timeStamp,
4649
+ lastX: touch.clientX,
4650
+ lastY: touch.clientY,
4651
+ lockedAxis: null,
4652
+ startX: touch.clientX,
4653
+ startY: touch.clientY,
4654
+ velocityX: 0,
4655
+ velocityY: 0,
4656
+ verticalAllowed
4657
+ };
4658
+ };
4659
+ const handleTouchMove = (e) => {
4660
+ const touch = e.targetTouches[0];
4661
+ const state = touchStateRef.current;
4662
+ if (!touch || !state) return;
4663
+ const rawDx = touch.clientX - state.startX;
4664
+ const rawDy = touch.clientY - state.startY;
4665
+ if (!state.lockedAxis) {
4666
+ if (Math.abs(rawDx) < DIRECTION_LOCK_THRESHOLD_PX && Math.abs(rawDy) < DIRECTION_LOCK_THRESHOLD_PX) {
4667
+ return;
4668
+ }
4669
+ const horizontalWins = Math.abs(rawDx) > Math.abs(rawDy) || Math.abs(rawDx) === Math.abs(rawDy) && axisPriority === "horizontal";
4670
+ if (horizontalWins) {
4671
+ state.lockedAxis = "x";
4672
+ } else if (verticalDrag && state.verticalAllowed) {
4673
+ state.lockedAxis = "y";
4674
+ } else {
4675
+ state.lockedAxis = "passthrough";
4676
+ }
4677
+ }
4678
+ if (state.lockedAxis === "passthrough") return;
4679
+ const dt = e.timeStamp - state.lastT;
4680
+ if (dt > 0) {
4681
+ state.velocityX = (touch.clientX - state.lastX) / dt;
4682
+ state.velocityY = (touch.clientY - state.lastY) / dt;
4683
+ }
4684
+ state.lastX = touch.clientX;
4685
+ state.lastY = touch.clientY;
4686
+ state.lastT = e.timeStamp;
4687
+ if (state.lockedAxis === "x") {
4688
+ if (!isDraggingX) setIsDraggingX(true);
4689
+ const atStart = activeIndex === 0 && rawDx > 0;
4690
+ const atEnd = activeIndex === items.length - 1 && rawDx < 0;
4691
+ setDragX(atStart || atEnd ? rawDx * EDGE_RESISTANCE : rawDx);
4692
+ } else if (verticalDrag) {
4693
+ const direction = verticalDrag.direction ?? "down";
4694
+ let clamped = rawDy;
4695
+ if (direction === "down") clamped = Math.max(0, rawDy);
4696
+ if (direction === "up") clamped = Math.min(0, rawDy);
4697
+ const beyondDeadZone = Math.sign(clamped) * Math.max(0, Math.abs(clamped) - VERTICAL_DEAD_ZONE_PX);
4698
+ if (!isDraggingY) setIsDraggingY(true);
4699
+ setDragY(beyondDeadZone);
4700
+ verticalDrag.onDragChange?.(beyondDeadZone, true);
4701
+ }
4702
+ if (e.cancelable) {
4703
+ e.preventDefault();
4704
+ }
4705
+ };
4706
+ const endDrag = () => {
4707
+ const state = touchStateRef.current;
4708
+ touchStateRef.current = null;
4709
+ setIsDraggingX(false);
4710
+ setIsDraggingY(false);
4711
+ if (!state) {
4712
+ setDragX(0);
4713
+ setDragY(0);
4714
+ return;
4715
+ }
4716
+ if (state.lockedAxis === "x") {
4717
+ const horizontalTriggered = Math.abs(dragX) > SWIPE_DISTANCE_THRESHOLD_PX || Math.abs(state.velocityX) > SWIPE_VELOCITY_THRESHOLD;
4718
+ if (horizontalTriggered) {
4719
+ const nextIndex = dragX < 0 ? Math.min(items.length - 1, activeIndex + 1) : Math.max(0, activeIndex - 1);
4720
+ commitIndex(nextIndex);
4721
+ }
4722
+ } else if (state.lockedAxis === "y") {
4723
+ const verticalThreshold = verticalDrag?.dismissThreshold ?? DEFAULT_VERTICAL_DISMISS_THRESHOLD_PX;
4724
+ const verticalVelocityThreshold = verticalDrag?.dismissVelocity ?? DEFAULT_VERTICAL_DISMISS_VELOCITY;
4725
+ const direction = verticalDrag?.direction ?? "down";
4726
+ const directionalVelocityY = direction === "down" ? Math.max(0, state.velocityY) : direction === "up" ? Math.max(0, -state.velocityY) : Math.abs(state.velocityY);
4727
+ const verticalTriggered = Math.abs(dragY) > verticalThreshold || directionalVelocityY > verticalVelocityThreshold;
4728
+ if (verticalTriggered) verticalDrag?.onDismiss?.();
4729
+ }
4730
+ setDragX(0);
4731
+ setDragY(0);
4732
+ verticalDrag?.onDragChange?.(0, false);
4733
+ };
4734
+ const windowStart = Math.max(0, activeIndex - overscan);
4735
+ const windowEnd = Math.min(items.length - 1, activeIndex + overscan);
4736
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4737
+ "div",
4738
+ {
4739
+ className: `relative overflow-hidden touch-pan-y ${className ?? ""}`,
4740
+ onTouchCancel: endDrag,
4741
+ onTouchEnd: endDrag,
4742
+ onTouchMove: handleTouchMove,
4743
+ onTouchStart: handleTouchStart,
4744
+ ref: containerRef,
4745
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4746
+ "div",
4747
+ {
4748
+ className: "relative h-full",
4749
+ style: {
4750
+ transform: `translateX(${translateX}px)`,
4751
+ transition: isDraggingX ? "none" : SNAP_TRANSITION,
4752
+ willChange: "transform"
4753
+ },
4754
+ children: items.map((item, index) => {
4755
+ if (index < windowStart || index > windowEnd) return null;
4756
+ const isActive = index === activeIndex;
4757
+ const verticalOffset = isActive ? dragY : 0;
4758
+ const distance = Math.abs(index - activeIndex);
4759
+ const isVisible = distance <= visibleOverscan;
4760
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4761
+ "div",
4762
+ {
4763
+ className: `absolute top-0 left-0 h-full shrink-0 ${itemClassName ?? ""} ${item.className ?? ""}`,
4764
+ style: {
4765
+ opacity: isVisible ? 1 : 0,
4766
+ pointerEvents: isVisible ? void 0 : "none",
4767
+ transform: `translateX(${index * step}px) translateY(${verticalOffset}px)`,
4768
+ transition: isActive && isDraggingY ? "none" : SNAP_TRANSITION,
4769
+ width: `${slideWidth}px`,
4770
+ // Layer by distance from the active slide (not DOM/index
4771
+ // order) so it always paints above its neighbors on BOTH
4772
+ // sides symmetrically — with `peek` this close, unstyled
4773
+ // z-index left neighbor bleed (shadow/blur) showing through
4774
+ // asymmetrically depending on swipe direction.
4775
+ zIndex: overscan + 1 - distance
4776
+ },
4777
+ children: item.content
4778
+ },
4779
+ item.id
4780
+ );
4781
+ })
4782
+ }
4783
+ )
4784
+ }
4785
+ );
4128
4786
  };
4129
4787
 
4130
4788
  // src/host/routingHandler.ts
@@ -4209,9 +4867,11 @@ var src_default = sdk;
4209
4867
  MapMenuItem,
4210
4868
  MapMenuTitle,
4211
4869
  MiniAppSDK,
4870
+ MockLocationContext,
4212
4871
  RouteLayer,
4213
4872
  SDKMapProvider,
4214
4873
  SDKProvider,
4874
+ SwipeCarousel,
4215
4875
  UIEvent,
4216
4876
  handleClearRoute,
4217
4877
  handleDrawRoute,
@@ -4219,8 +4879,10 @@ var src_default = sdk;
4219
4879
  renderMap,
4220
4880
  sdk,
4221
4881
  useIsMocked,
4882
+ useJourney,
4222
4883
  useLiveRouting,
4223
4884
  useMapControls,
4885
+ useMockLocation,
4224
4886
  useRoute,
4225
4887
  useTrimmedRoute,
4226
4888
  useUserLocation