@cloudparse/up-miniapps-sdk 0.6.7 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -65,6 +65,7 @@ __export(src_exports, {
65
65
  useMapControls: () => useMapControls,
66
66
  useMockLocation: () => useMockLocation,
67
67
  useRoute: () => useRoute,
68
+ useTapAction: () => useTapAction,
68
69
  useTrimmedRoute: () => useTrimmedRoute,
69
70
  useUserLocation: () => useUserLocation
70
71
  });
@@ -137,6 +138,58 @@ function isRunningInsideNativeShell() {
137
138
  // src/bridge.ts
138
139
  var BridgeTimeoutError = class extends Error {
139
140
  };
141
+ var MOCK_ACHIEVEMENTS = [
142
+ {
143
+ completed: false,
144
+ description: "Discover 5 points of interest around Annecy.",
145
+ imageUrl: "https://api.dicebear.com/9.x/icons/svg?seed=explore",
146
+ playerActionCount: 3,
147
+ slug: "explore-5-pois",
148
+ title: "Explorer",
149
+ totalActionCount: 5,
150
+ upReward: 50,
151
+ xpReward: 100
152
+ },
153
+ {
154
+ completed: true,
155
+ description: "Complete your first navigation journey.",
156
+ imageUrl: "https://api.dicebear.com/9.x/icons/svg?seed=journey",
157
+ playerActionCount: 1,
158
+ slug: "first-journey",
159
+ title: "First Steps",
160
+ totalActionCount: 1,
161
+ upReward: 20,
162
+ xpReward: 40
163
+ },
164
+ {
165
+ completed: false,
166
+ description: "Scan 10 QR codes at partner venues.",
167
+ imageUrl: "https://api.dicebear.com/9.x/icons/svg?seed=scan",
168
+ playerActionCount: 4,
169
+ slug: "scan-10-qrcodes",
170
+ title: "Code Breaker",
171
+ totalActionCount: 10,
172
+ upReward: 80,
173
+ xpReward: 150
174
+ }
175
+ ];
176
+ function mockAchievement(slug) {
177
+ const found = MOCK_ACHIEVEMENTS.find((a) => a.slug === slug);
178
+ if (found) return found;
179
+ return {
180
+ completed: false,
181
+ description: "Mocked achievement (no native shell attached).",
182
+ playerActionCount: 0,
183
+ slug: slug || "unknown-achievement",
184
+ title: slug || "Unknown Achievement",
185
+ totalActionCount: 1,
186
+ upReward: 0,
187
+ xpReward: 0
188
+ };
189
+ }
190
+ function mockAchievements() {
191
+ return MOCK_ACHIEVEMENTS;
192
+ }
140
193
  var Bridge = class {
141
194
  callbacks = /* @__PURE__ */ new Map();
142
195
  eventListeners = /* @__PURE__ */ new Map();
@@ -287,6 +340,12 @@ var Bridge = class {
287
340
  return this.mockSaveImage(
288
341
  payload
289
342
  );
343
+ case "GET_ACHIEVEMENT":
344
+ return Promise.resolve(
345
+ mockAchievement(payload?.slug)
346
+ );
347
+ case "GET_ACHIEVEMENTS":
348
+ return Promise.resolve(mockAchievements());
290
349
  default:
291
350
  console.warn(
292
351
  `[Bridge] Mock mode active: Unhandled message type ${type}`
@@ -475,412 +534,27 @@ SheetDescription.displayName = SheetPrimitive.Description.displayName;
475
534
  // src/components/Map/components/MapDrawer.tsx
476
535
  var import_react2 = require("react");
477
536
  var import_jsx_runtime3 = require("react/jsx-runtime");
478
- var resolveHeightToPixels = (height, containerHeight) => {
479
- if (typeof height === "number") {
480
- return height;
481
- }
482
- if (height.endsWith("%")) {
483
- return parseFloat(height) / 100 * containerHeight;
484
- }
485
- return parseFloat(height);
486
- };
487
- var CONTENT_EDGE_PULL_THRESHOLD_PX = 24;
488
- var HANDLE_BAR_HEIGHT_PX = 32;
489
- var HANDLE_TAP_CLICK_SUPPRESSION_MS = 400;
490
537
  var MapDrawer = (0, import_react2.forwardRef)(
491
538
  ({
492
539
  menuItems,
493
540
  state,
494
541
  onChangeState,
495
- side,
496
- etaBarHeight = 0,
497
- etaData,
498
- touchStartY,
499
- setTouchStartY,
500
- currentTouchY,
501
- setCurrentTouchY,
502
- isDragging,
503
- clampedDragOffset,
504
- drawerPeekHeight,
505
- drawerFullHeight,
506
- drawerAutoMaxHeight,
507
- containerHeight,
508
542
  menuContent,
509
- enableTouchDrag = false,
510
- handleVisible = true,
511
- onAutoContentHeightChange,
512
543
  showScrollToTopButton = true,
513
- scrollToTopThreshold = 300,
514
- safeAreaInsets = { bottom: 0, left: 0, right: 0, top: 0 }
544
+ scrollToTopThreshold = 300
515
545
  }, ref) => {
516
546
  const scrollContainerRef = (0, import_react2.useRef)(null);
517
- const containerRef = (0, import_react2.useRef)(null);
518
- const handleBarRef = (0, import_react2.useRef)(null);
519
- const contentAreaRef = (0, import_react2.useRef)(null);
520
547
  (0, import_react2.useImperativeHandle)(
521
548
  ref,
522
549
  () => scrollContainerRef.current
523
550
  );
524
- const handleHandleClick = () => {
525
- if (side === "left") {
526
- onChangeState(state === "closed" ? "full" : "closed");
527
- } else {
528
- if (state === "closed") {
529
- onChangeState("peek");
530
- } else if (state === "peek") {
531
- onChangeState("full");
532
- } else if (state === "auto") {
533
- onChangeState("closed");
534
- } else {
535
- onChangeState("peek");
536
- }
537
- }
538
- };
539
- const handleHandleClickRef = (0, import_react2.useRef)(handleHandleClick);
540
- handleHandleClickRef.current = handleHandleClick;
541
- const [autoContentPx, setAutoContentPx] = (0, import_react2.useState)(0);
542
- (0, import_react2.useEffect)(() => {
543
- if (state !== "auto") return;
544
- const scrollEl = scrollContainerRef.current;
545
- const contentAreaEl = contentAreaRef.current;
546
- if (!scrollEl || !contentAreaEl) return;
547
- const handleHeight = handleVisible ? handleBarRef.current?.offsetHeight ?? 0 : 0;
548
- const contentEl = scrollEl.firstElementChild;
549
- const measure = () => {
550
- const contentAreaStyle = window.getComputedStyle(contentAreaEl);
551
- const verticalPadding = parseFloat(contentAreaStyle.paddingTop || "0") + parseFloat(contentAreaStyle.paddingBottom || "0");
552
- const contentHeight = contentEl?.scrollHeight ?? scrollEl.scrollHeight;
553
- const px = handleHeight + verticalPadding + contentHeight;
554
- setAutoContentPx(px);
555
- onAutoContentHeightChange?.(px);
556
- };
557
- measure();
558
- const ro = new ResizeObserver(measure);
559
- ro.observe(contentEl ?? scrollEl);
560
- return () => ro.disconnect();
561
- }, [state, handleVisible, onAutoContentHeightChange]);
562
551
  const [showScrollTop, setShowScrollTop] = (0, import_react2.useState)(false);
563
552
  const handleScroll = (e) => {
564
553
  const scrollTop = e.currentTarget.scrollTop;
565
554
  setShowScrollTop(state !== "closed" && scrollTop > scrollToTopThreshold);
566
555
  };
567
- (0, import_react2.useEffect)(() => {
568
- if (state === "closed") {
569
- setShowScrollTop(false);
570
- } else {
571
- const scrollTop = scrollContainerRef.current?.scrollTop || 0;
572
- setShowScrollTop(scrollTop > scrollToTopThreshold);
573
- }
574
- }, [state, scrollToTopThreshold]);
575
- const isDraggingSheet = (0, import_react2.useRef)(false);
576
- const hasDeterminedDirection = (0, import_react2.useRef)(false);
577
- const isTouchOnContent = (0, import_react2.useRef)(false);
578
- const isTouchOnHandle = (0, import_react2.useRef)(false);
579
- const suppressNextClickRef = (0, import_react2.useRef)(false);
580
- const contentAtTopSinceY = (0, import_react2.useRef)(null);
581
- const contentAtBottomSinceY = (0, import_react2.useRef)(null);
582
- const dragStartYRef = (0, import_react2.useRef)(null);
583
- const dragBaseHeightPxRef = (0, import_react2.useRef)(0);
584
- const stateRef = (0, import_react2.useRef)(state);
585
- const touchStartYRef = (0, import_react2.useRef)(touchStartY);
586
- const currentTouchYRef = (0, import_react2.useRef)(currentTouchY);
587
- (0, import_react2.useEffect)(() => {
588
- stateRef.current = state;
589
- }, [state]);
590
- (0, import_react2.useEffect)(() => {
591
- touchStartYRef.current = touchStartY;
592
- }, [touchStartY]);
593
- (0, import_react2.useEffect)(() => {
594
- currentTouchYRef.current = currentTouchY;
595
- }, [currentTouchY]);
596
- (0, import_react2.useEffect)(() => {
597
- const container = containerRef.current;
598
- if (!container || side !== "bottom" || !enableTouchDrag) return;
599
- const handleNativeTouchStart = (e) => {
600
- const clientY = e.targetTouches[0].clientY;
601
- setTouchStartY(clientY);
602
- setCurrentTouchY(clientY);
603
- isDraggingSheet.current = false;
604
- hasDeterminedDirection.current = false;
605
- contentAtTopSinceY.current = null;
606
- contentAtBottomSinceY.current = null;
607
- dragStartYRef.current = null;
608
- const target = e.target;
609
- isTouchOnContent.current = scrollContainerRef.current ? scrollContainerRef.current.contains(target) : false;
610
- isTouchOnHandle.current = handleBarRef.current ? handleBarRef.current.contains(target) : false;
611
- };
612
- const handleNativeTouchMove = (e) => {
613
- const startY = touchStartYRef.current;
614
- if (startY === null) return;
615
- const currentY = e.targetTouches[0].clientY;
616
- const deltaY = startY - currentY;
617
- const scrollTop = scrollContainerRef.current ? scrollContainerRef.current.scrollTop : 0;
618
- const clientHeight = scrollContainerRef.current ? scrollContainerRef.current.clientHeight : 0;
619
- const scrollHeight = scrollContainerRef.current ? scrollContainerRef.current.scrollHeight : 0;
620
- const isAtBottom = scrollTop + clientHeight >= scrollHeight - 1;
621
- const currentState = stateRef.current;
622
- const containerHForHeights = containerHeight || container.parentElement?.getBoundingClientRect().height || window.innerHeight;
623
- const fullPxNow = resolveHeightToPixels(
624
- drawerFullHeight || "85%",
625
- containerHForHeights
626
- );
627
- const peekPxNow = resolveHeightToPixels(
628
- drawerPeekHeight || "15%",
629
- containerHForHeights
630
- );
631
- const closedPxNow = (handleVisible ? HANDLE_BAR_HEIGHT_PX : 0) + (currentState === "closed" ? safeAreaInsets.bottom : 0);
632
- const autoMaxPxNow = resolveHeightToPixels(
633
- drawerAutoMaxHeight || "100%",
634
- containerHForHeights
635
- );
636
- const autoPxNow = Math.min(autoMaxPxNow, autoContentPx);
637
- const baselineHeightPxForState = (s) => {
638
- if (s === "full") return fullPxNow;
639
- if (s === "peek") return peekPxNow;
640
- if (s === "auto") return autoPxNow;
641
- return closedPxNow;
642
- };
643
- const commitDrag = () => {
644
- isDraggingSheet.current = true;
645
- dragStartYRef.current = currentY;
646
- dragBaseHeightPxRef.current = baselineHeightPxForState(currentState);
647
- };
648
- if (scrollTop <= 0) {
649
- if (contentAtTopSinceY.current === null) {
650
- contentAtTopSinceY.current = currentY;
651
- }
652
- } else {
653
- contentAtTopSinceY.current = null;
654
- }
655
- if (isAtBottom) {
656
- if (contentAtBottomSinceY.current === null) {
657
- contentAtBottomSinceY.current = currentY;
658
- }
659
- } else {
660
- contentAtBottomSinceY.current = null;
661
- }
662
- const pullPastTop = contentAtTopSinceY.current !== null ? currentY - contentAtTopSinceY.current : 0;
663
- const pullPastBottom = contentAtBottomSinceY.current !== null ? contentAtBottomSinceY.current - currentY : 0;
664
- if (!hasDeterminedDirection.current) {
665
- if (!isTouchOnContent.current) {
666
- if (Math.abs(deltaY) < CONTENT_EDGE_PULL_THRESHOLD_PX) {
667
- return;
668
- }
669
- commitDrag();
670
- hasDeterminedDirection.current = true;
671
- } else if (currentState !== "full") {
672
- if (deltaY > 0 && isAtBottom && pullPastBottom >= CONTENT_EDGE_PULL_THRESHOLD_PX) {
673
- commitDrag();
674
- hasDeterminedDirection.current = true;
675
- } else if (deltaY < 0 && scrollTop <= 0 && pullPastTop >= CONTENT_EDGE_PULL_THRESHOLD_PX) {
676
- commitDrag();
677
- hasDeterminedDirection.current = true;
678
- } else if (deltaY > 0 && isAtBottom || deltaY < 0 && scrollTop <= 0) {
679
- return;
680
- } else {
681
- isDraggingSheet.current = false;
682
- hasDeterminedDirection.current = true;
683
- }
684
- } else {
685
- if (deltaY < 0 && scrollTop <= 0 && pullPastTop >= CONTENT_EDGE_PULL_THRESHOLD_PX) {
686
- commitDrag();
687
- hasDeterminedDirection.current = true;
688
- } else if (deltaY < 0 && scrollTop <= 0) {
689
- return;
690
- } else {
691
- isDraggingSheet.current = false;
692
- hasDeterminedDirection.current = true;
693
- }
694
- }
695
- } else if (!isDraggingSheet.current && isTouchOnContent.current) {
696
- if (deltaY < 0 && scrollTop <= 0 && pullPastTop >= CONTENT_EDGE_PULL_THRESHOLD_PX) {
697
- commitDrag();
698
- return;
699
- }
700
- if (deltaY > 0 && isAtBottom && currentState !== "full" && pullPastBottom >= CONTENT_EDGE_PULL_THRESHOLD_PX) {
701
- commitDrag();
702
- return;
703
- }
704
- }
705
- if (isDraggingSheet.current) {
706
- if (e.cancelable) {
707
- e.preventDefault();
708
- }
709
- const parentContainer = container.parentElement;
710
- if (parentContainer) {
711
- const dragOffset = currentY - (dragStartYRef.current ?? currentY);
712
- let localClamped = dragOffset;
713
- if (currentState === "full") {
714
- localClamped = Math.max(
715
- 0,
716
- Math.min(fullPxNow - closedPxNow, dragOffset)
717
- );
718
- } else if (currentState === "peek") {
719
- localClamped = Math.max(
720
- -(fullPxNow - peekPxNow),
721
- Math.min(peekPxNow - closedPxNow, dragOffset)
722
- );
723
- } else if (currentState === "closed") {
724
- localClamped = Math.min(
725
- 0,
726
- Math.max(-(fullPxNow - closedPxNow), dragOffset)
727
- );
728
- } else if (currentState === "auto") {
729
- localClamped = Math.max(0, dragOffset);
730
- }
731
- parentContainer.style.setProperty(
732
- "--drag-offset",
733
- `${localClamped}px`
734
- );
735
- }
736
- }
737
- };
738
- const handleNativeTouchEnd = (e) => {
739
- const startY = touchStartYRef.current;
740
- const currentY = currentTouchYRef.current;
741
- const parentContainer = container.parentElement;
742
- if (startY === null || currentY === null) {
743
- if (parentContainer) {
744
- parentContainer.style.setProperty("--drag-offset", "0px");
745
- }
746
- return;
747
- }
748
- if (!isDraggingSheet.current) {
749
- if (isTouchOnHandle.current) {
750
- handleHandleClickRef.current();
751
- suppressNextClickRef.current = true;
752
- setTimeout(() => {
753
- suppressNextClickRef.current = false;
754
- }, HANDLE_TAP_CLICK_SUPPRESSION_MS);
755
- }
756
- setTouchStartY(null);
757
- setCurrentTouchY(null);
758
- if (parentContainer) {
759
- parentContainer.style.setProperty("--drag-offset", "0px");
760
- }
761
- return;
762
- }
763
- const touchEndY = e.changedTouches[0].clientY;
764
- const dragStartY = dragStartYRef.current ?? startY;
765
- const dragDistance = Math.abs(touchEndY - dragStartY);
766
- if (dragDistance < 10) {
767
- setTouchStartY(null);
768
- setCurrentTouchY(null);
769
- if (parentContainer) {
770
- parentContainer.style.setProperty("--drag-offset", "0px");
771
- }
772
- return;
773
- }
774
- const containerH2 = containerHeight || (parentContainer ? parentContainer.getBoundingClientRect().height : window.innerHeight);
775
- const fullPx2 = resolveHeightToPixels(
776
- drawerFullHeight || "85%",
777
- containerH2
778
- );
779
- const peekPx2 = resolveHeightToPixels(
780
- drawerPeekHeight || "15%",
781
- containerH2
782
- );
783
- const currentState = stateRef.current;
784
- const closedPx = (handleVisible ? HANDLE_BAR_HEIGHT_PX : 0) + (currentState === "closed" ? safeAreaInsets.bottom : 0);
785
- const dragDelta = touchEndY - dragStartY;
786
- const drawerHeightFromBottom = dragBaseHeightPxRef.current - dragDelta;
787
- const distToClosed = Math.abs(drawerHeightFromBottom - closedPx);
788
- let targetState;
789
- if (currentState === "auto") {
790
- const autoMaxPx2 = resolveHeightToPixels(
791
- drawerAutoMaxHeight || "100%",
792
- containerH2
793
- );
794
- const autoPx2 = Math.min(autoMaxPx2, autoContentPx);
795
- const distToAuto = Math.abs(drawerHeightFromBottom - autoPx2);
796
- targetState = distToAuto <= distToClosed ? "auto" : "closed";
797
- } else {
798
- const distToFull = Math.abs(drawerHeightFromBottom - fullPx2);
799
- const distToPeek = Math.abs(drawerHeightFromBottom - peekPx2);
800
- const minDist = Math.min(distToFull, distToPeek, distToClosed);
801
- if (minDist === distToFull) {
802
- targetState = "full";
803
- } else if (minDist === distToPeek) {
804
- targetState = "peek";
805
- } else {
806
- targetState = "closed";
807
- }
808
- }
809
- setTouchStartY(null);
810
- setCurrentTouchY(null);
811
- onChangeState(targetState);
812
- requestAnimationFrame(() => {
813
- if (parentContainer) {
814
- parentContainer.style.setProperty("--drag-offset", "0px");
815
- }
816
- });
817
- };
818
- const handleNativeClickCapture = (e) => {
819
- if (!suppressNextClickRef.current) return;
820
- suppressNextClickRef.current = false;
821
- e.preventDefault();
822
- e.stopPropagation();
823
- };
824
- container.addEventListener("touchstart", handleNativeTouchStart, {
825
- passive: true
826
- });
827
- container.addEventListener("touchmove", handleNativeTouchMove, {
828
- passive: false
829
- });
830
- container.addEventListener("touchend", handleNativeTouchEnd, {
831
- passive: true
832
- });
833
- container.addEventListener("click", handleNativeClickCapture, {
834
- capture: true
835
- });
836
- return () => {
837
- container.removeEventListener("touchstart", handleNativeTouchStart);
838
- container.removeEventListener("touchmove", handleNativeTouchMove);
839
- container.removeEventListener("touchend", handleNativeTouchEnd);
840
- container.removeEventListener("click", handleNativeClickCapture, {
841
- capture: true
842
- });
843
- };
844
- }, [
845
- side,
846
- enableTouchDrag,
847
- containerHeight,
848
- drawerFullHeight,
849
- drawerPeekHeight,
850
- drawerAutoMaxHeight,
851
- safeAreaInsets,
852
- onChangeState,
853
- setTouchStartY,
854
- setCurrentTouchY,
855
- autoContentPx,
856
- handleVisible
857
- ]);
858
- const isBackdropActive = state === "full" || state === "auto";
556
+ const isBackdropActive = state !== "closed";
859
557
  const backdropStyles = isBackdropActive ? "opacity-100 pointer-events-auto" : "opacity-0 pointer-events-none";
860
- const containerH = containerHeight || window.innerHeight;
861
- const fullPx = resolveHeightToPixels(drawerFullHeight || "85%", containerH);
862
- const peekPx = resolveHeightToPixels(drawerPeekHeight || "15%", containerH);
863
- const autoMaxPx = resolveHeightToPixels(
864
- drawerAutoMaxHeight || "100%",
865
- containerH
866
- );
867
- const shiftPx = fullPx - peekPx;
868
- const autoPx = Math.min(autoMaxPx, autoContentPx);
869
- const autoShiftPx = Math.max(fullPx - autoPx, 0);
870
- const getBottomDrawerTransform = () => {
871
- if (state === "full") {
872
- return "translateY(var(--drag-offset, 0px))";
873
- }
874
- if (state === "peek") {
875
- return `translateY(calc(${shiftPx}px + var(--drag-offset, 0px)))`;
876
- }
877
- if (state === "auto") {
878
- return `translateY(calc(${autoShiftPx}px + var(--drag-offset, 0px)))`;
879
- }
880
- const closedVisibleHeight = handleVisible ? HANDLE_BAR_HEIGHT_PX : 0;
881
- const closedShiftPx = fullPx - closedVisibleHeight;
882
- return `translateY(calc(${closedShiftPx}px + var(--drag-offset, 0px)))`;
883
- };
884
558
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
885
559
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("style", { children: `
886
560
  .no-scrollbar {
@@ -898,233 +572,113 @@ var MapDrawer = (0, import_react2.forwardRef)(
898
572
  onClick: () => onChangeState("closed")
899
573
  }
900
574
  ),
901
- side === "left" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
902
- state === "closed" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
903
- Button,
904
- {
905
- className: "absolute top-4 left-4 z-40 w-12 h-12 rounded-full bg-zinc-950/80 backdrop-blur-md border border-white/10 shadow-lg flex items-center justify-center text-white active:scale-95 transition-all cursor-pointer hover:bg-zinc-900 hover:text-white p-0!",
906
- onClick: () => onChangeState("full"),
907
- variant: "ghost",
908
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
909
- "svg",
910
- {
911
- fill: "none",
912
- height: "24",
913
- stroke: "currentColor",
914
- strokeLinecap: "round",
915
- strokeLinejoin: "round",
916
- strokeWidth: "2",
917
- viewBox: "0 0 24 24",
918
- width: "24",
919
- xmlns: "http://www.w3.org/2000/svg",
920
- children: [
921
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "4", x2: "20", y1: "12", y2: "12" }),
922
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "4", x2: "20", y1: "6", y2: "6" }),
923
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "4", x2: "20", y1: "18", y2: "18" })
924
- ]
925
- }
926
- )
927
- }
928
- ),
929
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
930
- Sheet,
931
- {
932
- onOpenChange: (open) => onChangeState(open ? "full" : "closed"),
933
- open: state !== "closed",
934
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
935
- SheetContent,
936
- {
937
- className: "w-80 bg-zinc-950/85 backdrop-blur-md border-r border-y border-white/10 rounded-r-2xl shadow-2xl p-4 text-white flex flex-col h-full overflow-hidden",
938
- portal: false,
939
- side: "left",
940
- children: [
941
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SheetHeader, { className: "pb-3 border-b border-white/10 mb-2 text-left", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SheetTitle, { className: "text-sm font-bold tracking-wider text-zinc-400 uppercase", children: "Menu" }) }),
942
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
943
- "div",
944
- {
945
- className: "flex-1 overflow-y-auto no-scrollbar pr-2",
946
- onScroll: handleScroll,
947
- ref: scrollContainerRef,
948
- children: menuContent ? menuContent : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex flex-col gap-1.5", children: menuItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
949
- Button,
950
- {
951
- className: `flex items-center gap-3 w-full py-3 px-3.5 rounded-xl text-left cursor-pointer transition-all duration-150 justify-start hover:bg-white/5 hover:text-white active:bg-white/10 text-white ${item.disabled ? "opacity-45 cursor-not-allowed pointer-events-none" : ""}`,
952
- disabled: item.disabled,
953
- onClick: () => {
954
- if (!item.disabled) {
955
- item.onPress();
956
- onChangeState("closed");
957
- }
958
- },
959
- variant: "ghost",
960
- children: [
961
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "relative flex items-center justify-center w-8 h-8 rounded-lg bg-white/5 text-zinc-300", children: [
962
- item.icon,
963
- item.badge !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "absolute -top-1 -right-1 bg-cyan-500 text-black text-[9px] font-extrabold min-w-[15px] h-3.5 rounded-full flex items-center justify-center px-1 border border-zinc-950 shadow", children: item.badge })
964
- ] }),
965
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-sm font-medium tracking-wide flex-1", children: item.label })
966
- ]
967
- },
968
- item.id
969
- )) })
970
- }
971
- ),
972
- showScrollToTopButton && showScrollTop && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
973
- Button,
974
- {
975
- className: "absolute bottom-6 right-6 z-50 flex items-center justify-center w-10 h-10 rounded-full bg-cyan-500 hover:bg-cyan-400 active:scale-95 text-black hover:text-black shadow-lg shadow-cyan-500/25 transition-all duration-200 cursor-pointer p-0!",
976
- onClick: () => {
977
- scrollContainerRef.current?.scrollTo({
978
- behavior: "smooth",
979
- top: 0
980
- });
981
- },
982
- variant: "ghost",
983
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
984
- "svg",
985
- {
986
- fill: "none",
987
- height: "20",
988
- stroke: "currentColor",
989
- strokeLinecap: "round",
990
- strokeLinejoin: "round",
991
- strokeWidth: "2.5",
992
- viewBox: "0 0 24 24",
993
- width: "20",
994
- xmlns: "http://www.w3.org/2000/svg",
995
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polyline", { points: "18 15 12 9 6 15" })
996
- }
997
- )
998
- }
999
- )
1000
- ]
1001
- }
1002
- )
1003
- }
1004
- )
1005
- ] }) : (
1006
- /* Bottom Sheet Panel - Hardware accelerated translateY transitions */
1007
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1008
- "div",
1009
- {
1010
- className: `absolute w-full bg-zinc-950/85 backdrop-blur-md border border-white/10 rounded-t-2xl shadow-2xl flex flex-col z-40 select-none ${isDragging ? "transition-none" : "transition-transform duration-300 ease-out"}`,
1011
- ref: containerRef,
1012
- style: {
1013
- bottom: "0px",
1014
- // Box height must stay exactly fullPx for "closed"/"peek"/
1015
- // "full" — every other transform calc in this component
1016
- // assumes the box IS fullPx tall. Only "auto" grows it (up to
1017
- // autoMaxPx) when content needs more room than fullPx offers;
1018
- // getBottomDrawerTransform()'s auto branch is derived to match
1019
- // (shift = max(fullPx - autoPx, 0), so a taller box needs zero
1020
- // extra shift to fully reveal itself).
1021
- height: `${state === "auto" ? Math.max(fullPx, autoPx) : fullPx}px`,
1022
- marginBottom: state === "closed" ? `${safeAreaInsets.bottom}px` : "0px",
1023
- transform: getBottomDrawerTransform(),
1024
- // `height` is animated too (not just transform/margin-bottom):
1025
- // entering/leaving "auto" with content taller than fullPx
1026
- // changes the box's actual CSS height, and without this it
1027
- // would snap instantly while transform eases in over 300ms —
1028
- // a visible pop of content before the slide animation catches
1029
- // up.
1030
- transition: isDragging ? "none" : "transform 300ms ease-out, height 300ms ease-out, margin-bottom 250ms ease-in-out"
1031
- },
1032
- children: [
1033
- handleVisible && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1034
- "div",
1035
- {
1036
- 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",
1037
- onClick: () => {
1038
- if (suppressNextClickRef.current) return;
1039
- handleHandleClick();
1040
- },
1041
- ref: handleBarRef,
1042
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "w-12 h-1 bg-white/25 rounded-full" })
1043
- }
1044
- ),
1045
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1046
- "div",
1047
- {
1048
- className: "flex-1 flex flex-col overflow-hidden px-4 pb-4 pt-2 transition-[margin-top] duration-250 ease-in-out relative",
1049
- ref: contentAreaRef,
1050
- style: {
1051
- marginTop: state === "closed" ? `${safeAreaInsets.bottom}px` : "0px"
1052
- },
1053
- children: [
1054
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1055
- "div",
1056
- {
1057
- className: "flex-1 overflow-y-auto no-scrollbar",
1058
- onScroll: handleScroll,
1059
- ref: scrollContainerRef,
1060
- style: {
1061
- paddingBottom: state === "peek" ? `${shiftPx}px` : "0px"
1062
- },
1063
- children: menuContent ? menuContent : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex flex-col gap-1", children: menuItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1064
- Button,
1065
- {
1066
- className: `flex items-center gap-3 w-full py-3 px-3.5 rounded-xl text-left cursor-pointer transition-all duration-150 justify-start hover:bg-white/5 hover:text-white active:bg-white/10 text-white ${item.disabled ? "opacity-45 cursor-not-allowed pointer-events-none" : ""}`,
1067
- disabled: item.disabled,
1068
- onClick: () => {
1069
- if (!item.disabled) {
1070
- item.onPress();
1071
- onChangeState("closed");
1072
- }
1073
- },
1074
- variant: "ghost",
1075
- children: [
1076
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "relative flex items-center justify-center w-8 h-8 rounded-lg bg-white/5 text-zinc-300", children: [
1077
- item.icon,
1078
- item.badge !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "absolute -top-1 -right-1 bg-cyan-500 text-black text-[9px] font-extrabold min-w-[15px] h-3.5 rounded-full flex items-center justify-center px-1 border border-zinc-950 shadow", children: item.badge })
1079
- ] }),
1080
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-sm font-medium tracking-wide", children: item.label })
1081
- ]
1082
- },
1083
- item.id
1084
- )) })
1085
- }
1086
- ),
1087
- showScrollToTopButton && showScrollTop && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
575
+ state === "closed" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
576
+ Button,
577
+ {
578
+ className: "absolute top-4 left-4 z-40 w-12 h-12 rounded-full bg-zinc-950/80 backdrop-blur-md border border-white/10 shadow-lg flex items-center justify-center text-white active:scale-95 transition-all cursor-pointer hover:bg-zinc-900 hover:text-white p-0!",
579
+ onClick: () => onChangeState("full"),
580
+ variant: "ghost",
581
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
582
+ "svg",
583
+ {
584
+ fill: "none",
585
+ height: "24",
586
+ stroke: "currentColor",
587
+ strokeLinecap: "round",
588
+ strokeLinejoin: "round",
589
+ strokeWidth: "2",
590
+ viewBox: "0 0 24 24",
591
+ width: "24",
592
+ xmlns: "http://www.w3.org/2000/svg",
593
+ children: [
594
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "4", x2: "20", y1: "12", y2: "12" }),
595
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "4", x2: "20", y1: "6", y2: "6" }),
596
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "4", x2: "20", y1: "18", y2: "18" })
597
+ ]
598
+ }
599
+ )
600
+ }
601
+ ),
602
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
603
+ Sheet,
604
+ {
605
+ onOpenChange: (open) => onChangeState(open ? "full" : "closed"),
606
+ open: state !== "closed",
607
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
608
+ SheetContent,
609
+ {
610
+ className: "w-80 bg-zinc-950/85 backdrop-blur-md border-r border-y border-white/10 rounded-r-2xl shadow-2xl p-4 text-white flex flex-col h-full overflow-hidden",
611
+ portal: false,
612
+ side: "left",
613
+ children: [
614
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SheetHeader, { className: "pb-3 border-b border-white/10 mb-2 text-left", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SheetTitle, { className: "text-sm font-bold tracking-wider text-zinc-400 uppercase", children: "Menu" }) }),
615
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
616
+ "div",
617
+ {
618
+ className: "flex-1 overflow-y-auto no-scrollbar pr-2",
619
+ onScroll: handleScroll,
620
+ ref: scrollContainerRef,
621
+ children: menuContent ? menuContent : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex flex-col gap-1.5", children: menuItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1088
622
  Button,
1089
623
  {
1090
- className: "absolute right-6 z-50 flex items-center justify-center w-10 h-10 rounded-full bg-cyan-500 hover:bg-cyan-400 active:scale-95 text-black hover:text-black shadow-lg shadow-cyan-500/25 transition-all duration-200 cursor-pointer p-0!",
624
+ className: `flex items-center gap-3 w-full py-3 px-3.5 rounded-xl text-left cursor-pointer transition-all duration-150 justify-start hover:bg-white/5 hover:text-white active:bg-white/10 text-white ${item.disabled ? "opacity-45 cursor-not-allowed pointer-events-none" : ""}`,
625
+ disabled: item.disabled,
1091
626
  onClick: () => {
1092
- scrollContainerRef.current?.scrollTo({
1093
- behavior: "smooth",
1094
- top: 0
1095
- });
1096
- },
1097
- style: {
1098
- bottom: state === "peek" ? `calc(${24 + shiftPx}px + var(--drag-offset, 0px))` : `calc(24px + var(--drag-offset, 0px))`
627
+ if (!item.disabled) {
628
+ item.onPress();
629
+ onChangeState("closed");
630
+ }
1099
631
  },
1100
632
  variant: "ghost",
1101
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1102
- "svg",
1103
- {
1104
- fill: "none",
1105
- height: "20",
1106
- stroke: "currentColor",
1107
- strokeLinecap: "round",
1108
- strokeLinejoin: "round",
1109
- strokeWidth: "2.5",
1110
- viewBox: "0 0 24 24",
1111
- width: "20",
1112
- xmlns: "http://www.w3.org/2000/svg",
1113
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polyline", { points: "18 15 12 9 6 15" })
1114
- }
1115
- )
633
+ children: [
634
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "relative flex items-center justify-center w-8 h-8 rounded-lg bg-white/5 text-zinc-300", children: [
635
+ item.icon,
636
+ item.badge !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "absolute -top-1 -right-1 bg-cyan-500 text-black text-[9px] font-extrabold min-w-[15px] h-3.5 rounded-full flex items-center justify-center px-1 border border-zinc-950 shadow", children: item.badge })
637
+ ] }),
638
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-sm font-medium tracking-wide flex-1", children: item.label })
639
+ ]
640
+ },
641
+ item.id
642
+ )) })
643
+ }
644
+ ),
645
+ showScrollToTopButton && showScrollTop && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
646
+ Button,
647
+ {
648
+ className: "absolute bottom-6 right-6 z-50 flex items-center justify-center w-10 h-10 rounded-full bg-cyan-500 hover:bg-cyan-400 active:scale-95 text-black hover:text-black shadow-lg shadow-cyan-500/25 transition-all duration-200 cursor-pointer p-0!",
649
+ onClick: () => {
650
+ scrollContainerRef.current?.scrollTo({
651
+ behavior: "smooth",
652
+ top: 0
653
+ });
654
+ },
655
+ variant: "ghost",
656
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
657
+ "svg",
658
+ {
659
+ fill: "none",
660
+ height: "20",
661
+ stroke: "currentColor",
662
+ strokeLinecap: "round",
663
+ strokeLinejoin: "round",
664
+ strokeWidth: "2.5",
665
+ viewBox: "0 0 24 24",
666
+ width: "20",
667
+ xmlns: "http://www.w3.org/2000/svg",
668
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polyline", { points: "18 15 12 9 6 15" })
1116
669
  }
1117
670
  )
1118
- ]
1119
- }
1120
- )
1121
- ]
1122
- }
1123
- )
671
+ }
672
+ )
673
+ ]
674
+ }
675
+ )
676
+ }
1124
677
  )
1125
678
  ] });
1126
679
  }
1127
680
  );
681
+ MapDrawer.displayName = "MapDrawer";
1128
682
 
1129
683
  // src/components/ui/card.tsx
1130
684
  var React3 = __toESM(require("react"), 1);
@@ -1556,52 +1110,352 @@ var MapRightControls = ({
1556
1110
  }
1557
1111
  )
1558
1112
  )
1559
- }
1560
- ) }),
1561
- belowControls.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex flex-col gap-2 pointer-events-auto", children: belowControls.map((control) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "relative group flex items-center", children: [
1562
- control.tooltip && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "absolute right-14 pointer-events-none opacity-0 scale-95 origin-right group-hover:opacity-100 group-hover:scale-100 transition-all duration-150 bg-zinc-900/95 border border-white/10 text-white text-xs px-2.5 py-1.5 rounded-lg shadow-xl whitespace-nowrap", children: control.tooltip }),
1563
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1564
- Button,
1565
- {
1566
- className: `w-12 h-12 rounded-full bg-zinc-950/80 backdrop-blur-md border border-white/10 shadow-lg flex items-center justify-center text-white active:scale-95 transition-all cursor-pointer p-0! hover:bg-zinc-900 hover:text-white ${control.activeState ? "ring-2 ring-cyan-400 ring-offset-2 ring-offset-zinc-950" : ""}`,
1567
- onClick: control.onPress,
1568
- variant: "ghost",
1569
- children: control.icon
1570
- }
1571
- )
1572
- ] }, control.id)) })
1573
- ]
1113
+ }
1114
+ ) }),
1115
+ belowControls.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex flex-col gap-2 pointer-events-auto", children: belowControls.map((control) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "relative group flex items-center", children: [
1116
+ control.tooltip && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "absolute right-14 pointer-events-none opacity-0 scale-95 origin-right group-hover:opacity-100 group-hover:scale-100 transition-all duration-150 bg-zinc-900/95 border border-white/10 text-white text-xs px-2.5 py-1.5 rounded-lg shadow-xl whitespace-nowrap", children: control.tooltip }),
1117
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1118
+ Button,
1119
+ {
1120
+ className: `w-12 h-12 rounded-full bg-zinc-950/80 backdrop-blur-md border border-white/10 shadow-lg flex items-center justify-center text-white active:scale-95 transition-all cursor-pointer p-0! hover:bg-zinc-900 hover:text-white ${control.activeState ? "ring-2 ring-cyan-400 ring-offset-2 ring-offset-zinc-950" : ""}`,
1121
+ onClick: control.onPress,
1122
+ variant: "ghost",
1123
+ children: control.icon
1124
+ }
1125
+ )
1126
+ ] }, control.id)) })
1127
+ ]
1128
+ }
1129
+ );
1130
+ };
1131
+
1132
+ // src/components/Map/components/MobileBottomDrawer.tsx
1133
+ var import_react3 = require("motion/react");
1134
+ var import_react4 = require("react");
1135
+ var import_react_modal_sheet = require("react-modal-sheet");
1136
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1137
+ var resolveHeightToPixels = (height, containerHeight) => {
1138
+ if (typeof height === "number") {
1139
+ return height;
1140
+ }
1141
+ if (height.endsWith("%")) {
1142
+ return parseFloat(height) / 100 * containerHeight;
1143
+ }
1144
+ return parseFloat(height);
1145
+ };
1146
+ var HANDLE_HEIGHT_PX = 32;
1147
+ var SHEET_TWEEN_CONFIG = {
1148
+ duration: 0.4,
1149
+ ease: [0.32, 0.72, 0, 1]
1150
+ };
1151
+ var SHEET_DRAG_VELOCITY_THRESHOLD = 1700;
1152
+ var MobileBottomDrawer = (0, import_react4.forwardRef)(
1153
+ ({
1154
+ menuItems,
1155
+ state,
1156
+ onChangeState,
1157
+ drawerPeekHeight,
1158
+ drawerFullHeight,
1159
+ drawerAutoMaxHeight,
1160
+ containerHeight,
1161
+ menuContent,
1162
+ enableTouchDrag = true,
1163
+ handleVisible = true,
1164
+ onAutoContentHeightChange,
1165
+ showScrollToTopButton = true,
1166
+ scrollToTopThreshold = 300,
1167
+ safeAreaInsets = { bottom: 0, left: 0, right: 0, top: 0 }
1168
+ }, ref) => {
1169
+ const scrollRef = (0, import_react4.useRef)(null);
1170
+ (0, import_react4.useImperativeHandle)(ref, () => scrollRef.current);
1171
+ const headerRef = (0, import_react4.useRef)(null);
1172
+ const contentWrapperRef = (0, import_react4.useRef)(null);
1173
+ const [viewportHeight, setViewportHeight] = (0, import_react4.useState)(
1174
+ () => containerHeight ?? (typeof window !== "undefined" ? window.innerHeight : 800)
1175
+ );
1176
+ (0, import_react4.useEffect)(() => {
1177
+ if (containerHeight) {
1178
+ setViewportHeight(containerHeight);
1179
+ return;
1180
+ }
1181
+ if (typeof window === "undefined") return;
1182
+ const update = () => setViewportHeight(window.innerHeight);
1183
+ update();
1184
+ window.addEventListener("resize", update);
1185
+ return () => window.removeEventListener("resize", update);
1186
+ }, [containerHeight]);
1187
+ const [autoContentPx, setAutoContentPx] = (0, import_react4.useState)(0);
1188
+ (0, import_react4.useEffect)(() => {
1189
+ const contentEl = contentWrapperRef.current;
1190
+ if (!contentEl) return;
1191
+ const measure = () => {
1192
+ const headerHeight = handleVisible ? headerRef.current?.offsetHeight ?? 0 : 0;
1193
+ const px = headerHeight + contentEl.scrollHeight;
1194
+ setAutoContentPx(px);
1195
+ onAutoContentHeightChange?.(px);
1196
+ };
1197
+ measure();
1198
+ const ro = new ResizeObserver(measure);
1199
+ ro.observe(contentEl);
1200
+ return () => ro.disconnect();
1201
+ }, [handleVisible, onAutoContentHeightChange]);
1202
+ const closedPx = (handleVisible ? HANDLE_HEIGHT_PX : 0) + safeAreaInsets.bottom;
1203
+ const peekPx = resolveHeightToPixels(
1204
+ drawerPeekHeight ?? "15%",
1205
+ viewportHeight
1206
+ );
1207
+ const autoMaxPx = resolveHeightToPixels(
1208
+ drawerAutoMaxHeight ?? "100%",
1209
+ viewportHeight
1210
+ );
1211
+ const autoPx = Math.min(autoMaxPx, Math.max(autoContentPx, closedPx + 1));
1212
+ const { snapPoints, snapLabels, backdropOutput } = (0, import_react4.useMemo)(() => {
1213
+ const normalize = (raw) => raw > 0 && raw <= 1 ? raw * viewportHeight : raw;
1214
+ const unsorted = [
1215
+ { label: "closed", raw: 0 },
1216
+ { label: "closed", raw: closedPx },
1217
+ { label: "peek", raw: peekPx },
1218
+ { label: "auto", raw: autoPx },
1219
+ { label: "full", raw: 1 }
1220
+ ];
1221
+ const entries = unsorted.sort(
1222
+ (a, b) => normalize(a.raw) - normalize(b.raw)
1223
+ );
1224
+ const deduped = [];
1225
+ for (const entry of entries) {
1226
+ const prev = deduped[deduped.length - 1];
1227
+ if (prev && Math.abs(normalize(prev.raw) - normalize(entry.raw)) < 0.5) {
1228
+ deduped[deduped.length - 1] = entry;
1229
+ continue;
1230
+ }
1231
+ deduped.push(entry);
1232
+ }
1233
+ return {
1234
+ backdropOutput: deduped.map(
1235
+ (d) => d.label === "full" || d.label === "auto" ? 1 : 0
1236
+ ),
1237
+ snapLabels: deduped.map((d) => d.label),
1238
+ snapPoints: deduped.map((d) => d.raw)
1239
+ };
1240
+ }, [closedPx, peekPx, autoPx, viewportHeight]);
1241
+ const currentIndex = Math.max(0, snapLabels.lastIndexOf(state));
1242
+ const sheetRef = (0, import_react4.useRef)(null);
1243
+ (0, import_react4.useEffect)(() => {
1244
+ let cancelled = false;
1245
+ let attempts = 0;
1246
+ const trySnap = () => {
1247
+ if (cancelled) return;
1248
+ const ref2 = sheetRef.current;
1249
+ if (ref2 && ref2.snapPoints.length > 0) {
1250
+ ref2.snapTo(currentIndex);
1251
+ return;
1252
+ }
1253
+ attempts += 1;
1254
+ if (attempts > 60) return;
1255
+ requestAnimationFrame(trySnap);
1256
+ };
1257
+ trySnap();
1258
+ return () => {
1259
+ cancelled = true;
1260
+ };
1261
+ }, [currentIndex]);
1262
+ const handleSnap = (0, import_react4.useCallback)(
1263
+ (index) => {
1264
+ const label = snapLabels[index] ?? "closed";
1265
+ if (label !== state) onChangeState(label);
1266
+ },
1267
+ [snapLabels, state, onChangeState]
1268
+ );
1269
+ const handleHandleClick = () => {
1270
+ if (state === "closed") {
1271
+ onChangeState("peek");
1272
+ } else if (state === "peek") {
1273
+ onChangeState("full");
1274
+ } else if (state === "auto") {
1275
+ onChangeState("closed");
1276
+ } else {
1277
+ onChangeState("peek");
1278
+ }
1279
+ };
1280
+ const [showScrollTop, setShowScrollTop] = (0, import_react4.useState)(false);
1281
+ (0, import_react4.useEffect)(() => {
1282
+ const el = scrollRef.current;
1283
+ if (!el) return;
1284
+ const onScroll = () => {
1285
+ setShowScrollTop(
1286
+ state !== "closed" && el.scrollTop > scrollToTopThreshold
1287
+ );
1288
+ };
1289
+ el.addEventListener("scroll", onScroll);
1290
+ return () => el.removeEventListener("scroll", onScroll);
1291
+ }, [state, scrollToTopThreshold]);
1292
+ (0, import_react4.useEffect)(() => {
1293
+ if (state === "closed") setShowScrollTop(false);
1294
+ }, [state]);
1295
+ const dragDisabled = !enableTouchDrag;
1296
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1297
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `
1298
+ .no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
1299
+ .no-scrollbar::-webkit-scrollbar { display: none; }
1300
+ ` }),
1301
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1302
+ import_react_modal_sheet.Sheet,
1303
+ {
1304
+ disableDismiss: true,
1305
+ disableDrag: dragDisabled,
1306
+ dragVelocityThreshold: SHEET_DRAG_VELOCITY_THRESHOLD,
1307
+ initialSnap: currentIndex,
1308
+ isOpen: true,
1309
+ onClose: () => onChangeState("closed"),
1310
+ onSnap: handleSnap,
1311
+ ref: sheetRef,
1312
+ snapPoints,
1313
+ tweenConfig: SHEET_TWEEN_CONFIG,
1314
+ children: [
1315
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1316
+ import_react_modal_sheet.Sheet.Container,
1317
+ {
1318
+ className: "!bg-zinc-950/85 !backdrop-blur-md !border !border-white/10 !border-b-0 !rounded-t-2xl !shadow-2xl ",
1319
+ style: { paddingBottom: safeAreaInsets.bottom },
1320
+ children: [
1321
+ handleVisible && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1322
+ import_react_modal_sheet.Sheet.Header,
1323
+ {
1324
+ className: "!bg-transparent cursor-pointer hover:!bg-white/5 transition-colors",
1325
+ onClick: handleHandleClick,
1326
+ ref: headerRef
1327
+ }
1328
+ ),
1329
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1330
+ import_react_modal_sheet.Sheet.Content,
1331
+ {
1332
+ className: "!bg-transparent",
1333
+ disableDrag: (info) => dragDisabled || info.scrollPosition === "middle",
1334
+ disableScroll: (info) => !dragDisabled && info.currentSnap !== snapPoints.length - 1,
1335
+ scrollClassName: "no-scrollbar",
1336
+ scrollRef,
1337
+ children: [
1338
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "px-4 pb-4 pt-2 relative", ref: contentWrapperRef, children: menuContent ? menuContent : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex flex-col gap-1", children: menuItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1339
+ Button,
1340
+ {
1341
+ className: `flex items-center gap-3 w-full py-3 px-3.5 rounded-xl text-left cursor-pointer transition-all duration-150 justify-start hover:bg-white/5 hover:text-white active:bg-white/10 text-white ${item.disabled ? "opacity-45 cursor-not-allowed pointer-events-none" : ""}`,
1342
+ disabled: item.disabled,
1343
+ onClick: () => {
1344
+ if (!item.disabled) {
1345
+ item.onPress();
1346
+ onChangeState("closed");
1347
+ }
1348
+ },
1349
+ variant: "ghost",
1350
+ children: [
1351
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "relative flex items-center justify-center w-8 h-8 rounded-lg bg-white/5 text-zinc-300", children: [
1352
+ item.icon,
1353
+ item.badge !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "absolute -top-1 -right-1 bg-cyan-500 text-black text-[9px] font-extrabold min-w-[15px] h-3.5 rounded-full flex items-center justify-center px-1 border border-zinc-950 shadow", children: item.badge })
1354
+ ] }),
1355
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-sm font-medium tracking-wide", children: item.label })
1356
+ ]
1357
+ },
1358
+ item.id
1359
+ )) }) }),
1360
+ showScrollToTopButton && showScrollTop && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1361
+ Button,
1362
+ {
1363
+ className: "absolute bottom-4 right-6 z-50 flex items-center justify-center w-10 h-10 rounded-full bg-cyan-500 hover:bg-cyan-400 active:scale-95 text-black hover:text-black shadow-lg shadow-cyan-500/25 transition-all duration-200 cursor-pointer p-0!",
1364
+ onClick: () => {
1365
+ scrollRef.current?.scrollTo({ behavior: "smooth", top: 0 });
1366
+ },
1367
+ variant: "ghost",
1368
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1369
+ "svg",
1370
+ {
1371
+ fill: "none",
1372
+ height: "20",
1373
+ stroke: "currentColor",
1374
+ strokeLinecap: "round",
1375
+ strokeLinejoin: "round",
1376
+ strokeWidth: "2.5",
1377
+ viewBox: "0 0 24 24",
1378
+ width: "20",
1379
+ xmlns: "http://www.w3.org/2000/svg",
1380
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "18 15 12 9 6 15" })
1381
+ }
1382
+ )
1383
+ }
1384
+ )
1385
+ ]
1386
+ }
1387
+ )
1388
+ ]
1389
+ }
1390
+ ),
1391
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1392
+ DrawerBackdrop,
1393
+ {
1394
+ active: state === "full" || state === "auto",
1395
+ onTap: () => onChangeState("closed"),
1396
+ output: backdropOutput
1397
+ }
1398
+ )
1399
+ ]
1400
+ }
1401
+ )
1402
+ ] });
1403
+ }
1404
+ );
1405
+ MobileBottomDrawer.displayName = "MobileBottomDrawer";
1406
+ function DrawerBackdrop({
1407
+ active,
1408
+ output,
1409
+ onTap
1410
+ }) {
1411
+ const { y, snapPoints } = import_react_modal_sheet.Sheet.useContext();
1412
+ const opacity = (0, import_react3.useTransform)(y, (value) => {
1413
+ if (snapPoints.length === 0 || output.length !== snapPoints.length) {
1414
+ return 0;
1415
+ }
1416
+ const mix = (0, import_react3.interpolate)(
1417
+ snapPoints.map((point) => point.snapValueY),
1418
+ output
1419
+ );
1420
+ return mix(value) * 0.45;
1421
+ });
1422
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1423
+ import_react_modal_sheet.Sheet.Backdrop,
1424
+ {
1425
+ className: "!bg-black !backdrop-blur-[1px]",
1426
+ onTap: active ? onTap : void 0,
1427
+ style: { opacity }
1574
1428
  }
1575
1429
  );
1576
- };
1430
+ }
1577
1431
 
1578
1432
  // src/components/Map/MapContext.tsx
1579
- var import_react3 = require("react");
1580
- var import_jsx_runtime7 = require("react/jsx-runtime");
1581
- var MapControlsContext = (0, import_react3.createContext)(
1433
+ var import_react5 = require("react");
1434
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1435
+ var MapControlsContext = (0, import_react5.createContext)(
1582
1436
  null
1583
1437
  );
1584
1438
  var SDKMapProvider = ({
1585
1439
  children
1586
1440
  }) => {
1587
- const [isFollowing, setIsFollowing] = (0, import_react3.useState)(true);
1588
- const [bearing, setBearingState] = (0, import_react3.useState)(0);
1589
- const [pitch, setPitchState] = (0, import_react3.useState)(0);
1590
- const [drawerState, setDrawerStateInternal] = (0, import_react3.useState)("closed");
1591
- const drawerContentRef = (0, import_react3.useRef)(null);
1592
- const setDrawerState = (0, import_react3.useCallback)((val) => {
1441
+ const [isFollowing, setIsFollowing] = (0, import_react5.useState)(true);
1442
+ const [bearing, setBearingState] = (0, import_react5.useState)(0);
1443
+ const [pitch, setPitchState] = (0, import_react5.useState)(0);
1444
+ const [drawerState, setDrawerStateInternal] = (0, import_react5.useState)("closed");
1445
+ const drawerContentRef = (0, import_react5.useRef)(null);
1446
+ const setDrawerState = (0, import_react5.useCallback)((val) => {
1593
1447
  setDrawerStateInternal(val);
1594
1448
  }, []);
1595
- const [drawerHandleVisible, setDrawerHandleVisibleState] = (0, import_react3.useState)(true);
1596
- const setDrawerHandleVisible = (0, import_react3.useCallback)((val) => {
1449
+ const [drawerHandleVisible, setDrawerHandleVisibleState] = (0, import_react5.useState)(true);
1450
+ const setDrawerHandleVisible = (0, import_react5.useCallback)((val) => {
1597
1451
  setDrawerHandleVisibleState((prev) => prev === val ? prev : val);
1598
1452
  }, []);
1599
- const [hasControls, setHasControlsState] = (0, import_react3.useState)(false);
1600
- const setHasControls = (0, import_react3.useCallback)((val) => {
1453
+ const [hasControls, setHasControlsState] = (0, import_react5.useState)(false);
1454
+ const setHasControls = (0, import_react5.useCallback)((val) => {
1601
1455
  setHasControlsState((prev) => prev === val ? prev : val);
1602
1456
  }, []);
1603
- const [etaData, setEtaDataState] = (0, import_react3.useState)(void 0);
1604
- const setEtaData = (0, import_react3.useCallback)((newData) => {
1457
+ const [etaData, setEtaDataState] = (0, import_react5.useState)(void 0);
1458
+ const setEtaData = (0, import_react5.useCallback)((newData) => {
1605
1459
  setEtaDataState((prev) => {
1606
1460
  if (!prev && !newData) return prev;
1607
1461
  if (!prev || !newData) return newData;
@@ -1611,29 +1465,29 @@ var SDKMapProvider = ({
1611
1465
  return newData;
1612
1466
  });
1613
1467
  }, []);
1614
- const [insets, setInsetsState] = (0, import_react3.useState)({
1468
+ const [insets, setInsetsState] = (0, import_react5.useState)({
1615
1469
  bottom: 0,
1616
1470
  left: 0,
1617
1471
  right: 0,
1618
1472
  top: 0
1619
1473
  });
1620
- const setInsets = (0, import_react3.useCallback)((newInsets) => {
1474
+ const setInsets = (0, import_react5.useCallback)((newInsets) => {
1621
1475
  setInsetsState((prev) => ({ ...prev, ...newInsets }));
1622
1476
  }, []);
1623
- const centerCallbackRef = (0, import_react3.useRef)(null);
1624
- const resetBearingCallbackRef = (0, import_react3.useRef)(null);
1625
- const flyToCallbackRef = (0, import_react3.useRef)(null);
1626
- const centerOnUser = (0, import_react3.useCallback)((params) => {
1477
+ const centerCallbackRef = (0, import_react5.useRef)(null);
1478
+ const resetBearingCallbackRef = (0, import_react5.useRef)(null);
1479
+ const flyToCallbackRef = (0, import_react5.useRef)(null);
1480
+ const centerOnUser = (0, import_react5.useCallback)((params) => {
1627
1481
  if (centerCallbackRef.current) {
1628
1482
  centerCallbackRef.current(params);
1629
1483
  }
1630
1484
  }, []);
1631
- const resetBearing = (0, import_react3.useCallback)((params) => {
1485
+ const resetBearing = (0, import_react5.useCallback)((params) => {
1632
1486
  if (resetBearingCallbackRef.current) {
1633
1487
  resetBearingCallbackRef.current(params);
1634
1488
  }
1635
1489
  }, []);
1636
- const flyTo = (0, import_react3.useCallback)(
1490
+ const flyTo = (0, import_react5.useCallback)(
1637
1491
  (coords, params) => {
1638
1492
  if (flyToCallbackRef.current) {
1639
1493
  flyToCallbackRef.current(coords, params);
@@ -1641,31 +1495,31 @@ var SDKMapProvider = ({
1641
1495
  },
1642
1496
  []
1643
1497
  );
1644
- const _registerCenterCallback = (0, import_react3.useCallback)(
1498
+ const _registerCenterCallback = (0, import_react5.useCallback)(
1645
1499
  (cb) => {
1646
1500
  centerCallbackRef.current = cb;
1647
1501
  },
1648
1502
  []
1649
1503
  );
1650
- const _registerResetBearingCallback = (0, import_react3.useCallback)(
1504
+ const _registerResetBearingCallback = (0, import_react5.useCallback)(
1651
1505
  (cb) => {
1652
1506
  resetBearingCallbackRef.current = cb;
1653
1507
  },
1654
1508
  []
1655
1509
  );
1656
- const _registerFlyToCallback = (0, import_react3.useCallback)(
1510
+ const _registerFlyToCallback = (0, import_react5.useCallback)(
1657
1511
  (cb) => {
1658
1512
  flyToCallbackRef.current = cb;
1659
1513
  },
1660
1514
  []
1661
1515
  );
1662
- const setBearing = (0, import_react3.useCallback)((b) => {
1516
+ const setBearing = (0, import_react5.useCallback)((b) => {
1663
1517
  setBearingState(b);
1664
1518
  }, []);
1665
- const setPitch = (0, import_react3.useCallback)((p) => {
1519
+ const setPitch = (0, import_react5.useCallback)((p) => {
1666
1520
  setPitchState(p);
1667
1521
  }, []);
1668
- const contextValue = (0, import_react3.useMemo)(
1522
+ const contextValue = (0, import_react5.useMemo)(
1669
1523
  () => ({
1670
1524
  _registerCenterCallback,
1671
1525
  _registerFlyToCallback,
@@ -1715,10 +1569,10 @@ var SDKMapProvider = ({
1715
1569
  setInsets
1716
1570
  ]
1717
1571
  );
1718
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MapControlsContext.Provider, { value: contextValue, children });
1572
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MapControlsContext.Provider, { value: contextValue, children });
1719
1573
  };
1720
1574
  var useMapControls = () => {
1721
- const context = (0, import_react3.useContext)(MapControlsContext);
1575
+ const context = (0, import_react5.useContext)(MapControlsContext);
1722
1576
  if (!context) {
1723
1577
  throw new Error("useMapControls must be used within a MapControlsProvider");
1724
1578
  }
@@ -1726,8 +1580,8 @@ var useMapControls = () => {
1726
1580
  };
1727
1581
 
1728
1582
  // src/components/Map/components/MapControls.tsx
1729
- var import_react4 = require("react");
1730
- var import_jsx_runtime8 = require("react/jsx-runtime");
1583
+ var import_react6 = require("react");
1584
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1731
1585
  var resolveHeightToPixels2 = (height, containerHeight) => {
1732
1586
  if (typeof height === "number") {
1733
1587
  return height;
@@ -1763,9 +1617,9 @@ var MapControls = ({
1763
1617
  controlsBottomOffset = 0,
1764
1618
  isInternal = false
1765
1619
  }) => {
1766
- const mapContext = (0, import_react4.useContext)(MapControlsContext);
1620
+ const mapContext = (0, import_react6.useContext)(MapControlsContext);
1767
1621
  const contextRef = mapContext?.drawerContentRef;
1768
- const mergedRef = (0, import_react4.useCallback)(
1622
+ const mergedRef = (0, import_react6.useCallback)(
1769
1623
  (node) => {
1770
1624
  if (drawerContentRef) {
1771
1625
  if (typeof drawerContentRef === "function") {
@@ -1780,11 +1634,11 @@ var MapControls = ({
1780
1634
  },
1781
1635
  [drawerContentRef, contextRef]
1782
1636
  );
1783
- const [localDrawerState, setLocalDrawerState] = (0, import_react4.useState)(
1637
+ const [localDrawerState, setLocalDrawerState] = (0, import_react6.useState)(
1784
1638
  defaultState ?? "closed"
1785
1639
  );
1786
1640
  const drawerState = mapContext ? mapContext.drawerState : localDrawerState;
1787
- const setDrawerState = (0, import_react4.useCallback)(
1641
+ const setDrawerState = (0, import_react6.useCallback)(
1788
1642
  (state) => {
1789
1643
  if (mapContext) {
1790
1644
  mapContext.setDrawerState(state);
@@ -1794,15 +1648,15 @@ var MapControls = ({
1794
1648
  },
1795
1649
  [mapContext]
1796
1650
  );
1797
- (0, import_react4.useEffect)(() => {
1651
+ (0, import_react6.useEffect)(() => {
1798
1652
  if (defaultState && mapContext) {
1799
1653
  mapContext.setDrawerState(defaultState);
1800
1654
  }
1801
1655
  }, []);
1802
- const [side, setSide] = (0, import_react4.useState)("left");
1803
- const containerRef = (0, import_react4.useRef)(null);
1804
- const [mapHeight, setMapHeight] = (0, import_react4.useState)(600);
1805
- (0, import_react4.useEffect)(() => {
1656
+ const [side, setSide] = (0, import_react6.useState)("left");
1657
+ const containerRef = (0, import_react6.useRef)(null);
1658
+ const [mapHeight, setMapHeight] = (0, import_react6.useState)(600);
1659
+ (0, import_react6.useEffect)(() => {
1806
1660
  const parent = containerRef.current?.parentElement;
1807
1661
  if (!parent) return;
1808
1662
  const updateHeight = () => {
@@ -1816,7 +1670,7 @@ var MapControls = ({
1816
1670
  };
1817
1671
  }, []);
1818
1672
  const setHasControls = mapContext?.setHasControls;
1819
- (0, import_react4.useEffect)(() => {
1673
+ (0, import_react6.useEffect)(() => {
1820
1674
  if (setHasControls && !isInternal) {
1821
1675
  setHasControls(true);
1822
1676
  return () => setHasControls(false);
@@ -1840,10 +1694,8 @@ var MapControls = ({
1840
1694
  };
1841
1695
  const mapPitch = mapContext ? mapContext.pitch : 0;
1842
1696
  const resolvedEtaData = etaData !== void 0 ? etaData : mapContext?.etaData;
1843
- const [touchStartY, setTouchStartY] = (0, import_react4.useState)(null);
1844
- const [currentTouchY, setCurrentTouchY] = (0, import_react4.useState)(null);
1845
- const [autoContentPx, setAutoContentPx] = (0, import_react4.useState)(0);
1846
- (0, import_react4.useEffect)(() => {
1697
+ const [autoContentPx, setAutoContentPx] = (0, import_react6.useState)(0);
1698
+ (0, import_react6.useEffect)(() => {
1847
1699
  if (typeof window === "undefined") return;
1848
1700
  const checkLayout = () => {
1849
1701
  if (drawerSide) {
@@ -1860,8 +1712,8 @@ var MapControls = ({
1860
1712
  window.addEventListener("resize", checkLayout);
1861
1713
  return () => window.removeEventListener("resize", checkLayout);
1862
1714
  }, [drawerSide]);
1863
- const isDragging = touchStartY !== null && currentTouchY !== null;
1864
- const dragOffset = isDragging ? currentTouchY - touchStartY : 0;
1715
+ const isDragging = false;
1716
+ const clampedDragOffset = 0;
1865
1717
  const fullPx = resolveHeightToPixels2(drawerFullHeight || "85%", mapHeight);
1866
1718
  const peekPx = resolveHeightToPixels2(drawerPeekHeight || "15%", mapHeight);
1867
1719
  const autoMaxPx = resolveHeightToPixels2(
@@ -1871,22 +1723,6 @@ var MapControls = ({
1871
1723
  const autoPx = Math.min(autoMaxPx, autoContentPx);
1872
1724
  const bottomInset = mapContext?.insets.bottom || 0;
1873
1725
  const handleVisible = mapContext ? mapContext.drawerHandleVisible : true;
1874
- const closedPx = (handleVisible ? 32 : 0) + (drawerState === "closed" ? bottomInset : 0);
1875
- let clampedDragOffset = dragOffset;
1876
- if (drawerState === "full") {
1877
- clampedDragOffset = Math.max(0, Math.min(fullPx - closedPx, dragOffset));
1878
- } else if (drawerState === "peek") {
1879
- clampedDragOffset = Math.max(
1880
- -(fullPx - peekPx),
1881
- // up to full
1882
- Math.min(peekPx - closedPx, dragOffset)
1883
- // down to closed
1884
- );
1885
- } else if (drawerState === "closed") {
1886
- clampedDragOffset = Math.min(0, Math.max(-(fullPx - closedPx), dragOffset));
1887
- } else if (drawerState === "auto") {
1888
- clampedDragOffset = Math.max(0, dragOffset);
1889
- }
1890
1726
  let baseHeight = handleVisible ? 32 : 0;
1891
1727
  if (drawerState === "peek") {
1892
1728
  baseHeight = peekPx;
@@ -1895,7 +1731,7 @@ var MapControls = ({
1895
1731
  } else if (drawerState === "auto") {
1896
1732
  baseHeight = autoPx;
1897
1733
  }
1898
- const currentDrawerHeight = baseHeight - clampedDragOffset;
1734
+ const currentDrawerHeight = baseHeight;
1899
1735
  const startFadeHeight = peekPx + 20;
1900
1736
  const endFadeHeight = peekPx + (fullPx - peekPx) * 0.35;
1901
1737
  let etaOpacity = 1;
@@ -1915,22 +1751,17 @@ var MapControls = ({
1915
1751
  etaOpacity = drawerState === "full" ? 0 : 1;
1916
1752
  etaBottomStyle = `calc(1rem + ${bottomInset}px)`;
1917
1753
  }
1918
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1919
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { ref: containerRef, style: { display: "none" } }),
1920
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1921
- MapDrawer,
1754
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1755
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { ref: containerRef, style: { display: "none" } }),
1756
+ side === "bottom" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1757
+ MobileBottomDrawer,
1922
1758
  {
1923
- clampedDragOffset,
1924
1759
  containerHeight: mapHeight,
1925
- currentTouchY,
1926
1760
  drawerAutoMaxHeight,
1927
1761
  drawerFullHeight,
1928
1762
  drawerPeekHeight,
1929
1763
  enableTouchDrag,
1930
- etaBarHeight,
1931
- etaData: resolvedEtaData,
1932
1764
  handleVisible,
1933
- isDragging,
1934
1765
  menuContent: children || menuContent,
1935
1766
  menuItems,
1936
1767
  onAutoContentHeightChange: setAutoContentPx,
@@ -1938,15 +1769,22 @@ var MapControls = ({
1938
1769
  ref: mergedRef,
1939
1770
  safeAreaInsets: mapContext?.insets,
1940
1771
  scrollToTopThreshold,
1941
- setCurrentTouchY,
1942
- setTouchStartY,
1943
1772
  showScrollToTopButton,
1944
- side,
1945
- state: drawerState,
1946
- touchStartY
1773
+ state: drawerState
1774
+ }
1775
+ ) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1776
+ MapDrawer,
1777
+ {
1778
+ menuContent: children || menuContent,
1779
+ menuItems,
1780
+ onChangeState: setDrawerState,
1781
+ ref: mergedRef,
1782
+ scrollToTopThreshold,
1783
+ showScrollToTopButton,
1784
+ state: drawerState
1947
1785
  }
1948
1786
  ),
1949
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1787
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1950
1788
  MapRightControls,
1951
1789
  {
1952
1790
  bottomOffset: controlsBottomOffset,
@@ -1969,7 +1807,7 @@ var MapControls = ({
1969
1807
  side
1970
1808
  }
1971
1809
  ),
1972
- resolvedEtaData && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1810
+ resolvedEtaData && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1973
1811
  MapEtaPanel,
1974
1812
  {
1975
1813
  etaData: resolvedEtaData,
@@ -1987,10 +1825,10 @@ var MapControls = ({
1987
1825
  };
1988
1826
 
1989
1827
  // src/components/Map/components/MapMenu.tsx
1990
- var import_react5 = require("react");
1991
- var import_jsx_runtime9 = require("react/jsx-runtime");
1828
+ var import_react7 = require("react");
1829
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1992
1830
  var MapMenu = ({ children }) => {
1993
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex flex-col gap-1.5", children });
1831
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex flex-col gap-1.5", children });
1994
1832
  };
1995
1833
  var MapMenuItem = ({
1996
1834
  id,
@@ -2001,7 +1839,7 @@ var MapMenuItem = ({
2001
1839
  disabled = false,
2002
1840
  children
2003
1841
  }) => {
2004
- const context = (0, import_react5.useContext)(MapControlsContext);
1842
+ const context = (0, import_react7.useContext)(MapControlsContext);
2005
1843
  const handleClick = (e) => {
2006
1844
  if (disabled) return;
2007
1845
  if (onPress) onPress();
@@ -2009,7 +1847,7 @@ var MapMenuItem = ({
2009
1847
  context.setDrawerState("closed");
2010
1848
  }
2011
1849
  };
2012
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1850
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2013
1851
  "button",
2014
1852
  {
2015
1853
  className: `flex items-center gap-3 w-full py-3 px-3.5 rounded-xl text-left cursor-pointer transition-all duration-150 ${disabled ? "opacity-45 cursor-not-allowed pointer-events-none" : "hover:bg-white/5 active:bg-white/10 text-white"}`,
@@ -2017,12 +1855,12 @@ var MapMenuItem = ({
2017
1855
  onClick: handleClick,
2018
1856
  type: "button",
2019
1857
  children: [
2020
- icon && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "relative flex items-center justify-center w-8 h-8 rounded-lg bg-white/5 text-zinc-300", children: [
1858
+ icon && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "relative flex items-center justify-center w-8 h-8 rounded-lg bg-white/5 text-zinc-300", children: [
2021
1859
  icon,
2022
- badge !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "absolute -top-1 -right-1 bg-cyan-500 text-black text-[9px] font-extrabold min-w-[15px] h-3.5 rounded-full flex items-center justify-center px-1 border border-zinc-950 shadow", children: badge })
1860
+ badge !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "absolute -top-1 -right-1 bg-cyan-500 text-black text-[9px] font-extrabold min-w-[15px] h-3.5 rounded-full flex items-center justify-center px-1 border border-zinc-950 shadow", children: badge })
2023
1861
  ] }),
2024
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex-1 flex flex-col justify-center", children: [
2025
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-sm font-medium tracking-wide flex-1", children: label }),
1862
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex-1 flex flex-col justify-center", children: [
1863
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-sm font-medium tracking-wide flex-1", children: label }),
2026
1864
  children
2027
1865
  ] })
2028
1866
  ]
@@ -2036,7 +1874,7 @@ var MapMenuTitle = ({
2036
1874
  showDivider = true,
2037
1875
  className = ""
2038
1876
  }) => {
2039
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1877
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2040
1878
  "div",
2041
1879
  {
2042
1880
  className: `flex items-center justify-between pb-3 first:mt-0 px-3.5 ${className} ${showDivider ? "border-b border-white/10 mb-2 mt-4" : ""}`,
@@ -2048,14 +1886,14 @@ MapMenuTitle.displayName = "MapMenuTitle";
2048
1886
  var MapMenuDivider = ({
2049
1887
  className = ""
2050
1888
  }) => {
2051
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: `h-[1px] bg-white/10 my-3 mx-3.5 ${className}` });
1889
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: `h-[1px] bg-white/10 my-3 mx-3.5 ${className}` });
2052
1890
  };
2053
1891
  MapMenuDivider.displayName = "MapMenuDivider";
2054
1892
  var MapMenuFooter = ({
2055
1893
  children,
2056
1894
  className = ""
2057
1895
  }) => {
2058
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1896
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2059
1897
  "div",
2060
1898
  {
2061
1899
  className: `mt-auto pt-4 border-t border-white/10 px-3.5 text-xs text-zinc-500 font-medium ${className}`,
@@ -2083,122 +1921,149 @@ var GlobalEvent = /* @__PURE__ */ ((GlobalEvent2) => {
2083
1921
  })(GlobalEvent || {});
2084
1922
 
2085
1923
  // src/components/Map/hooks/useUserLocation.ts
2086
- var import_react6 = require("react");
1924
+ var import_react8 = require("react");
2087
1925
  var LERP_FACTOR = 0.12;
2088
- var useUserLocation = () => {
2089
- const [locationState, setLocationState] = (0, import_react6.useState)({
2090
- accuracy: null,
2091
- coords: null,
2092
- heading: null
2093
- });
2094
- const targetRef = (0, import_react6.useRef)({
2095
- accuracy: null,
2096
- coords: null,
2097
- heading: null
2098
- });
2099
- const currentRef = (0, import_react6.useRef)({
2100
- accuracy: null,
2101
- coords: null,
2102
- heading: null
2103
- });
2104
- const mapPayload = (0, import_react6.useCallback)((payload) => {
2105
- const coords = payload.location?.coords || payload.coords;
2106
- const headingData = payload.heading;
2107
- const newCoords = coords ? [coords.longitude, coords.latitude] : null;
2108
- let heading = null;
2109
- if (headingData?.trueHeading !== void 0 && headingData.trueHeading >= 0) {
2110
- heading = headingData.trueHeading;
2111
- } else if (headingData?.magneticHeading !== void 0 && headingData.magneticHeading >= 0) {
2112
- heading = headingData.magneticHeading;
2113
- } else if (headingData?.heading !== null && headingData?.heading >= 0) {
2114
- heading = headingData.heading;
2115
- }
2116
- return {
2117
- accuracy: coords?.accuracy || null,
2118
- coords: newCoords,
2119
- heading
2120
- };
2121
- }, []);
2122
- (0, import_react6.useEffect)(() => {
2123
- let rafId;
2124
- const animate = () => {
2125
- let changed = false;
2126
- if (targetRef.current.coords) {
2127
- if (!currentRef.current.coords) {
2128
- currentRef.current.coords = [...targetRef.current.coords];
2129
- changed = true;
2130
- } else {
2131
- const [tLng, tLat] = targetRef.current.coords;
2132
- const [cLng, cLat] = currentRef.current.coords;
2133
- const nLng = cLng + (tLng - cLng) * LERP_FACTOR;
2134
- const nLat = cLat + (tLat - cLat) * LERP_FACTOR;
2135
- if (Math.abs(nLng - cLng) > 1e-7 || Math.abs(nLat - cLat) > 1e-7) {
2136
- currentRef.current.coords = [nLng, nLat];
2137
- changed = true;
2138
- }
2139
- }
2140
- }
2141
- if (targetRef.current.heading !== null) {
2142
- if (currentRef.current.heading === null) {
2143
- currentRef.current.heading = targetRef.current.heading;
2144
- changed = true;
2145
- } else {
2146
- const target = targetRef.current.heading;
2147
- const current = currentRef.current.heading;
2148
- let delta = target - current;
2149
- if (delta > 180) delta -= 360;
2150
- if (delta < -180) delta += 360;
2151
- const nHeading = current + delta * LERP_FACTOR;
2152
- const normalized = (nHeading % 360 + 360) % 360;
2153
- if (Math.abs(delta) > 0.1) {
2154
- currentRef.current.heading = normalized;
2155
- changed = true;
2156
- }
2157
- }
2158
- }
2159
- if (changed) {
2160
- setLocationState({
2161
- accuracy: targetRef.current.accuracy,
2162
- coords: currentRef.current.coords ? [...currentRef.current.coords] : null,
2163
- heading: currentRef.current.heading
2164
- });
2165
- }
2166
- rafId = requestAnimationFrame(animate);
2167
- };
2168
- rafId = requestAnimationFrame(animate);
2169
- sdk.location.getCurrentPosition().then((data) => {
2170
- const payload = mapPayload(data);
2171
- targetRef.current = payload;
2172
- }).catch((e) => console.warn("Initial location fetch failed", e));
2173
- const unsubscribeStream = sdk.on(
2174
- "LOCATION_STREAM_UPDATE" /* LOCATION_STREAM_UPDATE */,
2175
- (payload) => {
2176
- targetRef.current = mapPayload(payload);
1926
+ var EMPTY_STATE = {
1927
+ accuracy: null,
1928
+ coords: null,
1929
+ heading: null
1930
+ };
1931
+ function mapPayload(payload) {
1932
+ const coords = payload.location?.coords || payload.coords;
1933
+ const headingData = payload.heading;
1934
+ const newCoords = coords ? [coords.longitude, coords.latitude] : null;
1935
+ let heading = null;
1936
+ if (headingData?.trueHeading !== void 0 && headingData.trueHeading >= 0) {
1937
+ heading = headingData.trueHeading;
1938
+ } else if (headingData?.magneticHeading !== void 0 && headingData.magneticHeading >= 0) {
1939
+ heading = headingData.magneticHeading;
1940
+ } else if (headingData?.heading !== null && headingData?.heading >= 0) {
1941
+ heading = headingData.heading;
1942
+ }
1943
+ return {
1944
+ accuracy: coords?.accuracy || null,
1945
+ coords: newCoords,
1946
+ heading
1947
+ };
1948
+ }
1949
+ var refCount = 0;
1950
+ var generation = 0;
1951
+ var subscribers = /* @__PURE__ */ new Set();
1952
+ var targetState = { ...EMPTY_STATE };
1953
+ var currentInterpolated = { coords: null, heading: null };
1954
+ var rafId = null;
1955
+ var unsubscribeStream = null;
1956
+ var unsubscribeLegacy = null;
1957
+ function getSnapshot() {
1958
+ return {
1959
+ accuracy: targetState.accuracy,
1960
+ coords: currentInterpolated.coords ? [...currentInterpolated.coords] : null,
1961
+ heading: currentInterpolated.heading
1962
+ };
1963
+ }
1964
+ function notify() {
1965
+ const snapshot = getSnapshot();
1966
+ for (const callback of subscribers) callback(snapshot);
1967
+ }
1968
+ function animate() {
1969
+ let changed = false;
1970
+ if (targetState.coords) {
1971
+ if (!currentInterpolated.coords) {
1972
+ currentInterpolated.coords = [...targetState.coords];
1973
+ changed = true;
1974
+ } else {
1975
+ const [tLng, tLat] = targetState.coords;
1976
+ const [cLng, cLat] = currentInterpolated.coords;
1977
+ const nLng = cLng + (tLng - cLng) * LERP_FACTOR;
1978
+ const nLat = cLat + (tLat - cLat) * LERP_FACTOR;
1979
+ if (Math.abs(nLng - cLng) > 1e-7 || Math.abs(nLat - cLat) > 1e-7) {
1980
+ currentInterpolated.coords = [nLng, nLat];
1981
+ changed = true;
2177
1982
  }
2178
- );
2179
- const unsubscribeLegacy = sdk.on(
2180
- "LOCATION_UPDATE" /* LOCATION_UPDATE */,
2181
- (payload) => {
2182
- targetRef.current = mapPayload(payload);
1983
+ }
1984
+ }
1985
+ if (targetState.heading !== null) {
1986
+ if (currentInterpolated.heading === null) {
1987
+ currentInterpolated.heading = targetState.heading;
1988
+ changed = true;
1989
+ } else {
1990
+ const target = targetState.heading;
1991
+ const current = currentInterpolated.heading;
1992
+ let delta = target - current;
1993
+ if (delta > 180) delta -= 360;
1994
+ if (delta < -180) delta += 360;
1995
+ const nHeading = current + delta * LERP_FACTOR;
1996
+ const normalized = (nHeading % 360 + 360) % 360;
1997
+ if (Math.abs(delta) > 0.1) {
1998
+ currentInterpolated.heading = normalized;
1999
+ changed = true;
2183
2000
  }
2184
- );
2185
- sdk.location.startStream({
2186
- distanceFilter: 1,
2187
- headingThreshold: 2
2188
- }).catch((e) => console.warn("Failed to start location stream", e));
2001
+ }
2002
+ }
2003
+ if (changed) notify();
2004
+ rafId = requestAnimationFrame(animate);
2005
+ }
2006
+ function startSharedStream() {
2007
+ rafId = requestAnimationFrame(animate);
2008
+ generation++;
2009
+ const thisGeneration = generation;
2010
+ sdk.location.getCurrentPosition().then((data) => {
2011
+ if (thisGeneration !== generation) return;
2012
+ targetState = mapPayload(data);
2013
+ }).catch((e) => console.warn("Initial location fetch failed", e));
2014
+ unsubscribeStream = sdk.on(
2015
+ "LOCATION_STREAM_UPDATE" /* LOCATION_STREAM_UPDATE */,
2016
+ (payload) => {
2017
+ targetState = mapPayload(payload);
2018
+ }
2019
+ );
2020
+ unsubscribeLegacy = sdk.on(
2021
+ "LOCATION_UPDATE" /* LOCATION_UPDATE */,
2022
+ (payload) => {
2023
+ targetState = mapPayload(payload);
2024
+ }
2025
+ );
2026
+ sdk.location.startStream({
2027
+ distanceFilter: 1,
2028
+ headingThreshold: 2
2029
+ }).catch((e) => console.warn("Failed to start location stream", e));
2030
+ }
2031
+ function stopSharedStream() {
2032
+ generation++;
2033
+ if (rafId !== null) cancelAnimationFrame(rafId);
2034
+ rafId = null;
2035
+ unsubscribeStream?.();
2036
+ unsubscribeLegacy?.();
2037
+ unsubscribeStream = null;
2038
+ unsubscribeLegacy = null;
2039
+ sdk.location.stopStream().catch(() => {
2040
+ });
2041
+ targetState = { ...EMPTY_STATE };
2042
+ currentInterpolated = { coords: null, heading: null };
2043
+ }
2044
+ var useUserLocation = () => {
2045
+ const [locationState, setLocationState] = (0, import_react8.useState)(getSnapshot);
2046
+ (0, import_react8.useEffect)(() => {
2047
+ refCount++;
2048
+ if (refCount === 1) {
2049
+ startSharedStream();
2050
+ } else {
2051
+ setLocationState(getSnapshot());
2052
+ }
2053
+ subscribers.add(setLocationState);
2189
2054
  return () => {
2190
- cancelAnimationFrame(rafId);
2191
- unsubscribeStream();
2192
- unsubscribeLegacy();
2193
- sdk.location.stopStream().catch(() => {
2194
- });
2055
+ subscribers.delete(setLocationState);
2056
+ refCount--;
2057
+ if (refCount === 0) {
2058
+ stopSharedStream();
2059
+ }
2195
2060
  };
2196
- }, [mapPayload]);
2061
+ }, []);
2197
2062
  return locationState;
2198
2063
  };
2199
2064
 
2200
2065
  // src/components/Map/hooks/useLiveRouting.ts
2201
- var import_react7 = require("react");
2066
+ var import_react9 = require("react");
2202
2067
  var useLiveRouting = ({
2203
2068
  origin: manualOrigin,
2204
2069
  destination,
@@ -2207,19 +2072,19 @@ var useLiveRouting = ({
2207
2072
  enabled = true,
2208
2073
  initialMode = "preview"
2209
2074
  }) => {
2210
- const [route, setRoute] = (0, import_react7.useState)(null);
2211
- const [totalDistance, setTotalDistance] = (0, import_react7.useState)(null);
2212
- const [isCalculating, setIsCalculating] = (0, import_react7.useState)(false);
2213
- const [error, setError] = (0, import_react7.useState)(null);
2214
- const [mode, setMode] = (0, import_react7.useState)(initialMode);
2075
+ const [route, setRoute] = (0, import_react9.useState)(null);
2076
+ const [totalDistance, setTotalDistance] = (0, import_react9.useState)(null);
2077
+ const [isCalculating, setIsCalculating] = (0, import_react9.useState)(false);
2078
+ const [error, setError] = (0, import_react9.useState)(null);
2079
+ const [mode, setMode] = (0, import_react9.useState)(initialMode);
2215
2080
  const userLocationState = useUserLocation();
2216
2081
  const calculationOrigin = manualOrigin || userLocationState.coords;
2217
2082
  const trackingLocation = userLocationState.coords || manualOrigin;
2218
- const lastCalcOrigin = (0, import_react7.useRef)(null);
2219
- const lastCalcDest = (0, import_react7.useRef)(null);
2220
- const isRequestInProgress = (0, import_react7.useRef)(false);
2221
- const lastResetDestKey = (0, import_react7.useRef)(null);
2222
- const getDistance = (0, import_react7.useCallback)(
2083
+ const lastCalcOrigin = (0, import_react9.useRef)(null);
2084
+ const lastCalcDest = (0, import_react9.useRef)(null);
2085
+ const isRequestInProgress = (0, import_react9.useRef)(false);
2086
+ const lastResetDestKey = (0, import_react9.useRef)(null);
2087
+ const getDistance = (0, import_react9.useCallback)(
2223
2088
  (p1, p2) => {
2224
2089
  const R = 6371e3;
2225
2090
  const \u03C61 = p1[1] * Math.PI / 180;
@@ -2232,7 +2097,7 @@ var useLiveRouting = ({
2232
2097
  },
2233
2098
  []
2234
2099
  );
2235
- const currentDistanceMeters = (0, import_react7.useMemo)(() => {
2100
+ const currentDistanceMeters = (0, import_react9.useMemo)(() => {
2236
2101
  if (!trackingLocation || !route || route.geometry.coordinates.length < 2) {
2237
2102
  if (trackingLocation && destination) {
2238
2103
  return getDistance(trackingLocation, destination);
@@ -2259,7 +2124,7 @@ var useLiveRouting = ({
2259
2124
  }
2260
2125
  return dist;
2261
2126
  }, [trackingLocation, route, destination, getDistance]);
2262
- const calculate = (0, import_react7.useCallback)(
2127
+ const calculate = (0, import_react9.useCallback)(
2263
2128
  async (origin, dest, isNewDest) => {
2264
2129
  if (isRequestInProgress.current) return;
2265
2130
  isRequestInProgress.current = true;
@@ -2294,12 +2159,12 @@ var useLiveRouting = ({
2294
2159
  },
2295
2160
  [profile, getDistance]
2296
2161
  );
2297
- (0, import_react7.useEffect)(() => {
2162
+ (0, import_react9.useEffect)(() => {
2298
2163
  if (initialMode === "navigation") {
2299
2164
  setMode("navigation");
2300
2165
  }
2301
2166
  }, [initialMode]);
2302
- (0, import_react7.useEffect)(() => {
2167
+ (0, import_react9.useEffect)(() => {
2303
2168
  if (!enabled || !destination || !calculationOrigin) {
2304
2169
  if (!enabled || !destination) {
2305
2170
  setRoute(null);
@@ -2350,10 +2215,10 @@ var useLiveRouting = ({
2350
2215
  };
2351
2216
  };
2352
2217
  var useRoute = (origin, destination, profile = "driving") => {
2353
- const [route, setRoute] = (0, import_react7.useState)(null);
2354
- const [isCalculating, setIsCalculating] = (0, import_react7.useState)(false);
2355
- const [error, setError] = (0, import_react7.useState)(null);
2356
- (0, import_react7.useEffect)(() => {
2218
+ const [route, setRoute] = (0, import_react9.useState)(null);
2219
+ const [isCalculating, setIsCalculating] = (0, import_react9.useState)(false);
2220
+ const [error, setError] = (0, import_react9.useState)(null);
2221
+ (0, import_react9.useEffect)(() => {
2357
2222
  if (!origin || !destination) {
2358
2223
  setRoute(null);
2359
2224
  return;
@@ -2380,12 +2245,12 @@ var useRoute = (origin, destination, profile = "driving") => {
2380
2245
  };
2381
2246
 
2382
2247
  // src/components/Map/hooks/useJourney.ts
2383
- var import_react8 = require("react");
2248
+ var import_react10 = require("react");
2384
2249
  var useJourney = (options = {}) => {
2385
2250
  const { navigation, onAbort, onModeChange } = options;
2386
- const [progNav, setProgNav] = (0, import_react8.useState)(null);
2387
- const [isAborted, setIsAborted] = (0, import_react8.useState)(false);
2388
- (0, import_react8.useEffect)(() => {
2251
+ const [progNav, setProgNav] = (0, import_react10.useState)(null);
2252
+ const [isAborted, setIsAborted] = (0, import_react10.useState)(false);
2253
+ (0, import_react10.useEffect)(() => {
2389
2254
  const unsubCreate = sdk.on("SDK_NAVIGATION_CREATE", (payload) => {
2390
2255
  setIsAborted(false);
2391
2256
  setProgNav(payload);
@@ -2413,17 +2278,17 @@ var useJourney = (options = {}) => {
2413
2278
  profile: effectiveOptions?.profile || "driving",
2414
2279
  recalculateThreshold: effectiveOptions?.recalculateThreshold || 50
2415
2280
  });
2416
- const prevDest = (0, import_react8.useRef)(null);
2281
+ const prevDest = (0, import_react10.useRef)(null);
2417
2282
  const currentDest = effectiveOptions?.destination;
2418
- (0, import_react8.useEffect)(() => {
2283
+ (0, import_react10.useEffect)(() => {
2419
2284
  if (currentDest && (!prevDest.current || prevDest.current[0] !== currentDest[0] || prevDest.current[1] !== currentDest[1])) {
2420
2285
  setIsAborted(false);
2421
2286
  }
2422
2287
  prevDest.current = currentDest;
2423
2288
  }, [currentDest]);
2424
- const onModeChangeRef = (0, import_react8.useRef)(onModeChange);
2289
+ const onModeChangeRef = (0, import_react10.useRef)(onModeChange);
2425
2290
  onModeChangeRef.current = onModeChange;
2426
- (0, import_react8.useEffect)(() => {
2291
+ (0, import_react10.useEffect)(() => {
2427
2292
  onModeChangeRef.current?.(internalNav.mode);
2428
2293
  }, [internalNav.mode]);
2429
2294
  const isActive = !isAborted && !!effectiveOptions?.destination;
@@ -2445,13 +2310,13 @@ var useJourney = (options = {}) => {
2445
2310
  (totalDistanceMeters - remainingMeters) / totalDistanceMeters * 100
2446
2311
  )
2447
2312
  ) : 0;
2448
- const cancel = (0, import_react8.useCallback)(() => {
2313
+ const cancel = (0, import_react10.useCallback)(() => {
2449
2314
  setIsAborted(true);
2450
2315
  setProgNav(null);
2451
2316
  sdk.navigation.abort();
2452
2317
  if (onAbort) onAbort();
2453
2318
  }, [onAbort]);
2454
- const start = (0, import_react8.useCallback)(() => {
2319
+ const start = (0, import_react10.useCallback)(() => {
2455
2320
  sdk.navigation.start();
2456
2321
  internalNav.start();
2457
2322
  }, [internalNav.start]);
@@ -2473,9 +2338,9 @@ var useJourney = (options = {}) => {
2473
2338
  };
2474
2339
 
2475
2340
  // src/components/Map/hooks/useTrimmedRoute.ts
2476
- var import_react9 = require("react");
2341
+ var import_react11 = require("react");
2477
2342
  var useTrimmedRoute = (route, userLocation) => {
2478
- return (0, import_react9.useMemo)(() => {
2343
+ return (0, import_react11.useMemo)(() => {
2479
2344
  if (!route || !userLocation || route.coordinates.length < 2) return route;
2480
2345
  const coords = route.coordinates;
2481
2346
  let minDistance = Infinity;
@@ -2500,7 +2365,7 @@ var useTrimmedRoute = (route, userLocation) => {
2500
2365
 
2501
2366
  // src/components/Map/layers/RouteLayer.tsx
2502
2367
  var import_react_maplibre = require("@vis.gl/react-maplibre");
2503
- var import_jsx_runtime10 = require("react/jsx-runtime");
2368
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2504
2369
  var RouteLayer = ({
2505
2370
  geometry,
2506
2371
  color = "#3b82f6",
@@ -2513,8 +2378,8 @@ var RouteLayer = ({
2513
2378
  properties: {},
2514
2379
  type: "Feature"
2515
2380
  };
2516
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_maplibre.Source, { data, id: "sdk-route-source", type: "geojson", children: [
2517
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2381
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_maplibre.Source, { data, id: "sdk-route-source", type: "geojson", children: [
2382
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2518
2383
  import_react_maplibre.Layer,
2519
2384
  {
2520
2385
  id: "sdk-route-layer-casing",
@@ -2527,7 +2392,7 @@ var RouteLayer = ({
2527
2392
  type: "line"
2528
2393
  }
2529
2394
  ),
2530
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2395
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2531
2396
  import_react_maplibre.Layer,
2532
2397
  {
2533
2398
  id: "sdk-route-layer",
@@ -2570,8 +2435,8 @@ var buildGeoCircle = (center, radiusMeters, points = 64) => {
2570
2435
 
2571
2436
  // src/components/Map/layers/MockRadiusLayer.tsx
2572
2437
  var import_react_maplibre2 = require("@vis.gl/react-maplibre");
2573
- var import_react10 = require("react");
2574
- var import_jsx_runtime11 = require("react/jsx-runtime");
2438
+ var import_react12 = require("react");
2439
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2575
2440
  var MockRadiusLayer = ({
2576
2441
  center,
2577
2442
  radiusMeters,
@@ -2584,12 +2449,12 @@ var MockRadiusLayer = ({
2584
2449
  // pastel palette with no neon accents at all).
2585
2450
  color = "#e2e8f0"
2586
2451
  }) => {
2587
- const data = (0, import_react10.useMemo)(
2452
+ const data = (0, import_react12.useMemo)(
2588
2453
  () => buildGeoCircle(center, radiusMeters),
2589
2454
  [center, radiusMeters]
2590
2455
  );
2591
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_maplibre2.Source, { data, id: "sdk-mock-radius-source", type: "geojson", children: [
2592
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2456
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_maplibre2.Source, { data, id: "sdk-mock-radius-source", type: "geojson", children: [
2457
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2593
2458
  import_react_maplibre2.Layer,
2594
2459
  {
2595
2460
  id: "sdk-mock-radius-fill",
@@ -2600,7 +2465,7 @@ var MockRadiusLayer = ({
2600
2465
  type: "fill"
2601
2466
  }
2602
2467
  ),
2603
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2468
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2604
2469
  import_react_maplibre2.Layer,
2605
2470
  {
2606
2471
  id: "sdk-mock-radius-outline",
@@ -2617,8 +2482,8 @@ var MockRadiusLayer = ({
2617
2482
 
2618
2483
  // src/components/Map/layers/POILayers.tsx
2619
2484
  var import_react_maplibre3 = require("@vis.gl/react-maplibre");
2620
- var import_react11 = require("react");
2621
- var import_jsx_runtime12 = require("react/jsx-runtime");
2485
+ var import_react13 = require("react");
2486
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2622
2487
  function createEmojiIcon(emoji, size = 64) {
2623
2488
  const canvas = document.createElement("canvas");
2624
2489
  canvas.width = size;
@@ -2631,13 +2496,13 @@ function createEmojiIcon(emoji, size = 64) {
2631
2496
  return ctx.getImageData(0, 0, size, size);
2632
2497
  }
2633
2498
  var POILayers = ({ pois }) => {
2634
- const [loadedImages, setLoadedImages] = (0, import_react11.useState)(0);
2499
+ const [loadedImages, setLoadedImages] = (0, import_react13.useState)(0);
2635
2500
  const { current: map } = (0, import_react_maplibre3.useMap)();
2636
- const glPois = (0, import_react11.useMemo)(
2501
+ const glPois = (0, import_react13.useMemo)(
2637
2502
  () => pois.filter((p) => !p.displayMode || p.displayMode === "gl"),
2638
2503
  [pois]
2639
2504
  );
2640
- (0, import_react11.useEffect)(() => {
2505
+ (0, import_react13.useEffect)(() => {
2641
2506
  if (!map) return;
2642
2507
  const glMap = map.getMap();
2643
2508
  const defaults = [
@@ -2677,7 +2542,7 @@ var POILayers = ({ pois }) => {
2677
2542
  setLoadedImages((prev) => prev + updates);
2678
2543
  }
2679
2544
  }, [map, glPois]);
2680
- const geojson = (0, import_react11.useMemo)(
2545
+ const geojson = (0, import_react13.useMemo)(
2681
2546
  () => ({
2682
2547
  features: glPois.map((poi) => ({
2683
2548
  geometry: {
@@ -2695,7 +2560,7 @@ var POILayers = ({ pois }) => {
2695
2560
  }),
2696
2561
  [glPois]
2697
2562
  );
2698
- 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)(
2563
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_maplibre3.Source, { data: geojson, id: "sdk-pois", type: "geojson", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2699
2564
  import_react_maplibre3.Layer,
2700
2565
  {
2701
2566
  id: "sdk-poi-layer",
@@ -2732,11 +2597,11 @@ var POILayers = ({ pois }) => {
2732
2597
 
2733
2598
  // src/components/Map/layers/POIMarkers.tsx
2734
2599
  var import_react_maplibre4 = require("@vis.gl/react-maplibre");
2735
- var import_jsx_runtime13 = require("react/jsx-runtime");
2600
+ var import_jsx_runtime14 = require("react/jsx-runtime");
2736
2601
  var POIMarkers = ({ pois, onClick }) => {
2737
2602
  const markerPois = pois.filter((p) => p.displayMode === "marker");
2738
2603
  if (markerPois.length === 0) return null;
2739
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_jsx_runtime13.Fragment, { children: markerPois.map((poi) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2604
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children: markerPois.map((poi) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2740
2605
  import_react_maplibre4.Marker,
2741
2606
  {
2742
2607
  anchor: "bottom",
@@ -2746,7 +2611,7 @@ var POIMarkers = ({ pois, onClick }) => {
2746
2611
  e.originalEvent.stopPropagation();
2747
2612
  if (onClick) onClick(poi);
2748
2613
  },
2749
- children: poi.markerComponent ? poi.markerComponent : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2614
+ children: poi.markerComponent ? poi.markerComponent : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2750
2615
  "div",
2751
2616
  {
2752
2617
  style: {
@@ -2755,7 +2620,7 @@ var POIMarkers = ({ pois, onClick }) => {
2755
2620
  transform: "transition-transform duration-200 hover:scale-110"
2756
2621
  },
2757
2622
  children: [
2758
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2623
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2759
2624
  "div",
2760
2625
  {
2761
2626
  style: {
@@ -2768,7 +2633,7 @@ var POIMarkers = ({ pois, onClick }) => {
2768
2633
  justifyContent: "center",
2769
2634
  width: "32px"
2770
2635
  },
2771
- children: poi.emoji ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontSize: "16px" }, children: poi.emoji }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2636
+ children: poi.emoji ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: { fontSize: "16px" }, children: poi.emoji }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2772
2637
  "div",
2773
2638
  {
2774
2639
  style: {
@@ -2781,7 +2646,7 @@ var POIMarkers = ({ pois, onClick }) => {
2781
2646
  )
2782
2647
  }
2783
2648
  ),
2784
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2649
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2785
2650
  "div",
2786
2651
  {
2787
2652
  style: {
@@ -2804,19 +2669,19 @@ var POIMarkers = ({ pois, onClick }) => {
2804
2669
 
2805
2670
  // src/components/Map/layers/UserLocationLayer.tsx
2806
2671
  var import_react_maplibre5 = require("@vis.gl/react-maplibre");
2807
- var import_jsx_runtime14 = require("react/jsx-runtime");
2672
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2808
2673
  var UserLocationLayer = ({
2809
2674
  forcedLocation,
2810
2675
  heading
2811
2676
  }) => {
2812
2677
  if (!forcedLocation) return null;
2813
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2678
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2814
2679
  import_react_maplibre5.Marker,
2815
2680
  {
2816
2681
  anchor: "center",
2817
2682
  latitude: forcedLocation[1],
2818
2683
  longitude: forcedLocation[0],
2819
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2684
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2820
2685
  "div",
2821
2686
  {
2822
2687
  style: {
@@ -2826,7 +2691,7 @@ var UserLocationLayer = ({
2826
2691
  position: "relative"
2827
2692
  },
2828
2693
  children: [
2829
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2694
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2830
2695
  "div",
2831
2696
  {
2832
2697
  style: {
@@ -2839,7 +2704,7 @@ var UserLocationLayer = ({
2839
2704
  }
2840
2705
  }
2841
2706
  ),
2842
- heading !== void 0 && heading !== null && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2707
+ heading !== void 0 && heading !== null && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2843
2708
  "div",
2844
2709
  {
2845
2710
  style: {
@@ -2849,13 +2714,13 @@ var UserLocationLayer = ({
2849
2714
  width: "60px",
2850
2715
  zIndex: 0
2851
2716
  },
2852
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2717
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2853
2718
  "svg",
2854
2719
  {
2855
2720
  style: { height: "100%", width: "100%" },
2856
2721
  viewBox: "0 0 100 100",
2857
2722
  children: [
2858
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2723
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2859
2724
  "radialGradient",
2860
2725
  {
2861
2726
  cx: "50%",
@@ -2865,7 +2730,7 @@ var UserLocationLayer = ({
2865
2730
  id: "grad1",
2866
2731
  r: "50%",
2867
2732
  children: [
2868
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2733
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2869
2734
  "stop",
2870
2735
  {
2871
2736
  offset: "0%",
@@ -2875,7 +2740,7 @@ var UserLocationLayer = ({
2875
2740
  }
2876
2741
  }
2877
2742
  ),
2878
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2743
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2879
2744
  "stop",
2880
2745
  {
2881
2746
  offset: "100%",
@@ -2888,7 +2753,7 @@ var UserLocationLayer = ({
2888
2753
  ]
2889
2754
  }
2890
2755
  ) }),
2891
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2756
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2892
2757
  "path",
2893
2758
  {
2894
2759
  d: "M 50 50 L 35 0 A 50 50 0 0 1 65 0 Z",
@@ -2900,7 +2765,7 @@ var UserLocationLayer = ({
2900
2765
  )
2901
2766
  }
2902
2767
  ),
2903
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2768
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2904
2769
  "div",
2905
2770
  {
2906
2771
  style: {
@@ -2914,7 +2779,7 @@ var UserLocationLayer = ({
2914
2779
  width: "20px",
2915
2780
  zIndex: 1
2916
2781
  },
2917
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2782
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2918
2783
  "div",
2919
2784
  {
2920
2785
  style: {
@@ -2928,7 +2793,7 @@ var UserLocationLayer = ({
2928
2793
  )
2929
2794
  }
2930
2795
  ),
2931
- /* @__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; } }` })
2796
+ /* @__PURE__ */ (0, import_jsx_runtime15.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; } }` })
2932
2797
  ]
2933
2798
  }
2934
2799
  )
@@ -2938,9 +2803,9 @@ var UserLocationLayer = ({
2938
2803
 
2939
2804
  // src/components/Map/Map.tsx
2940
2805
  var import_react_maplibre6 = require("@vis.gl/react-maplibre");
2941
- var import_react12 = __toESM(require("react"), 1);
2806
+ var import_react14 = __toESM(require("react"), 1);
2942
2807
  var import_maplibre_gl = require("maplibre-gl/dist/maplibre-gl.css");
2943
- var import_jsx_runtime15 = require("react/jsx-runtime");
2808
+ var import_jsx_runtime16 = require("react/jsx-runtime");
2944
2809
  var MapInternal = ({
2945
2810
  initialViewState = {
2946
2811
  latitude: 45.90583599233422,
@@ -2978,9 +2843,9 @@ var MapInternal = ({
2978
2843
  controlProps = {},
2979
2844
  enableTouchDrag = false
2980
2845
  }) => {
2981
- const mapControls = (0, import_react12.useContext)(MapControlsContext);
2982
- const mockLocation = (0, import_react12.useContext)(MockLocationContext);
2983
- const mapRef = (0, import_react12.useRef)(null);
2846
+ const mapControls = (0, import_react14.useContext)(MapControlsContext);
2847
+ const mockLocation = (0, import_react14.useContext)(MockLocationContext);
2848
+ const mapRef = (0, import_react14.useRef)(null);
2984
2849
  const userLocationState = useUserLocation();
2985
2850
  const journey = useJourney({
2986
2851
  navigation,
@@ -2998,24 +2863,24 @@ var MapInternal = ({
2998
2863
  const showNavigationUI = hasIntegratedNav ? externalShowNavigationUI !== false && navigation?.showUI !== false : externalShowNavigationUI;
2999
2864
  const mode = navigationData?.mode || "preview";
3000
2865
  const resolvedInitialFollow = mapControls ? mapControls.isFollowing : initialFollowUser;
3001
- const isFollowingRef = (0, import_react12.useRef)(resolvedInitialFollow);
3002
- const isFlyingRef = (0, import_react12.useRef)(false);
3003
- const flyingGenerationRef = (0, import_react12.useRef)(0);
3004
- const lockFlying = (0, import_react12.useCallback)(() => {
2866
+ const isFollowingRef = (0, import_react14.useRef)(resolvedInitialFollow);
2867
+ const isFlyingRef = (0, import_react14.useRef)(false);
2868
+ const flyingGenerationRef = (0, import_react14.useRef)(0);
2869
+ const lockFlying = (0, import_react14.useCallback)(() => {
3005
2870
  isFlyingRef.current = true;
3006
2871
  return ++flyingGenerationRef.current;
3007
2872
  }, []);
3008
- const releaseFlyingIfCurrent = (0, import_react12.useCallback)((flightId) => {
2873
+ const releaseFlyingIfCurrent = (0, import_react14.useCallback)((flightId) => {
3009
2874
  if (flyingGenerationRef.current === flightId) {
3010
2875
  isFlyingRef.current = false;
3011
2876
  }
3012
2877
  }, []);
3013
- const [localIsFollowingUI, setLocalIsFollowingUI] = (0, import_react12.useState)(
2878
+ const [localIsFollowingUI, setLocalIsFollowingUI] = (0, import_react14.useState)(
3014
2879
  resolvedInitialFollow
3015
2880
  );
3016
2881
  const isFollowingUI = mapControls ? mapControls.isFollowing : localIsFollowingUI;
3017
2882
  const setIsFollowingCtx = mapControls?.setIsFollowing;
3018
- const setFollowMode = (0, import_react12.useCallback)(
2883
+ const setFollowMode = (0, import_react14.useCallback)(
3019
2884
  (follow) => {
3020
2885
  isFollowingRef.current = follow;
3021
2886
  setLocalIsFollowingUI(follow);
@@ -3025,7 +2890,7 @@ var MapInternal = ({
3025
2890
  },
3026
2891
  [setIsFollowingCtx]
3027
2892
  );
3028
- (0, import_react12.useEffect)(() => {
2893
+ (0, import_react14.useEffect)(() => {
3029
2894
  if (mapControls && mapControls.isFollowing !== isFollowingRef.current) {
3030
2895
  isFollowingRef.current = mapControls.isFollowing;
3031
2896
  }
@@ -3034,8 +2899,8 @@ var MapInternal = ({
3034
2899
  if (pois.length > 0 && !mergedInteractiveLayerIds.includes("sdk-poi-layer")) {
3035
2900
  mergedInteractiveLayerIds.push("sdk-poi-layer");
3036
2901
  }
3037
- const prevInitialFollow = (0, import_react12.useRef)(initialFollowUser);
3038
- (0, import_react12.useEffect)(() => {
2902
+ const prevInitialFollow = (0, import_react14.useRef)(initialFollowUser);
2903
+ (0, import_react14.useEffect)(() => {
3039
2904
  if (initialFollowUser !== prevInitialFollow.current) {
3040
2905
  setFollowMode(initialFollowUser);
3041
2906
  prevInitialFollow.current = initialFollowUser;
@@ -3059,9 +2924,9 @@ var MapInternal = ({
3059
2924
  lockFlying,
3060
2925
  releaseFlyingIfCurrent
3061
2926
  ]);
3062
- const lastAutoLockedRouteRef = (0, import_react12.useRef)(null);
3063
- const lastModeRef = (0, import_react12.useRef)(null);
3064
- (0, import_react12.useEffect)(() => {
2927
+ const lastAutoLockedRouteRef = (0, import_react14.useRef)(null);
2928
+ const lastModeRef = (0, import_react14.useRef)(null);
2929
+ (0, import_react14.useEffect)(() => {
3065
2930
  if (!route || !mapRef.current) {
3066
2931
  if (!route) lastAutoLockedRouteRef.current = null;
3067
2932
  return;
@@ -3117,7 +2982,7 @@ var MapInternal = ({
3117
2982
  lockFlying,
3118
2983
  releaseFlyingIfCurrent
3119
2984
  ]);
3120
- (0, import_react12.useEffect)(() => {
2985
+ (0, import_react14.useEffect)(() => {
3121
2986
  if (isFollowingRef.current && !isFlyingRef.current && userLocationState.coords && mapRef.current) {
3122
2987
  mapRef.current.easeTo({
3123
2988
  center: userLocationState.coords,
@@ -3161,23 +3026,23 @@ var MapInternal = ({
3161
3026
  progress: progressValue
3162
3027
  } : void 0;
3163
3028
  const setEtaDataCtx = mapControls?.setEtaData;
3164
- (0, import_react12.useEffect)(() => {
3029
+ (0, import_react14.useEffect)(() => {
3165
3030
  if (setEtaDataCtx) {
3166
3031
  setEtaDataCtx(showEtaData);
3167
3032
  }
3168
3033
  }, [showEtaData, setEtaDataCtx]);
3169
3034
  const setDrawerStateCtx = mapControls?.setDrawerState;
3170
- (0, import_react12.useEffect)(() => {
3035
+ (0, import_react14.useEffect)(() => {
3171
3036
  if (setDrawerStateCtx && propDrawerState !== void 0) {
3172
3037
  setDrawerStateCtx(propDrawerState);
3173
3038
  }
3174
3039
  }, [propDrawerState, setDrawerStateCtx]);
3175
3040
  const resolvedMenuItems = menuItems ?? [];
3176
- const { mapLibreChildren, menuContentFromChildren } = (0, import_react12.useMemo)(() => {
3041
+ const { mapLibreChildren, menuContentFromChildren } = (0, import_react14.useMemo)(() => {
3177
3042
  const mapLibreChildren2 = [];
3178
3043
  const extractedMenuItems = [];
3179
- import_react12.default.Children.forEach(children, (child) => {
3180
- if (import_react12.default.isValidElement(child)) {
3044
+ import_react14.default.Children.forEach(children, (child) => {
3045
+ if (import_react14.default.isValidElement(child)) {
3181
3046
  const type = child.type;
3182
3047
  const displayName = type?.displayName || type?.name;
3183
3048
  const isMenu = type === MapMenu || displayName === "MapMenu";
@@ -3188,7 +3053,7 @@ var MapInternal = ({
3188
3053
  "MapMenuFooter"
3189
3054
  ].includes(displayName);
3190
3055
  if (isMenu) {
3191
- import_react12.default.Children.forEach(
3056
+ import_react14.default.Children.forEach(
3192
3057
  child.props.children,
3193
3058
  (nestedChild) => {
3194
3059
  if (nestedChild) {
@@ -3205,7 +3070,7 @@ var MapInternal = ({
3205
3070
  mapLibreChildren2.push(child);
3206
3071
  }
3207
3072
  });
3208
- const menuContentFromChildren2 = extractedMenuItems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MapMenu, { children: extractedMenuItems }) : null;
3073
+ const menuContentFromChildren2 = extractedMenuItems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(MapMenu, { children: extractedMenuItems }) : null;
3209
3074
  return { mapLibreChildren: mapLibreChildren2, menuContentFromChildren: menuContentFromChildren2 };
3210
3075
  }, [children]);
3211
3076
  const handleMapClick = (e) => {
@@ -3233,7 +3098,7 @@ var MapInternal = ({
3233
3098
  }
3234
3099
  if (onClick) onClick(e);
3235
3100
  };
3236
- const handleCenterOnUser = (0, import_react12.useCallback)(
3101
+ const handleCenterOnUser = (0, import_react14.useCallback)(
3237
3102
  (payload) => {
3238
3103
  if (userLocationState.coords && mapRef.current) {
3239
3104
  setFollowMode(true);
@@ -3258,7 +3123,7 @@ var MapInternal = ({
3258
3123
  releaseFlyingIfCurrent
3259
3124
  ]
3260
3125
  );
3261
- const handleFlyTo = (0, import_react12.useCallback)(
3126
+ const handleFlyTo = (0, import_react14.useCallback)(
3262
3127
  (coords, params) => {
3263
3128
  const map = mapRef.current;
3264
3129
  if (!map) return;
@@ -3278,7 +3143,7 @@ var MapInternal = ({
3278
3143
  },
3279
3144
  [setFollowMode, lockFlying, releaseFlyingIfCurrent]
3280
3145
  );
3281
- const handleResetBearing = (0, import_react12.useCallback)((params) => {
3146
+ const handleResetBearing = (0, import_react14.useCallback)((params) => {
3282
3147
  if (mapRef.current) {
3283
3148
  mapRef.current.easeTo({
3284
3149
  bearing: 0,
@@ -3288,14 +3153,14 @@ var MapInternal = ({
3288
3153
  });
3289
3154
  }
3290
3155
  }, []);
3291
- (0, import_react12.useEffect)(() => {
3156
+ (0, import_react14.useEffect)(() => {
3292
3157
  if (mapControls) {
3293
3158
  mapControls._registerCenterCallback(handleCenterOnUser);
3294
3159
  mapControls._registerResetBearingCallback(handleResetBearing);
3295
3160
  mapControls._registerFlyToCallback(handleFlyTo);
3296
3161
  }
3297
3162
  }, [mapControls, handleCenterOnUser, handleResetBearing, handleFlyTo]);
3298
- const handleMove = (0, import_react12.useCallback)(() => {
3163
+ const handleMove = (0, import_react14.useCallback)(() => {
3299
3164
  if (mapRef.current && mapControls) {
3300
3165
  mapControls.setBearing(mapRef.current.getBearing());
3301
3166
  mapControls.setPitch(mapRef.current.getPitch());
@@ -3310,13 +3175,13 @@ var MapInternal = ({
3310
3175
  }
3311
3176
  }
3312
3177
  };
3313
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
3178
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
3314
3179
  "div",
3315
3180
  {
3316
3181
  className: `w-full h-full overflow-hidden relative ${mockLocation?.isPlacingLocation ? "cursor-crosshair" : ""} ${className}`,
3317
3182
  style,
3318
3183
  children: [
3319
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
3184
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
3320
3185
  import_react_maplibre6.Map,
3321
3186
  {
3322
3187
  attributionControl: false,
@@ -3346,30 +3211,30 @@ var MapInternal = ({
3346
3211
  showUserLocation && userLocationState.coords && (renderUserLocation ? renderUserLocation({
3347
3212
  coords: userLocationState.coords,
3348
3213
  heading: userLocationState.heading
3349
- }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3214
+ }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3350
3215
  UserLocationLayer,
3351
3216
  {
3352
3217
  forcedLocation: userLocationState.coords,
3353
3218
  heading: userLocationState.heading
3354
3219
  }
3355
3220
  )),
3356
- mockLocation && mockLocation.radiusMeters > 0 && userLocationState.coords && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3221
+ mockLocation && mockLocation.radiusMeters > 0 && userLocationState.coords && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3357
3222
  MockRadiusLayer,
3358
3223
  {
3359
3224
  center: userLocationState.coords,
3360
3225
  radiusMeters: mockLocation.radiusMeters
3361
3226
  }
3362
3227
  ),
3363
- displayRoute && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(RouteLayer, { geometry: displayRoute }),
3364
- pois.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
3365
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(POILayers, { pois }),
3366
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(POIMarkers, { onClick: onPoiClick, pois })
3228
+ displayRoute && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(RouteLayer, { geometry: displayRoute }),
3229
+ pois.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
3230
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(POILayers, { pois }),
3231
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(POIMarkers, { onClick: onPoiClick, pois })
3367
3232
  ] }),
3368
3233
  mapLibreChildren
3369
3234
  ]
3370
3235
  }
3371
3236
  ),
3372
- showControls && mapControls && !mapControls.hasControls && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3237
+ showControls && mapControls && !mapControls.hasControls && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3373
3238
  MapControls,
3374
3239
  {
3375
3240
  drawerContentRef,
@@ -3389,18 +3254,18 @@ var MapInternal = ({
3389
3254
  var SDKMapProviderWrapper = ({
3390
3255
  children
3391
3256
  }) => {
3392
- const context = (0, import_react12.useContext)(MapControlsContext);
3257
+ const context = (0, import_react14.useContext)(MapControlsContext);
3393
3258
  if (context) {
3394
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
3259
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
3395
3260
  }
3396
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SDKMapProvider, { children });
3261
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SDKMapProvider, { children });
3397
3262
  };
3398
3263
  var Map2 = (props) => {
3399
- 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 }) }) });
3264
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SDKMapProviderWrapper, { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_maplibre6.MapProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(MapInternal, { ...props }) }) });
3400
3265
  };
3401
3266
 
3402
3267
  // src/components/MapWrapper.tsx
3403
- var import_react13 = __toESM(require("react"), 1);
3268
+ var import_react15 = __toESM(require("react"), 1);
3404
3269
  var import_client = require("react-dom/client");
3405
3270
  function renderMap(containerId, props = {}) {
3406
3271
  const container = document.getElementById(containerId);
@@ -3408,7 +3273,7 @@ function renderMap(containerId, props = {}) {
3408
3273
  throw new Error(`Container with id "${containerId}" not found.`);
3409
3274
  }
3410
3275
  const root = (0, import_client.createRoot)(container);
3411
- root.render(import_react13.default.createElement(Map2, props));
3276
+ root.render(import_react15.default.createElement(Map2, props));
3412
3277
  return root;
3413
3278
  }
3414
3279
 
@@ -3765,7 +3630,7 @@ var RoutingService = {
3765
3630
  };
3766
3631
 
3767
3632
  // package.json
3768
- var version = "0.6.7";
3633
+ var version = "0.7.0";
3769
3634
 
3770
3635
  // src/sdk.ts
3771
3636
  function deepFreeze(obj) {
@@ -4111,6 +3976,8 @@ var MiniAppSDK = class {
4111
3976
  );
4112
3977
  this.initialize = this.initialize.bind(this);
4113
3978
  this.getEnv = this.getEnv.bind(this);
3979
+ this.achievement = this.achievement.bind(this);
3980
+ this.achievements = this.achievements.bind(this);
4114
3981
  this.on = this.on.bind(this);
4115
3982
  this.off = this.off.bind(this);
4116
3983
  }
@@ -4151,6 +4018,23 @@ var MiniAppSDK = class {
4151
4018
  getEnv() {
4152
4019
  return lastKnownEnv;
4153
4020
  }
4021
+ /**
4022
+ * Fetches a single Achievement's current progress by slug — read-only, for
4023
+ * rendering things like a progress bar. Progress is reported server-side
4024
+ * by the mini-app's own backend calling the Hub's M2M endpoint directly;
4025
+ * there is no corresponding "report progress" method on this SDK.
4026
+ * @param slug Unique slug identifying the Achievement.
4027
+ */
4028
+ achievement(slug) {
4029
+ return this.bridge.send("GET_ACHIEVEMENT", { slug });
4030
+ }
4031
+ /**
4032
+ * Fetches every Achievement (with current progress) visible to this
4033
+ * mini-app — read-only, same boundary as {@link MiniAppSDK.achievement}.
4034
+ */
4035
+ achievements() {
4036
+ return this.bridge.send("GET_ACHIEVEMENTS");
4037
+ }
4154
4038
  /**
4155
4039
  * Registers a callback for a specific event from the native shell.
4156
4040
  * @param event The name of the event to listen for.
@@ -4172,11 +4056,45 @@ var MiniAppSDK = class {
4172
4056
  var sdk = deepFreeze(new MiniAppSDK());
4173
4057
 
4174
4058
  // src/components/BridgeMocker.tsx
4175
- var import_react14 = require("react");
4176
- var import_jsx_runtime16 = require("react/jsx-runtime");
4059
+ var import_react16 = require("react");
4060
+ var import_jsx_runtime17 = require("react/jsx-runtime");
4061
+ var MOCK_ACHIEVEMENTS2 = [
4062
+ {
4063
+ completed: false,
4064
+ description: "Discover 5 points of interest around Annecy.",
4065
+ imageUrl: "https://api.dicebear.com/9.x/icons/svg?seed=explore",
4066
+ playerActionCount: 3,
4067
+ slug: "explore-5-pois",
4068
+ title: "Explorer",
4069
+ totalActionCount: 5,
4070
+ upReward: 50,
4071
+ xpReward: 100
4072
+ },
4073
+ {
4074
+ completed: true,
4075
+ description: "Complete your first navigation journey.",
4076
+ imageUrl: "https://api.dicebear.com/9.x/icons/svg?seed=journey",
4077
+ playerActionCount: 1,
4078
+ slug: "first-journey",
4079
+ title: "First Steps",
4080
+ totalActionCount: 1,
4081
+ upReward: 20,
4082
+ xpReward: 40
4083
+ },
4084
+ {
4085
+ completed: false,
4086
+ description: "Scan 10 QR codes at partner venues.",
4087
+ imageUrl: "https://api.dicebear.com/9.x/icons/svg?seed=scan",
4088
+ playerActionCount: 4,
4089
+ slug: "scan-10-qrcodes",
4090
+ title: "Code Breaker",
4091
+ totalActionCount: 10,
4092
+ upReward: 80,
4093
+ xpReward: 150
4094
+ }
4095
+ ];
4177
4096
  var AVATAR_MOUTH_VARIANTS = [
4178
4097
  "variant03",
4179
- "variant06",
4180
4098
  "variant07",
4181
4099
  "variant08",
4182
4100
  "variant09",
@@ -4261,19 +4179,19 @@ var BridgeMocker = ({
4261
4179
  mockJWTToken,
4262
4180
  children
4263
4181
  }) => {
4264
- const [autoMove, setAutoMove] = (0, import_react14.useState)(isMoving);
4265
- const [location, setLocation] = (0, import_react14.useState)(initialLocation);
4266
- const [heading, setHeading] = (0, import_react14.useState)(0);
4267
- const [speedMultiplier, setSpeedMultiplier] = (0, import_react14.useState)(simulationSpeed);
4268
- const [isReady, setIsReady] = (0, import_react14.useState)(false);
4269
- const [isMinimized, setIsMinimized] = (0, import_react14.useState)(true);
4270
- const [radiusMeters, setRadiusMeters] = (0, import_react14.useState)(0);
4271
- const [radiusUnit, setRadiusUnit] = (0, import_react14.useState)("m");
4272
- const [isPlacingLocation, setIsPlacingLocation] = (0, import_react14.useState)(false);
4273
- const streamIntervalRef = (0, import_react14.useRef)(null);
4274
- const pathIndexRef = (0, import_react14.useRef)(0);
4275
- const activeConfigRef = (0, import_react14.useRef)(null);
4276
- const stateRef = (0, import_react14.useRef)({
4182
+ const [autoMove, setAutoMove] = (0, import_react16.useState)(isMoving);
4183
+ const [location, setLocation] = (0, import_react16.useState)(initialLocation);
4184
+ const [heading, setHeading] = (0, import_react16.useState)(0);
4185
+ const [speedMultiplier, setSpeedMultiplier] = (0, import_react16.useState)(simulationSpeed);
4186
+ const [isReady, setIsReady] = (0, import_react16.useState)(false);
4187
+ const [isMinimized, setIsMinimized] = (0, import_react16.useState)(true);
4188
+ const [radiusMeters, setRadiusMeters] = (0, import_react16.useState)(0);
4189
+ const [radiusUnit, setRadiusUnit] = (0, import_react16.useState)("m");
4190
+ const [isPlacingLocation, setIsPlacingLocation] = (0, import_react16.useState)(false);
4191
+ const streamIntervalRef = (0, import_react16.useRef)(null);
4192
+ const pathIndexRef = (0, import_react16.useRef)(0);
4193
+ const activeConfigRef = (0, import_react16.useRef)(null);
4194
+ const stateRef = (0, import_react16.useRef)({
4277
4195
  autoMove,
4278
4196
  heading,
4279
4197
  location,
@@ -4285,7 +4203,7 @@ var BridgeMocker = ({
4285
4203
  simulationPath,
4286
4204
  speedMultiplier
4287
4205
  });
4288
- const pushLocationUpdateFor = (0, import_react14.useCallback)(
4206
+ const pushLocationUpdateFor = (0, import_react16.useCallback)(
4289
4207
  (coords, headingDeg) => {
4290
4208
  const currentState = stateRef.current;
4291
4209
  const payload = {
@@ -4317,11 +4235,11 @@ var BridgeMocker = ({
4317
4235
  },
4318
4236
  []
4319
4237
  );
4320
- const pushLocationUpdate = (0, import_react14.useCallback)(() => {
4238
+ const pushLocationUpdate = (0, import_react16.useCallback)(() => {
4321
4239
  const currentState = stateRef.current;
4322
4240
  pushLocationUpdateFor(currentState.location, currentState.heading);
4323
4241
  }, [pushLocationUpdateFor]);
4324
- const placeLocation = (0, import_react14.useCallback)(
4242
+ const placeLocation = (0, import_react16.useCallback)(
4325
4243
  (coords) => {
4326
4244
  setLocation(coords);
4327
4245
  setIsPlacingLocation(false);
@@ -4329,7 +4247,7 @@ var BridgeMocker = ({
4329
4247
  },
4330
4248
  [pushLocationUpdateFor]
4331
4249
  );
4332
- (0, import_react14.useEffect)(() => {
4250
+ (0, import_react16.useEffect)(() => {
4333
4251
  stateRef.current = {
4334
4252
  autoMove,
4335
4253
  heading,
@@ -4350,19 +4268,19 @@ var BridgeMocker = ({
4350
4268
  speedMultiplier,
4351
4269
  mockJWTToken
4352
4270
  ]);
4353
- (0, import_react14.useEffect)(() => {
4271
+ (0, import_react16.useEffect)(() => {
4354
4272
  setAutoMove(isMoving);
4355
4273
  }, [isMoving]);
4356
- (0, import_react14.useEffect)(() => {
4274
+ (0, import_react16.useEffect)(() => {
4357
4275
  setSpeedMultiplier(simulationSpeed);
4358
4276
  }, [simulationSpeed]);
4359
- (0, import_react14.useEffect)(() => {
4277
+ (0, import_react16.useEffect)(() => {
4360
4278
  if (simulationPath && simulationPath.length > 0) {
4361
4279
  pathIndexRef.current = 0;
4362
4280
  setLocation(simulationPath[0]);
4363
4281
  }
4364
4282
  }, [simulationPath]);
4365
- (0, import_react14.useEffect)(() => {
4283
+ (0, import_react16.useEffect)(() => {
4366
4284
  if (streamIntervalRef.current && activeConfigRef.current) {
4367
4285
  sdk.bridge.send(
4368
4286
  "START_LOCATION_STREAM",
@@ -4370,7 +4288,7 @@ var BridgeMocker = ({
4370
4288
  );
4371
4289
  }
4372
4290
  }, [speedMultiplier]);
4373
- (0, import_react14.useEffect)(() => {
4291
+ (0, import_react16.useEffect)(() => {
4374
4292
  const bridge = sdk.bridge;
4375
4293
  const originalSend = bridge.send.bind(bridge);
4376
4294
  const stopStream = () => {
@@ -4531,6 +4449,24 @@ var BridgeMocker = ({
4531
4449
  if (type === "GET_FIDELITY_BALANCE") {
4532
4450
  return Promise.resolve({ balance: 1337, currency: "FPoints" });
4533
4451
  }
4452
+ if (type === "GET_ACHIEVEMENTS") {
4453
+ return Promise.resolve(MOCK_ACHIEVEMENTS2);
4454
+ }
4455
+ if (type === "GET_ACHIEVEMENT") {
4456
+ const slug = payload?.slug;
4457
+ return Promise.resolve(
4458
+ MOCK_ACHIEVEMENTS2.find((a) => a.slug === slug) ?? {
4459
+ completed: false,
4460
+ description: "Mocked achievement (no native shell attached).",
4461
+ playerActionCount: 0,
4462
+ slug: slug || "unknown-achievement",
4463
+ title: slug || "Unknown Achievement",
4464
+ totalActionCount: 1,
4465
+ upReward: 0,
4466
+ xpReward: 0
4467
+ }
4468
+ );
4469
+ }
4534
4470
  if (type === "PAYMENT_REQUEST") {
4535
4471
  return Promise.resolve({
4536
4472
  success: true,
@@ -4549,7 +4485,7 @@ var BridgeMocker = ({
4549
4485
  };
4550
4486
  }, [appId]);
4551
4487
  const radiusInMeters = radiusUnit === "km" ? radiusMeters * 1e3 : radiusMeters;
4552
- const mockLocationContextValue = (0, import_react14.useMemo)(
4488
+ const mockLocationContextValue = (0, import_react16.useMemo)(
4553
4489
  () => ({
4554
4490
  isPlacingLocation,
4555
4491
  placeLocation,
@@ -4558,9 +4494,9 @@ var BridgeMocker = ({
4558
4494
  [isPlacingLocation, placeLocation, radiusInMeters]
4559
4495
  );
4560
4496
  if (!isReady) return null;
4561
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "relative w-full h-full", children: [
4562
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "w-full h-full", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(MockLocationContext.Provider, { value: mockLocationContextValue, children }) }),
4563
- isMinimized ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4497
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "relative w-full h-full", children: [
4498
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "w-full h-full", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(MockLocationContext.Provider, { value: mockLocationContextValue, children }) }),
4499
+ isMinimized ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4564
4500
  Button,
4565
4501
  {
4566
4502
  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!",
@@ -4568,7 +4504,7 @@ var BridgeMocker = ({
4568
4504
  title: "Open Simulation Controls",
4569
4505
  type: "button",
4570
4506
  variant: "ghost",
4571
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
4507
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
4572
4508
  "svg",
4573
4509
  {
4574
4510
  className: "group-hover:scale-110 transition-transform",
@@ -4582,34 +4518,34 @@ var BridgeMocker = ({
4582
4518
  width: "14",
4583
4519
  xmlns: "http://www.w3.org/2000/svg",
4584
4520
  children: [
4585
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M21 4H3" }),
4586
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M10 8H3" }),
4587
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M21 12H3" }),
4588
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M10 16H3" }),
4589
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M21 20H3" }),
4590
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "14", cy: "8", r: "2" }),
4591
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "14", cy: "16", r: "2" })
4521
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M21 4H3" }),
4522
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M10 8H3" }),
4523
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M21 12H3" }),
4524
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M10 16H3" }),
4525
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M21 20H3" }),
4526
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "14", cy: "8", r: "2" }),
4527
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "14", cy: "16", r: "2" })
4592
4528
  ]
4593
4529
  }
4594
4530
  )
4595
4531
  }
4596
- ) : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
4532
+ ) : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
4597
4533
  "div",
4598
4534
  {
4599
4535
  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",
4600
4536
  style: { zIndex: 9998 },
4601
4537
  children: [
4602
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
4538
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
4603
4539
  "div",
4604
4540
  {
4605
4541
  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",
4606
4542
  onClick: () => setIsMinimized(true),
4607
4543
  children: [
4608
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "font-bold text-slate-100 flex items-center gap-2", children: [
4609
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-lg", children: "\u{1F6E0}\uFE0F" }),
4544
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "font-bold text-slate-100 flex items-center gap-2", children: [
4545
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-lg", children: "\u{1F6E0}\uFE0F" }),
4610
4546
  " Simulation Controls"
4611
4547
  ] }),
4612
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4548
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4613
4549
  Button,
4614
4550
  {
4615
4551
  className: "text-slate-500 hover:text-white p-0 h-auto hover:bg-transparent cursor-pointer",
@@ -4621,10 +4557,10 @@ var BridgeMocker = ({
4621
4557
  ]
4622
4558
  }
4623
4559
  ),
4624
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "p-4 flex flex-col gap-3", children: [
4625
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex justify-between items-center", children: [
4626
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer", children: [
4627
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4560
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "p-4 flex flex-col gap-3", children: [
4561
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex justify-between items-center", children: [
4562
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer", children: [
4563
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4628
4564
  "input",
4629
4565
  {
4630
4566
  checked: autoMove,
@@ -4633,20 +4569,20 @@ var BridgeMocker = ({
4633
4569
  type: "checkbox"
4634
4570
  }
4635
4571
  ),
4636
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "text-slate-200 font-bold", children: [
4572
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "text-slate-200 font-bold", children: [
4637
4573
  "Auto-Move ",
4638
4574
  simulationPath ? "(Path)" : "(Random)"
4639
4575
  ] })
4640
4576
  ] }),
4641
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-2", children: [
4642
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-[10px] text-slate-500", children: "Speed:" }),
4643
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4577
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-2", children: [
4578
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-[10px] text-slate-500", children: "Speed:" }),
4579
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4644
4580
  "select",
4645
4581
  {
4646
4582
  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]",
4647
4583
  onChange: (e) => setSpeedMultiplier(Number(e.target.value)),
4648
4584
  value: speedMultiplier,
4649
- children: [1, 2, 5, 10, 50, 100, 250].map((s) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("option", { value: s, children: [
4585
+ children: [1, 2, 5, 10, 50, 100, 250].map((s) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("option", { value: s, children: [
4650
4586
  s,
4651
4587
  "x"
4652
4588
  ] }, s))
@@ -4654,10 +4590,10 @@ var BridgeMocker = ({
4654
4590
  )
4655
4591
  ] })
4656
4592
  ] }),
4657
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
4658
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-col gap-1", children: [
4659
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-[10px] text-slate-500 text-left", children: "Lng" }),
4660
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4593
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
4594
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-col gap-1", children: [
4595
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-[10px] text-slate-500 text-left", children: "Lng" }),
4596
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4661
4597
  "input",
4662
4598
  {
4663
4599
  className: "bg-slate-800 border border-slate-700 rounded px-2 py-1 text-white focus:outline-none focus:border-blue-500",
@@ -4672,9 +4608,9 @@ var BridgeMocker = ({
4672
4608
  }
4673
4609
  )
4674
4610
  ] }),
4675
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-col gap-1", children: [
4676
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-[10px] text-slate-500 text-left", children: "Lat" }),
4677
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4611
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-col gap-1", children: [
4612
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-[10px] text-slate-500 text-left", children: "Lat" }),
4613
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4678
4614
  "input",
4679
4615
  {
4680
4616
  className: "bg-slate-800 border border-slate-700 rounded px-2 py-1 text-white focus:outline-none focus:border-blue-500",
@@ -4689,9 +4625,9 @@ var BridgeMocker = ({
4689
4625
  }
4690
4626
  )
4691
4627
  ] }),
4692
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-col gap-1 col-span-2", children: [
4693
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-[10px] text-slate-500", children: "Heading (Degrees)" }),
4694
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4628
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-col gap-1 col-span-2", children: [
4629
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-[10px] text-slate-500", children: "Heading (Degrees)" }),
4630
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4695
4631
  "input",
4696
4632
  {
4697
4633
  className: "w-full accent-blue-500",
@@ -4705,13 +4641,13 @@ var BridgeMocker = ({
4705
4641
  value: heading
4706
4642
  }
4707
4643
  ),
4708
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "text-right text-slate-400", children: [
4644
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "text-right text-slate-400", children: [
4709
4645
  heading,
4710
4646
  "\xB0"
4711
4647
  ] })
4712
4648
  ] })
4713
4649
  ] }),
4714
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4650
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4715
4651
  Button,
4716
4652
  {
4717
4653
  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"}`,
@@ -4721,11 +4657,11 @@ var BridgeMocker = ({
4721
4657
  children: isPlacingLocation ? "\u{1F4CD} Click the map to drop location\u2026" : "\u{1F4CD} Drop location on map"
4722
4658
  }
4723
4659
  ),
4724
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-col gap-1 border-t border-slate-800 pt-3", children: [
4725
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex justify-between items-center", children: [
4726
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-[10px] text-slate-500", children: "Scan Radius" }),
4727
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-1", children: [
4728
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4660
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-col gap-1 border-t border-slate-800 pt-3", children: [
4661
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex justify-between items-center", children: [
4662
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-[10px] text-slate-500", children: "Scan Radius" }),
4663
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-1", children: [
4664
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4729
4665
  "input",
4730
4666
  {
4731
4667
  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",
@@ -4735,21 +4671,21 @@ var BridgeMocker = ({
4735
4671
  value: radiusMeters
4736
4672
  }
4737
4673
  ),
4738
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
4674
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
4739
4675
  "select",
4740
4676
  {
4741
4677
  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",
4742
4678
  onChange: (e) => setRadiusUnit(e.target.value),
4743
4679
  value: radiusUnit,
4744
4680
  children: [
4745
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "m", children: "m" }),
4746
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("option", { value: "km", children: "km" })
4681
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: "m", children: "m" }),
4682
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: "km", children: "km" })
4747
4683
  ]
4748
4684
  }
4749
4685
  )
4750
4686
  ] })
4751
4687
  ] }),
4752
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4688
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4753
4689
  "input",
4754
4690
  {
4755
4691
  className: "w-full accent-blue-500",
@@ -4761,7 +4697,7 @@ var BridgeMocker = ({
4761
4697
  value: radiusMeters
4762
4698
  }
4763
4699
  ),
4764
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "text-right text-slate-400", children: radiusMeters === 0 ? "hidden" : `${radiusMeters}${radiusUnit} radius around user` })
4700
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "text-right text-slate-400", children: radiusMeters === 0 ? "hidden" : `${radiusMeters}${radiusUnit} radius around user` })
4765
4701
  ] })
4766
4702
  ] })
4767
4703
  ]
@@ -4771,20 +4707,20 @@ var BridgeMocker = ({
4771
4707
  };
4772
4708
 
4773
4709
  // src/components/DebugConsole.tsx
4774
- var import_react15 = require("react");
4775
- var import_jsx_runtime17 = require("react/jsx-runtime");
4710
+ var import_react17 = require("react");
4711
+ var import_jsx_runtime18 = require("react/jsx-runtime");
4776
4712
  var DebugConsole = ({
4777
4713
  isOpen: initialOpen = false,
4778
4714
  onClose
4779
4715
  }) => {
4780
- const [showConsole, setShowConsole] = (0, import_react15.useState)(initialOpen);
4781
- const [logs, setLogs] = (0, import_react15.useState)([]);
4782
- const scrollRef = (0, import_react15.useRef)(null);
4783
- (0, import_react15.useEffect)(() => {
4716
+ const [showConsole, setShowConsole] = (0, import_react17.useState)(initialOpen);
4717
+ const [logs, setLogs] = (0, import_react17.useState)([]);
4718
+ const scrollRef = (0, import_react17.useRef)(null);
4719
+ (0, import_react17.useEffect)(() => {
4784
4720
  setShowConsole(initialOpen);
4785
4721
  }, [initialOpen]);
4786
4722
  const clearLogs = () => setLogs([]);
4787
- const addLog = (0, import_react15.useCallback)((label, data) => {
4723
+ const addLog = (0, import_react17.useCallback)((label, data) => {
4788
4724
  if (label.includes("LOCATION_STREAM_UPDATE" /* LOCATION_STREAM_UPDATE */)) return;
4789
4725
  const entry = {
4790
4726
  content: typeof data === "string" ? data : JSON.stringify(data, null, 2),
@@ -4794,7 +4730,7 @@ var DebugConsole = ({
4794
4730
  };
4795
4731
  setLogs((prev) => [entry, ...prev].slice(0, 100));
4796
4732
  }, []);
4797
- (0, import_react15.useEffect)(() => {
4733
+ (0, import_react17.useEffect)(() => {
4798
4734
  if (typeof window === "undefined") return;
4799
4735
  const bridge = sdk.bridge;
4800
4736
  const originalSend = bridge.send.bind(bridge);
@@ -4816,7 +4752,7 @@ var DebugConsole = ({
4816
4752
  };
4817
4753
  }, [addLog]);
4818
4754
  if (!showConsole) {
4819
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4755
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4820
4756
  Button,
4821
4757
  {
4822
4758
  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!",
@@ -4824,7 +4760,7 @@ var DebugConsole = ({
4824
4760
  title: "Open Debug Console",
4825
4761
  type: "button",
4826
4762
  variant: "ghost",
4827
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
4763
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4828
4764
  "svg",
4829
4765
  {
4830
4766
  className: "group-hover:scale-110 transition-transform",
@@ -4838,31 +4774,31 @@ var DebugConsole = ({
4838
4774
  width: "14",
4839
4775
  xmlns: "http://www.w3.org/2000/svg",
4840
4776
  children: [
4841
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "m8 2 1.88 1.88" }),
4842
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M14.12 3.88 16 2" }),
4843
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M9 7.13v-1a3.003 3.003 0 1 1 6 0v1" }),
4844
- /* @__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" }),
4845
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M12 20v-9" }),
4846
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M6.53 9C4.6 8.8 3 7.1 3 5" }),
4847
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M6 13H2" }),
4848
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M3 21c0-2.1 1.7-3.9 3.8-4" }),
4849
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M20.97 5c0 2.1-1.6 3.8-3.5 4" }),
4850
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M22 13h-4" }),
4851
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M17.2 17c2.1.1 3.8 1.9 3.8 4" })
4777
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "m8 2 1.88 1.88" }),
4778
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M14.12 3.88 16 2" }),
4779
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M9 7.13v-1a3.003 3.003 0 1 1 6 0v1" }),
4780
+ /* @__PURE__ */ (0, import_jsx_runtime18.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" }),
4781
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M12 20v-9" }),
4782
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M6.53 9C4.6 8.8 3 7.1 3 5" }),
4783
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M6 13H2" }),
4784
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M3 21c0-2.1 1.7-3.9 3.8-4" }),
4785
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M20.97 5c0 2.1-1.6 3.8-3.5 4" }),
4786
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M22 13h-4" }),
4787
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M17.2 17c2.1.1 3.8 1.9 3.8 4" })
4852
4788
  ]
4853
4789
  }
4854
4790
  )
4855
4791
  }
4856
4792
  );
4857
4793
  }
4858
- 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: [
4859
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [
4860
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "text-[10px] font-bold uppercase tracking-widest text-slate-400 flex items-center gap-2", children: [
4861
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "w-2 h-2 rounded-full bg-emerald-500 animate-pulse" }),
4794
+ return /* @__PURE__ */ (0, import_jsx_runtime18.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: [
4795
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [
4796
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "text-[10px] font-bold uppercase tracking-widest text-slate-400 flex items-center gap-2", children: [
4797
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "w-2 h-2 rounded-full bg-emerald-500 animate-pulse" }),
4862
4798
  "UP SDK Debug Console"
4863
4799
  ] }),
4864
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex gap-4", children: [
4865
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4800
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex gap-4", children: [
4801
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4866
4802
  Button,
4867
4803
  {
4868
4804
  className: "text-[10px] text-slate-500 font-bold uppercase hover:text-slate-300 hover:bg-transparent transition-colors p-0 h-auto cursor-pointer",
@@ -4872,7 +4808,7 @@ var DebugConsole = ({
4872
4808
  children: "Clear"
4873
4809
  }
4874
4810
  ),
4875
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4811
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4876
4812
  Button,
4877
4813
  {
4878
4814
  className: "text-[10px] text-pink-500 font-bold uppercase hover:text-pink-400 hover:bg-transparent transition-colors p-0 h-auto cursor-pointer",
@@ -4887,21 +4823,21 @@ var DebugConsole = ({
4887
4823
  )
4888
4824
  ] })
4889
4825
  ] }),
4890
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4826
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4891
4827
  "div",
4892
4828
  {
4893
4829
  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",
4894
4830
  ref: scrollRef,
4895
- 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)(
4831
+ children: logs.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.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_runtime18.jsxs)(
4896
4832
  "div",
4897
4833
  {
4898
4834
  className: "mb-3 pb-3 border-b border-slate-900/50 last:border-0 last:mb-0 last:pb-0",
4899
4835
  children: [
4900
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex gap-2 text-slate-500 mb-1 items-center", children: [
4901
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-[8px]", children: log.time }),
4902
- /* @__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 })
4836
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex gap-2 text-slate-500 mb-1 items-center", children: [
4837
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-[8px]", children: log.time }),
4838
+ /* @__PURE__ */ (0, import_jsx_runtime18.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 })
4903
4839
  ] }),
4904
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("pre", { className: "whitespace-pre-wrap break-all opacity-90", children: log.content })
4840
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("pre", { className: "whitespace-pre-wrap break-all opacity-90", children: log.content })
4905
4841
  ]
4906
4842
  },
4907
4843
  log.id
@@ -4912,8 +4848,8 @@ var DebugConsole = ({
4912
4848
  };
4913
4849
 
4914
4850
  // src/components/PullToRefresh.tsx
4915
- var import_react16 = require("react");
4916
- var import_jsx_runtime18 = require("react/jsx-runtime");
4851
+ var import_react18 = require("react");
4852
+ var import_jsx_runtime19 = require("react/jsx-runtime");
4917
4853
  var DEFAULT_PULL_THRESHOLD = 64;
4918
4854
  var DEFAULT_MAX_PULL = 96;
4919
4855
  var RESISTANCE = 0.5;
@@ -4924,7 +4860,7 @@ function DefaultIndicator({
4924
4860
  progress,
4925
4861
  isRefreshing
4926
4862
  }) {
4927
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4863
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4928
4864
  "div",
4929
4865
  {
4930
4866
  style: {
@@ -4939,7 +4875,7 @@ function DefaultIndicator({
4939
4875
  width: 28
4940
4876
  },
4941
4877
  children: [
4942
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4878
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4943
4879
  "svg",
4944
4880
  {
4945
4881
  height: 14,
@@ -4951,8 +4887,8 @@ function DefaultIndicator({
4951
4887
  viewBox: "0 0 24 24",
4952
4888
  width: 14,
4953
4889
  children: [
4954
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("title", { children: "Refreshing" }),
4955
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4890
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("title", { children: "Refreshing" }),
4891
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4956
4892
  "path",
4957
4893
  {
4958
4894
  d: "M21 12a9 9 0 1 1-2.64-6.36",
@@ -4965,7 +4901,7 @@ function DefaultIndicator({
4965
4901
  ]
4966
4902
  }
4967
4903
  ),
4968
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("style", { children: "@keyframes up-sdk-ptr-spin { to { transform: rotate(360deg); } }" })
4904
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("style", { children: "@keyframes up-sdk-ptr-spin { to { transform: rotate(360deg); } }" })
4969
4905
  ]
4970
4906
  }
4971
4907
  );
@@ -4979,27 +4915,46 @@ var PullToRefresh = ({
4979
4915
  maxPull = DEFAULT_MAX_PULL,
4980
4916
  renderIndicator
4981
4917
  }) => {
4982
- const containerRef = (0, import_react16.useRef)(null);
4983
- const startYRef = (0, import_react16.useRef)(null);
4984
- const lastYRef = (0, import_react16.useRef)(0);
4985
- const lastMoveTimeRef = (0, import_react16.useRef)(0);
4986
- const velocityRef = (0, import_react16.useRef)(0);
4987
- const pointerIdRef = (0, import_react16.useRef)(null);
4988
- const isPullingRef = (0, import_react16.useRef)(false);
4989
- const pullDistanceRef = (0, import_react16.useRef)(0);
4990
- const flingRafRef = (0, import_react16.useRef)(null);
4991
- const [pullDistance, setPullDistance] = (0, import_react16.useState)(0);
4992
- const [isRefreshing, setIsRefreshing] = (0, import_react16.useState)(false);
4993
- const [isTracking, setIsTracking] = (0, import_react16.useState)(false);
4994
- const disabledRef = (0, import_react16.useRef)(disabled);
4918
+ const containerRef = (0, import_react18.useRef)(null);
4919
+ const startYRef = (0, import_react18.useRef)(null);
4920
+ const lastYRef = (0, import_react18.useRef)(0);
4921
+ const lastMoveTimeRef = (0, import_react18.useRef)(0);
4922
+ const velocityRef = (0, import_react18.useRef)(0);
4923
+ const pointerIdRef = (0, import_react18.useRef)(null);
4924
+ const isPullingRef = (0, import_react18.useRef)(false);
4925
+ const pullDistanceRef = (0, import_react18.useRef)(0);
4926
+ const flingRafRef = (0, import_react18.useRef)(null);
4927
+ const [pullDistance, setPullDistance] = (0, import_react18.useState)(0);
4928
+ const [isRefreshing, setIsRefreshing] = (0, import_react18.useState)(false);
4929
+ const [isTracking, setIsTracking] = (0, import_react18.useState)(false);
4930
+ const disabledRef = (0, import_react18.useRef)(disabled);
4995
4931
  disabledRef.current = disabled;
4996
- const onRefreshRef = (0, import_react16.useRef)(onRefresh);
4932
+ const onRefreshRef = (0, import_react18.useRef)(onRefresh);
4997
4933
  onRefreshRef.current = onRefresh;
4998
- const pullThresholdRef = (0, import_react16.useRef)(pullThreshold);
4934
+ const pullThresholdRef = (0, import_react18.useRef)(pullThreshold);
4999
4935
  pullThresholdRef.current = pullThreshold;
5000
- const maxPullRef = (0, import_react16.useRef)(maxPull);
4936
+ const maxPullRef = (0, import_react18.useRef)(maxPull);
5001
4937
  maxPullRef.current = maxPull;
5002
- (0, import_react16.useEffect)(() => {
4938
+ (0, import_react18.useEffect)(() => {
4939
+ const el = containerRef.current;
4940
+ if (!el || typeof window === "undefined") return;
4941
+ const checkScrollChain = () => {
4942
+ const noInternalOverflow = el.scrollHeight <= el.clientHeight;
4943
+ const tallerThanViewport = el.clientHeight > window.innerHeight;
4944
+ if (noInternalOverflow && tallerThanViewport) {
4945
+ console.warn(
4946
+ "[PullToRefresh] This container is taller than the viewport but has no internal scroll (scrollHeight <= clientHeight). Because this component disables native touch scrolling entirely (touch-action: none), scrolling is now completely broken here. This almost always means either: (1) an ancestor's flex-1 item is missing `min-h-0` (a flex item defaults to min-height:auto and refuses to shrink below its content size), or (2) an ancestor uses `min-h-screen`/`min-h-full` (a floor, not a ceiling) instead of `h-full`/`h-screen`/`h-dvh`. See the vault skill js/pull-to-refresh-scroll-chain.md for the fix pattern."
4947
+ );
4948
+ }
4949
+ };
4950
+ const raf = requestAnimationFrame(checkScrollChain);
4951
+ window.addEventListener("resize", checkScrollChain);
4952
+ return () => {
4953
+ cancelAnimationFrame(raf);
4954
+ window.removeEventListener("resize", checkScrollChain);
4955
+ };
4956
+ }, []);
4957
+ (0, import_react18.useEffect)(() => {
5003
4958
  const el = containerRef.current;
5004
4959
  if (!el) return;
5005
4960
  const updatePullDistance = (value) => {
@@ -5130,7 +5085,7 @@ var PullToRefresh = ({
5130
5085
  const indicatorHeight = isRefreshing ? pullThreshold : pullDistance;
5131
5086
  const progress = Math.min(indicatorHeight / pullThreshold, 1);
5132
5087
  const isSettling = pullDistance === 0 && !isRefreshing && !isTracking;
5133
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5088
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
5134
5089
  "div",
5135
5090
  {
5136
5091
  className: `up-sdk-pull-to-refresh ${className}`,
@@ -5141,8 +5096,8 @@ var PullToRefresh = ({
5141
5096
  touchAction: "none"
5142
5097
  },
5143
5098
  children: [
5144
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("style", { children: ".up-sdk-pull-to-refresh::-webkit-scrollbar { display: none; } .up-sdk-pull-to-refresh { scrollbar-width: none; -ms-overflow-style: none; }" }),
5145
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5099
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("style", { children: ".up-sdk-pull-to-refresh::-webkit-scrollbar { display: none; } .up-sdk-pull-to-refresh { scrollbar-width: none; -ms-overflow-style: none; }" }),
5100
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5146
5101
  "div",
5147
5102
  {
5148
5103
  style: {
@@ -5155,7 +5110,7 @@ var PullToRefresh = ({
5155
5110
  userSelect: "none",
5156
5111
  width: "100%"
5157
5112
  },
5158
- children: renderIndicator ? renderIndicator({ isRefreshing, progress }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DefaultIndicator, { isRefreshing, progress })
5113
+ children: renderIndicator ? renderIndicator({ isRefreshing, progress }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DefaultIndicator, { isRefreshing, progress })
5159
5114
  }
5160
5115
  ),
5161
5116
  children
@@ -5166,16 +5121,16 @@ var PullToRefresh = ({
5166
5121
 
5167
5122
  // src/components/QRScanner.tsx
5168
5123
  var import_jsqr2 = __toESM(require("jsqr"), 1);
5169
- var import_react17 = require("react");
5170
- var import_jsx_runtime19 = require("react/jsx-runtime");
5124
+ var import_react19 = require("react");
5125
+ var import_jsx_runtime20 = require("react/jsx-runtime");
5171
5126
  function QRScanner({ onScan, onError, className = "" }) {
5172
- const videoRef = (0, import_react17.useRef)(null);
5173
- const canvasRef = (0, import_react17.useRef)(null);
5174
- const streamRef = (0, import_react17.useRef)(null);
5175
- const tickRequestRef = (0, import_react17.useRef)(null);
5176
- const hasScannedRef = (0, import_react17.useRef)(false);
5177
- const [isReady, setIsReady] = (0, import_react17.useState)(false);
5178
- (0, import_react17.useEffect)(() => {
5127
+ const videoRef = (0, import_react19.useRef)(null);
5128
+ const canvasRef = (0, import_react19.useRef)(null);
5129
+ const streamRef = (0, import_react19.useRef)(null);
5130
+ const tickRequestRef = (0, import_react19.useRef)(null);
5131
+ const hasScannedRef = (0, import_react19.useRef)(false);
5132
+ const [isReady, setIsReady] = (0, import_react19.useState)(false);
5133
+ (0, import_react19.useEffect)(() => {
5179
5134
  let cancelled = false;
5180
5135
  hasScannedRef.current = false;
5181
5136
  const cleanup = () => {
@@ -5258,7 +5213,7 @@ function QRScanner({ onScan, onError, className = "" }) {
5258
5213
  cleanup();
5259
5214
  };
5260
5215
  }, []);
5261
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
5216
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
5262
5217
  "div",
5263
5218
  {
5264
5219
  className,
@@ -5270,7 +5225,7 @@ function QRScanner({ onScan, onError, className = "" }) {
5270
5225
  position: "relative"
5271
5226
  },
5272
5227
  children: [
5273
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5228
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5274
5229
  "video",
5275
5230
  {
5276
5231
  playsInline: true,
@@ -5278,8 +5233,8 @@ function QRScanner({ onScan, onError, className = "" }) {
5278
5233
  style: { height: "100%", objectFit: "cover", width: "100%" }
5279
5234
  }
5280
5235
  ),
5281
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("canvas", { ref: canvasRef, style: { display: "none" } }),
5282
- isReady && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5236
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("canvas", { ref: canvasRef, style: { display: "none" } }),
5237
+ isReady && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5283
5238
  "div",
5284
5239
  {
5285
5240
  style: {
@@ -5300,30 +5255,30 @@ function QRScanner({ onScan, onError, className = "" }) {
5300
5255
  }
5301
5256
 
5302
5257
  // src/components/SDKProvider.tsx
5303
- var import_react18 = require("react");
5304
- var import_jsx_runtime20 = require("react/jsx-runtime");
5305
- var SDKContext = (0, import_react18.createContext)({ isMocked: false });
5306
- var useIsMocked = () => (0, import_react18.useContext)(SDKContext).isMocked;
5258
+ var import_react20 = require("react");
5259
+ var import_jsx_runtime21 = require("react/jsx-runtime");
5260
+ var SDKContext = (0, import_react20.createContext)({ isMocked: false });
5261
+ var useIsMocked = () => (0, import_react20.useContext)(SDKContext).isMocked;
5307
5262
  var SDKProvider = ({
5308
5263
  children,
5309
5264
  debug = false,
5310
5265
  ...mockerProps
5311
5266
  }) => {
5312
5267
  const isMocked = typeof window !== "undefined" && !(window.__UP_REACT_NATIVE_APP__ === true || !!window.ReactNativeWebView);
5313
- const value = (0, import_react18.useMemo)(() => ({ isMocked }), [isMocked]);
5314
- const content = /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
5268
+ const value = (0, import_react20.useMemo)(() => ({ isMocked }), [isMocked]);
5269
+ const content = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
5315
5270
  children,
5316
- (debug || isMocked) && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DebugConsole, {})
5271
+ (debug || isMocked) && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DebugConsole, {})
5317
5272
  ] });
5318
5273
  if (isMocked) {
5319
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SDKContext.Provider, { value, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(BridgeMocker, { ...mockerProps, children: content }) });
5274
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SDKContext.Provider, { value, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(BridgeMocker, { ...mockerProps, children: content }) });
5320
5275
  }
5321
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SDKContext.Provider, { value, children: content });
5276
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SDKContext.Provider, { value, children: content });
5322
5277
  };
5323
5278
 
5324
5279
  // src/components/SwipeCarousel.tsx
5325
- var import_react19 = require("react");
5326
- var import_jsx_runtime21 = require("react/jsx-runtime");
5280
+ var import_react21 = require("react");
5281
+ var import_jsx_runtime22 = require("react/jsx-runtime");
5327
5282
  var DIRECTION_LOCK_THRESHOLD_PX = 8;
5328
5283
  var SWIPE_DISTANCE_THRESHOLD_PX = 40;
5329
5284
  var SWIPE_VELOCITY_THRESHOLD = 0.4;
@@ -5350,28 +5305,28 @@ var SwipeCarousel = ({
5350
5305
  overscan = DEFAULT_OVERSCAN,
5351
5306
  visibleOverscan = DEFAULT_VISIBLE_OVERSCAN
5352
5307
  }) => {
5353
- const containerRef = (0, import_react19.useRef)(null);
5354
- const [containerWidth, setContainerWidth] = (0, import_react19.useState)(0);
5355
- const [dragX, setDragX] = (0, import_react19.useState)(0);
5356
- const [dragY, setDragY] = (0, import_react19.useState)(0);
5357
- const [isDraggingX, setIsDraggingX] = (0, import_react19.useState)(false);
5358
- const [isDraggingY, setIsDraggingY] = (0, import_react19.useState)(false);
5359
- const touchStateRef = (0, import_react19.useRef)(null);
5360
- const [internalIndex, setInternalIndex] = (0, import_react19.useState)(
5308
+ const containerRef = (0, import_react21.useRef)(null);
5309
+ const [containerWidth, setContainerWidth] = (0, import_react21.useState)(0);
5310
+ const [dragX, setDragX] = (0, import_react21.useState)(0);
5311
+ const [dragY, setDragY] = (0, import_react21.useState)(0);
5312
+ const [isDraggingX, setIsDraggingX] = (0, import_react21.useState)(false);
5313
+ const [isDraggingY, setIsDraggingY] = (0, import_react21.useState)(false);
5314
+ const touchStateRef = (0, import_react21.useRef)(null);
5315
+ const [internalIndex, setInternalIndex] = (0, import_react21.useState)(
5361
5316
  () => Math.max(
5362
5317
  0,
5363
5318
  items.findIndex((item) => item.id === activeId)
5364
5319
  )
5365
5320
  );
5366
- const prevActiveIdRef = (0, import_react19.useRef)(activeId);
5367
- const [timingWaiting, setTimingWaiting] = (0, import_react19.useState)(true);
5368
- (0, import_react19.useEffect)(() => {
5321
+ const prevActiveIdRef = (0, import_react21.useRef)(activeId);
5322
+ const [timingWaiting, setTimingWaiting] = (0, import_react21.useState)(true);
5323
+ (0, import_react21.useEffect)(() => {
5369
5324
  const timer = setTimeout(() => {
5370
5325
  setTimingWaiting(false);
5371
5326
  }, 1e3);
5372
5327
  return () => clearTimeout(timer);
5373
5328
  }, []);
5374
- (0, import_react19.useEffect)(() => {
5329
+ (0, import_react21.useEffect)(() => {
5375
5330
  if (activeId !== prevActiveIdRef.current) {
5376
5331
  const idx = items.findIndex((item) => item.id === activeId);
5377
5332
  if (idx !== -1) setInternalIndex(idx);
@@ -5382,7 +5337,7 @@ var SwipeCarousel = ({
5382
5337
  Math.max(internalIndex, 0),
5383
5338
  Math.max(items.length - 1, 0)
5384
5339
  );
5385
- (0, import_react19.useLayoutEffect)(() => {
5340
+ (0, import_react21.useLayoutEffect)(() => {
5386
5341
  const el = containerRef.current;
5387
5342
  if (!el) return;
5388
5343
  const update = () => setContainerWidth(el.clientWidth);
@@ -5500,7 +5455,7 @@ var SwipeCarousel = ({
5500
5455
  };
5501
5456
  const windowStart = Math.max(0, activeIndex - overscan);
5502
5457
  const windowEnd = Math.min(items.length - 1, activeIndex + overscan);
5503
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5458
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5504
5459
  "div",
5505
5460
  {
5506
5461
  className: `relative overflow-hidden touch-pan-y ${className ?? ""}`,
@@ -5509,7 +5464,7 @@ var SwipeCarousel = ({
5509
5464
  onTouchMove: handleTouchMove,
5510
5465
  onTouchStart: handleTouchStart,
5511
5466
  ref: containerRef,
5512
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5467
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5513
5468
  "div",
5514
5469
  {
5515
5470
  className: "relative h-full",
@@ -5524,7 +5479,7 @@ var SwipeCarousel = ({
5524
5479
  const verticalOffset = isActive ? dragY : 0;
5525
5480
  const distance = Math.abs(index - activeIndex);
5526
5481
  const isVisible = distance <= visibleOverscan;
5527
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5482
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5528
5483
  "div",
5529
5484
  {
5530
5485
  className: `absolute top-0 left-0 h-full shrink-0 ${itemClassName ?? ""} ${item.className ?? ""}`,
@@ -5552,6 +5507,40 @@ var SwipeCarousel = ({
5552
5507
  );
5553
5508
  };
5554
5509
 
5510
+ // src/hooks/useTapAction.ts
5511
+ var import_react22 = require("react");
5512
+ var TAP_MOVE_TOLERANCE_PX = 10;
5513
+ var CLICK_SUPPRESS_WINDOW_MS = 500;
5514
+ var useTapAction = (action) => {
5515
+ const startRef = (0, import_react22.useRef)(null);
5516
+ const handledByTouchRef = (0, import_react22.useRef)(false);
5517
+ const onTouchStart = (e) => {
5518
+ const touch = e.targetTouches[0];
5519
+ startRef.current = touch ? { x: touch.clientX, y: touch.clientY } : null;
5520
+ };
5521
+ const onTouchEnd = (e) => {
5522
+ const start = startRef.current;
5523
+ const touch = e.changedTouches[0];
5524
+ startRef.current = null;
5525
+ if (!start || !touch) return;
5526
+ const moved = Math.hypot(touch.clientX - start.x, touch.clientY - start.y);
5527
+ if (moved > TAP_MOVE_TOLERANCE_PX) return;
5528
+ handledByTouchRef.current = true;
5529
+ setTimeout(() => {
5530
+ handledByTouchRef.current = false;
5531
+ }, CLICK_SUPPRESS_WINDOW_MS);
5532
+ action();
5533
+ };
5534
+ const onClick = () => {
5535
+ if (handledByTouchRef.current) {
5536
+ handledByTouchRef.current = false;
5537
+ return;
5538
+ }
5539
+ action();
5540
+ };
5541
+ return { onClick, onTouchEnd, onTouchStart };
5542
+ };
5543
+
5555
5544
  // src/host/routingHandler.ts
5556
5545
  async function handleRouteRequest(req, config) {
5557
5546
  return RoutingService.fetchRoute(req, config);
@@ -5885,6 +5874,7 @@ var src_default = sdk;
5885
5874
  useMapControls,
5886
5875
  useMockLocation,
5887
5876
  useRoute,
5877
+ useTapAction,
5888
5878
  useTrimmedRoute,
5889
5879
  useUserLocation
5890
5880
  });