@cloudparse/up-miniapps-sdk 0.6.8 → 0.7.3

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/components/Map/MockLocationContext.tsx","../src/lib/utils.ts","../src/components/ui/button.tsx","../src/utils/environment.ts","../src/bridge.ts","../src/components/ui/sheet.tsx","../src/components/Map/components/MapDrawer.tsx","../src/components/ui/card.tsx","../src/components/Map/components/MapEtaPanel.tsx","../src/components/Map/components/MapRightControls.tsx","../src/components/Map/MapContext.tsx","../src/components/Map/components/MapControls.tsx","../src/components/Map/components/MapMenu.tsx","../src/types/types.ts","../src/components/Map/hooks/useUserLocation.ts","../src/components/Map/hooks/useLiveRouting.ts","../src/components/Map/hooks/useJourney.ts","../src/components/Map/hooks/useTrimmedRoute.ts","../src/components/Map/layers/RouteLayer.tsx","../src/components/Map/utils/geoCircle.ts","../src/components/Map/layers/MockRadiusLayer.tsx","../src/components/Map/layers/POILayers.tsx","../src/components/Map/layers/POIMarkers.tsx","../src/components/Map/layers/UserLocationLayer.tsx","../src/components/Map/Map.tsx","../src/components/MapWrapper.tsx","../src/services/qrCodeService.ts","../src/services/qrDecodeService.ts","../src/services/routingService.ts","../package.json","../src/sdk.ts","../src/components/BridgeMocker.tsx","../src/components/DebugConsole.tsx","../src/components/PullToRefresh.tsx","../src/components/QRScanner.tsx","../src/components/SDKProvider.tsx","../src/components/SwipeCarousel.tsx","../src/host/routingHandler.ts","../src/services/apiService.ts","../src/services/wsService.ts"],"sourcesContent":["export * from \"@miniapps-sdk/components\";\nexport * from \"@miniapps-sdk/host\";\nexport { MiniAppSDK, sdk } from \"@miniapps-sdk/sdk\";\nexport * from \"@miniapps-sdk/services/apiService\";\nexport * from \"@miniapps-sdk/services/wsService\";\nexport * from \"@miniapps-sdk/types\";\n\nimport { sdk } from \"@miniapps-sdk/sdk\";\n\nexport default sdk;\n","import { createContext, useContext } from \"react\";\n\nexport interface MockLocationContextType {\n /** Radius in meters to draw around the mocked user location. 0 hides it. */\n radiusMeters: number;\n /** When true, the next map click drops the mocked location there instead\n * of firing the app's own onClick/onMapClickMiss handlers. */\n isPlacingLocation: boolean;\n /** Called by the Map when a click lands while isPlacingLocation is true. */\n placeLocation: (coords: [number, number]) => void;\n}\n\n/**\n * Bridges BridgeMocker (owns the mocked location/radius state, rendered as\n * a sibling dev panel outside the map's DOM tree) and the Map component\n * (needs to read that state to draw the radius overlay and intercept\n * \"drop location here\" clicks) without prop-drilling through every\n * consumer app's own Map usage.\n */\nexport const MockLocationContext =\n createContext<MockLocationContextType | null>(null);\n\nexport const useMockLocation = (): MockLocationContextType | null =>\n useContext(MockLocationContext);\n","import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import { cn } from \"@miniapps-sdk/lib/utils\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport * as React from \"react\";\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n defaultVariants: {\n size: \"default\",\n variant: \"default\",\n },\n variants: {\n size: {\n default: \"h-10 px-4 py-2\",\n icon: \"h-10 w-10\",\n lg: \"h-11 rounded-md px-8\",\n sm: \"h-9 rounded-md px-3\",\n },\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n outline:\n \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n },\n },\n },\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n className={cn(buttonVariants({ className, size, variant }))}\n ref={ref}\n {...props}\n />\n );\n },\n);\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants };\n","/**\n * Detects whether this WebView is actually running inside the native UP\n * shell, vs. a plain standalone browser (dev server, `vite preview`, a\n * bare tab someone opened the built HTML in directly). Deliberately a\n * runtime check against injected globals, not a build-mode flag like\n * Vite's `import.meta.env.PROD` — a production-mode standalone preview is\n * still not inside the shell, and `import.meta.env` isn't even reliably\n * available inside this package to begin with (this SDK is bundled by\n * tsup, not Vite, so Vite's compile-time env replacement never runs here).\n */\nexport function isRunningInsideNativeShell(): boolean {\n if (typeof window === \"undefined\") return false;\n const w = window as unknown as {\n __UP_REACT_NATIVE_APP__?: boolean;\n ReactNativeWebView?: unknown;\n };\n return w.__UP_REACT_NATIVE_APP__ === true || !!w.ReactNativeWebView;\n}\n","import type { IBridgeEnvelope } from \"@miniapps-sdk/types\";\nimport { isRunningInsideNativeShell } from \"@miniapps-sdk/utils/environment\";\n\n/** Distinguishes a lost-in-transit timeout from a definitive host rejection — see `Bridge.send`'s retry logic. */\nexport class BridgeTimeoutError extends Error {}\n\n/**\n * The Bridge handles low-level communication between the Mini-App WebView\n * and the Native Host Shell (iOS/Android).\n *\n * It manages asynchronous request-response cycles via callbacks and\n * supports subscription to pushed events from the native environment.\n */\nexport class Bridge {\n private callbacks = new Map<\n string,\n {\n resolve: (val: unknown) => void;\n reject: (err: unknown) => void;\n timeout: ReturnType<typeof setTimeout>;\n }\n >();\n private eventListeners = new Map<string, ((data: any) => void)[]>();\n\n /**\n * Registers a global listener for messages coming from the native shell.\n * Also listens for standard browser `message` events to support multiple\n * communication channels (e.g., React Native WebView postMessage).\n */\n constructor() {\n if (typeof window !== \"undefined\") {\n const bridgeReceiver = Object.freeze({\n onNativeMessage: (envelope: IBridgeEnvelope) =>\n this.handleNativeMessage(envelope),\n });\n\n // Use defineProperty to bind the receiver, allowing reconfiguration for HMR environments\n if (typeof (window as any).__MiniAppBridge === \"undefined\") {\n Object.defineProperty(window, \"__MiniAppBridge\", {\n configurable: true, // MUST be true for React StrictMode / HMR unmount/remount cycles\n value: bridgeReceiver,\n writable: false,\n });\n }\n\n window.addEventListener(\"message\", (event) => {\n // SECURITY: Filter events. If inside a mobile shell, the origin of native postMessage\n // varies by platform (e.g., file://, or specific app schemes).\n // For production, this should be restricted to the expected host origin.\n if (!event.data) return;\n\n try {\n const data =\n typeof event.data === \"string\"\n ? JSON.parse(event.data)\n : event.data;\n\n // SECURITY: Basic envelope validation\n if (\n data &&\n typeof data === \"object\" &&\n (data.callbackId || data.event || data.eventName)\n ) {\n this.handleNativeMessage(data);\n }\n } catch (_e) {\n // Ignore non-JSON or malformed messages\n }\n });\n }\n }\n\n /**\n * Subscribes to a pushed event from the native shell.\n *\n * @param event The event name to listen for.\n * @param callback Function to execute when the event occurs.\n * @returns An unsubscription function.\n */\n public on<T = unknown>(event: string, callback: (data: T) => void) {\n let listeners = this.eventListeners.get(event);\n if (!listeners) {\n listeners = [];\n this.eventListeners.set(event, listeners);\n }\n listeners.push(callback);\n return () => this.off(event, callback);\n }\n\n /**\n * Unsubscribes a specific callback from an event.\n *\n * @param event The event name.\n * @param callback The callback function to remove.\n */\n public off<T = unknown>(event: string, callback: (data: T) => void) {\n const listeners = this.eventListeners.get(event);\n if (!listeners) return;\n this.eventListeners.set(\n event,\n listeners.filter((cb) => cb !== callback),\n );\n }\n\n /**\n * Sends a message to the native shell and waits for a response.\n *\n * @template T The expected response type.\n * @param type The action type (e.g., \"GET_LOCATION\").\n * @param payload Data associated with the action.\n * @param timeoutMs Time in milliseconds to wait for a response before rejecting.\n * @param retries Number of additional attempts if a request times out (default 1 — one retry).\n * Exists because the response for a request can be lost in transit — e.g. the host's\n * injected response script running before this WebView's own `message` listener has\n * attached, worse under rapid mount/unmount cycles — with no application-visible symptom\n * other than the full 30s timeout. A blind retry self-heals that class of loss without\n * needing to diagnose which specific transport race dropped the original message; every\n * call site benefits automatically instead of each consumer app hand-rolling its own\n * retry-after-catch logic (which previously only covered `initialize()`, and imperfectly).\n * @returns A promise that resolves with the native response.\n */\n public send<T = unknown>(\n type: string,\n payload?: unknown,\n timeoutMs = 30000,\n retries = 1,\n ): Promise<T> {\n if (!this.isNative()) {\n return this.handleMockMessage(type, payload);\n }\n\n return this.sendOnce<T>(type, payload, timeoutMs).catch((err) => {\n // Only retry an actual lost-in-transit timeout — never a definitive\n // rejection the host already answered (e.g. a security-origin block,\n // or any other application-level `success: false`). Retrying those\n // is pointless (the same deterministic input produces the same\n // deterministic \"no\") and, with zero backoff between attempts, can\n // turn one legitimate rejection into a tight retry storm if a caller\n // up the stack also reacts to the failure by re-triggering the same\n // request.\n if (retries <= 0 || !(err instanceof BridgeTimeoutError)) throw err;\n return this.send<T>(type, payload, timeoutMs, retries - 1);\n });\n }\n\n /**\n * Internal handler for all incoming messages from the native shell.\n * Matches incoming payloads to either pending callbacks or event listeners.\n *\n * @internal\n * @param envelope The message envelope received from native code.\n */\n public handleNativeMessage(envelope: IBridgeEnvelope) {\n if (!envelope || typeof envelope !== \"object\") return;\n\n // 1. Handle Response Callbacks\n const callbackId = envelope.callbackId;\n if (callbackId && typeof callbackId === \"string\") {\n const callback = this.callbacks.get(callbackId);\n if (callback) {\n clearTimeout(callback.timeout);\n const { resolve, reject } = callback;\n\n if (envelope.success === false || envelope.error) {\n reject(envelope.error || \"Unknown error\");\n } else {\n resolve(envelope.value ?? envelope.payload ?? envelope);\n }\n\n this.callbacks.delete(callbackId);\n return;\n }\n }\n\n // 2. Handle Pushed Events\n const eventName = envelope.eventName || envelope.event;\n if (eventName) {\n // If using the new protocol with type=\"EVENT\", ensure we only process if type matches\n if (envelope.type === \"EVENT\" || !envelope.type || envelope.event) {\n const listeners = this.eventListeners.get(eventName);\n if (listeners) {\n for (const listener of listeners) {\n try {\n listener(envelope.payload || envelope.value);\n } catch (e) {\n console.error(`Error in event listener for ${eventName}:`, e);\n }\n }\n }\n }\n }\n }\n\n /**\n * Internal handler for mock message processing, overrideable in test environments.\n *\n * Every mini-app that calls a bridge method also has to run standalone in a plain\n * browser (dev, and this vault's own Chrome-based verification) with no native shell\n * attached — `isNative()` is false, so `send()` never round-trips through the real\n * host at all. Before this switch existed, EVERY unhandled type here resolved with\n * plain `undefined` (see the `default` branch below), which silently broke any caller\n * checking a result shape like `{success: boolean}` — `undefined?.success` reads as\n * `false`, not \"no answer\", so e.g. `sdk.media.saveImage()` looked like a real\n * permission-denied rejection in the browser instead of \"there's no native shell\n * here to ask.\" Add a `case` here — instead of leaving every mini-app to\n * individually special-case \"what happens when I call this with no shell attached\" —\n * whenever a bridge method's mock behavior should be more than a no-op.\n */\n protected handleMockMessage(type: string, payload: unknown): Promise<any> {\n switch (type) {\n case \"SAVE_IMAGE\":\n return this.mockSaveImage(\n payload as { base64: string; filename?: string },\n );\n default:\n console.warn(\n `[Bridge] Mock mode active: Unhandled message type ${type}`,\n );\n return Promise.resolve();\n }\n }\n\n /**\n * Standalone-browser stand-in for the native `SAVE_IMAGE` handler: triggers a real\n * browser download (an `<a download>` click) instead of writing to a device photo\n * library, which doesn't exist here. Resolves `{success: true}` on a real trigger so\n * every mini-app's own `result?.success` check gets the same shape/semantics as the\n * real native response — no per-app \"am I in mock mode\" branching needed. Consumers\n * can still keep their own `catch` fallback for the genuinely different case of a\n * native shell that's missing its WebView bridge (see `sendOnce`'s own rejection\n * path) — that's a real native edge case, not mocking, and this method never runs\n * for it (`send()` only reaches `handleMockMessage` when `!isNative()`).\n */\n private mockSaveImage(payload: {\n base64: string;\n filename?: string;\n }): Promise<{ success: boolean }> {\n if (typeof document === \"undefined\") {\n return Promise.resolve({ success: false });\n }\n\n try {\n const href = payload.base64.startsWith(\"data:\")\n ? payload.base64\n : `data:image/png;base64,${payload.base64}`;\n\n const link = document.createElement(\"a\");\n link.href = href;\n link.download = payload.filename\n ? `${payload.filename}.png`\n : \"image.png\";\n document.body.appendChild(link);\n link.click();\n link.remove();\n\n return Promise.resolve({ success: true });\n } catch (err) {\n console.warn(\"[Bridge] Mock SAVE_IMAGE download failed:\", err);\n return Promise.resolve({ success: false });\n }\n }\n\n private sendOnce<T = unknown>(\n type: string,\n payload: unknown,\n timeoutMs: number,\n ): Promise<T> {\n return new Promise((resolve, reject) => {\n const callbackId = `${type}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\n const timeout = setTimeout(() => {\n if (this.callbacks.has(callbackId)) {\n this.callbacks.delete(callbackId);\n reject(new BridgeTimeoutError(`Bridge request timeout: ${type}`));\n }\n }, timeoutMs);\n\n this.callbacks.set(callbackId, {\n reject,\n resolve: resolve as (val: unknown) => void,\n timeout,\n });\n\n const message = {\n callbackId,\n payload,\n type,\n };\n\n const win = window as unknown as {\n ReactNativeWebView?: { postMessage: (msg: string) => void };\n };\n\n if (win.ReactNativeWebView?.postMessage) {\n win.ReactNativeWebView.postMessage(JSON.stringify(message));\n } else {\n clearTimeout(timeout);\n this.callbacks.delete(callbackId);\n reject(new Error(\"Bridge not available\"));\n }\n });\n }\n\n /**\n * Determine environment. Check flag or cache result.\n */\n private isNative(): boolean {\n return isRunningInsideNativeShell();\n }\n}\n","import { cn } from \"@miniapps-sdk/lib/utils\";\nimport * as SheetPrimitive from \"@radix-ui/react-dialog\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { X } from \"lucide-react\";\nimport * as React from \"react\";\n\nconst Sheet = SheetPrimitive.Root;\n\nconst SheetTrigger = SheetPrimitive.Trigger;\n\nconst SheetClose = SheetPrimitive.Close;\n\nconst SheetPortal = SheetPrimitive.Portal;\n\nconst SheetOverlay = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Overlay\n className={cn(\n \"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className,\n )}\n {...props}\n ref={ref}\n />\n));\nSheetOverlay.displayName = SheetPrimitive.Overlay.displayName;\n\nconst sheetVariants = cva(\n \"z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500\",\n {\n defaultVariants: {\n side: \"right\",\n },\n variants: {\n side: {\n bottom:\n \"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom\",\n left: \"inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm\",\n right:\n \"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm\",\n top: \"inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top\",\n },\n },\n },\n);\n\ninterface SheetContentProps\n extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,\n VariantProps<typeof sheetVariants> {\n portal?: boolean;\n}\n\nconst SheetContent = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Content>,\n SheetContentProps\n>(({ side = \"right\", className, children, portal = true, ...props }, ref) => {\n const Content = (\n <SheetPrimitive.Content\n className={cn(\n sheetVariants({ side }),\n portal ? \"fixed\" : \"absolute\",\n className,\n )}\n ref={ref}\n {...props}\n >\n {children}\n <SheetPrimitive.Close className=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-105 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary\">\n <X className=\"h-4 w-4\" />\n <span className=\"sr-only\">Close</span>\n </SheetPrimitive.Close>\n </SheetPrimitive.Content>\n );\n\n if (!portal) {\n return Content;\n }\n\n return (\n <SheetPortal>\n <SheetOverlay />\n {Content}\n </SheetPortal>\n );\n});\nSheetContent.displayName = SheetPrimitive.Content.displayName;\n\nconst SheetHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-2 text-center sm:text-left\",\n className,\n )}\n {...props}\n />\n);\nSheetHeader.displayName = \"SheetHeader\";\n\nconst SheetFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n className,\n )}\n {...props}\n />\n);\nSheetFooter.displayName = \"SheetFooter\";\n\nconst SheetTitle = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Title\n className={cn(\"text-lg font-semibold text-foreground\", className)}\n ref={ref}\n {...props}\n />\n));\nSheetTitle.displayName = SheetPrimitive.Title.displayName;\n\nconst SheetDescription = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Description\n className={cn(\"text-sm text-muted-foreground\", className)}\n ref={ref}\n {...props}\n />\n));\nSheetDescription.displayName = SheetPrimitive.Description.displayName;\n\nexport {\n Sheet,\n SheetClose,\n SheetContent,\n SheetDescription,\n SheetFooter,\n SheetHeader,\n SheetOverlay,\n SheetPortal,\n SheetTitle,\n SheetTrigger,\n};\n","import type { EtaData, MenuItem } from \"@miniapps-sdk/components/Map/types\";\nimport { Button } from \"@miniapps-sdk/components/ui/button\";\nimport {\n Sheet,\n SheetContent,\n SheetHeader,\n SheetTitle,\n} from \"@miniapps-sdk/components/ui/sheet\";\nimport type React from \"react\";\nimport {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\n\nconst resolveHeightToPixels = (\n height: string | number,\n containerHeight: number,\n): number => {\n if (typeof height === \"number\") {\n return height;\n }\n if (height.endsWith(\"%\")) {\n return (parseFloat(height) / 100) * containerHeight;\n }\n return parseFloat(height);\n};\n\nexport type DrawerState = \"closed\" | \"peek\" | \"full\" | \"auto\";\n\n// How far (px) the finger must keep pulling PAST the moment content scroll\n// hits its top/bottom limit before that's treated as \"drag the sheet\"\n// instead of \"the scroll is just settling\" — without this, a fast scroll\n// that naturally stops at the top instantly hijacks into closing the sheet\n// on its very first post-limit touchmove sample.\nconst CONTENT_EDGE_PULL_THRESHOLD_PX = 24;\n\n// Height of the sliver still visible in the \"closed\" state — normally just\n// the handle bar. When the handle is hidden (`handleVisible=false`), the\n// whole panel (including its background/border/shadow) must go fully\n// off-screen too, not just the handle graphic inside it.\nconst HANDLE_BAR_HEIGHT_PX = 32;\n\n// How long a handle-tap's stray delayed synthetic `click` can stay\n// swallowed (see suppressNextClickRef / handleNativeClickCapture below).\n// Only ever consumes the FIRST click that arrives, so this is a ceiling on\n// how long a genuine, separate tap elsewhere in the drawer could be eaten\n// if it happens to land before the stray click does — kept close to the\n// 300ms open/close transition (plus a small margin for this WebView's\n// documented click-delivery lag) rather than a much longer arbitrary value.\nconst HANDLE_TAP_CLICK_SUPPRESSION_MS = 400;\n\nexport interface MapDrawerProps {\n menuItems: MenuItem[];\n state: DrawerState;\n onChangeState: (state: DrawerState) => void;\n side: \"left\" | \"bottom\";\n etaBarHeight?: number;\n etaData?: EtaData;\n\n // Hoisted drag states\n touchStartY: number | null;\n setTouchStartY: (val: number | null) => void;\n currentTouchY: number | null;\n setCurrentTouchY: (val: number | null) => void;\n isDragging: boolean;\n clampedDragOffset: number;\n\n // Drawer customization\n drawerPeekHeight?: string | number;\n drawerFullHeight?: string | number;\n /** Max height the \"auto\" state can grow to. Default \"100%\" (full container height). */\n drawerAutoMaxHeight?: string | number;\n containerHeight?: number;\n menuContent?: React.ReactNode;\n enableTouchDrag?: boolean;\n /** Show/hide the drag-handle bar. Default true. */\n handleVisible?: boolean;\n /**\n * Fires whenever the measured \"auto\" content height changes (px), so a\n * parent (MapControls' drag-clamp math) can size an \"auto\" sheet\n * correctly instead of falling back to a fixed guess.\n */\n onAutoContentHeightChange?: (px: number) => void;\n\n // Scroll to top button customization\n showScrollToTopButton?: boolean;\n scrollToTopThreshold?: number;\n\n // Safe area support\n safeAreaInsets?: { top: number; bottom: number; left: number; right: number };\n}\n\nexport const MapDrawer = forwardRef<HTMLDivElement, MapDrawerProps>(\n (\n {\n menuItems,\n state,\n onChangeState,\n side,\n etaBarHeight = 0,\n etaData,\n touchStartY,\n setTouchStartY,\n currentTouchY,\n setCurrentTouchY,\n isDragging,\n clampedDragOffset,\n drawerPeekHeight,\n drawerFullHeight,\n drawerAutoMaxHeight,\n containerHeight,\n menuContent,\n enableTouchDrag = false,\n handleVisible = true,\n onAutoContentHeightChange,\n showScrollToTopButton = true,\n scrollToTopThreshold = 300,\n safeAreaInsets = { bottom: 0, left: 0, right: 0, top: 0 },\n },\n ref,\n ) => {\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const handleBarRef = useRef<HTMLDivElement>(null);\n const contentAreaRef = useRef<HTMLDivElement>(null);\n\n useImperativeHandle(\n ref,\n () => scrollContainerRef.current as HTMLDivElement,\n );\n\n const handleHandleClick = () => {\n if (side === \"left\") {\n onChangeState(state === \"closed\" ? \"full\" : \"closed\");\n } else {\n if (state === \"closed\") {\n onChangeState(\"peek\");\n } else if (state === \"peek\") {\n onChangeState(\"full\");\n } else if (state === \"auto\") {\n onChangeState(\"closed\");\n } else {\n onChangeState(\"peek\");\n }\n }\n };\n // Mirrored into a ref so the native touch handlers below (which live\n // inside an effect NOT re-created on every `state` change — see\n // `stateRef`) can call the CURRENT click behavior without capturing a\n // stale `state`/`side` closure.\n const handleHandleClickRef = useRef(handleHandleClick);\n handleHandleClickRef.current = handleHandleClick;\n\n // Total drawer height that exactly fits content in \"auto\" state: the\n // scrollable content's real height plus the handle bar and content-area\n // padding, all measured live (not assumed from Tailwind class names —\n // this host app may customize its spacing scale) so the sheet never\n // ends up shorter than what it's actually rendering.\n const [autoContentPx, setAutoContentPx] = useState(0);\n\n useEffect(() => {\n if (state !== \"auto\") return;\n const scrollEl = scrollContainerRef.current;\n const contentAreaEl = contentAreaRef.current;\n if (!scrollEl || !contentAreaEl) return;\n // handleBarRef is only attached when the handle is actually rendered\n // (handleVisible) — fall back to 0 rather than bailing the whole\n // measurement, or auto-sizing would silently stop working the moment\n // a consumer hides the handle.\n const handleHeight = handleVisible\n ? (handleBarRef.current?.offsetHeight ?? 0)\n : 0;\n\n // scrollEl itself is stretched to fill the drawer (flex-1) so its\n // scrollHeight can never read below that stretched box height, even\n // when the actual content is much shorter — scrollHeight is always\n // max(contentHeight, clientHeight). Measure its first child instead,\n // which sizes naturally to the rendered content, not the flex box.\n const contentEl = scrollEl.firstElementChild as HTMLElement | null;\n\n const measure = () => {\n const contentAreaStyle = window.getComputedStyle(contentAreaEl);\n const verticalPadding =\n parseFloat(contentAreaStyle.paddingTop || \"0\") +\n parseFloat(contentAreaStyle.paddingBottom || \"0\");\n const contentHeight = contentEl?.scrollHeight ?? scrollEl.scrollHeight;\n const px = handleHeight + verticalPadding + contentHeight;\n setAutoContentPx(px);\n onAutoContentHeightChange?.(px);\n };\n measure();\n\n const ro = new ResizeObserver(measure);\n ro.observe(contentEl ?? scrollEl);\n return () => ro.disconnect();\n }, [state, handleVisible, onAutoContentHeightChange]);\n\n const [showScrollTop, setShowScrollTop] = useState(false);\n\n const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {\n const scrollTop = e.currentTarget.scrollTop;\n setShowScrollTop(state !== \"closed\" && scrollTop > scrollToTopThreshold);\n };\n\n useEffect(() => {\n if (state === \"closed\") {\n setShowScrollTop(false);\n } else {\n const scrollTop = scrollContainerRef.current?.scrollTop || 0;\n setShowScrollTop(scrollTop > scrollToTopThreshold);\n }\n }, [state, scrollToTopThreshold]);\n\n const isDraggingSheet = useRef(false);\n const hasDeterminedDirection = useRef(false);\n const isTouchOnContent = useRef(false);\n // Whether THIS touch started on the handle bar itself (as opposed to\n // content, or the panel's own padding). Used to detect a genuine tap on\n // the handle directly from the touch pipeline — relying on the\n // browser's synthetic `click` event after a touch sequence turned out\n // to be unreliable in this WebView (click-suppression heuristics after\n // `preventDefault()` during touchmove don't behave consistently here).\n const isTouchOnHandle = useRef(false);\n // Set right after we handle a tap-on-handle ourselves via touchend, so\n // the handle's own onClick (still needed for mouse/non-touch input)\n // doesn't ALSO fire and double-toggle the state for the same physical\n // tap on a touch device where the browser click still goes through.\n const suppressNextClickRef = useRef(false);\n // clientY at the moment content scroll first hit its top/bottom limit\n // THIS gesture — null while not at that limit. Used to require a real\n // pull PAST the limit before hijacking into sheet-dragging, instead of\n // the very first touchmove sample once the limit is reached (which\n // fires immediately when a fast scroll-to-top naturally settles at\n // scrollTop 0 and the finger keeps moving a hair further).\n const contentAtTopSinceY = useRef<number | null>(null);\n const contentAtBottomSinceY = useRef<number | null>(null);\n // clientY + the drawer's own baseline height (for `stateRef.current`) at\n // the MOMENT `isDraggingSheet` became true — NOT the original touchstart.\n // The final snap decision needs \"how far did the user actually drag the\n // sheet\" (a delta from this point), not \"where did their finger end up\n // on screen\" — a content-scroll gesture can end with the finger\n // anywhere, having dragged the sheet itself not at all.\n const dragStartYRef = useRef<number | null>(null);\n const dragBaseHeightPxRef = useRef(0);\n\n // Sync refs to avoid stale closures in native touch listeners\n const stateRef = useRef(state);\n const touchStartYRef = useRef(touchStartY);\n const currentTouchYRef = useRef(currentTouchY);\n\n useEffect(() => {\n stateRef.current = state;\n }, [state]);\n\n useEffect(() => {\n touchStartYRef.current = touchStartY;\n }, [touchStartY]);\n\n useEffect(() => {\n currentTouchYRef.current = currentTouchY;\n }, [currentTouchY]);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container || side !== \"bottom\" || !enableTouchDrag) return;\n\n const handleNativeTouchStart = (e: TouchEvent) => {\n const clientY = e.targetTouches[0].clientY;\n setTouchStartY(clientY);\n setCurrentTouchY(clientY);\n isDraggingSheet.current = false;\n hasDeterminedDirection.current = false;\n contentAtTopSinceY.current = null;\n contentAtBottomSinceY.current = null;\n dragStartYRef.current = null;\n\n const target = e.target as Node;\n isTouchOnContent.current = scrollContainerRef.current\n ? scrollContainerRef.current.contains(target)\n : false;\n isTouchOnHandle.current = handleBarRef.current\n ? handleBarRef.current.contains(target)\n : false;\n };\n\n const handleNativeTouchMove = (e: TouchEvent) => {\n const startY = touchStartYRef.current;\n if (startY === null) return;\n\n const currentY = e.targetTouches[0].clientY;\n const deltaY = startY - currentY; // positive means dragging UP, negative means dragging DOWN\n\n const scrollTop = scrollContainerRef.current\n ? scrollContainerRef.current.scrollTop\n : 0;\n const clientHeight = scrollContainerRef.current\n ? scrollContainerRef.current.clientHeight\n : 0;\n const scrollHeight = scrollContainerRef.current\n ? scrollContainerRef.current.scrollHeight\n : 0;\n const isAtBottom = scrollTop + clientHeight >= scrollHeight - 1;\n const currentState = stateRef.current;\n\n // Computed once per move: the baseline pixel height for every\n // state, needed both to clamp the live drag AND (via\n // dragBaseHeightPxRef, captured only at the instant dragging\n // commits) to make the release decision delta-based instead of\n // absolute-finger-position-based.\n const containerHForHeights =\n containerHeight ||\n container.parentElement?.getBoundingClientRect().height ||\n window.innerHeight;\n const fullPxNow = resolveHeightToPixels(\n drawerFullHeight || \"85%\",\n containerHForHeights,\n );\n const peekPxNow = resolveHeightToPixels(\n drawerPeekHeight || \"15%\",\n containerHForHeights,\n );\n const closedPxNow =\n (handleVisible ? HANDLE_BAR_HEIGHT_PX : 0) +\n (currentState === \"closed\" ? safeAreaInsets.bottom : 0);\n const autoMaxPxNow = resolveHeightToPixels(\n drawerAutoMaxHeight || \"100%\",\n containerHForHeights,\n );\n const autoPxNow = Math.min(autoMaxPxNow, autoContentPx);\n const baselineHeightPxForState = (s: DrawerState) => {\n if (s === \"full\") return fullPxNow;\n if (s === \"peek\") return peekPxNow;\n if (s === \"auto\") return autoPxNow;\n return closedPxNow;\n };\n const commitDrag = () => {\n isDraggingSheet.current = true;\n dragStartYRef.current = currentY;\n dragBaseHeightPxRef.current = baselineHeightPxForState(currentState);\n };\n\n // Track how far the finger has kept moving PAST the moment content\n // scroll hit its limit this gesture — not the raw deltaY since\n // touchstart, which is already large by the time a long scroll\n // reaches the top/bottom and would make the threshold below a\n // no-op for exactly the scenario it's meant to catch.\n if (scrollTop <= 0) {\n if (contentAtTopSinceY.current === null) {\n contentAtTopSinceY.current = currentY;\n }\n } else {\n contentAtTopSinceY.current = null;\n }\n if (isAtBottom) {\n if (contentAtBottomSinceY.current === null) {\n contentAtBottomSinceY.current = currentY;\n }\n } else {\n contentAtBottomSinceY.current = null;\n }\n const pullPastTop =\n contentAtTopSinceY.current !== null\n ? currentY - contentAtTopSinceY.current\n : 0;\n const pullPastBottom =\n contentAtBottomSinceY.current !== null\n ? contentAtBottomSinceY.current - currentY\n : 0;\n\n if (!hasDeterminedDirection.current) {\n if (!isTouchOnContent.current) {\n // Dragging the handle always controls the sheet — but only\n // once there's real movement. Committing (and calling\n // preventDefault below) on the very first touchmove sample,\n // even a couple px of tap jitter, suppresses the browser's\n // synthetic click event that follows touchend — which is the\n // ONLY thing that reopens a closed drawer via a plain tap on\n // the handle. Wait for genuine drag distance first.\n if (Math.abs(deltaY) < CONTENT_EDGE_PULL_THRESHOLD_PX) {\n return;\n }\n commitDrag();\n hasDeterminedDirection.current = true;\n } else if (currentState !== \"full\") {\n // Dragging content in peek/closed state:\n // Can drag UP to full only if already at the bottom, and pulled\n // past that point by more than a hair-trigger\n // Can drag DOWN to close only if already at the top, same deal\n if (\n deltaY > 0 &&\n isAtBottom &&\n pullPastBottom >= CONTENT_EDGE_PULL_THRESHOLD_PX\n ) {\n commitDrag();\n hasDeterminedDirection.current = true;\n } else if (\n deltaY < 0 &&\n scrollTop <= 0 &&\n pullPastTop >= CONTENT_EDGE_PULL_THRESHOLD_PX\n ) {\n commitDrag();\n hasDeterminedDirection.current = true;\n } else if (\n (deltaY > 0 && isAtBottom) ||\n (deltaY < 0 && scrollTop <= 0)\n ) {\n // At the edge and pulling the right way, but hasn't cleared\n // the threshold yet — wait for more movement before deciding\n // either way, so a scroll that's about to naturally settle\n // doesn't get hijacked into a sheet drag on its first sample.\n return;\n } else {\n // Otherwise, let the content scroll\n isDraggingSheet.current = false;\n hasDeterminedDirection.current = true;\n }\n } else {\n // In full state: dragging down at the very top of content drags the sheet down\n if (\n deltaY < 0 &&\n scrollTop <= 0 &&\n pullPastTop >= CONTENT_EDGE_PULL_THRESHOLD_PX\n ) {\n commitDrag();\n hasDeterminedDirection.current = true;\n } else if (deltaY < 0 && scrollTop <= 0) {\n // At the top and pulling down, but not past threshold yet\n return;\n } else {\n // Dragging up or scroll is not at top: scrolls the container content\n isDraggingSheet.current = false;\n hasDeterminedDirection.current = true;\n }\n }\n } else if (!isDraggingSheet.current && isTouchOnContent.current) {\n // Transition from scroll to sheet dragging mid-gesture when reaching top or bottom limits\n if (\n deltaY < 0 &&\n scrollTop <= 0 &&\n pullPastTop >= CONTENT_EDGE_PULL_THRESHOLD_PX\n ) {\n commitDrag();\n return;\n }\n if (\n deltaY > 0 &&\n isAtBottom &&\n currentState !== \"full\" &&\n pullPastBottom >= CONTENT_EDGE_PULL_THRESHOLD_PX\n ) {\n commitDrag();\n return;\n }\n }\n\n if (isDraggingSheet.current) {\n if (e.cancelable) {\n e.preventDefault();\n }\n\n const parentContainer = container.parentElement;\n if (parentContainer) {\n // Rebased to the moment dragging actually started, not the\n // original touchstart — a content-scroll gesture can travel a\n // long way (and back) before ever becoming a sheet drag, and\n // that distance must not count as drag offset.\n const dragOffset = currentY - (dragStartYRef.current ?? currentY);\n let localClamped = dragOffset;\n\n if (currentState === \"full\") {\n localClamped = Math.max(\n 0,\n Math.min(fullPxNow - closedPxNow, dragOffset),\n );\n } else if (currentState === \"peek\") {\n localClamped = Math.max(\n -(fullPxNow - peekPxNow),\n Math.min(peekPxNow - closedPxNow, dragOffset),\n );\n } else if (currentState === \"closed\") {\n localClamped = Math.min(\n 0,\n Math.max(-(fullPxNow - closedPxNow), dragOffset),\n );\n } else if (currentState === \"auto\") {\n // Auto-sized sheets only support dragging down to dismiss.\n localClamped = Math.max(0, dragOffset);\n }\n\n parentContainer.style.setProperty(\n \"--drag-offset\",\n `${localClamped}px`,\n );\n }\n }\n };\n\n const handleNativeTouchEnd = (e: TouchEvent) => {\n const startY = touchStartYRef.current;\n const currentY = currentTouchYRef.current;\n const parentContainer = container.parentElement;\n\n if (startY === null || currentY === null) {\n if (parentContainer) {\n parentContainer.style.setProperty(\"--drag-offset\", \"0px\");\n }\n return;\n }\n\n if (!isDraggingSheet.current) {\n // A tap that never became a drag. Trigger the handle's click\n // behavior directly from here instead of waiting on the\n // browser's own synthetic `click` event — that event isn't\n // reliably delivered in every WebView after a touch sequence\n // that included `preventDefault()`-capable listeners, which was\n // silently breaking \"tap the handle to reopen a closed drawer\".\n if (isTouchOnHandle.current) {\n handleHandleClickRef.current();\n suppressNextClickRef.current = true;\n setTimeout(() => {\n suppressNextClickRef.current = false;\n }, HANDLE_TAP_CLICK_SUPPRESSION_MS);\n }\n setTouchStartY(null);\n setCurrentTouchY(null);\n if (parentContainer) {\n parentContainer.style.setProperty(\"--drag-offset\", \"0px\");\n }\n return;\n }\n\n const touchEndY = e.changedTouches[0].clientY;\n // Rebased to when dragging actually started — NOT the original\n // touchstart, which for a content-scroll-turned-drag gesture could\n // be far away (and in the opposite direction) from any real\n // intentional pull on the sheet itself.\n const dragStartY = dragStartYRef.current ?? startY;\n const dragDistance = Math.abs(touchEndY - dragStartY);\n\n if (dragDistance < 10) {\n setTouchStartY(null);\n setCurrentTouchY(null);\n if (parentContainer) {\n parentContainer.style.setProperty(\"--drag-offset\", \"0px\");\n }\n return;\n }\n\n const containerH =\n containerHeight ||\n (parentContainer\n ? parentContainer.getBoundingClientRect().height\n : window.innerHeight);\n\n const fullPx = resolveHeightToPixels(\n drawerFullHeight || \"85%\",\n containerH,\n );\n const peekPx = resolveHeightToPixels(\n drawerPeekHeight || \"15%\",\n containerH,\n );\n const currentState = stateRef.current;\n const closedPx =\n (handleVisible ? HANDLE_BAR_HEIGHT_PX : 0) +\n (currentState === \"closed\" ? safeAreaInsets.bottom : 0);\n\n // Target height = the baseline height AT THE MOMENT dragging\n // started, minus however far the finger has actually moved since\n // then (down = shorter). This is what makes the release decision\n // reflect actual drag distance instead of the finger's absolute\n // position on screen — the latter is meaningless once dragging can\n // start mid-content-scroll, from anywhere on the screen.\n const dragDelta = touchEndY - dragStartY;\n const drawerHeightFromBottom = dragBaseHeightPxRef.current - dragDelta;\n\n const distToClosed = Math.abs(drawerHeightFromBottom - closedPx);\n\n let targetState: DrawerState;\n if (currentState === \"auto\") {\n // Auto-sized sheets only snap between their content height and\n // closed, capped at drawerAutoMaxHeight (default 100% of the\n // container) — NOT drawerFullHeight, which defaults to a much\n // smaller 85% and would clip taller auto content.\n const autoMaxPx = resolveHeightToPixels(\n drawerAutoMaxHeight || \"100%\",\n containerH,\n );\n const autoPx = Math.min(autoMaxPx, autoContentPx);\n const distToAuto = Math.abs(drawerHeightFromBottom - autoPx);\n targetState = distToAuto <= distToClosed ? \"auto\" : \"closed\";\n } else {\n const distToFull = Math.abs(drawerHeightFromBottom - fullPx);\n const distToPeek = Math.abs(drawerHeightFromBottom - peekPx);\n const minDist = Math.min(distToFull, distToPeek, distToClosed);\n\n if (minDist === distToFull) {\n targetState = \"full\";\n } else if (minDist === distToPeek) {\n targetState = \"peek\";\n } else {\n targetState = \"closed\";\n }\n }\n\n // Re-enable transition properties\n setTouchStartY(null);\n setCurrentTouchY(null);\n onChangeState(targetState);\n\n // Snap from current drag coordinates by delaying cleanup of compositor offset\n requestAnimationFrame(() => {\n if (parentContainer) {\n parentContainer.style.setProperty(\"--drag-offset\", \"0px\");\n }\n });\n };\n\n // The browser's synthetic `click` that follows a handled handle-tap\n // (see handleNativeTouchEnd's isTouchOnHandle branch) can be delivered\n // late enough in this WebView that the 300ms open/close transform has\n // already moved the drawer by the time it fires — `elementFromPoint`\n // at the original touch coordinates then resolves to whatever slid\n // into that spot (typically the first list item now revealed under\n // the handle), not the handle itself. suppressNextClickRef alone only\n // guarded the handle's OWN onClick, so that stray click still reached\n // — and activated — the element underneath. A capture-phase listener\n // on the whole container intercepts it before it can reach ANY\n // descendant, regardless of which one ends up under the pointer.\n // Assumes the shifted touch point stays within `container`'s own box\n // (true for the default peek/full heights — the animated shift is\n // always well under the container's own fullPx height); an extreme\n // custom drawerPeekHeight/drawerFullHeight config could theoretically\n // move it outside, escaping this guard.\n const handleNativeClickCapture = (e: MouseEvent) => {\n if (!suppressNextClickRef.current) return;\n suppressNextClickRef.current = false;\n e.preventDefault();\n e.stopPropagation();\n };\n\n container.addEventListener(\"touchstart\", handleNativeTouchStart, {\n passive: true,\n });\n container.addEventListener(\"touchmove\", handleNativeTouchMove, {\n passive: false,\n });\n container.addEventListener(\"touchend\", handleNativeTouchEnd, {\n passive: true,\n });\n container.addEventListener(\"click\", handleNativeClickCapture, {\n capture: true,\n });\n\n return () => {\n container.removeEventListener(\"touchstart\", handleNativeTouchStart);\n container.removeEventListener(\"touchmove\", handleNativeTouchMove);\n container.removeEventListener(\"touchend\", handleNativeTouchEnd);\n container.removeEventListener(\"click\", handleNativeClickCapture, {\n capture: true,\n });\n };\n }, [\n side,\n enableTouchDrag,\n containerHeight,\n drawerFullHeight,\n drawerPeekHeight,\n drawerAutoMaxHeight,\n safeAreaInsets,\n onChangeState,\n setTouchStartY,\n setCurrentTouchY,\n autoContentPx,\n handleVisible,\n ]);\n\n // Backdrop visible (and tap-outside-to-close active) when fully open OR\n // auto-sized — both are modal-style sheets that cover meaningful screen\n // real estate, unlike peek/closed which leave the map fully usable.\n const isBackdropActive = state === \"full\" || state === \"auto\";\n const backdropStyles = isBackdropActive\n ? \"opacity-100 pointer-events-auto\"\n : \"opacity-0 pointer-events-none\";\n\n const containerH = containerHeight || window.innerHeight;\n const fullPx = resolveHeightToPixels(drawerFullHeight || \"85%\", containerH);\n const peekPx = resolveHeightToPixels(drawerPeekHeight || \"15%\", containerH);\n const autoMaxPx = resolveHeightToPixels(\n drawerAutoMaxHeight || \"100%\",\n containerH,\n );\n const shiftPx = fullPx - peekPx;\n const autoPx = Math.min(autoMaxPx, autoContentPx);\n // The box itself is Math.max(fullPx, autoPx) tall in \"auto\" (see the\n // `height` style below) — a taller-than-fullPx box needs zero extra\n // shift to be fully revealed, it's already sized to exactly fit.\n const autoShiftPx = Math.max(fullPx - autoPx, 0);\n\n // Calculate bottom drawer transform dynamically to enable smooth hardware-accelerated transitions\n const getBottomDrawerTransform = () => {\n if (state === \"full\") {\n return \"translateY(var(--drag-offset, 0px))\";\n }\n if (state === \"peek\") {\n return `translateY(calc(${shiftPx}px + var(--drag-offset, 0px)))`;\n }\n if (state === \"auto\") {\n return `translateY(calc(${autoShiftPx}px + var(--drag-offset, 0px)))`;\n }\n // Closed state: show only the drag handle bar — or nothing at all\n // (fully off-screen) when the handle itself is hidden, so no sliver\n // of the panel's background/border/shadow peeks through.\n const closedVisibleHeight = handleVisible ? HANDLE_BAR_HEIGHT_PX : 0;\n const closedShiftPx = fullPx - closedVisibleHeight;\n return `translateY(calc(${closedShiftPx}px + var(--drag-offset, 0px)))`;\n };\n\n return (\n <>\n <style>{`\n .no-scrollbar {\n -ms-overflow-style: none;\n scrollbar-width: none;\n }\n .no-scrollbar::-webkit-scrollbar {\n display: none;\n }\n `}</style>\n\n {/* Backdrop overlay for closing on outside tap */}\n <div\n className={`absolute inset-0 bg-black/45 backdrop-blur-[1px] transition-opacity duration-300 z-30 ${backdropStyles}`}\n onClick={() => onChangeState(\"closed\")}\n />\n\n {side === \"left\" ? (\n <>\n {state === \"closed\" && (\n <Button\n 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!\"\n onClick={() => onChangeState(\"full\")}\n variant=\"ghost\"\n >\n <svg\n fill=\"none\"\n height=\"24\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2\"\n viewBox=\"0 0 24 24\"\n width=\"24\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <line x1=\"4\" x2=\"20\" y1=\"12\" y2=\"12\" />\n <line x1=\"4\" x2=\"20\" y1=\"6\" y2=\"6\" />\n <line x1=\"4\" x2=\"20\" y1=\"18\" y2=\"18\" />\n </svg>\n </Button>\n )}\n <Sheet\n onOpenChange={(open) => onChangeState(open ? \"full\" : \"closed\")}\n open={state !== \"closed\"}\n >\n <SheetContent\n 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\"\n portal={false}\n side=\"left\"\n >\n <SheetHeader className=\"pb-3 border-b border-white/10 mb-2 text-left\">\n <SheetTitle className=\"text-sm font-bold tracking-wider text-zinc-400 uppercase\">\n Menu\n </SheetTitle>\n </SheetHeader>\n\n <div\n className=\"flex-1 overflow-y-auto no-scrollbar pr-2\"\n onScroll={handleScroll}\n ref={scrollContainerRef}\n >\n {menuContent ? (\n menuContent\n ) : (\n <div className=\"flex flex-col gap-1.5\">\n {menuItems.map((item) => (\n <Button\n 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 ${\n item.disabled\n ? \"opacity-45 cursor-not-allowed pointer-events-none\"\n : \"\"\n }`}\n disabled={item.disabled}\n key={item.id}\n onClick={() => {\n if (!item.disabled) {\n item.onPress();\n onChangeState(\"closed\");\n }\n }}\n variant=\"ghost\"\n >\n <div className=\"relative flex items-center justify-center w-8 h-8 rounded-lg bg-white/5 text-zinc-300\">\n {item.icon}\n {item.badge !== undefined && (\n <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\">\n {item.badge}\n </span>\n )}\n </div>\n <span className=\"text-sm font-medium tracking-wide flex-1\">\n {item.label}\n </span>\n </Button>\n ))}\n </div>\n )}\n </div>\n\n {showScrollToTopButton && showScrollTop && (\n <Button\n 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!\"\n onClick={() => {\n scrollContainerRef.current?.scrollTo({\n behavior: \"smooth\",\n top: 0,\n });\n }}\n variant=\"ghost\"\n >\n <svg\n fill=\"none\"\n height=\"20\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2.5\"\n viewBox=\"0 0 24 24\"\n width=\"20\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <polyline points=\"18 15 12 9 6 15\"></polyline>\n </svg>\n </Button>\n )}\n </SheetContent>\n </Sheet>\n </>\n ) : (\n /* Bottom Sheet Panel - Hardware accelerated translateY transitions */\n <div\n 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 ${\n isDragging\n ? \"transition-none\"\n : \"transition-transform duration-300 ease-out\"\n }`}\n ref={containerRef}\n style={{\n bottom: \"0px\",\n // Box height must stay exactly fullPx for \"closed\"/\"peek\"/\n // \"full\" — every other transform calc in this component\n // assumes the box IS fullPx tall. Only \"auto\" grows it (up to\n // autoMaxPx) when content needs more room than fullPx offers;\n // getBottomDrawerTransform()'s auto branch is derived to match\n // (shift = max(fullPx - autoPx, 0), so a taller box needs zero\n // extra shift to fully reveal itself).\n height: `${state === \"auto\" ? Math.max(fullPx, autoPx) : fullPx}px`,\n marginBottom:\n state === \"closed\" ? `${safeAreaInsets.bottom}px` : \"0px\",\n transform: getBottomDrawerTransform(),\n // `height` is animated too (not just transform/margin-bottom):\n // entering/leaving \"auto\" with content taller than fullPx\n // changes the box's actual CSS height, and without this it\n // would snap instantly while transform eases in over 300ms —\n // a visible pop of content before the slide animation catches\n // up.\n transition: isDragging\n ? \"none\"\n : \"transform 300ms ease-out, height 300ms ease-out, margin-bottom 250ms ease-in-out\",\n }}\n >\n {/* Bottom Sheet Handle Bar */}\n {handleVisible && (\n <div\n 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\"\n onClick={() => {\n // Defensive fallback only — in practice the capture-phase\n // handleNativeClickCapture (registered on the container\n // above) already stops a suppressed click before it can\n // reach this handler at all. Kept in case a future change\n // ever calls handleHandleClick a different way that\n // bypasses that capture listener.\n if (suppressNextClickRef.current) return;\n handleHandleClick();\n }}\n ref={handleBarRef}\n >\n <div className=\"w-12 h-1 bg-white/25 rounded-full\" />\n </div>\n )}\n\n {/* Content Area */}\n <div\n className=\"flex-1 flex flex-col overflow-hidden px-4 pb-4 pt-2 transition-[margin-top] duration-250 ease-in-out relative\"\n ref={contentAreaRef}\n style={{\n marginTop:\n state === \"closed\" ? `${safeAreaInsets.bottom}px` : \"0px\",\n }}\n >\n {/* Menu items scrollable list */}\n <div\n className=\"flex-1 overflow-y-auto no-scrollbar\"\n onScroll={handleScroll}\n ref={scrollContainerRef}\n style={{\n paddingBottom: state === \"peek\" ? `${shiftPx}px` : \"0px\",\n }}\n >\n {menuContent ? (\n menuContent\n ) : (\n <div className=\"flex flex-col gap-1\">\n {menuItems.map((item) => (\n <Button\n 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 ${\n item.disabled\n ? \"opacity-45 cursor-not-allowed pointer-events-none\"\n : \"\"\n }`}\n disabled={item.disabled}\n key={item.id}\n onClick={() => {\n if (!item.disabled) {\n item.onPress();\n onChangeState(\"closed\");\n }\n }}\n variant=\"ghost\"\n >\n <div className=\"relative flex items-center justify-center w-8 h-8 rounded-lg bg-white/5 text-zinc-300\">\n {item.icon}\n {item.badge !== undefined && (\n <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\">\n {item.badge}\n </span>\n )}\n </div>\n <span className=\"text-sm font-medium tracking-wide\">\n {item.label}\n </span>\n </Button>\n ))}\n </div>\n )}\n </div>\n\n {showScrollToTopButton && showScrollTop && (\n <Button\n 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!\"\n onClick={() => {\n scrollContainerRef.current?.scrollTo({\n behavior: \"smooth\",\n top: 0,\n });\n }}\n style={{\n bottom:\n state === \"peek\"\n ? `calc(${24 + shiftPx}px + var(--drag-offset, 0px))`\n : `calc(24px + var(--drag-offset, 0px))`,\n }}\n variant=\"ghost\"\n >\n <svg\n fill=\"none\"\n height=\"20\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2.5\"\n viewBox=\"0 0 24 24\"\n width=\"20\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <polyline points=\"18 15 12 9 6 15\"></polyline>\n </svg>\n </Button>\n )}\n </div>\n </div>\n )}\n </>\n );\n },\n);\n","import { cn } from \"@miniapps-sdk/lib/utils\";\nimport * as React from \"react\";\n\nconst Card = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n className={cn(\n \"rounded-lg border bg-card text-card-foreground shadow-sm\",\n className,\n )}\n ref={ref}\n {...props}\n />\n));\nCard.displayName = \"Card\";\n\nconst CardHeader = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n className={cn(\"flex flex-col space-y-1.5 p-6\", className)}\n ref={ref}\n {...props}\n />\n));\nCardHeader.displayName = \"CardHeader\";\n\nconst CardTitle = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n className={cn(\n \"text-2xl font-semibold leading-none tracking-tight\",\n className,\n )}\n ref={ref}\n {...props}\n />\n));\nCardTitle.displayName = \"CardTitle\";\n\nconst CardDescription = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n className={cn(\"text-sm text-muted-foreground\", className)}\n ref={ref}\n {...props}\n />\n));\nCardDescription.displayName = \"CardDescription\";\n\nconst CardContent = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div className={cn(\"p-6 pt-0\", className)} ref={ref} {...props} />\n));\nCardContent.displayName = \"CardContent\";\n\nconst CardFooter = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n className={cn(\"flex items-center p-6 pt-0\", className)}\n ref={ref}\n {...props}\n />\n));\nCardFooter.displayName = \"CardFooter\";\n\nexport {\n Card,\n CardContent,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n};\n","import type { EtaData } from \"@miniapps-sdk/components/Map/types\";\nimport { Button } from \"@miniapps-sdk/components/ui/button\";\nimport { Card, CardContent } from \"@miniapps-sdk/components/ui/card\";\nimport type React from \"react\";\n\nexport interface MapEtaPanelProps {\n etaData: EtaData;\n layoutMode: \"closed-banner\" | \"open-card\" | \"floating-card\";\n onHeaderClick?: () => void;\n style?: React.CSSProperties;\n isDragging?: boolean;\n}\n\nexport const MapEtaPanel: React.FC<MapEtaPanelProps> = ({\n etaData,\n layoutMode,\n onHeaderClick,\n style,\n isDragging = false,\n}) => {\n if (layoutMode === \"closed-banner\") {\n return (\n <div className=\"w-full h-10 flex items-center justify-between px-4 pb-2 pt-1 border-b border-white/5 bg-zinc-950/15 relative overflow-hidden\">\n <div\n className=\"flex items-center gap-2 cursor-pointer flex-1\"\n onClick={onHeaderClick}\n >\n <span className=\"w-2 h-2 rounded-full bg-emerald-500 animate-pulse\" />\n <span className=\"text-xs font-bold text-emerald-400\">\n {etaData.etaMins} min ({etaData.distanceRemainingKm.toFixed(1)} km)\n </span>\n </div>\n {etaData.onAbort && (\n <Button\n className=\"px-1 py-1 text-[10px] font-black bg-red-500/20 text-red-400 hover:bg-red-500/30 border border-red-500/25 active:scale-95 rounded-md transition-all cursor-pointer pointer-events-auto h-auto p-0!\"\n onClick={(e) => {\n e.stopPropagation();\n etaData.onAbort?.();\n }}\n variant=\"ghost\"\n >\n <svg\n className=\"lucide lucide-x\"\n fill=\"none\"\n height=\"18\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2.5\"\n viewBox=\"0 0 24 24\"\n width=\"18\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M18 6 6 18\"></path>\n <path d=\"m6 6 12 12\"></path>\n </svg>\n </Button>\n )}\n {etaData.progress !== undefined && (\n <div className=\"absolute bottom-0 left-0 right-0 h-[2px] bg-white/5\">\n <div\n className=\"h-full bg-cyan-400\"\n style={{ width: `${etaData.progress}%` }}\n />\n </div>\n )}\n </div>\n );\n }\n\n if (layoutMode === \"open-card\") {\n return (\n <Card className=\"mx-4 mt-2 p-4 bg-white/5 border border-white/10 rounded-xl flex flex-col text-card-foreground\">\n <div className=\"flex items-center justify-between mb-2\">\n <div className=\"flex items-center gap-2\">\n <span className=\"w-2 h-2 rounded-full bg-emerald-500 animate-pulse\" />\n <span className=\"text-[10px] font-bold text-emerald-400 uppercase tracking-wider\">\n {etaData.label || \"Journey Active\"}\n </span>\n </div>\n {etaData.onAbort && (\n <Button\n className=\"px-1 py-1 text-xs font-bold bg-red-500/20 text-red-400 hover:bg-red-500/30 border border-red-500/30 active:scale-95 rounded-lg transition-all cursor-pointer pointer-events-auto h-auto p-0!\"\n onClick={etaData.onAbort}\n variant=\"ghost\"\n >\n <svg\n className=\"lucide lucide-x\"\n fill=\"none\"\n height=\"18\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2.5\"\n viewBox=\"0 0 24 24\"\n width=\"18\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M18 6 6 18\"></path>\n <path d=\"m6 6 12 12\"></path>\n </svg>\n </Button>\n )}\n </div>\n\n <CardContent className=\"p-0 flex flex-col\">\n <div className=\"grid grid-cols-2 divide-x divide-white/10 py-1.5 mb-2.5\">\n <div className=\"text-center\">\n <div className=\"text-xl font-black text-white leading-none\">\n {etaData.etaMins}\n <span className=\"text-xs text-zinc-400 font-normal\"> min</span>\n </div>\n <div className=\"text-[8px] text-zinc-500 font-bold uppercase tracking-wider mt-1\">\n Time Remaining\n </div>\n </div>\n <div className=\"text-center\">\n <div className=\"text-xl font-black text-white leading-none\">\n {etaData.distanceRemainingKm.toFixed(1)}\n <span className=\"text-xs text-zinc-400 font-normal\"> km</span>\n </div>\n <div className=\"text-[8px] text-zinc-500 font-bold uppercase tracking-wider mt-1\">\n Distance Remaining\n </div>\n </div>\n </div>\n\n {etaData.progress !== undefined && (\n <div className=\"mb-3\">\n <div className=\"flex justify-between text-[9px] font-bold text-zinc-400 mb-1\">\n <span>Progress</span>\n <span>{Math.round(etaData.progress)}%</span>\n </div>\n <div className=\"h-1 bg-white/10 rounded-full overflow-hidden\">\n <div\n className=\"h-full bg-cyan-400 rounded-full\"\n style={{ width: `${etaData.progress}%` }}\n />\n </div>\n </div>\n )}\n\n {etaData.mode === \"preview\" && etaData.onStart && (\n <Button\n className=\"w-full py-2.5 text-xs font-bold bg-cyan-500 text-black hover:bg-cyan-400 hover:text-black active:scale-95 rounded-lg transition-all cursor-pointer h-auto\"\n onClick={etaData.onStart}\n variant=\"ghost\"\n >\n Start Guidance\n </Button>\n )}\n </CardContent>\n </Card>\n );\n }\n\n // floating-card (centered at bottom of map)\n return (\n <Card\n className={`absolute left-1/2 -translate-x-1/2 z-40 w-[calc(100%-2rem)] max-w-[320px] sm:max-w-[380px] bg-zinc-950/85 backdrop-blur-md border border-white/10 rounded-2xl shadow-2xl p-3 sm:p-4 flex flex-col pointer-events-auto select-none text-card-foreground ${\n isDragging ? \"transition-none\" : \"transition-all duration-300 ease-out\"\n }`}\n style={style}\n >\n <div className=\"flex items-center justify-between mb-2 sm:mb-3\">\n <div className=\"flex items-center gap-2\">\n <span className=\"w-1.5 h-1.5 sm:w-2 sm:h-2 rounded-full bg-emerald-500 animate-pulse\" />\n <span className=\"text-[9px] sm:text-[10px] font-bold text-emerald-400 uppercase tracking-wider\">\n {etaData.label || \"Guidance Active\"}\n </span>\n </div>\n {etaData.onAbort && (\n <Button\n className=\"px-1 py-1 text-[10px] sm:text-xs font-bold bg-red-500/20 text-red-400 hover:bg-red-500/30 border border-red-500/30 active:scale-95 rounded-lg transition-all cursor-pointer h-auto p-0!\"\n onClick={etaData.onAbort}\n variant=\"ghost\"\n >\n <svg\n className=\"lucide lucide-x\"\n fill=\"none\"\n height=\"18\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2.5\"\n viewBox=\"0 0 24 24\"\n width=\"18\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M18 6 6 18\"></path>\n <path d=\"m6 6 12 12\"></path>\n </svg>\n </Button>\n )}\n </div>\n\n <CardContent className=\"p-0 flex flex-col\">\n <div className=\"grid grid-cols-2 divide-x divide-white/10 py-0.5 sm:py-1 mb-2 sm:mb-3\">\n <div className=\"text-center\">\n <div className=\"text-base sm:text-lg font-black text-white leading-none\">\n {etaData.etaMins}\n <span className=\"text-[10px] sm:text-xs text-zinc-400 font-normal\">\n {\" \"}\n min\n </span>\n </div>\n </div>\n <div className=\"text-center\">\n <div className=\"text-base sm:text-lg font-black text-white leading-none\">\n {etaData.distanceRemainingKm.toFixed(1)}\n <span className=\"text-[10px] sm:text-xs text-zinc-400 font-normal\">\n {\" \"}\n km\n </span>\n </div>\n </div>\n </div>\n\n {etaData.progress !== undefined && (\n <div>\n <div className=\"flex justify-between text-[8px] sm:text-[9px] font-bold text-zinc-400 mb-1\">\n <span>Progress</span>\n <span>{Math.round(etaData.progress)}%</span>\n </div>\n <div className=\"h-1 sm:h-1.5 bg-white/10 rounded-full overflow-hidden\">\n <div\n className=\"h-full bg-cyan-400 rounded-full\"\n style={{ width: `${etaData.progress}%` }}\n />\n </div>\n </div>\n )}\n\n {etaData.mode === \"preview\" && etaData.onStart && (\n <Button\n className=\"mt-2.5 sm:mt-3 py-1.5 sm:py-2 text-[11px] sm:text-xs font-bold bg-cyan-500 text-black hover:bg-cyan-400 hover:text-black active:scale-95 rounded-lg transition-all cursor-pointer h-auto\"\n onClick={etaData.onStart}\n variant=\"ghost\"\n >\n Start Guidance\n </Button>\n )}\n </CardContent>\n </Card>\n );\n};\n","import type { CenterCallbackParams } from \"@miniapps-sdk/components\";\nimport type {\n CustomControl,\n EtaData,\n} from \"@miniapps-sdk/components/Map/types\";\nimport { Button } from \"@miniapps-sdk/components/ui/button\";\nimport type { ViewState } from \"@vis.gl/react-maplibre\";\nimport type React from \"react\";\nimport type { DrawerState } from \"./MapDrawer\";\n\nexport interface MapRightControlsProps {\n customControls?: CustomControl[];\n etaBarHeight: number;\n onRecenter: (params?: CenterCallbackParams) => void;\n isMapCentered: boolean;\n mapBearing: number;\n mapPitch: number;\n onResetBearing: (params?: CenterCallbackParams) => void;\n drawerState: DrawerState;\n side: \"left\" | \"bottom\";\n etaData?: EtaData;\n initialViewState?: Partial<ViewState>;\n\n isDragging: boolean;\n clampedDragOffset: number;\n\n // Custom button overrides passed down from facade\n customRecenterButton?: React.ReactNode;\n customCompassButton?: React.ReactNode;\n\n // Drawer customization\n drawerPeekHeight?: string | number;\n\n // Safe area insets\n insets?: { top: number; bottom: number; left: number; right: number };\n\n // Extra bottom offset (px) independent of ETA/drawer state — e.g. to clear\n // a fixed center-screen button that would otherwise overlap the stack.\n bottomOffset?: number;\n}\n\nexport const MapRightControls: React.FC<MapRightControlsProps> = ({\n customControls = [],\n etaBarHeight,\n onRecenter,\n isMapCentered,\n mapBearing,\n mapPitch,\n onResetBearing,\n initialViewState,\n drawerState,\n side,\n etaData,\n isDragging,\n clampedDragOffset,\n customRecenterButton,\n customCompassButton,\n drawerPeekHeight,\n insets = { bottom: 0, left: 0, right: 0, top: 0 },\n bottomOffset = 0,\n}) => {\n const aboveControls = customControls.filter(\n (c) => c.position === \"above-recenter\",\n );\n const belowControls = customControls.filter(\n (c) => c.position === \"below-recenter\",\n );\n\n const isCompassVisible =\n Math.abs(mapBearing) >= 0.5 || Math.abs(mapPitch) >= 0.5;\n\n // Since ETA is floating outside the drawer, the closed drawer height is always 32px (the handle).\n const closedHeightOffset = \"32px\";\n\n // If ETA is active, shift controls up by etaBarHeight to avoid overlapping the centered floating ETA card.\n // Note: when drawer is closed, etaBarHeight already includes bottom inset passed from MapControls\n const activeEtaHeight = etaData\n ? etaBarHeight\n : drawerState === \"closed\"\n ? insets.bottom\n : 0;\n\n const peekStyle =\n typeof drawerPeekHeight === \"number\"\n ? `${drawerPeekHeight}px`\n : drawerPeekHeight || \"15%\";\n\n // Compute bottom positioning offset:\n // If drawer is closed: sits above closed height + active ETA bar height (or inset) + margin\n // If drawer is peek: sits above peek height sheet + active ETA bar height + margin\n const controlsBottom =\n side === \"bottom\"\n ? drawerState === \"closed\"\n ? `calc(${closedHeightOffset} + 1rem + ${activeEtaHeight}px + ${bottomOffset}px - var(--drag-offset, 0px))`\n : `calc(${peekStyle} + 1rem + ${etaData ? etaBarHeight : 0}px + ${bottomOffset}px - var(--drag-offset, 0px))`\n : `calc(1rem + ${insets.bottom}px + ${bottomOffset}px)`;\n\n // Hide right-side controls entirely when drawer is fully open in bottom mode\n const isControlsVisible = side !== \"bottom\" || drawerState !== \"full\";\n\n return (\n <div\n className={`absolute right-4 z-30 flex flex-col items-center gap-3 select-none pointer-events-none ${\n isDragging ? \"transition-none\" : \"transition-all duration-300 ease-out\"\n } ${\n isControlsVisible\n ? \"opacity-100 scale-100 pointer-events-auto\"\n : \"opacity-0 scale-75 pointer-events-none\"\n }`}\n style={{\n bottom: controlsBottom,\n }}\n >\n {/* ABOVE-RECENTER CUSTOM CONTROLS */}\n {aboveControls.length > 0 && (\n <div className=\"flex flex-col gap-2 pointer-events-auto\">\n {aboveControls.map((control) => (\n <div className=\"relative group flex items-center\" key={control.id}>\n {/* Tooltip */}\n {control.tooltip && (\n <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\">\n {control.tooltip}\n </div>\n )}\n\n {/* Action Button */}\n <Button\n 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 ${\n control.activeState\n ? \"ring-2 ring-cyan-400 ring-offset-2 ring-offset-zinc-950\"\n : \"\"\n }`}\n onClick={control.onPress}\n variant=\"ghost\"\n >\n {control.icon}\n </Button>\n </div>\n ))}\n </div>\n )}\n\n {/* COMPASS (OVERRIDDEN OR DEFAULT HIDDEN NORTH-UP) */}\n {isCompassVisible &&\n (customCompassButton ? (\n <div className=\"pointer-events-auto\">{customCompassButton}</div>\n ) : (\n <div className=\"pointer-events-auto\">\n <Button\n 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 duration-300 p-0! hover:bg-zinc-900 hover:text-white ${\n isCompassVisible\n ? \"opacity-100 pointer-events-auto\"\n : \"opacity-0 pointer-events-none h-0 w-0 border-none m-0 p-0 overflow-hidden\"\n }`}\n onClick={() =>\n onResetBearing({ pitch: initialViewState?.pitch ?? 0 })\n }\n style={{\n transform: isCompassVisible\n ? \"scale(1) rotate(0deg)\"\n : \"scale(0.7) rotate(0deg)\",\n }}\n title=\"Reset bearing to North\"\n variant=\"ghost\"\n >\n <svg\n className=\"w-7 h-7 transition-transform duration-75 ease-out\"\n fill=\"none\"\n style={{\n transform: `rotate(${-mapBearing}deg)`,\n }}\n viewBox=\"0 0 24 24\"\n >\n {/* Outer ring */}\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"9.5\"\n stroke=\"white\"\n strokeOpacity=\"0.2\"\n strokeWidth=\"1\"\n />\n {/* North Indicator Needle (Red) */}\n <path d=\"M12 4.5L15 12H9L12 4.5Z\" fill=\"#ef4444\" />\n {/* South Indicator Needle (White) */}\n <path d=\"M12 19.5L9 12H15L12 19.5Z\" fill=\"#f4f4f5\" />\n {/* Pivot Center Point */}\n <circle cx=\"12\" cy=\"12\" fill=\"#18181b\" r=\"1.5\" />\n </svg>\n </Button>\n </div>\n ))}\n\n {/* RECENTER BUTTON (OVERRIDDEN OR DEFAULT) */}\n {customRecenterButton ? (\n <div className=\"pointer-events-auto\">{customRecenterButton}</div>\n ) : (\n <div className=\"pointer-events-auto\">\n <Button\n 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 ${\n isMapCentered\n ? \"ring-2 ring-cyan-400 ring-offset-2 ring-offset-zinc-950\"\n : \"\"\n }`}\n onClick={() => onRecenter()}\n title=\"Recenter Map\"\n variant=\"ghost\"\n >\n {isMapCentered ? (\n /* Filled active lock state */\n <svg\n className=\"w-6 h-6 text-cyan-400\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.2\"\n viewBox=\"0 0 24 24\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n <circle cx=\"12\" cy=\"12\" fill=\"currentColor\" r=\"3\" />\n <line x1=\"12\" x2=\"12\" y1=\"2\" y2=\"4\" />\n <line x1=\"12\" x2=\"12\" y1=\"20\" y2=\"22\" />\n <line x1=\"2\" x2=\"4\" y1=\"12\" y2=\"12\" />\n <line x1=\"20\" x2=\"22\" y1=\"12\" y2=\"12\" />\n </svg>\n ) : (\n /* Outlined drifted state */\n <svg\n className=\"w-6 h-6 text-zinc-300\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n viewBox=\"0 0 24 24\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n <line x1=\"12\" x2=\"12\" y1=\"2\" y2=\"4\" />\n <line x1=\"12\" x2=\"12\" y1=\"20\" y2=\"22\" />\n <line x1=\"2\" x2=\"4\" y1=\"12\" y2=\"12\" />\n <line x1=\"20\" x2=\"22\" y1=\"12\" y2=\"12\" />\n </svg>\n )}\n </Button>\n </div>\n )}\n\n {/* BELOW-RECENTER CUSTOM CONTROLS */}\n {belowControls.length > 0 && (\n <div className=\"flex flex-col gap-2 pointer-events-auto\">\n {belowControls.map((control) => (\n <div className=\"relative group flex items-center\" key={control.id}>\n {/* Tooltip */}\n {control.tooltip && (\n <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\">\n {control.tooltip}\n </div>\n )}\n\n {/* Action Button */}\n <Button\n 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 ${\n control.activeState\n ? \"ring-2 ring-cyan-400 ring-offset-2 ring-offset-zinc-950\"\n : \"\"\n }`}\n onClick={control.onPress}\n variant=\"ghost\"\n >\n {control.icon}\n </Button>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n};\n","import type { DrawerState, EtaData } from \"@miniapps-sdk/components/Map/types\";\nimport type React from \"react\";\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nexport interface MapInsets {\n top: number;\n bottom: number;\n left: number;\n right: number;\n}\n\nexport interface MapControlsState {\n isFollowing: boolean;\n setIsFollowing: (following: boolean) => void;\n centerOnUser: (params?: CenterCallbackParams) => void;\n /**\n * Fly the camera to an arbitrary [lng, lat] — e.g. jumping to a venue\n * selected from a list. Unlike calling the raw MapLibre instance's own\n * `flyTo` directly, this also disables follow-mode and locks out the\n * \"recenter on the user\" live-location tracking for the duration of the\n * animation, so a GPS update arriving mid-flight doesn't immediately snap\n * the camera back to the user and undo it (this exact bug — flyTo only\n * \"worked\" after the first manual pan, which is what actually disabled\n * follow-mode — is why this exists instead of every consumer reaching\n * into the MapLibre instance themselves).\n */\n flyTo: (coords: [number, number], params?: FlyToParams) => void;\n bearing: number;\n setBearing: (bearing: number) => void;\n pitch: number;\n setPitch: (pitch: number) => void;\n resetBearing: (params?: CenterCallbackParams) => void;\n\n // Navigation details and controls presence state\n etaData?: EtaData;\n setEtaData: (data?: EtaData) => void;\n hasControls: boolean;\n setHasControls: (hasControls: boolean) => void;\n\n // Drawer state controls\n drawerState: DrawerState;\n setDrawerState: (state: DrawerState) => void;\n /** Stable ref to the drawer's scrollable container. Always available. */\n drawerContentRef: React.RefObject<HTMLDivElement | null>;\n /**\n * Show/hide the drawer's drag-handle bar programmatically — e.g. hide it\n * while `menuContent` is itself a full-bleed swipeable detail view (its\n * own drag handle/affordance would double up with the drawer's). Defaults\n * to `true`. Remember to restore it (e.g. in a `useEffect` cleanup) when\n * the content that needed it hidden unmounts.\n */\n drawerHandleVisible: boolean;\n setDrawerHandleVisible: (visible: boolean) => void;\n\n // Safe area insets (e.g. for mobile home indicators/notches)\n insets: MapInsets;\n setInsets: (insets: Partial<MapInsets>) => void;\n}\n\nexport interface CenterCallbackParams {\n pitch?: number;\n /**\n * Optional bearing to animate to in the same motion as the center/zoom/pitch\n * change. Pass this instead of calling `resetBearing()` right after\n * `centerOnUser()` — two separate flyTo/easeTo calls on the same camera\n * race each other (both touch pitch) and read as sluggish, multi-second\n * drift instead of one clean fast motion.\n */\n bearing?: number;\n}\n\nexport interface FlyToParams {\n zoom?: number;\n pitch?: number;\n bearing?: number;\n /** ms. Defaults to MapLibre's own distance-based duration if omitted. */\n duration?: number;\n}\n\ninterface MapControlsContextType extends MapControlsState {\n // Internal registration callbacks for the Map component to hook up its controls\n _registerCenterCallback: (\n cb: (params?: CenterCallbackParams) => void,\n ) => void;\n _registerResetBearingCallback: (\n cb: (params?: CenterCallbackParams) => void,\n ) => void;\n _registerFlyToCallback: (\n cb: (coords: [number, number], params?: FlyToParams) => void,\n ) => void;\n}\n\nexport const MapControlsContext = createContext<MapControlsContextType | null>(\n null,\n);\n\nexport const SDKMapProvider: React.FC<{ children: React.ReactNode }> = ({\n children,\n}) => {\n const [isFollowing, setIsFollowing] = useState(true);\n const [bearing, setBearingState] = useState(0);\n const [pitch, setPitchState] = useState(0);\n const [drawerState, setDrawerStateInternal] = useState<DrawerState>(\"closed\");\n\n // Stable ref created by the provider to ensure it's always available to hook users\n const drawerContentRef = useRef<HTMLDivElement>(null);\n\n const setDrawerState = useCallback((val: DrawerState) => {\n setDrawerStateInternal(val);\n }, []);\n\n const [drawerHandleVisible, setDrawerHandleVisibleState] = useState(true);\n const setDrawerHandleVisible = useCallback((val: boolean) => {\n setDrawerHandleVisibleState((prev) => (prev === val ? prev : val));\n }, []);\n\n // Use stable handlers for hasControls\n const [hasControls, setHasControlsState] = useState(false);\n const setHasControls = useCallback((val: boolean) => {\n setHasControlsState((prev) => (prev === val ? prev : val));\n }, []);\n\n // Use shallow comparison for etaData setter to prevent update loops\n const [etaData, setEtaDataState] = useState<EtaData | undefined>(undefined);\n const setEtaData = useCallback((newData?: EtaData) => {\n setEtaDataState((prev) => {\n if (!prev && !newData) return prev;\n if (!prev || !newData) return newData;\n if (\n prev.etaMins === newData.etaMins &&\n prev.distanceRemainingKm === newData.distanceRemainingKm &&\n prev.label === newData.label &&\n prev.progress === newData.progress &&\n prev.mode === newData.mode &&\n prev.isCalculating === newData.isCalculating &&\n prev.error === newData.error\n ) {\n return prev;\n }\n return newData;\n });\n }, []);\n\n const [insets, setInsetsState] = useState<MapInsets>({\n bottom: 0,\n left: 0,\n right: 0,\n top: 0,\n });\n\n const setInsets = useCallback((newInsets: Partial<MapInsets>) => {\n setInsetsState((prev) => ({ ...prev, ...newInsets }));\n }, []);\n\n const centerCallbackRef = useRef<\n ((params?: CenterCallbackParams) => void) | null\n >(null);\n const resetBearingCallbackRef = useRef<\n ((params?: CenterCallbackParams) => void) | null\n >(null);\n const flyToCallbackRef = useRef<\n ((coords: [number, number], params?: FlyToParams) => void) | null\n >(null);\n\n const centerOnUser = useCallback((params?: CenterCallbackParams) => {\n if (centerCallbackRef.current) {\n centerCallbackRef.current(params);\n }\n }, []);\n\n const resetBearing = useCallback((params?: CenterCallbackParams) => {\n if (resetBearingCallbackRef.current) {\n resetBearingCallbackRef.current(params);\n }\n }, []);\n\n const flyTo = useCallback(\n (coords: [number, number], params?: FlyToParams) => {\n if (flyToCallbackRef.current) {\n flyToCallbackRef.current(coords, params);\n }\n },\n [],\n );\n\n const _registerCenterCallback = useCallback(\n (cb: (params?: CenterCallbackParams) => void) => {\n centerCallbackRef.current = cb;\n },\n [],\n );\n\n const _registerResetBearingCallback = useCallback(\n (cb: (params?: CenterCallbackParams) => void) => {\n resetBearingCallbackRef.current = cb;\n },\n [],\n );\n\n const _registerFlyToCallback = useCallback(\n (cb: (coords: [number, number], params?: FlyToParams) => void) => {\n flyToCallbackRef.current = cb;\n },\n [],\n );\n\n const setBearing = useCallback((b: number) => {\n setBearingState(b);\n }, []);\n\n const setPitch = useCallback((p: number) => {\n setPitchState(p);\n }, []);\n\n // Memoize context value to block redundant re-renders of listeners\n const contextValue = useMemo(\n () => ({\n _registerCenterCallback,\n _registerFlyToCallback,\n _registerResetBearingCallback,\n bearing,\n centerOnUser,\n drawerContentRef,\n drawerHandleVisible,\n drawerState,\n etaData,\n flyTo,\n hasControls,\n insets,\n isFollowing,\n pitch,\n resetBearing,\n setBearing,\n setDrawerHandleVisible,\n setDrawerState,\n setEtaData,\n setHasControls,\n setInsets,\n setIsFollowing,\n setPitch,\n }),\n [\n _registerCenterCallback,\n _registerFlyToCallback,\n _registerResetBearingCallback,\n bearing,\n centerOnUser,\n drawerHandleVisible,\n drawerState,\n etaData,\n flyTo,\n hasControls,\n isFollowing,\n pitch,\n resetBearing,\n setBearing,\n setDrawerHandleVisible,\n setDrawerState,\n setEtaData,\n setHasControls,\n setPitch,\n insets,\n setInsets,\n ],\n );\n\n return (\n <MapControlsContext.Provider value={contextValue}>\n {children}\n </MapControlsContext.Provider>\n );\n};\n\nexport const useMapControls = (): MapControlsState => {\n const context = useContext(MapControlsContext);\n if (!context) {\n throw new Error(\"useMapControls must be used within a MapControlsProvider\");\n }\n return context;\n};\n","import { MapDrawer } from \"@miniapps-sdk/components/Map/components/MapDrawer\";\nimport { MapEtaPanel } from \"@miniapps-sdk/components/Map/components/MapEtaPanel\";\nimport { MapRightControls } from \"@miniapps-sdk/components/Map/components/MapRightControls\";\nimport {\n type CenterCallbackParams,\n MapControlsContext,\n} from \"@miniapps-sdk/components/Map/MapContext\";\nimport type {\n CustomControl,\n DrawerState,\n EtaData,\n MenuItem,\n} from \"@miniapps-sdk/components/Map/types\";\nimport type { ViewState } from \"@vis.gl/react-maplibre\";\nimport type React from \"react\";\nimport { useCallback, useContext, useEffect, useRef, useState } from \"react\";\n\nconst resolveHeightToPixels = (\n height: string | number,\n containerHeight: number,\n): number => {\n if (typeof height === \"number\") {\n return height;\n }\n if (height.endsWith(\"%\")) {\n return (parseFloat(height) / 100) * containerHeight;\n }\n return parseFloat(height);\n};\n\nexport interface MapControlsProps {\n // Drawer\n menuItems?: MenuItem[];\n drawerSide?: \"left\" | \"bottom\"; // default: 'left' on landscape, 'bottom' on portrait\n defaultState?: DrawerState; // default: 'closed'\n menuContent?: React.ReactNode;\n children?: React.ReactNode;\n\n // Controls\n customControls?: CustomControl[];\n etaBarHeight?: number; // px — keeps controls above ETA bar\n onRecenter?: (params?: CenterCallbackParams) => void;\n isMapCentered?: boolean;\n mapBearing?: number; // degrees — drives compass visibility and rotation\n initialViewState?: Partial<ViewState>;\n\n // Compass\n onResetBearing?: (params?: CenterCallbackParams) => void;\n\n // Integrated ETA details\n etaData?: EtaData;\n\n // Custom button overrides\n customRecenterButton?: React.ReactNode;\n customCompassButton?: React.ReactNode;\n\n // Drawer customization\n drawerPeekHeight?: string | number;\n drawerFullHeight?: string | number;\n /**\n * Max height the \"auto\" drawer state (sized to fit `menuContent`) can\n * grow to. Default \"100%\" — the full available map container height\n * (i.e. effectively 100vh), NOT `drawerFullHeight` (85% by default),\n * so auto-sized content isn't clipped just because it's taller than the\n * manual \"full\" state's height.\n */\n drawerAutoMaxHeight?: string | number;\n drawerContentRef?: React.Ref<HTMLDivElement>;\n\n // Touch drag customization\n enableTouchDrag?: boolean;\n\n // Scroll to top button customization\n showScrollToTopButton?: boolean;\n scrollToTopThreshold?: number;\n\n // Extra bottom offset (px) for the right-side floating controls stack,\n // independent of ETA/drawer state — e.g. to clear a fixed center-screen\n // action button that would otherwise sit under it.\n controlsBottomOffset?: number;\n\n // Internal flag to avoid registry update loops\n isInternal?: boolean;\n}\n\nexport const MapControls: React.FC<MapControlsProps> = ({\n menuItems = [],\n drawerSide,\n customControls = [],\n etaBarHeight = 100,\n onRecenter: propRecenter,\n isMapCentered: propMapCentered,\n mapBearing: propMapBearing,\n onResetBearing: propResetBearing,\n etaData,\n customRecenterButton,\n defaultState,\n initialViewState,\n customCompassButton,\n drawerPeekHeight,\n drawerFullHeight,\n drawerAutoMaxHeight,\n drawerContentRef,\n menuContent,\n children,\n enableTouchDrag = false,\n showScrollToTopButton = true,\n scrollToTopThreshold = 300,\n controlsBottomOffset = 0,\n isInternal = false,\n}) => {\n const mapContext = useContext(MapControlsContext);\n\n const contextRef = mapContext?.drawerContentRef;\n\n // Combine property ref and context ref into a single sync callback\n const mergedRef = useCallback(\n (node: HTMLDivElement | null) => {\n // Sync prop ref\n if (drawerContentRef) {\n if (typeof drawerContentRef === \"function\") {\n drawerContentRef(node);\n } else {\n (drawerContentRef as any).current = node;\n }\n }\n // Sync context ref (always an object ref from provider)\n if (contextRef) {\n (contextRef as any).current = node;\n }\n },\n [drawerContentRef, contextRef],\n );\n\n // Local fallback if context is not available (e.g. isolated storybook without provider)\n const [localDrawerState, setLocalDrawerState] = useState<DrawerState>(\n defaultState ?? \"closed\",\n );\n\n const drawerState = mapContext ? mapContext.drawerState : localDrawerState;\n const setDrawerState = useCallback(\n (state: DrawerState) => {\n if (mapContext) {\n mapContext.setDrawerState(state);\n } else {\n setLocalDrawerState(state);\n }\n },\n [mapContext],\n );\n\n // Sync defaultState into context on mount if provided\n // biome-ignore lint/correctness/useExhaustiveDependencies: only run on mount to set initial state\n useEffect(() => {\n if (defaultState && mapContext) {\n mapContext.setDrawerState(defaultState);\n }\n }, []);\n\n const [side, setSide] = useState<\"left\" | \"bottom\">(\"left\");\n const containerRef = useRef<HTMLDivElement>(null);\n const [mapHeight, setMapHeight] = useState(600);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: containerRef is stable and parent is resolved once on mount\n useEffect(() => {\n const parent = containerRef.current?.parentElement;\n if (!parent) return;\n\n const updateHeight = () => {\n setMapHeight(parent.getBoundingClientRect().height);\n };\n\n updateHeight();\n\n const observer = new ResizeObserver(updateHeight);\n observer.observe(parent);\n\n return () => {\n observer.disconnect();\n };\n }, []);\n\n // Set registry flag\n const setHasControls = mapContext?.setHasControls;\n useEffect(() => {\n if (setHasControls && !isInternal) {\n setHasControls(true);\n return () => setHasControls(false);\n }\n }, [setHasControls, isInternal]);\n\n // Fallbacks using context properties if props are not explicitly passed\n const isMapCentered =\n propMapCentered !== undefined\n ? propMapCentered\n : mapContext\n ? mapContext.isFollowing\n : true;\n\n const mapBearing =\n propMapBearing !== undefined\n ? propMapBearing\n : mapContext\n ? mapContext.bearing\n : 0;\n\n const onRecenter = (params?: CenterCallbackParams) => {\n if (propRecenter) {\n propRecenter(params);\n } else if (mapContext) {\n mapContext.centerOnUser(params);\n }\n };\n\n const onResetBearing = (params?: CenterCallbackParams) => {\n if (propResetBearing) {\n propResetBearing(params);\n } else if (mapContext) {\n mapContext.resetBearing(params);\n }\n };\n\n const mapPitch = mapContext ? mapContext.pitch : 0;\n\n // Resolve etaData from context if not explicitly passed as a prop\n const resolvedEtaData = etaData !== undefined ? etaData : mapContext?.etaData;\n\n // Hoisted touch coordinates for live drag sync\n const [touchStartY, setTouchStartY] = useState<number | null>(null);\n const [currentTouchY, setCurrentTouchY] = useState<number | null>(null);\n\n // Mirrors MapDrawer's own \"auto\" content measurement so THIS component's\n // drag-clamp/height math (used for the ETA card fade/position, not the\n // drawer's own transform) doesn't fall back to a nonsensical fixed guess\n // while dragging an open \"auto\" sheet.\n const [autoContentPx, setAutoContentPx] = useState(0);\n\n // Handle responsive layout detection for orientation matching\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const checkLayout = () => {\n if (drawerSide) {\n setSide(drawerSide);\n } else {\n // Landscape: left drawer panel, Portrait: bottom sheet panel\n if (window.innerWidth < 768) {\n setSide(\"bottom\");\n } else {\n setSide(\"left\");\n }\n }\n };\n\n checkLayout();\n window.addEventListener(\"resize\", checkLayout);\n return () => window.removeEventListener(\"resize\", checkLayout);\n }, [drawerSide]);\n\n // Compute live drag offset\n const isDragging = touchStartY !== null && currentTouchY !== null;\n const dragOffset = isDragging ? currentTouchY - touchStartY : 0;\n\n // Resolve height limits\n const fullPx = resolveHeightToPixels(drawerFullHeight || \"85%\", mapHeight);\n const peekPx = resolveHeightToPixels(drawerPeekHeight || \"15%\", mapHeight);\n const autoMaxPx = resolveHeightToPixels(\n drawerAutoMaxHeight || \"100%\",\n mapHeight,\n );\n const autoPx = Math.min(autoMaxPx, autoContentPx);\n const bottomInset = mapContext?.insets.bottom || 0;\n const handleVisible = mapContext ? mapContext.drawerHandleVisible : true;\n const closedPx =\n (handleVisible ? 32 : 0) + (drawerState === \"closed\" ? bottomInset : 0);\n\n // Clamp drag offset based on the current state to prevent boundaries overshoot\n let clampedDragOffset = dragOffset;\n if (drawerState === \"full\") {\n clampedDragOffset = Math.max(0, Math.min(fullPx - closedPx, dragOffset)); // only down, max to closed\n } else if (drawerState === \"peek\") {\n clampedDragOffset = Math.max(\n -(fullPx - peekPx), // up to full\n Math.min(peekPx - closedPx, dragOffset), // down to closed\n );\n } else if (drawerState === \"closed\") {\n clampedDragOffset = Math.min(0, Math.max(-(fullPx - closedPx), dragOffset)); // only up, max to full\n } else if (drawerState === \"auto\") {\n clampedDragOffset = Math.max(0, dragOffset); // auto sheets only support dragging down, matching MapDrawer's own touch handler\n }\n\n // Calculate dynamic drawer height and opacity for portrait bottom sheet\n let baseHeight = handleVisible ? 32 : 0;\n if (drawerState === \"peek\") {\n baseHeight = peekPx;\n } else if (drawerState === \"full\") {\n baseHeight = fullPx;\n } else if (drawerState === \"auto\") {\n baseHeight = autoPx;\n }\n\n const currentDrawerHeight = baseHeight - clampedDragOffset;\n\n // Smoothly fade out opacity between peek height and 35% of the distance to full\n const startFadeHeight = peekPx + 20; // start fading just above peek\n const endFadeHeight = peekPx + (fullPx - peekPx) * 0.35; // fully faded out at 35% progress\n\n let etaOpacity = 1;\n let etaBottomStyle: string | number = \"1rem\";\n\n if (side === \"bottom\") {\n if (currentDrawerHeight <= startFadeHeight) {\n etaOpacity = 1;\n } else if (currentDrawerHeight >= endFadeHeight) {\n etaOpacity = 0;\n } else {\n const fraction =\n (currentDrawerHeight - startFadeHeight) /\n (endFadeHeight - startFadeHeight);\n etaOpacity = 1 - fraction;\n }\n\n // Add inset if closed, otherwise drawer already pushed up\n const effectiveInset = drawerState === \"closed\" ? bottomInset : 0;\n etaBottomStyle = `calc(${baseHeight + effectiveInset + 16}px - var(--drag-offset, 0px))`;\n } else {\n // Landscape / Left drawer side\n etaOpacity = drawerState === \"full\" ? 0 : 1;\n etaBottomStyle = `calc(1rem + ${bottomInset}px)`;\n }\n\n return (\n <>\n <div ref={containerRef} style={{ display: \"none\" }} />\n\n {/* Dynamic Slide-out Menu Drawer */}\n <MapDrawer\n clampedDragOffset={clampedDragOffset}\n containerHeight={mapHeight}\n currentTouchY={currentTouchY}\n drawerAutoMaxHeight={drawerAutoMaxHeight}\n drawerFullHeight={drawerFullHeight}\n drawerPeekHeight={drawerPeekHeight}\n enableTouchDrag={enableTouchDrag}\n etaBarHeight={etaBarHeight}\n etaData={resolvedEtaData}\n handleVisible={handleVisible}\n isDragging={isDragging}\n menuContent={children || menuContent}\n menuItems={menuItems}\n onAutoContentHeightChange={setAutoContentPx}\n onChangeState={setDrawerState}\n ref={mergedRef}\n safeAreaInsets={mapContext?.insets}\n scrollToTopThreshold={scrollToTopThreshold}\n setCurrentTouchY={setCurrentTouchY}\n setTouchStartY={setTouchStartY}\n showScrollToTopButton={showScrollToTopButton}\n side={side}\n state={drawerState}\n touchStartY={touchStartY}\n />\n\n {/* Floating Controls stacked on the right side */}\n <MapRightControls\n bottomOffset={controlsBottomOffset}\n clampedDragOffset={clampedDragOffset}\n customCompassButton={customCompassButton}\n customControls={customControls}\n customRecenterButton={customRecenterButton}\n drawerPeekHeight={drawerPeekHeight}\n drawerState={drawerState}\n etaBarHeight={\n etaBarHeight + (drawerState === \"closed\" ? bottomInset : 0)\n }\n etaData={resolvedEtaData}\n initialViewState={initialViewState}\n insets={mapContext?.insets}\n isDragging={isDragging}\n isMapCentered={isMapCentered}\n mapBearing={mapBearing}\n mapPitch={mapPitch}\n onRecenter={() => onRecenter()}\n onResetBearing={onResetBearing}\n side={side}\n />\n\n {/* Floating Bottom ETA Card (Landscape or Portrait peek/closed) */}\n {resolvedEtaData && (\n <MapEtaPanel\n etaData={resolvedEtaData}\n isDragging={isDragging}\n layoutMode=\"floating-card\"\n style={{\n bottom: etaBottomStyle,\n opacity: etaOpacity,\n pointerEvents: etaOpacity > 0.1 ? \"auto\" : \"none\",\n transition: isDragging\n ? \"none\"\n : \"bottom 250ms ease-in-out, opacity 300ms ease-out\",\n }}\n />\n )}\n </>\n );\n};\n\nexport type { DrawerState };\n","import { MapControlsContext } from \"@miniapps-sdk/components/Map/MapContext\";\nimport type React from \"react\";\nimport { useContext } from \"react\";\n\nexport interface MapMenuProps {\n children?: React.ReactNode;\n}\n\nexport const MapMenu: React.FC<MapMenuProps> = ({ children }) => {\n return <div className=\"flex flex-col gap-1.5\">{children}</div>;\n};\n\nexport interface MapMenuItemProps {\n id: string;\n label: string;\n icon?: React.ReactNode;\n onPress?: () => void;\n badge?: string | number;\n disabled?: boolean;\n children?: React.ReactNode;\n}\n\nexport const MapMenuItem: React.FC<MapMenuItemProps> = ({\n id,\n label,\n icon,\n onPress,\n badge,\n disabled = false,\n children,\n}) => {\n const context = useContext(MapControlsContext);\n\n const handleClick = (e: React.MouseEvent) => {\n if (disabled) return;\n if (onPress) onPress();\n if (context && context.setDrawerState) {\n context.setDrawerState(\"closed\");\n }\n };\n\n return (\n <button\n className={`flex items-center gap-3 w-full py-3 px-3.5 rounded-xl text-left cursor-pointer transition-all duration-150 ${\n disabled\n ? \"opacity-45 cursor-not-allowed pointer-events-none\"\n : \"hover:bg-white/5 active:bg-white/10 text-white\"\n }`}\n disabled={disabled}\n onClick={handleClick}\n type=\"button\"\n >\n {icon && (\n <div className=\"relative flex items-center justify-center w-8 h-8 rounded-lg bg-white/5 text-zinc-300\">\n {icon}\n {badge !== undefined && (\n <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\">\n {badge}\n </span>\n )}\n </div>\n )}\n <div className=\"flex-1 flex flex-col justify-center\">\n <span className=\"text-sm font-medium tracking-wide flex-1\">\n {label}\n </span>\n {children}\n </div>\n </button>\n );\n};\n\nMapMenu.displayName = \"MapMenu\";\nMapMenuItem.displayName = \"MapMenuItem\";\n\nexport interface MapMenuTitleProps {\n children: React.ReactNode;\n className?: string;\n showDivider?: boolean;\n}\n\nexport const MapMenuTitle: React.FC<MapMenuTitleProps> = ({\n children,\n showDivider = true,\n className = \"\",\n}) => {\n return (\n <div\n 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\" : \"\"}`}\n >\n {children}\n </div>\n );\n};\nMapMenuTitle.displayName = \"MapMenuTitle\";\n\nexport interface MapMenuDividerProps {\n className?: string;\n}\n\nexport const MapMenuDivider: React.FC<MapMenuDividerProps> = ({\n className = \"\",\n}) => {\n return <div className={`h-[1px] bg-white/10 my-3 mx-3.5 ${className}`} />;\n};\nMapMenuDivider.displayName = \"MapMenuDivider\";\n\nexport interface MapMenuFooterProps {\n children: React.ReactNode;\n className?: string;\n}\n\nexport const MapMenuFooter: React.FC<MapMenuFooterProps> = ({\n children,\n className = \"\",\n}) => {\n return (\n <div\n className={`mt-auto pt-4 border-t border-white/10 px-3.5 text-xs text-zinc-500 font-medium ${className}`}\n >\n {children}\n </div>\n );\n};\nMapMenuFooter.displayName = \"MapMenuFooter\";\n","import type {\n CornerDotType,\n CornerSquareType,\n DotType,\n ErrorCorrectionLevel,\n Gradient,\n ShapeType,\n} from \"qr-code-styling\";\n\n/**\n * UP Mini-App SDK Types\n */\n\n/**\n * Represents the user's profile information.\n */\nexport interface IUserProfile {\n /** Unique identifier for the user. */\n uuid: string;\n /** Full legal name of the user. */\n fullName: string;\n /** First name of the user. */\n firstName: string;\n /** Last name of the user. */\n lastName: string;\n /** Primary email address. */\n email?: string;\n /** Chosen username within the UP ecosystem. */\n username?: string;\n /** ISO country code (e.g., \"FR\", \"US\"). */\n countryCode: string;\n /** Phone number without country code. */\n localNumber: string;\n /** How the user's account was created/registered. */\n registrationType: \"up\" | \"apple\" | \"google\";\n /** Admin status. */\n admin: boolean;\n /** UP points balance. */\n ups: number;\n /** Experience points balance. */\n xp: number;\n /** ISO timestamp of user creation. */\n createdAt: string;\n /** ISO timestamp of last password update. */\n lastPasswordUpdate?: string;\n /** URL to profile picture. */\n avatarUrl?: string;\n /** UUID of profile picture. */\n avatarUuid?: string;\n /** URL to user badge. */\n badgeUrl?: string;\n /** UUID of user badge. */\n badgeUuid?: string;\n /** URL to user profile theme. */\n themeUrl?: string;\n /** UUID of user profile theme. */\n themeUuid?: string;\n}\n\n/**\n * Geographic location data.\n */\nexport interface ILocationData {\n coords: {\n /** Latitude in decimal degrees. */\n latitude: number;\n /** Longitude in decimal degrees. */\n longitude: number;\n /** Altitude in meters above the WGS 84 reference ellipsoid, or null if not available. */\n altitude: number | null;\n /** Accuracy of the latitude and longitude properties in meters. */\n accuracy: number | null;\n /** Accuracy of the altitude property in meters. */\n altitudeAccuracy: number | null;\n /** The direction in which the device is traveling, in degrees (0-360). */\n heading: number | null;\n /** The velocity of the device in meters per second. */\n speed: number | null;\n };\n /** The time at which the location was retrieved (Unix timestamp). */\n timestamp: number;\n}\n\n/**\n * Request payload for triggering a payment flow.\n */\nexport interface IPaymentRequest {\n /** The specific amount to charge. */\n amount: number;\n /** ISO currency code (e.g., \"EUR\", \"USD\"). */\n currency: string;\n /** Total amount including taxes/fees. */\n total: number;\n /** Itemized breakdown of the purchase. */\n items: Array<{\n /** Name or description of the item. */\n item: string;\n /** Price per unit. */\n price?: number;\n /** Number of units. */\n quantity?: number;\n }>;\n}\n\n/**\n * Style of haptic feedback.\n */\nexport type HapticStyleType =\n | \"light\"\n | \"medium\"\n | \"heavy\"\n | \"rigid\"\n | \"soft\"\n | \"success\"\n | \"warning\"\n | \"error\";\n\n/**\n * Network Proxy Types\n */\n\n/**\n * The HTTP method to use as request method\n */\nexport type NetworkMethodType = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n/**\n * Configuration for network proxy requests.\n */\nexport interface INetworkOptions {\n /** Full URL for the request. */\n url: string;\n /** HTTP method to use. */\n method: NetworkMethodType;\n /** Request body for POST/PUT/PATCH. */\n body?: unknown;\n /** Custom HTTP headers. */\n headers?: Record<string, string>;\n}\n\n/**\n * Response from a network proxy request.\n */\nexport interface INetworkResponse<T = unknown> {\n /** HTTP status code. */\n status: number;\n /** Response data payload. */\n data: T;\n /** Response headers. */\n headers: Headers;\n}\n\n/**\n * Fidelity & Rewards Types\n */\n\n/**\n * Fidelity program balance information.\n */\nexport interface IFidelityBalance {\n /** Current point or currency balance. */\n balance: number;\n /** Name or symbol of the fidelity currency (e.g., \"FPoints\"). */\n currency: string;\n}\n\n/**\n * Parameters for retrieving fidelity transaction history.\n */\nexport interface IFidelityHistoryParams {\n /** Maximum number of records to return. */\n limit?: number;\n\n /** Cursor for pagination; null for the first page. */\n cursor?: string | null;\n}\n\n/** Type of transaction: credit (add) or debit (remove). */\nexport type FidelityTransactionTypeType = \"credit\" | \"debit\";\n\n/**\n * A single fidelity program transaction.\n */\nexport interface IFidelityTransaction {\n /** Unique identifier for the transaction. */\n id: string;\n /** Amount of the transaction. */\n amount: number;\n /** Human-readable description. */\n description: string;\n /** ISO 8601 date string. */\n date: string;\n /** Type of transaction */\n type: FidelityTransactionTypeType;\n}\n\n/**\n * The initialization options required to set up the Mini-App SDK.\n */\nexport type IInitializationOptions = {\n /**\n * The Mini-App's own dark/light theme preference, applied by the host\n * immediately from the INITIALIZE payload — pass it here instead of a\n * separate `sdk.updateContext({isDark})` call right after `initialize()`\n * resolves, which left the host rendering its own theme for the whole\n * round-trip before flipping to the Mini-App's real one.\n */\n isDark?: boolean;\n};\n\n/**\n * The post initialization response\n */\nexport interface IInitializationResponse<\n Env extends Record<string, unknown> = Record<string, unknown>,\n UserData extends Record<string, unknown> = Record<string, unknown>,\n Params extends Record<string, unknown> = Record<string, unknown>,\n> {\n /** The name of the mini app */\n name: string;\n /** The uuid of the mini app */\n uuid: string;\n /** The description of the mini app */\n description: string;\n /** The authors of the mini app */\n authors?: string;\n /** The current version in the registry */\n version?: string;\n /** The scoped profile based on the requested fields during initialization or the getUserProfile call */\n profile: Partial<IUserProfile | null>;\n /** The environment variables defined for the mini app in the shell's backend */\n env: Env;\n /** The user data passed during the initialization or the setUserData call */\n userData: UserData;\n /** The params passed during the initialization */\n params: Params;\n /** The edge insets of the mini app, representing the padding around the mini app's view within the Host Shell. */\n insets: IEdgeInsets;\n}\n\n/**\n * Events emitted by the UI module.\n */\nexport enum UIEvent {\n /** Triggered when the user performs a native \"Pull-to-Refresh\". */\n TOP_SCROLL_MORE = \"TOP_SCROLL_MORE\",\n /** Triggered when the user scrolls near the bottom of the page (within 200px threshold). */\n BOTTOM_SCROLL_MORE = \"BOTTOM_SCROLL_MORE\",\n /** Triggered when the user performs a native back gesture or presses the native back button. */\n BACK_GESTURE = \"BACK_GESTURE\",\n}\n\n/**\n * Events emitted by the Geolocation module.\n */\nexport enum GeolocationEvent {\n /** Triggered when the user's location is updated (legacy polling). */\n LOCATION_UPDATE = \"LOCATION_UPDATE\",\n /** Triggered by the continuous location stream. */\n LOCATION_STREAM_UPDATE = \"LOCATION_STREAM_UPDATE\",\n}\n\n/**\n * Configuration options for the location stream.\n */\nexport interface LocationStreamConfig {\n /** Polling cycle rate in milliseconds. Default: 250 */\n interval?: number;\n /** Distance change in meters to trigger an update. Default: 5 */\n distanceFilter?: number;\n /** Heading change in degrees to trigger an update. Default: 5 */\n headingThreshold?: number;\n /** Accelerometer delta in G-force to trigger an update. Default: 0.1 */\n accelerometerThreshold?: number;\n}\n\nexport interface StreamLocationData {\n coords: {\n latitude: number;\n longitude: number;\n altitude: number | null;\n accuracy: number | null;\n altitudeAccuracy: number | null;\n heading: number | null;\n speed: number | null;\n };\n timestamp: number;\n}\n\nexport interface StreamHeadingData {\n magneticHeading: number;\n trueHeading: number;\n accuracy: number;\n}\n\nexport interface StreamAccelerometerData {\n x: number;\n y: number;\n z: number;\n}\n\nexport interface StreamUpdatePayload {\n location: StreamLocationData;\n heading: StreamHeadingData;\n accelerometer: StreamAccelerometerData | null;\n timestamp: number;\n}\n\n/**\n * Global events emitted by the Host Shell that may affect the mini-app's context.\n */\nexport enum GlobalEvent {\n /** Triggered when the Host Shell sends an update event to the mini-app, indicating changes in context. */\n UPDATE_CONTEXT = \"UPDATE_CONTEXT\",\n}\n\n/**\n * Union type for all SDK events, allowing for both known enums and custom strings.\n * The (string & {}) pattern preserves IntelliSense for enum members.\n */\nexport type SDKEvent = UIEvent | GeolocationEvent | GlobalEvent | (string & {});\n\n/**\n * Configuration for native scroll interactions managed by the Host Shell.\n */\nexport interface ScrollConfig {\n /** Configuration for Pull-to-Refresh (Top). */\n topScrollMore?: {\n /** Show/hide the native RefreshControl. */\n enabled: boolean;\n /** Set to true to show the loading spinner, false to hide it. */\n refreshing?: boolean;\n };\n /** Configuration for Infinite Scroll (Bottom). */\n bottomScrollMore?: {\n /** Enable/disable bottom scroll detection. */\n enabled: boolean;\n /** If false, detection stops and the indicator is hidden. */\n hasMore?: boolean;\n /** Set to true to show the bottom ActivityIndicator. */\n loadingMore?: boolean;\n };\n}\n\n/**\n * Result of a `sdk.media.saveImage` call.\n */\nexport interface ISaveImageResult {\n /** Whether the image was saved successfully. */\n success: boolean;\n}\n\n/**\n * Result of a `sdk.media.pickImage` call.\n */\nexport interface IPickImageResult {\n /** Whether an image was picked (false if permission was denied or the user canceled the picker). */\n success: boolean;\n /** Base64-encoded image data as a full data URI (e.g. `data:image/jpeg;base64,...`). Only set when `success` is true. */\n base64?: string;\n /** MIME type of the picked image (e.g. `image/jpeg`). Only set when `success` is true. */\n mimeType?: string;\n}\n\n/**\n * Options for `sdk.qrCode.generate`.\n */\nexport interface IGenerateQrCodeOptions {\n /** Square size of the QR code itself, in px. Default 512. */\n size?: number;\n /**\n * Mini-app name shown as a \"UP - <appName>\" label above the QR code (e.g.\n * the `name` field from `sdk.initialize()`'s response). Ignored if `label`\n * is also set. Omit both for no label.\n */\n appName?: string;\n /**\n * Explicit label text, overriding the \"UP - <appName>\" auto-format. Pass\n * an empty string (or omit both this and `appName`) for no label.\n */\n label?: string;\n /** Dot/corner color. Default a neutral dark gray — kept theme-agnostic since this SDK serves every mini-app, not just one product's brand. */\n color?: string;\n /** Background color behind the QR (and the label, if any). Default white. */\n backgroundColor?: string;\n /** Optional center logo, as a URL or base64 data URI. */\n logo?: string;\n /** Overall QR frame shape. Default \"square\". */\n shape?: ShapeType;\n /** Quiet-zone margin around the raw QR modules, in px. Default 0. */\n margin?: number;\n /** Error correction level — higher tolerates more damage/logo overlap at the cost of density. Default \"Q\". */\n errorCorrectionLevel?: ErrorCorrectionLevel;\n /** Dot module style. Default \"extra-rounded\". */\n dotsType?: DotType;\n /** Gradient for the dots — overrides `color` for the dots when set. */\n dotsGradient?: Gradient;\n /** Corner square (the 3 big position markers) style. Default \"extra-rounded\". */\n cornersSquareType?: CornerSquareType;\n /** Corner square color override. Defaults to `color`. */\n cornersSquareColor?: string;\n /** Gradient for the corner squares — overrides the corner square color when set. */\n cornersSquareGradient?: Gradient;\n /** Corner dot (the small dot inside each position marker) style. Default \"dot\". */\n cornersDotType?: CornerDotType;\n /** Corner dot color override. Defaults to `color`. */\n cornersDotColor?: string;\n /** Gradient for the corner dots — overrides the corner dot color when set. */\n cornersDotGradient?: Gradient;\n /** Gradient for the background — overrides `backgroundColor` when set. */\n backgroundGradient?: Gradient;\n /** Hide the QR dots directly behind the logo. Default true when `logo` is set. */\n hideBackgroundDots?: boolean;\n /** Logo size, as a fraction of the QR width (0-1). Default 0.4. */\n logoSize?: number;\n /** Blank margin around the logo, in px. Default 4. */\n logoMargin?: number;\n /**\n * Extra padding, in px, wrapped around the ENTIRE generated image (the QR\n * code plus the label band, if any) — same `backgroundColor` fill on all\n * four sides. Distinct from `margin`, which is `qr-code-styling`'s own\n * internal quiet-zone around just the QR modules. Default 32.\n */\n outerPadding?: number;\n /**\n * The final generated image is ALWAYS a square (padded on the shorter\n * side to force it, even when a label band makes the QR+label content\n * taller than it is wide) — this is the corner radius applied to that\n * square, as a PERCENTAGE of its side length (0-50, like CSS\n * `border-radius: N%` on a square element), not raw px. The area outside\n * the rounded corners is left transparent, not `backgroundColor`-filled.\n * Set to 0 for sharp corners, 50 for a full circle. Default 6.\n */\n borderRadius?: number;\n}\n\n/**\n * Edge insets representing padding or margins around a component, typically used for layout purposes.\n */\nexport interface IEdgeInsets {\n top: number;\n right: number;\n bottom: number;\n left: number;\n}\n\n/**\n * The context state of the mini-app, which includes dynamic properties provided by the Host Shell, such as edge insets for layout adjustments. This type can be extended with additional properties as needed.\n */\nexport type IContextState = Record<string, any> & {\n insets: IEdgeInsets;\n};\n","import { sdk } from \"@miniapps-sdk/sdk\";\nimport { GeolocationEvent } from \"@miniapps-sdk/types\";\nimport { useEffect, useState } from \"react\";\n\nexport interface UserLocationState {\n coords: [number, number] | null;\n heading: number | null;\n accuracy: number | null;\n}\n\n/**\n * Smoothing factor for interpolation.\n * Higher = faster/snappier (less lag, more jitter)\n * Lower = smoother/slower (more lag, zero jitter)\n */\nconst LERP_FACTOR = 0.12;\n\nconst EMPTY_STATE: UserLocationState = {\n accuracy: null,\n coords: null,\n heading: null,\n};\n\nfunction mapPayload(payload: any): UserLocationState {\n const coords = payload.location?.coords || payload.coords;\n const headingData = payload.heading;\n\n const newCoords: [number, number] | null = coords\n ? [coords.longitude, coords.latitude]\n : null;\n\n let heading = null;\n if (headingData?.trueHeading !== undefined && headingData.trueHeading >= 0) {\n heading = headingData.trueHeading;\n } else if (\n headingData?.magneticHeading !== undefined &&\n headingData.magneticHeading >= 0\n ) {\n heading = headingData.magneticHeading;\n } else if (headingData?.heading !== null && headingData?.heading >= 0) {\n heading = headingData.heading;\n }\n\n return {\n accuracy: coords?.accuracy || null,\n coords: newCoords,\n heading,\n };\n}\n\n/**\n * Module-level singleton: the native GPS stream (sdk.location.startStream /\n * stopStream) and its RAF interpolation loop are shared by EVERY\n * useUserLocation() call in the app, not one per call site.\n *\n * Bug fixed 2026-08-26: this hook is called concurrently from several\n * independent places at once (this SDK's own Map.tsx for the user-location\n * marker, plus each consumer app's own screens/buttons — up-miniapps-explore\n * alone had 4 concurrent instances). Each instance used to own a fully\n * independent stream lifecycle with NO reference counting — every mount\n * called the native startStream() and every unmount called the native\n * stopStream(), both GLOBAL signals to the host shell. Whenever any ONE\n * instance unmounted (e.g. a consumer remounting its map subtree on a\n * retry-after-timeout flow) while others stayed mounted, its stopStream()\n * could race ahead of another instance's startStream() (both are\n * independent async bridge round-trips with no ordering guarantee across\n * instances) and silently kill GPS delivery for the whole app — nothing\n * surfaces an error, every remaining consumer just stops receiving\n * location updates and freezes on the last known position. Fixed by\n * owning the stream here: it starts once, on the first mount across the\n * whole app, and stops only when the LAST consumer unmounts.\n */\nlet refCount = 0;\n// Bumped every time startSharedStream() runs. Guards the async\n// getCurrentPosition() fetch below, which has no cancellation of its own —\n// without this, a promise from a PREVIOUS stream generation (e.g. the one\n// torn down by a retry-remount) can resolve after stopSharedStream() has\n// already reset targetState, or worse, after a brand-new generation has\n// already fetched fresh data — clobbering it with stale coordinates.\nlet generation = 0;\nconst subscribers = new Set<(state: UserLocationState) => void>();\nlet targetState: UserLocationState = { ...EMPTY_STATE };\nlet currentInterpolated: {\n coords: [number, number] | null;\n heading: number | null;\n} = { coords: null, heading: null };\nlet rafId: number | null = null;\nlet unsubscribeStream: (() => void) | null = null;\nlet unsubscribeLegacy: (() => void) | null = null;\n\nfunction getSnapshot(): UserLocationState {\n return {\n accuracy: targetState.accuracy,\n coords: currentInterpolated.coords ? [...currentInterpolated.coords] : null,\n heading: currentInterpolated.heading,\n };\n}\n\nfunction notify() {\n const snapshot = getSnapshot();\n for (const callback of subscribers) callback(snapshot);\n}\n\nfunction animate() {\n let changed = false;\n\n // 1. Interpolate Coords\n if (targetState.coords) {\n if (!currentInterpolated.coords) {\n currentInterpolated.coords = [...targetState.coords];\n changed = true;\n } else {\n const [tLng, tLat] = targetState.coords;\n const [cLng, cLat] = currentInterpolated.coords;\n\n const nLng = cLng + (tLng - cLng) * LERP_FACTOR;\n const nLat = cLat + (tLat - cLat) * LERP_FACTOR;\n\n // Only update if difference is significant to save cycles\n if (Math.abs(nLng - cLng) > 1e-7 || Math.abs(nLat - cLat) > 1e-7) {\n currentInterpolated.coords = [nLng, nLat];\n changed = true;\n }\n }\n }\n\n // 2. Interpolate Heading (Shortest Path)\n if (targetState.heading !== null) {\n if (currentInterpolated.heading === null) {\n currentInterpolated.heading = targetState.heading;\n changed = true;\n } else {\n const target = targetState.heading;\n const current = currentInterpolated.heading;\n\n // Find shortest delta (handle 0/360 wrap)\n let delta = target - current;\n if (delta > 180) delta -= 360;\n if (delta < -180) delta += 360;\n\n const nHeading = current + delta * LERP_FACTOR;\n // Normalize to [0, 360)\n const normalized = ((nHeading % 360) + 360) % 360;\n\n if (Math.abs(delta) > 0.1) {\n currentInterpolated.heading = normalized;\n changed = true;\n }\n }\n }\n\n if (changed) notify();\n\n rafId = requestAnimationFrame(animate);\n}\n\nfunction startSharedStream() {\n rafId = requestAnimationFrame(animate);\n\n generation++;\n const thisGeneration = generation;\n\n // Initial fetch\n sdk.location\n .getCurrentPosition()\n .then((data) => {\n if (thisGeneration !== generation) return;\n targetState = mapPayload(data);\n })\n .catch((e) => console.warn(\"Initial location fetch failed\", e));\n\n unsubscribeStream = sdk.on(\n GeolocationEvent.LOCATION_STREAM_UPDATE,\n (payload: any) => {\n targetState = mapPayload(payload);\n },\n );\n\n unsubscribeLegacy = sdk.on(\n GeolocationEvent.LOCATION_UPDATE,\n (payload: any) => {\n targetState = mapPayload(payload);\n },\n );\n\n sdk.location\n .startStream({\n distanceFilter: 1,\n headingThreshold: 2,\n })\n .catch((e) => console.warn(\"Failed to start location stream\", e));\n}\n\nfunction stopSharedStream() {\n generation++;\n if (rafId !== null) cancelAnimationFrame(rafId);\n rafId = null;\n unsubscribeStream?.();\n unsubscribeLegacy?.();\n unsubscribeStream = null;\n unsubscribeLegacy = null;\n sdk.location.stopStream().catch(() => {});\n targetState = { ...EMPTY_STATE };\n currentInterpolated = { coords: null, heading: null };\n}\n\nexport const useUserLocation = () => {\n const [locationState, setLocationState] =\n useState<UserLocationState>(getSnapshot);\n\n useEffect(() => {\n refCount++;\n if (refCount === 1) {\n startSharedStream();\n } else {\n // Stream is already live — sync immediately instead of this consumer\n // starting from a blank state and waiting for the next RAF tick.\n setLocationState(getSnapshot());\n }\n\n subscribers.add(setLocationState);\n\n return () => {\n subscribers.delete(setLocationState);\n refCount--;\n if (refCount === 0) {\n stopSharedStream();\n }\n };\n }, []);\n\n return locationState;\n};\n","import { useUserLocation } from \"@miniapps-sdk/components/Map/hooks/useUserLocation\";\nimport { sdk } from \"@miniapps-sdk/sdk\";\nimport type { RouteResponse } from \"@miniapps-sdk/types\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nexport interface LiveRoutingOptions {\n /** Origin coordinates [lng, lat]. If not provided, uses device location. */\n origin?: [number, number] | null;\n /** Destination coordinates [lng, lat] */\n destination: [number, number] | null;\n /** Transport profile. Defaults to 'driving'. */\n profile?: \"driving\" | \"cycling\" | \"walking\";\n /** Minimum distance in meters the user must move before recalculating path geometry. Defaults to 50. */\n recalculateThreshold?: number;\n /** Whether live routing is active. */\n enabled?: boolean;\n /** Initial mode: 'preview' or 'navigation'. Defaults to 'preview'. */\n initialMode?: \"preview\" | \"navigation\";\n}\n\nexport interface LiveRoutingResult {\n /** The calculated route data from the last API call */\n route: RouteResponse[\"data\"] | null;\n /** Real-time distance to destination in meters */\n currentDistanceMeters: number | null;\n /** The initial total distance when the destination was first set */\n totalDistance: number | null;\n /** Whether a new calculation is in progress */\n isCalculating: boolean;\n /** Any error message from the routing service */\n error: string | null;\n /** Force a manual recalculation */\n recalculate: () => void;\n /** Current mode: 'preview' (overview) or 'navigation' (active guidance) */\n mode: \"preview\" | \"navigation\";\n /** Start active navigation (switch mode to 'navigation') */\n start: () => void;\n}\n\nexport const useLiveRouting = ({\n origin: manualOrigin,\n destination,\n profile = \"driving\",\n recalculateThreshold = 50,\n enabled = true,\n initialMode = \"preview\",\n}: LiveRoutingOptions): LiveRoutingResult => {\n const [route, setRoute] = useState<RouteResponse[\"data\"] | null>(null);\n const [totalDistance, setTotalDistance] = useState<number | null>(null);\n const [isCalculating, setIsCalculating] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [mode, setMode] = useState<\"preview\" | \"navigation\">(initialMode);\n\n const userLocationState = useUserLocation();\n // calculationOrigin: used for the route API call (can be a fixed start point)\n // trackingLocation: always live GPS — used for real-time distance/progress tracking\n const calculationOrigin = manualOrigin || userLocationState.coords;\n const trackingLocation = userLocationState.coords || manualOrigin;\n\n const lastCalcOrigin = useRef<[number, number] | null>(null);\n const lastCalcDest = useRef<[number, number] | null>(null);\n const isRequestInProgress = useRef(false);\n // Tracks the destination we've already reset `mode` for — separate from\n // lastCalcDest (which only updates once the async calculate() resolves),\n // so the mode reset happens exactly once per new destination instead of\n // repeating on every subsequent effect re-run (e.g. every GPS tick) while\n // the route calculation is still in flight.\n const lastResetDestKey = useRef<string | null>(null);\n\n // Helper to calculate distance between two points (Haversine)\n const getDistance = useCallback(\n (p1: [number, number], p2: [number, number]) => {\n const R = 6371e3; // meters\n const φ1 = (p1[1] * Math.PI) / 180;\n const φ2 = (p2[1] * Math.PI) / 180;\n const Δφ = ((p2[1] - p1[1]) * Math.PI) / 180;\n const Δλ = ((p2[0] - p1[0]) * Math.PI) / 180;\n\n const a =\n Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +\n Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ / 2) * Math.sin(Δλ / 2);\n const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n\n return R * c;\n },\n [],\n );\n\n // Real-time distance calculation along route coordinates.\n // ALWAYS uses trackingLocation (live GPS), never the fixed manualOrigin,\n // so it updates as the user physically moves.\n const currentDistanceMeters = useMemo(() => {\n if (!trackingLocation || !route || route.geometry.coordinates.length < 2) {\n if (trackingLocation && destination) {\n return getDistance(trackingLocation, destination);\n }\n return null;\n }\n\n const coords = route.geometry.coordinates as [number, number][];\n\n // Find the coordinate on the route closest to the user's live position\n let minDistSq = Infinity;\n let closestIndex = 0;\n\n const getDistSq = (p1: [number, number], p2: [number, number]) =>\n (p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2;\n\n for (let i = 0; i < coords.length; i++) {\n const d = getDistSq(trackingLocation, coords[i] as [number, number]);\n if (d < minDistSq) {\n minDistSq = d;\n closestIndex = i;\n }\n }\n\n // Sum distance along remaining route segments starting from the user's exact position\n const remainingCoords = coords.slice(closestIndex + 1);\n let dist = 0;\n let prev: [number, number] = trackingLocation;\n for (const coord of remainingCoords) {\n dist += getDistance(prev, coord as [number, number]);\n prev = coord as [number, number];\n }\n return dist;\n }, [trackingLocation, route, destination, getDistance]);\n\n const calculate = useCallback(\n async (\n origin: [number, number],\n dest: [number, number],\n isNewDest: boolean,\n ) => {\n if (isRequestInProgress.current) return;\n\n isRequestInProgress.current = true;\n setIsCalculating(true);\n\n try {\n const data = await sdk.routing.getRoute({\n destination: dest,\n origin,\n profile,\n });\n\n setRoute(data);\n setError(null);\n\n if (isNewDest) {\n const coords = data.geometry.coordinates;\n let sum = 0;\n for (let i = 0; i < coords.length - 1; i++) {\n sum += getDistance(\n coords[i] as [number, number],\n coords[i + 1] as [number, number],\n );\n }\n setTotalDistance(sum);\n }\n\n lastCalcOrigin.current = origin;\n lastCalcDest.current = dest;\n } catch (err: any) {\n setError(err.message || \"Failed to fetch route\");\n } finally {\n setIsCalculating(false);\n isRequestInProgress.current = false;\n }\n },\n [profile, getDistance],\n );\n\n useEffect(() => {\n if (initialMode === \"navigation\") {\n setMode(\"navigation\");\n }\n }, [initialMode]);\n\n useEffect(() => {\n if (!enabled || !destination || !calculationOrigin) {\n if (!enabled || !destination) {\n setRoute(null);\n setTotalDistance(null);\n lastCalcOrigin.current = null;\n lastCalcDest.current = null;\n lastResetDestKey.current = null;\n // A journey that's disabled/cleared (e.g. cancelled) must always\n // come back in preview mode next time — never resume mid-navigation.\n setMode(initialMode);\n }\n return;\n }\n\n const destChanged =\n !lastCalcDest.current ||\n lastCalcDest.current[0] !== destination[0] ||\n lastCalcDest.current[1] !== destination[1];\n\n // A new destination is a brand-new journey — always start it in preview.\n // Gated on a key separate from lastCalcDest (which only updates once the\n // async calculate() resolves) so this fires exactly once per destination,\n // not on every subsequent effect re-run while destChanged is still true.\n const destKey = `${destination[0]},${destination[1]}`;\n if (lastResetDestKey.current !== destKey) {\n lastResetDestKey.current = destKey;\n setMode(initialMode);\n }\n\n if (destChanged) {\n calculate(calculationOrigin, destination, true);\n } else if (lastCalcOrigin.current) {\n // Recalculate route geometry only if user drifted far from last calc origin\n const livePos = trackingLocation || calculationOrigin;\n const dist = getDistance(livePos, lastCalcOrigin.current);\n if (dist > recalculateThreshold) {\n calculate(livePos, destination, false);\n }\n } else {\n calculate(calculationOrigin, destination, true);\n }\n }, [\n calculationOrigin,\n trackingLocation,\n destination,\n enabled,\n initialMode,\n recalculateThreshold,\n calculate,\n getDistance,\n ]);\n\n return {\n currentDistanceMeters,\n error,\n isCalculating,\n mode,\n recalculate: () =>\n calculationOrigin &&\n destination &&\n calculate(calculationOrigin, destination, false),\n route,\n start: () => setMode(\"navigation\"),\n totalDistance,\n };\n};\n\n/**\n * A simple hook to fetch a route once between two points.\n * Does not automatically recalculate or track user location.\n */\nexport const useRoute = (\n origin: [number, number] | null,\n destination: [number, number] | null,\n profile: \"driving\" | \"cycling\" | \"walking\" = \"driving\",\n) => {\n const [route, setRoute] = useState<RouteResponse[\"data\"] | null>(null);\n const [isCalculating, setIsCalculating] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!origin || !destination) {\n setRoute(null);\n return;\n }\n\n const fetchRoute = async () => {\n setIsCalculating(true);\n try {\n const data = await sdk.routing.getRoute({\n destination,\n origin,\n profile,\n });\n setRoute(data);\n setError(null);\n } catch (err: any) {\n setError(err.message || \"Failed to fetch route\");\n } finally {\n setIsCalculating(false);\n }\n };\n\n fetchRoute();\n }, [origin, destination, profile]);\n\n return { error, isCalculating, route };\n};\n","import {\n type LiveRoutingOptions,\n useLiveRouting,\n} from \"@miniapps-sdk/components/Map/hooks/useLiveRouting\";\nimport { sdk } from \"@miniapps-sdk/sdk\";\nimport type { RouteResponse } from \"@miniapps-sdk/types\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\ntype NavMode = \"preview\" | \"navigation\";\n\nexport interface DeclarativeJourneyOptions {\n /** Destination coordinates [lng, lat] */\n destination: [number, number] | null;\n /** Transport profile. Defaults to 'driving'. */\n profile?: LiveRoutingOptions[\"profile\"];\n /** Minimum distance in meters the user must move before recalculating path geometry. Defaults to 50. */\n recalculateThreshold?: number;\n /** Optional manual origin. Defaults to real-time user location. */\n origin?: [number, number] | null;\n /** Initial mode. 'preview' shows the route overview, 'navigation' starts active guidance. Defaults to 'preview'. */\n mode?: NavMode;\n}\n\nexport interface UseJourneyOptions {\n /**\n * Declarative journey configuration. If provided, this hook manages route\n * calculation/tracking itself — equivalent to the `navigation` prop on `<Map/>`.\n * Omit this to instead drive the journey imperatively via `sdk.navigation.*`\n * (createJourney/start/abort), e.g. from elsewhere in the app or from `<Map/>` itself.\n */\n navigation?: DeclarativeJourneyOptions;\n /** Called whenever the journey is cancelled/aborted. */\n onAbort?: () => void;\n /** Called whenever the mode changes (e.g. preview -> navigation). */\n onModeChange?: (mode: NavMode) => void;\n}\n\nexport interface UseJourneyResult {\n /** Whether a journey (preview or navigation) is currently active. */\n isActive: boolean;\n /** Current mode: 'preview' (route overview) or 'navigation' (active guidance). */\n mode: NavMode;\n /** The calculated route geometry/data, or null if none. */\n route: RouteResponse[\"data\"] | null;\n /** Whether a route calculation is in flight. */\n isCalculating: boolean;\n /** Routing error message, if any. */\n error: string | null;\n /** Real-time remaining distance to destination, in meters. */\n distanceRemainingMeters: number | null;\n /** Real-time remaining distance to destination, in kilometers. */\n distanceRemainingKm: number;\n /** The total distance of the route when the destination was first set, in meters. */\n totalDistanceMeters: number | null;\n /** Estimated remaining time, in minutes, scaled proportionally to remaining distance. */\n etaMinutes: number;\n /** Journey completion progress, 0-100. */\n progress: number;\n /** Switch from 'preview' to active 'navigation' guidance. */\n start: () => void;\n /** Cancel the journey entirely. Always returns to 'preview' the next time a journey starts. */\n cancel: () => void;\n /** Force a manual route recalculation. */\n recalculate: () => void;\n}\n\n/**\n * Everything related to a map journey — preview, active navigation, and ETA —\n * exposed as plain data and actions so devs can build their own preview/journey\n * panel instead of using the SDK's built-in one.\n *\n * Stays in sync with `<Map/>`'s built-in navigation UI: both this hook and\n * `<Map/>` react to the same `sdk.navigation.*` imperative events, so you can\n * use `useJourney()` to drive a fully custom UI while `<Map/>` handles the\n * route line/camera, or use it standalone with the `navigation` option.\n */\nexport const useJourney = (\n options: UseJourneyOptions = {},\n): UseJourneyResult => {\n const { navigation, onAbort, onModeChange } = options;\n\n const [progNav, setProgNav] = useState<{\n destination: [number, number] | null;\n origin?: [number, number] | null;\n profile?: LiveRoutingOptions[\"profile\"];\n mode?: NavMode;\n recalculateThreshold?: number;\n } | null>(null);\n const [isAborted, setIsAborted] = useState(false);\n\n useEffect(() => {\n const unsubCreate = sdk.on(\"SDK_NAVIGATION_CREATE\", (payload: any) => {\n setIsAborted(false);\n setProgNav(payload);\n });\n const unsubStart = sdk.on(\"SDK_NAVIGATION_START\", () => {\n setIsAborted(false);\n setProgNav((prev) => (prev ? { ...prev, mode: \"navigation\" } : null));\n });\n const unsubAbort = sdk.on(\"SDK_NAVIGATION_ABORT\", () => {\n setIsAborted(true);\n setProgNav(null);\n });\n\n return () => {\n unsubCreate();\n unsubStart();\n unsubAbort();\n };\n }, []);\n\n const effectiveOptions = progNav || navigation;\n\n const internalNav = useLiveRouting({\n destination: effectiveOptions?.destination || null,\n enabled: !isAborted && !!effectiveOptions?.destination,\n initialMode: effectiveOptions?.mode || \"preview\",\n origin: effectiveOptions?.origin,\n profile: effectiveOptions?.profile || \"driving\",\n recalculateThreshold: effectiveOptions?.recalculateThreshold || 50,\n });\n\n // Reset isAborted whenever a genuinely new destination comes in — a fresh\n // journey should never inherit the aborted flag from a previous one.\n const prevDest = useRef<[number, number] | null | undefined>(null);\n const currentDest = effectiveOptions?.destination;\n useEffect(() => {\n if (\n currentDest &&\n (!prevDest.current ||\n prevDest.current[0] !== currentDest[0] ||\n prevDest.current[1] !== currentDest[1])\n ) {\n setIsAborted(false);\n }\n prevDest.current = currentDest;\n }, [currentDest]);\n\n const onModeChangeRef = useRef(onModeChange);\n onModeChangeRef.current = onModeChange;\n useEffect(() => {\n onModeChangeRef.current?.(internalNav.mode);\n }, [internalNav.mode]);\n\n const isActive = !isAborted && !!effectiveOptions?.destination;\n\n const distanceRemainingMeters = isActive\n ? internalNav.currentDistanceMeters\n : null;\n const totalDistanceMeters = isActive ? internalNav.totalDistance : null;\n const routeDurationSeconds = internalNav.route?.durationSeconds ?? null;\n\n const remainingMeters = distanceRemainingMeters ?? 0;\n const distanceRemainingKm = remainingMeters / 1000;\n\n const etaMinutes = (() => {\n if (\n !routeDurationSeconds ||\n !totalDistanceMeters ||\n !distanceRemainingMeters\n )\n return 0;\n const ratio = distanceRemainingMeters / totalDistanceMeters;\n return Math.ceil((routeDurationSeconds * ratio) / 60);\n })();\n\n const progress =\n totalDistanceMeters && totalDistanceMeters > 0\n ? Math.min(\n 100,\n Math.max(\n 0,\n ((totalDistanceMeters - remainingMeters) / totalDistanceMeters) *\n 100,\n ),\n )\n : 0;\n\n const cancel = useCallback(() => {\n setIsAborted(true);\n setProgNav(null);\n sdk.navigation.abort();\n if (onAbort) onAbort();\n }, [onAbort]);\n\n const start = useCallback(() => {\n sdk.navigation.start();\n internalNav.start();\n }, [internalNav.start]);\n\n return {\n cancel,\n distanceRemainingKm,\n distanceRemainingMeters,\n error: isActive ? internalNav.error : null,\n etaMinutes,\n isActive,\n isCalculating: isActive ? internalNav.isCalculating : false,\n mode: isActive ? internalNav.mode : \"preview\",\n progress,\n recalculate: internalNav.recalculate,\n route: isActive ? internalNav.route : null,\n start,\n totalDistanceMeters,\n };\n};\n","import { useMemo } from \"react\";\n\n/**\n * Slices a LineString to start at the point closest to the provided coordinates.\n * This removes the \"already traveled\" portion of the route.\n */\nexport const useTrimmedRoute = (\n route: GeoJSON.LineString | undefined,\n userLocation: [number, number] | null,\n): GeoJSON.LineString | undefined => {\n return useMemo(() => {\n if (!route || !userLocation || route.coordinates.length < 2) return route;\n\n const coords = route.coordinates as [number, number][];\n\n // 1. Find the index of the segment closest to the user\n let minDistance = Infinity;\n let closestIndex = 0;\n\n const getDistSq = (p1: [number, number], p2: [number, number]) => {\n return (p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2;\n };\n\n // We search for the point in the original geometry closest to the user\n for (let i = 0; i < coords.length; i++) {\n const dist = getDistSq(userLocation, coords[i]);\n if (dist < minDistance) {\n minDistance = dist;\n closestIndex = i;\n }\n }\n\n // 2. Slice the route from that point onwards\n // We also prepend the ACTUAL user location to ensure the line starts exactly at the blue dot\n const remainingCoords = coords.slice(closestIndex + 1);\n\n return {\n coordinates: [userLocation, ...remainingCoords],\n type: \"LineString\",\n };\n }, [route, userLocation]);\n};\n","import { Layer, Source } from \"@vis.gl/react-maplibre\";\nimport type React from \"react\";\n\nexport interface RouteLayerProps {\n /** The route geometry as a GeoJSON LineString */\n geometry?: GeoJSON.LineString;\n /** Color of the route line. Defaults to #3b82f6 (blue-500). */\n color?: string;\n /** Width of the route line. Defaults to 5. */\n width?: number;\n /** Opacity of the route line. Defaults to 0.8. */\n opacity?: number;\n}\n\nexport const RouteLayer: React.FC<RouteLayerProps> = ({\n geometry,\n color = \"#3b82f6\",\n width = 5,\n opacity = 0.8,\n}) => {\n if (!geometry) return null;\n\n const data: GeoJSON.Feature<GeoJSON.LineString> = {\n geometry,\n properties: {},\n type: \"Feature\",\n };\n\n return (\n <Source data={data} id=\"sdk-route-source\" type=\"geojson\">\n <Layer\n id=\"sdk-route-layer-casing\"\n paint={{\n \"line-blur\": 1,\n \"line-color\": \"#ffffff\",\n \"line-opacity\": opacity,\n \"line-width\": width + 2,\n }}\n type=\"line\"\n />\n <Layer\n id=\"sdk-route-layer\"\n layout={{\n \"line-cap\": \"round\",\n \"line-join\": \"round\",\n }}\n paint={{\n \"line-color\": color,\n \"line-opacity\": opacity,\n \"line-width\": width,\n }}\n type=\"line\"\n />\n </Source>\n );\n};\n","const EARTH_RADIUS_METERS = 6371000;\n\n/**\n * Builds an approximate geodesic circle polygon (GeoJSON) around a\n * [lng, lat] center for a given radius in meters. Used to render a\n * real-world-scaled radius overlay (e.g. the mock geolocation \"scan\n * radius\" helper) on the map — a fixed-pixel circle would not scale\n * correctly across zoom levels or latitudes.\n */\nexport const buildGeoCircle = (\n center: [number, number],\n radiusMeters: number,\n points = 64,\n): GeoJSON.Feature<GeoJSON.Polygon> => {\n const [lng, lat] = center;\n const latRad = (lat * Math.PI) / 180;\n const coordinates: [number, number][] = [];\n\n for (let i = 0; i <= points; i++) {\n const angle = (i / points) * 2 * Math.PI;\n const dLat =\n ((radiusMeters * Math.cos(angle)) / EARTH_RADIUS_METERS) *\n (180 / Math.PI);\n const dLng =\n ((radiusMeters * Math.sin(angle)) /\n (EARTH_RADIUS_METERS * Math.cos(latRad))) *\n (180 / Math.PI);\n coordinates.push([lng + dLng, lat + dLat]);\n }\n\n return {\n geometry: {\n coordinates: [coordinates],\n type: \"Polygon\",\n },\n properties: {},\n type: \"Feature\",\n };\n};\n","import { buildGeoCircle } from \"@miniapps-sdk/components/Map/utils/geoCircle\";\nimport { Layer, Source } from \"@vis.gl/react-maplibre\";\nimport type React from \"react\";\nimport { useMemo } from \"react\";\n\nexport interface MockRadiusLayerProps {\n center: [number, number];\n radiusMeters: number;\n color?: string;\n}\n\n/**\n * Dev-only visual aid drawn around the mocked user location, showing the\n * real-world distance (in meters) configured in the BridgeMocker's radius\n * slider — useful to eyeball whether a point-of-interest sits within a\n * \"scan\" radius (e.g. Explore's /explore/scan unlock distance) before\n * wiring up real GPS.\n */\nexport const MockRadiusLayer: React.FC<MockRadiusLayerProps> = ({\n center,\n radiusMeters,\n // Neutral gray, not any one app's accent color — this debug aid is shared\n // across every mini-app (each with its own, different palette), so it\n // shouldn't default to a color that reads as \"part of the app\" (was\n // #39ff88, a neon green/yellow left over from an earlier shared theme,\n // reported as looking like an unwanted yellow border around the user's\n // position marker in up-miniapps-explore, which has since moved to a\n // pastel palette with no neon accents at all).\n color = \"#e2e8f0\",\n}) => {\n const data = useMemo(\n () => buildGeoCircle(center, radiusMeters),\n [center, radiusMeters],\n );\n\n return (\n <Source data={data} id=\"sdk-mock-radius-source\" type=\"geojson\">\n <Layer\n id=\"sdk-mock-radius-fill\"\n paint={{\n \"fill-color\": color,\n \"fill-opacity\": 0.12,\n }}\n type=\"fill\"\n />\n <Layer\n id=\"sdk-mock-radius-outline\"\n paint={{\n \"line-color\": color,\n \"line-dasharray\": [2, 2],\n \"line-width\": 2,\n }}\n type=\"line\"\n />\n </Source>\n );\n};\n","import type { POI } from \"@miniapps-sdk/components/Map/types\";\nimport { Layer, Source, useMap } from \"@vis.gl/react-maplibre\";\nimport type React from \"react\";\nimport { useEffect, useMemo, useState } from \"react\";\n\n/**\n * Utility to render an emoji to ImageData for use as a MapLibre icon\n */\nfunction createEmojiIcon(emoji: string, size = 64): ImageData {\n const canvas = document.createElement(\"canvas\");\n canvas.width = size;\n canvas.height = size;\n const ctx = canvas.getContext(\"2d\")!;\n ctx.font = `${size * 0.75}px serif`;\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n ctx.fillText(emoji, size / 2, size / 2);\n return ctx.getImageData(0, 0, size, size);\n}\n\nexport const POILayers: React.FC<{\n pois: POI[];\n}> = ({ pois }) => {\n const [loadedImages, setLoadedImages] = useState<number>(0);\n const { current: map } = useMap();\n\n // Filter for GL-mode POIs - stable memoized list\n const glPois = useMemo(\n () => pois.filter((p) => !p.displayMode || p.displayMode === \"gl\"),\n [pois],\n );\n\n useEffect(() => {\n if (!map) return;\n const glMap = map.getMap();\n\n // Built-in default emoji icons\n const defaults = [\n { emoji: \"🍺\", name: \"sdk-default-bar\" },\n { emoji: \"🍽️\", name: \"sdk-default-restaurant\" },\n { emoji: \"📍\", name: \"sdk-default-poi\" },\n ];\n\n defaults.forEach((def) => {\n if (!glMap.hasImage(def.name)) {\n glMap.addImage(def.name, createEmojiIcon(def.emoji), { pixelRatio: 2 });\n }\n });\n\n // Handle custom image URLs and custom emojis\n let updates = 0;\n glPois.forEach((poi) => {\n // 1. Custom URL Image\n if (poi.imageUrl) {\n const name = `custom-url-${poi.id}`;\n if (!glMap.hasImage(name)) {\n (glMap.loadImage as any)(poi.imageUrl, (error: any, image: any) => {\n if (!error && image) {\n if (!glMap.hasImage(name)) {\n glMap.addImage(name, image);\n setLoadedImages((prev) => prev + 1);\n }\n }\n });\n }\n }\n\n // 2. Custom Emoji Icon\n if (poi.emoji) {\n const name = `custom-emoji-${poi.emoji}`;\n if (!glMap.hasImage(name)) {\n glMap.addImage(name, createEmojiIcon(poi.emoji), { pixelRatio: 2 });\n updates++;\n }\n }\n });\n\n if (updates > 0) {\n setLoadedImages((prev) => prev + updates);\n }\n }, [map, glPois]);\n\n const geojson: any = useMemo(\n () => ({\n features: glPois.map((poi) => ({\n geometry: {\n coordinates: [poi.longitude, poi.latitude],\n type: \"Point\" as const,\n },\n properties: {\n ...poi,\n // Selection logic for the icon in GL\n \"sdk-icon\": poi.imageUrl\n ? `custom-url-${poi.id}`\n : poi.spriteName\n ? poi.spriteName\n : poi.emoji\n ? `custom-emoji-${poi.emoji}`\n : poi.type === \"bar\"\n ? \"sdk-default-bar\"\n : poi.type === \"restaurant\"\n ? \"sdk-default-restaurant\"\n : \"sdk-default-poi\",\n },\n type: \"Feature\" as const,\n })),\n type: \"FeatureCollection\" as const,\n }),\n [glPois],\n );\n\n return (\n <Source data={geojson} id=\"sdk-pois\" type=\"geojson\">\n <Layer\n id=\"sdk-poi-layer\"\n layout={{\n \"icon-allow-overlap\": true,\n \"icon-image\": [\"get\", \"sdk-icon\"],\n \"icon-size\": 1,\n \"text-anchor\": \"top\",\n \"text-field\": [\n \"step\",\n [\"zoom\"],\n \"\", // Show nothing when zoomed out\n 14,\n [\"get\", \"name\"], // Show name when zoomed in\n ],\n \"text-font\": [\"Open Sans Bold\"],\n \"text-offset\": [0, 1.5],\n \"text-optional\": true,\n \"text-size\": 11,\n }}\n paint={{\n \"icon-opacity\": [\"interpolate\", [\"linear\"], [\"zoom\"], 11, 0, 12, 1],\n \"text-color\": \"#ffffff\",\n \"text-halo-color\": \"#000000\",\n \"text-halo-width\": 1,\n \"text-opacity\": [\"interpolate\", [\"linear\"], [\"zoom\"], 13.5, 0, 14, 1],\n }}\n type=\"symbol\"\n />\n </Source>\n );\n};\n","import type { POI } from \"@miniapps-sdk/components/Map/types\";\nimport { Marker } from \"@vis.gl/react-maplibre\";\nimport type React from \"react\";\n\nexport const POIMarkers: React.FC<{\n pois: POI[];\n onClick?: (poi: POI) => void;\n}> = ({ pois, onClick }) => {\n // Filter for Marker-mode POIs\n const markerPois = pois.filter((p) => p.displayMode === \"marker\");\n\n if (markerPois.length === 0) return null;\n\n return (\n <>\n {markerPois.map((poi) => (\n <Marker\n anchor=\"bottom\"\n key={poi.id}\n latitude={poi.latitude}\n longitude={poi.longitude}\n onClick={(e) => {\n e.originalEvent.stopPropagation();\n if (onClick) onClick(poi);\n }}\n >\n {poi.markerComponent ? (\n poi.markerComponent\n ) : (\n <div\n style={{\n cursor: \"pointer\",\n filter: \"drop-shadow(0 4px 6px rgba(0,0,0,0.1))\",\n transform: \"transition-transform duration-200 hover:scale-110\",\n }}\n >\n <div\n style={{\n alignItems: \"center\",\n backgroundColor: poi.type === \"bar\" ? \"#f97316\" : \"#10b981\",\n border: \"2px solid white\",\n borderRadius: \"50%\",\n display: \"flex\",\n height: \"32px\",\n justifyContent: \"center\",\n width: \"32px\",\n }}\n >\n {poi.emoji ? (\n <span style={{ fontSize: \"16px\" }}>{poi.emoji}</span>\n ) : (\n <div\n style={{\n backgroundColor: \"white\",\n borderRadius: \"50%\",\n height: \"8px\",\n width: \"8px\",\n }}\n ></div>\n )}\n </div>\n {/* Pin Tail */}\n <div\n style={{\n borderLeft: \"6px solid transparent\",\n borderRight: \"6px solid transparent\",\n borderTop: `8px solid ${poi.type === \"bar\" ? \"#f97316\" : \"#10b981\"}`,\n height: 0,\n margin: \"-2px auto 0\",\n width: 0,\n }}\n ></div>\n </div>\n )}\n </Marker>\n ))}\n </>\n );\n};\n","import { Marker } from \"@vis.gl/react-maplibre\";\nimport type React from \"react\";\n\nexport interface UserLocationLayerProps {\n /**\n * The location to display.\n */\n forcedLocation: [number, number] | null;\n /**\n * The user's heading (bearing) in degrees.\n */\n heading?: number | null;\n}\n\nexport const UserLocationLayer: React.FC<UserLocationLayerProps> = ({\n forcedLocation,\n heading,\n}) => {\n if (!forcedLocation) return null;\n\n return (\n <Marker\n anchor=\"center\"\n latitude={forcedLocation[1]}\n longitude={forcedLocation[0]}\n >\n <div\n style={{\n alignItems: \"center\",\n display: \"flex\",\n justifyContent: \"center\",\n position: \"relative\",\n }}\n >\n {/* Pulse Animation */}\n <div\n style={{\n animation: \"pulse 2s infinite\",\n backgroundColor: \"rgba(59, 130, 246, 0.4)\",\n borderRadius: \"50%\",\n height: \"40px\",\n position: \"absolute\",\n width: \"40px\",\n }}\n ></div>\n\n {/* Heading Indicator (Cone/Arrow) */}\n {heading !== undefined && heading !== null && (\n <div\n style={{\n height: \"60px\",\n position: \"absolute\",\n transform: `rotate(${heading}deg)`,\n width: \"60px\",\n zIndex: 0,\n }}\n >\n <svg\n style={{ height: \"100%\", width: \"100%\" }}\n viewBox=\"0 0 100 100\"\n >\n <defs>\n <radialGradient\n cx=\"50%\"\n cy=\"50%\"\n fx=\"50%\"\n fy=\"50%\"\n id=\"grad1\"\n r=\"50%\"\n >\n <stop\n offset=\"0%\"\n style={{\n stopColor: \"rgba(37, 99, 235, 0.6)\",\n stopOpacity: 1,\n }}\n />\n <stop\n offset=\"100%\"\n style={{\n stopColor: \"rgba(37, 99, 235, 0)\",\n stopOpacity: 0,\n }}\n />\n </radialGradient>\n </defs>\n {/* Visual Direction Cone */}\n <path\n d=\"M 50 50 L 35 0 A 50 50 0 0 1 65 0 Z\"\n fill=\"url(#grad1)\"\n />\n </svg>\n </div>\n )}\n\n {/* Main Blue Dot */}\n <div\n style={{\n alignItems: \"center\",\n backgroundColor: \"white\",\n borderRadius: \"50%\",\n boxShadow:\n \"0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 0 0 2px rgba(37, 99, 235, 0.2)\",\n display: \"flex\",\n height: \"20px\",\n justifyContent: \"center\",\n width: \"20px\",\n zIndex: 1,\n }}\n >\n <div\n style={{\n backgroundColor: \"#2563eb\",\n border: \"2px solid white\",\n borderRadius: \"50%\",\n height: \"12px\",\n width: \"12px\",\n }}\n ></div>\n </div>\n <style>{`@keyframes pulse { 0% { transform: scale(0.95); opacity: 0.7; } 70% { transform: scale(1.5); opacity: 0; } 100% { transform: scale(0.95); opacity: 0; } }`}</style>\n </div>\n </Marker>\n );\n};\n","import { MapControls } from \"@miniapps-sdk/components/Map/components/MapControls\";\nimport {\n MapMenu,\n MapMenuDivider,\n MapMenuFooter,\n MapMenuItem,\n MapMenuTitle,\n} from \"@miniapps-sdk/components/Map/components/MapMenu\";\nimport { useJourney } from \"@miniapps-sdk/components/Map/hooks/useJourney\";\nimport { useTrimmedRoute } from \"@miniapps-sdk/components/Map/hooks/useTrimmedRoute\";\nimport { useUserLocation } from \"@miniapps-sdk/components/Map/hooks/useUserLocation\";\nimport { MockRadiusLayer } from \"@miniapps-sdk/components/Map/layers/MockRadiusLayer\";\nimport { POILayers } from \"@miniapps-sdk/components/Map/layers/POILayers\";\nimport { POIMarkers } from \"@miniapps-sdk/components/Map/layers/POIMarkers\";\nimport { RouteLayer } from \"@miniapps-sdk/components/Map/layers/RouteLayer\";\nimport { UserLocationLayer } from \"@miniapps-sdk/components/Map/layers/UserLocationLayer\";\nimport {\n type CenterCallbackParams,\n type FlyToParams,\n MapControlsContext,\n SDKMapProvider,\n} from \"@miniapps-sdk/components/Map/MapContext\";\nimport { MockLocationContext } from \"@miniapps-sdk/components/Map/MockLocationContext\";\nimport type { MapProps, POI } from \"@miniapps-sdk/components/Map/types\";\nimport type { MapRef } from \"@vis.gl/react-maplibre\";\nimport { Map as MapLibre, MapProvider } from \"@vis.gl/react-maplibre\";\nimport React, {\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport \"maplibre-gl/dist/maplibre-gl.css\";\n\nconst MapInternal: React.FC<MapProps> = ({\n initialViewState = {\n latitude: 45.90583599233422,\n longitude: 6.12589018919138,\n zoom: 12,\n },\n style = {},\n mapStyle = \"https://tiles.cloudparse.fr/style/up_dark_matter\",\n className = \"\",\n maxBounds,\n children,\n onClick,\n onMapClickMiss,\n onContextMenu,\n interactiveLayerIds = [],\n onLoad,\n showUserLocation = true,\n followUser: initialFollowUser = false,\n lockToUser = false,\n showUserLocationButton = true,\n renderUserLocation,\n pois = [],\n onPoiClick,\n route: externalRoute,\n showNavigationUI: externalShowNavigationUI,\n navigationData: externalNavigationData,\n onNavigationAbort,\n onNavigationModeChange,\n navigation,\n showControls = true,\n menuItems,\n menuContent,\n drawerState: propDrawerState,\n drawerContentRef,\n controlProps = {},\n enableTouchDrag = false,\n}) => {\n const mapControls = useContext(MapControlsContext);\n const mockLocation = useContext(MockLocationContext);\n\n const mapRef = useRef<MapRef | null>(null);\n\n // Get user location state (data only)\n const userLocationState = useUserLocation();\n\n // Journey state (preview/navigation/eta) — used only when `navigation` prop\n // or the imperative sdk.navigation.* API drives this Map. See useJourney()\n // for the standalone public hook devs can use to build their own UI.\n const journey = useJourney({\n navigation,\n onModeChange: navigation ? onNavigationModeChange : undefined,\n });\n\n const hasIntegratedNav = journey.isActive;\n\n // Merge external and internal data\n const navigationData = hasIntegratedNav\n ? {\n currentDistanceMeters: journey.distanceRemainingMeters,\n mode: journey.mode,\n route: journey.route,\n start: journey.start,\n totalDistance: journey.totalDistanceMeters,\n }\n : externalNavigationData;\n const route = hasIntegratedNav ? journey.route?.geometry : externalRoute;\n const showNavigationUI = hasIntegratedNav\n ? externalShowNavigationUI !== false && navigation?.showUI !== false\n : externalShowNavigationUI;\n\n const mode = navigationData?.mode || \"preview\";\n const resolvedInitialFollow = mapControls\n ? mapControls.isFollowing\n : initialFollowUser;\n\n // Synchronous refs for the render loop to avoid React state batching race conditions\n const isFollowingRef = useRef(resolvedInitialFollow);\n const isFlyingRef = useRef(false);\n // Shared across EVERY camera-animation call site in this component\n // (initial-follow flyTo, navigation-lock flyTo, handleCenterOnUser,\n // handleFlyTo) — guards the lock-release against a later call\n // superseding an earlier one still mid-flight: without a SHARED counter,\n // an earlier call's release firing after a later call has already\n // started would clear isFlyingRef mid-animation of the later one,\n // letting a GPS tick fight it (the exact bug this locking exists to\n // prevent). A counter scoped to just one call site isn't enough — any\n // two of these can interleave (e.g. selecting a venue while navigation\n // auto-starts).\n const flyingGenerationRef = useRef(0);\n const lockFlying = useCallback(() => {\n isFlyingRef.current = true;\n return ++flyingGenerationRef.current;\n }, []);\n const releaseFlyingIfCurrent = useCallback((flightId: number) => {\n if (flyingGenerationRef.current === flightId) {\n isFlyingRef.current = false;\n }\n }, []);\n\n // We use the context directly for UI updates if it exists, otherwise we fallback to a local state\n const [localIsFollowingUI, setLocalIsFollowingUI] = useState(\n resolvedInitialFollow,\n );\n const isFollowingUI = mapControls\n ? mapControls.isFollowing\n : localIsFollowingUI;\n\n const setIsFollowingCtx = mapControls?.setIsFollowing;\n\n const setFollowMode = useCallback(\n (follow: boolean) => {\n isFollowingRef.current = follow;\n\n // Update local UI state as a fallback\n setLocalIsFollowingUI(follow);\n\n // Update context UI state\n if (setIsFollowingCtx) {\n setIsFollowingCtx(follow);\n }\n },\n [setIsFollowingCtx],\n );\n\n // Sync context state changes into the local ref (if external client called setFollowMode)\n useEffect(() => {\n if (mapControls && mapControls.isFollowing !== isFollowingRef.current) {\n isFollowingRef.current = mapControls.isFollowing;\n }\n }, [mapControls?.isFollowing, mapControls]);\n\n const mergedInteractiveLayerIds = [...interactiveLayerIds];\n if (pois.length > 0 && !mergedInteractiveLayerIds.includes(\"sdk-poi-layer\")) {\n mergedInteractiveLayerIds.push(\"sdk-poi-layer\");\n }\n\n const prevInitialFollow = useRef(initialFollowUser);\n // Reactive follow state sync from props\n useEffect(() => {\n if (initialFollowUser !== prevInitialFollow.current) {\n setFollowMode(initialFollowUser);\n prevInitialFollow.current = initialFollowUser;\n\n if (initialFollowUser && userLocationState.coords && mapRef.current) {\n const flightId = lockFlying();\n mapRef.current.flyTo({\n center: userLocationState.coords,\n duration: 1000,\n essential: true,\n zoom: Math.max(mapRef.current.getZoom(), 16),\n });\n setTimeout(() => {\n releaseFlyingIfCurrent(flightId);\n }, 1050);\n }\n }\n }, [\n initialFollowUser,\n setFollowMode,\n userLocationState.coords,\n lockFlying,\n releaseFlyingIfCurrent,\n ]);\n\n const lastAutoLockedRouteRef = useRef<any>(null);\n const lastModeRef = useRef<string | null>(null);\n\n // Auto-lock camera or fit bounds depending on mode\n useEffect(() => {\n if (!route || !mapRef.current) {\n if (!route) lastAutoLockedRouteRef.current = null;\n return;\n }\n\n const isNewRoute = route !== lastAutoLockedRouteRef.current;\n const modeChanged = lastModeRef.current !== mode;\n\n if (mode === \"navigation\") {\n if (modeChanged || isNewRoute) {\n // Only (re-)lock the camera when navigation just started or the\n // route just changed — not on every re-run of this effect (it also\n // depends on userLocationState.coords, which changes on every GPS\n // tick). Otherwise a manual pan/rotate during active navigation\n // would get re-locked on the very next location update.\n setFollowMode(true);\n }\n if (\n (modeChanged || isNewRoute) &&\n userLocationState.coords &&\n mapRef.current\n ) {\n const flightId = lockFlying();\n mapRef.current.flyTo({\n center: userLocationState.coords,\n duration: 1000,\n essential: true,\n zoom: 17, // Zoomed in on user for active guidance\n });\n setTimeout(() => {\n releaseFlyingIfCurrent(flightId);\n }, 1050);\n }\n } else if (mode === \"preview\" && isNewRoute) {\n setFollowMode(false);\n // Fit bounds to show entire route\n const coords = route.coordinates;\n if (coords.length > 0) {\n const bounds = coords.reduce(\n (acc, coord) => {\n return [\n [Math.min(acc[0][0], coord[0]), Math.min(acc[0][1], coord[1])],\n [Math.max(acc[1][0], coord[0]), Math.max(acc[1][1], coord[1])],\n ];\n },\n [\n [coords[0][0], coords[0][1]],\n [coords[0][0], coords[0][1]],\n ],\n );\n\n mapRef.current.fitBounds(\n [bounds[0][0], bounds[0][1], bounds[1][0], bounds[1][1]],\n { padding: 100, speed: 1.2 },\n );\n }\n }\n\n lastAutoLockedRouteRef.current = route;\n lastModeRef.current = mode;\n }, [\n route,\n mode,\n setFollowMode,\n userLocationState.coords,\n lockFlying,\n releaseFlyingIfCurrent,\n ]);\n\n // Continuous Camera Tracking\n useEffect(() => {\n // Read from the ref synchronously to guarantee we don't fight a manual interaction that just occurred\n if (\n isFollowingRef.current &&\n !isFlyingRef.current &&\n userLocationState.coords &&\n mapRef.current\n ) {\n mapRef.current.easeTo({\n center: userLocationState.coords,\n duration: 50, // Ultra-short for high-frequency interpolated stream\n easing: (t) => t,\n essential: true,\n });\n }\n }, [userLocationState.coords]);\n\n // Dynamically trim the route\n const displayRoute = useTrimmedRoute(\n route,\n showUserLocation ? userLocationState.coords : null,\n );\n\n // Compute etaData from navigationData if active\n // Extract primitives directly so useMemo dependency array can track changes\n const currentDistMeters = navigationData?.currentDistanceMeters ?? null;\n const totalDist = navigationData?.totalDistance ?? null;\n const routeDurationSeconds = navigationData?.route?.durationSeconds ?? null;\n\n // Use currentDistanceMeters (real-time along route) — never fall back to route.distanceMeters\n // (that's the total distance, which would make progress 0 or negative)\n const remainingMeters = currentDistMeters ?? 0;\n\n // ETA: scale route duration proportionally to remaining distance\n const etaMins = (() => {\n if (!routeDurationSeconds || !totalDist || !currentDistMeters) return 0;\n const ratio = currentDistMeters / totalDist;\n return Math.ceil((routeDurationSeconds * ratio) / 60);\n })();\n\n const kmRemaining = remainingMeters / 1000;\n\n const progressValue =\n totalDist && totalDist > 0\n ? Math.min(\n 100,\n Math.max(0, ((totalDist - remainingMeters) / totalDist) * 100),\n )\n : 0;\n\n // No useMemo here — primitive deps change on every location update,\n // useMemo was hiding the updates because navigationData object ref is stable\n const showEtaData =\n showNavigationUI && navigationData && route\n ? {\n distanceRemainingKm: kmRemaining,\n etaMins,\n label:\n mode === \"navigation\" ? \"Walking Guidance Active\" : \"Route Preview\",\n mode: mode,\n onAbort: () => {\n journey.cancel();\n if (onNavigationAbort) {\n onNavigationAbort();\n }\n },\n onStart: navigationData.start,\n progress: progressValue,\n }\n : undefined;\n\n // Sync etaData to context so controls can access it\n const setEtaDataCtx = mapControls?.setEtaData;\n useEffect(() => {\n if (setEtaDataCtx) {\n setEtaDataCtx(showEtaData);\n }\n }, [showEtaData, setEtaDataCtx]);\n\n // Sync propDrawerState to context so it can be controlled programmatically from Map props\n const setDrawerStateCtx = mapControls?.setDrawerState;\n useEffect(() => {\n if (setDrawerStateCtx && propDrawerState !== undefined) {\n setDrawerStateCtx(propDrawerState);\n }\n }, [propDrawerState, setDrawerStateCtx]);\n\n // No demo fallback here on purpose — a placeholder menu item used to leak\n // into real apps' UI as a visible flash whenever `menuContent`/`menuItems`\n // were momentarily empty (e.g. during a mode-switch re-render).\n const resolvedMenuItems = menuItems ?? [];\n\n const { mapLibreChildren, menuContentFromChildren } = useMemo(() => {\n const mapLibreChildren: React.ReactNode[] = [];\n const extractedMenuItems: React.ReactNode[] = [];\n\n React.Children.forEach(children, (child) => {\n if (React.isValidElement(child)) {\n const type = child.type;\n const displayName = (type as any)?.displayName || (type as any)?.name;\n const isMenu = type === MapMenu || displayName === \"MapMenu\";\n const isMenuComponent =\n isMenu ||\n type === MapMenuItem ||\n type === MapMenuTitle ||\n type === MapMenuDivider ||\n type === MapMenuFooter ||\n [\n \"MapMenuItem\",\n \"MapMenuTitle\",\n \"MapMenuDivider\",\n \"MapMenuFooter\",\n ].includes(displayName);\n\n if (isMenu) {\n React.Children.forEach(\n (child as React.ReactElement<any>).props.children,\n (nestedChild) => {\n if (nestedChild) {\n extractedMenuItems.push(nestedChild);\n }\n },\n );\n } else if (isMenuComponent) {\n extractedMenuItems.push(child);\n } else {\n mapLibreChildren.push(child);\n }\n } else {\n mapLibreChildren.push(child);\n }\n });\n\n const menuContentFromChildren =\n extractedMenuItems.length > 0 ? (\n <MapMenu>{extractedMenuItems}</MapMenu>\n ) : null;\n\n return { mapLibreChildren, menuContentFromChildren };\n }, [children]);\n\n const handleMapClick = (e: any) => {\n if (mockLocation?.isPlacingLocation) {\n mockLocation.placeLocation([e.lngLat.lng, e.lngLat.lat]);\n return;\n }\n\n const clickedFeatures = e.features || [];\n\n if (onPoiClick) {\n const poiFeature = clickedFeatures.find(\n (f: any) => f.layer.id === \"sdk-poi-layer\",\n );\n if (poiFeature) {\n onPoiClick(poiFeature.properties as POI);\n return;\n }\n }\n\n // Check if the click hit any interactive layers\n const hitInteractive = clickedFeatures.some((f: any) =>\n mergedInteractiveLayerIds.includes(f.layer.id),\n );\n\n if (!hitInteractive) {\n if (onMapClickMiss) {\n onMapClickMiss(e);\n }\n }\n\n if (onClick) onClick(e);\n };\n\n const handleCenterOnUser = useCallback(\n (payload?: CenterCallbackParams) => {\n if (userLocationState.coords && mapRef.current) {\n setFollowMode(true);\n const flightId = lockFlying(); // Lock continuous tracking during the cinematic flyTo\n\n mapRef.current.flyTo({\n center: userLocationState.coords,\n duration: 1000,\n essential: true,\n pitch: payload?.pitch || 0,\n zoom: Math.max(mapRef.current.getZoom(), 16),\n ...(payload?.bearing !== undefined\n ? { bearing: payload.bearing }\n : {}),\n });\n\n // Release the lock when flyTo completes\n setTimeout(() => {\n releaseFlyingIfCurrent(flightId);\n }, 1050);\n }\n },\n [\n userLocationState.coords,\n setFollowMode,\n lockFlying,\n releaseFlyingIfCurrent,\n ],\n );\n\n const handleFlyTo = useCallback(\n (coords: [number, number], params?: FlyToParams) => {\n const map = mapRef.current;\n if (!map) return;\n // Disable follow-mode AND lock out the continuous-tracking effect for\n // the duration of the animation — otherwise a live location update\n // arriving mid-flight immediately snaps the camera back onto the\n // user, undoing this flyTo (this only \"worked\" after the user first\n // manually panned the map, since panning is what disables follow).\n setFollowMode(false);\n const flightId = lockFlying();\n\n map.flyTo({\n center: coords,\n essential: true,\n pitch: params?.pitch ?? 0,\n zoom: params?.zoom ?? map.getZoom(),\n // Omit entirely (rather than defaulting to a fixed number) when\n // not given, so MapLibre computes its own distance-based duration.\n ...(params?.duration !== undefined\n ? { duration: params.duration }\n : {}),\n ...(params?.bearing !== undefined ? { bearing: params.bearing } : {}),\n });\n\n // Release tied to the actual animation completing (fires on\n // interruption too, e.g. a second flyTo cutting this one short) —\n // not a guessed timeout, which can't know the real duration once it's\n // MapLibre's own distance-based default.\n map.once(\"moveend\", () => releaseFlyingIfCurrent(flightId));\n },\n [setFollowMode, lockFlying, releaseFlyingIfCurrent],\n );\n\n const handleResetBearing = useCallback((params?: CenterCallbackParams) => {\n if (mapRef.current) {\n mapRef.current.easeTo({\n bearing: 0,\n duration: 500,\n essential: true,\n pitch: params?.pitch ?? 0,\n });\n }\n }, []);\n\n // Register callbacks to context so controls can trigger centering and resets\n useEffect(() => {\n if (mapControls) {\n mapControls._registerCenterCallback(handleCenterOnUser);\n mapControls._registerResetBearingCallback(handleResetBearing);\n mapControls._registerFlyToCallback(handleFlyTo);\n }\n }, [mapControls, handleCenterOnUser, handleResetBearing, handleFlyTo]);\n\n const handleMove = useCallback(() => {\n if (mapRef.current && mapControls) {\n mapControls.setBearing(mapRef.current.getBearing());\n mapControls.setPitch(mapRef.current.getPitch());\n }\n }, [mapControls]);\n\n // Instantly halt animations and drop tracking on manual input — unless\n // `lockToUser` is set, in which case following is an authoritative lock\n // (e.g. a GPS-driven tracker/game) rather than a one-time initial default,\n // and manual pointer interaction must not silently disable it (previously\n // the camera stopped following on the very first drag/wheel/touch event\n // and never recovered without an explicit recenter call).\n const handleUserInteraction = () => {\n if (lockToUser) return;\n\n if (isFollowingRef.current) {\n setFollowMode(false);\n if (mapRef.current) {\n mapRef.current.stop(); // Stops any ongoing easeTo immediately\n }\n }\n };\n\n return (\n <div\n className={`w-full h-full overflow-hidden relative ${mockLocation?.isPlacingLocation ? \"cursor-crosshair\" : \"\"} ${className}`}\n style={style}\n >\n <MapLibre\n attributionControl={false}\n initialViewState={initialViewState}\n interactiveLayerIds={mergedInteractiveLayerIds}\n mapStyle={mapStyle}\n maxBounds={maxBounds}\n onClick={handleMapClick}\n onContextMenu={onContextMenu}\n onDragStart={handleUserInteraction}\n onLoad={(e) => {\n if (onLoad) onLoad(e);\n if (initialFollowUser && userLocationState.coords && mapRef.current) {\n mapRef.current.jumpTo({\n center: userLocationState.coords,\n zoom: 16,\n });\n }\n }}\n onMouseDown={handleUserInteraction}\n onMove={handleMove}\n onRotateStart={handleUserInteraction}\n onTouchStart={handleUserInteraction}\n onWheel={handleUserInteraction}\n ref={mapRef}\n >\n {showUserLocation &&\n userLocationState.coords &&\n (renderUserLocation ? (\n renderUserLocation({\n coords: userLocationState.coords,\n heading: userLocationState.heading,\n })\n ) : (\n <UserLocationLayer\n forcedLocation={userLocationState.coords}\n heading={userLocationState.heading}\n />\n ))}\n\n {mockLocation &&\n mockLocation.radiusMeters > 0 &&\n userLocationState.coords && (\n <MockRadiusLayer\n center={userLocationState.coords}\n radiusMeters={mockLocation.radiusMeters}\n />\n )}\n\n {displayRoute && <RouteLayer geometry={displayRoute} />}\n\n {pois.length > 0 && (\n <>\n <POILayers pois={pois} />\n <POIMarkers onClick={onPoiClick} pois={pois} />\n </>\n )}\n {mapLibreChildren}\n </MapLibre>\n {showControls && mapControls && !mapControls.hasControls && (\n <MapControls\n drawerContentRef={drawerContentRef}\n enableTouchDrag={enableTouchDrag}\n etaData={showEtaData}\n initialViewState={initialViewState}\n isInternal={true}\n menuContent={menuContent || menuContentFromChildren}\n menuItems={resolvedMenuItems}\n {...controlProps}\n />\n )}\n </div>\n );\n};\n\nconst SDKMapProviderWrapper: React.FC<{ children: React.ReactNode }> = ({\n children,\n}) => {\n const context = useContext(MapControlsContext);\n if (context) {\n return <>{children}</>;\n }\n return <SDKMapProvider>{children}</SDKMapProvider>;\n};\n\nexport const Map: React.FC<MapProps> = (props) => {\n return (\n <SDKMapProviderWrapper>\n <MapProvider>\n <MapInternal {...props} />\n </MapProvider>\n </SDKMapProviderWrapper>\n );\n};\n","import { Map, type MapProps } from \"@miniapps-sdk/components/Map\";\nimport React from \"react\";\nimport { createRoot } from \"react-dom/client\";\n\n/**\n * Renders the Map component into a DOM element.\n * Useful for non-React environments (UMD/IIFE).\n *\n * @param containerId The ID of the HTML element where the map should be rendered.\n * @param props The props to pass to the Map component.\n * @returns The React root instance.\n */\nexport function renderMap(containerId: string, props: MapProps = {}) {\n const container = document.getElementById(containerId);\n if (!container) {\n throw new Error(`Container with id \"${containerId}\" not found.`);\n }\n\n const root = createRoot(container);\n root.render(React.createElement(Map, props));\n return root;\n}\n","import type { IGenerateQrCodeOptions } from \"@miniapps-sdk/types\";\nimport QRCodeStyling from \"qr-code-styling\";\n\nconst DEFAULT_SIZE = 512;\nconst DEFAULT_COLOR = \"#18181b\";\nconst DEFAULT_BACKGROUND = \"#ffffff\";\nconst DEFAULT_BORDER_RADIUS_PERCENT = 6;\nconst DEFAULT_LOGO_IMAGE =\n \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAAAXNSR0IB2cksfwAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB+oIBggpDsP9ZQ0AACAASURBVHja7L15tG3rVRf4m3ufc+6953bv3Zc83ktCBQgh9OkEAwgYQEKgpEBURB02Y6ChRALRSBqsGAgEIyKOoIJWY6FWjeGowbCaIVKWHVJhlF1ZqNiVFgUlMQl5zb339HvvNeuPtZu1vjW7b+1zX+65Z84x9jjn7LPWt9bXzjl/swOSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkh4IUQ5B0nkTf/9X7jBNnibC06DJbezuvxRXblzD3v4emsXjaBY3wHwFwLRdhctlyKsVSe3v4aVLxa/S/RRY+tR+zd1r2LiXhWevvqaiHePZq3duGmB2BsxO5Wu5GKv12LHzDKGvLLxvr93O7zdudS4m+RpvbM17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\";\nconst LABEL_FONT = \"600 %PXpx -apple-system, BlinkMacSystemFont, sans-serif\";\nconst LABEL_AREA_RATIO = 0.175; // fraction of `size` reserved for the label band, when present\nconst LABEL_PADDING_RATIO = -0.04;\n\n/**\n * Generates a styled QR code entirely client-side (canvas, no native bridge\n * round-trip needed — this never touches the Host Shell) and returns it as a\n * base64 PNG data URI, ready to hand straight to an `<img src>` or to\n * `sdk.media.saveImage()`.\n *\n * This is the SDK's single source of truth for QR code generation — mini-apps\n * must not reimplement this (canvas rasterization, styling, labeling) on\n * their own; that duplication is exactly what led every mini-app to drift\n * and made shared fixes/style updates painful to roll out consistently.\n */\nexport async function generateQrCode(\n data: string,\n options: IGenerateQrCodeOptions = {},\n): Promise<string> {\n const size = options.size ?? DEFAULT_SIZE;\n const color = options.color ?? DEFAULT_COLOR;\n const backgroundColor = options.backgroundColor ?? DEFAULT_BACKGROUND;\n const label =\n options.label || (options.appName ? `${options.appName} by UP` : \"\");\n\n // qr-code-styling merges its own default `imageOptions` with whatever's\n // passed in — but an explicitly-present `imageOptions: undefined` key\n // (e.g. from `options.logo ? {...} : undefined`) overwrites that default\n // during the merge instead of falling back to it, and the library reads\n // `imageOptions.hideBackgroundDots` unconditionally during rendering even\n // when there's no `image` — so `imageOptions: undefined` throws\n // (\"Cannot read properties of undefined\"), not just no-ops. The `image`\n // and `imageOptions` keys must be entirely ABSENT from the options object\n // when there's no logo, not present with an undefined value — hence the\n // conditional spread instead of a ternary-to-undefined.\n const qr = new QRCodeStyling({\n backgroundOptions: {\n color: backgroundColor,\n ...(options.backgroundGradient\n ? { gradient: options.backgroundGradient }\n : {}),\n },\n cornersDotOptions: {\n color: options.cornersDotColor ?? color,\n type: options.cornersDotType ?? \"extra-rounded\",\n ...(options.cornersDotGradient\n ? { gradient: options.cornersDotGradient }\n : {}),\n },\n cornersSquareOptions: {\n color: options.cornersSquareColor ?? color,\n type: options.cornersSquareType ?? \"extra-rounded\",\n ...(options.cornersSquareGradient\n ? { gradient: options.cornersSquareGradient }\n : {}),\n },\n data,\n dotsOptions: {\n color,\n type: options.dotsType ?? \"extra-rounded\",\n ...(options.dotsGradient ? { gradient: options.dotsGradient } : {}),\n },\n height: size,\n margin: options.margin ?? 0,\n qrOptions: {\n errorCorrectionLevel: options.errorCorrectionLevel ?? \"Q\",\n mode: \"Byte\",\n typeNumber: 0,\n },\n shape: options.shape ?? \"square\",\n type: \"canvas\",\n width: size,\n ...(options.logo !== null\n ? {\n image: options.logo ?? DEFAULT_LOGO_IMAGE,\n imageOptions: {\n hideBackgroundDots: options.hideBackgroundDots ?? true,\n imageSize: options.logoSize ?? 0.3,\n margin: options.logoMargin ?? 0,\n },\n }\n : {}),\n });\n\n const qrBlob = await qr.getRawData(\"png\");\n if (!qrBlob || !(qrBlob instanceof Blob)) {\n throw new Error(\"Failed to generate QR code image\");\n }\n const qrDataUrl = await blobToDataUrl(qrBlob);\n const outerPadding = options.outerPadding ?? 32;\n const borderRadiusPercent =\n options.borderRadius ?? DEFAULT_BORDER_RADIUS_PERCENT;\n\n const composed = label\n ? await composeWithLabel(qrDataUrl, label, size, backgroundColor, color)\n : qrDataUrl;\n\n return finalizeImage(\n composed,\n outerPadding,\n borderRadiusPercent,\n backgroundColor,\n );\n}\n\nconst blobToDataUrl = (blob: Blob): Promise<string> =>\n new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onloadend = () => resolve(reader.result as string);\n reader.onerror = reject;\n reader.readAsDataURL(blob);\n });\n\nconst loadImage = (src: string): Promise<HTMLImageElement> =>\n new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => resolve(img);\n img.onerror = reject;\n img.src = src;\n });\n\n/**\n * Draws the QR code onto a taller canvas with the label text centered above\n * it, and returns the composite as a base64 PNG data URI.\n */\nasync function composeWithLabel(\n qrDataUrl: string,\n label: string,\n size: number,\n backgroundColor: string,\n textColor: string,\n): Promise<string> {\n const qrImage = await loadImage(qrDataUrl);\n const labelAreaHeight = Math.round(size * LABEL_AREA_RATIO);\n const padding = Math.round(size * LABEL_PADDING_RATIO);\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = size;\n canvas.height = size + labelAreaHeight;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n // No 2D canvas context available — degrade to the unlabeled QR rather\n // than fail the whole generation over a cosmetic addition.\n return qrDataUrl;\n }\n\n ctx.fillStyle = backgroundColor;\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n\n const fontSize = Math.round(labelAreaHeight * 0.45);\n ctx.fillStyle = textColor;\n ctx.font = LABEL_FONT.replace(\"%PX\", String(fontSize));\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n ctx.fillText(\n label,\n canvas.width / 2,\n labelAreaHeight / 2 + padding / 2,\n canvas.width - padding * 2,\n );\n\n ctx.drawImage(qrImage, 0, labelAreaHeight, size, size);\n\n return canvas.toDataURL(\"image/png\");\n}\n\n/**\n * Traces a rounded-rectangle path on `ctx` without filling/stroking it —\n * caller decides (`.fill()`, `.clip()`, etc).\n */\nfunction traceRoundedRectPath(\n ctx: CanvasRenderingContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n radius: number,\n): void {\n ctx.beginPath();\n ctx.moveTo(x + radius, y);\n ctx.arcTo(x + width, y, x + width, y + height, radius);\n ctx.arcTo(x + width, y + height, x, y + height, radius);\n ctx.arcTo(x, y + height, x, y, radius);\n ctx.arcTo(x, y, x + width, y, radius);\n ctx.closePath();\n}\n\n/**\n * Forces the already-composed image (QR code, or QR code + label — the\n * latter is TALLER than it is wide, since the label band only adds height)\n * into a final SQUARE canvas: `outerPadding` is added on all four sides,\n * then the shorter dimension is padded further (content re-centered) so the\n * result is always `side × side`, never a rectangle. `borderRadius` is a\n * PERCENTAGE (0-50) of that final square's side, matching how CSS\n * `border-radius: N%` behaves on a square element — not raw px — so the\n * roundedness scales correctly with `size`/`outerPadding` instead of\n * looking sharper on a bigger QR and blobbier on a smaller one. The area\n * outside the rounded corners is left transparent (not `backgroundColor`\n * filled), so the PNG itself has real rounded corners, not just a\n * same-color illusion — matters once this is composited onto anything other\n * than a plain `backgroundColor` surface (e.g. a gallery photo grid).\n */\nasync function finalizeImage(\n imageDataUrl: string,\n outerPadding: number,\n borderRadiusPercent: number,\n backgroundColor: string,\n): Promise<string> {\n const image = await loadImage(imageDataUrl);\n const paddedWidth = image.width + outerPadding * 2;\n const paddedHeight = image.height + outerPadding * 2;\n const squareSize = Math.max(paddedWidth, paddedHeight);\n const radius =\n (Math.min(Math.max(borderRadiusPercent, 0), 50) / 100) * squareSize;\n\n const needsCanvas =\n radius > 0 || paddedWidth !== squareSize || paddedHeight !== squareSize;\n if (!needsCanvas) {\n return imageDataUrl;\n }\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = squareSize;\n canvas.height = squareSize;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n // No 2D canvas context available — degrade to the un-finalized image\n // rather than fail the whole generation over a cosmetic addition.\n return imageDataUrl;\n }\n\n if (radius > 0) {\n traceRoundedRectPath(ctx, 0, 0, squareSize, squareSize, radius);\n ctx.clip();\n }\n\n ctx.fillStyle = backgroundColor;\n ctx.fillRect(0, 0, squareSize, squareSize);\n\n const offsetX = Math.round((squareSize - image.width) / 2);\n const offsetY = Math.round((squareSize - image.height) / 2);\n ctx.drawImage(image, offsetX, offsetY);\n\n return canvas.toDataURL(\"image/png\");\n}\n","import jsQR from \"jsqr\";\n\n/**\n * Decodes a QR code from a static image (base64 data URI) — the single\n * source of truth for \"scan a photo instead of the live camera\" across\n * every Mini-App. Complements `<QRScanner>` (live camera decode loop): this\n * is for a gallery-picked photo (e.g. via `sdk.media.pickImage`, which\n * always returns a base64 data URI) that already contains a QR code, not a\n * live video frame.\n *\n * Deliberately data-URI-only, not \"or URL\": a cross-origin URL taints the\n * canvas and `getImageData` throws a `SecurityError`, which would silently\n * break the \"never throws for 'no code found'\" contract below for that\n * input shape. If a URL-based variant is ever needed, it must set\n * `img.crossOrigin` AND accept that it still depends on the remote host\n * sending CORS headers — not a drop-in support of arbitrary URLs.\n *\n * Returns the decoded string, or `null` if no QR code was found in the\n * image — never throws for \"no code found\", only for a genuinely unusable\n * image (fails to load, no 2D canvas context).\n */\nexport async function decodeQrCode(\n imageDataUrl: string,\n): Promise<string | null> {\n const image = await loadImage(imageDataUrl);\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = image.naturalWidth || image.width;\n canvas.height = image.naturalHeight || image.height;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n throw new Error(\"No 2D canvas context available to decode the image.\");\n }\n\n ctx.drawImage(image, 0, 0, canvas.width, canvas.height);\n const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n const code = jsQR(imageData.data, imageData.width, imageData.height, {\n inversionAttempts: \"attemptBoth\",\n });\n\n return code?.data ?? null;\n}\n\nconst loadImage = (src: string): Promise<HTMLImageElement> =>\n new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => resolve(img);\n img.onerror = reject;\n img.src = src;\n });\n","import type { RouteRequest, RouteResponse } from \"@miniapps-sdk/types/routing\";\n\nexport interface RoutingBackendConfig {\n backend: \"osrm\" | \"valhalla\";\n baseUrl: string;\n}\n\n/**\n * Core routing service that can be used by both SDK (for direct fetching)\n * and Host (for handling bridge requests).\n */\nexport const RoutingService = {\n createErrorResponse(\n req: RouteRequest,\n code: NonNullable<RouteResponse[\"error\"]>[\"code\"],\n message: string,\n ): RouteResponse {\n return {\n error: { code, message },\n requestId: req.requestId,\n sdkVersion: req.sdkVersion,\n success: false,\n type: \"SDK_ROUTING_GETROUTE_RESPONSE\",\n };\n },\n\n decodePolyline(str: string, precision: number): [number, number][] {\n let index = 0,\n lat = 0,\n lng = 0;\n const coordinates: [number, number][] = [];\n const shift = 10 ** precision;\n\n while (index < str.length) {\n let b: any,\n shiftNum = 0,\n result = 0;\n do {\n b = str.charCodeAt(index++) - 63;\n result |= (b & 0x1f) << shiftNum;\n shiftNum += 5;\n } while (b >= 0x20);\n const dlat = result & 1 ? ~(result >> 1) : result >> 1;\n lat += dlat;\n\n shiftNum = 0;\n result = 0;\n do {\n b = str.charCodeAt(index++) - 63;\n result |= (b & 0x1f) << shiftNum;\n shiftNum += 5;\n } while (b >= 0x20);\n const dlng = result & 1 ? ~(result >> 1) : result >> 1;\n lng += dlng;\n\n coordinates.push([lng / shift, lat / shift]);\n }\n return coordinates;\n },\n\n async fetchOSRMRoute(\n req: RouteRequest,\n coords: [number, number][],\n profile: string,\n baseUrl: string,\n ): Promise<RouteResponse> {\n const coordsString = coords.map((c) => `${c[0]},${c[1]}`).join(\";\");\n const osrmProfile =\n profile === \"walking\" ? \"foot\" : profile === \"driving\" ? \"car\" : \"bike\";\n const url = `${baseUrl}/route/v1/${osrmProfile}/${coordsString}?overview=full&geometries=geojson&steps=true`;\n\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`OSRM Error: ${response.statusText}`);\n }\n const data = await response.json();\n\n if (data.code !== \"Ok\" || !data.routes || data.routes.length === 0) {\n throw new Error(\"NO_ROUTE\");\n }\n\n const route = data.routes[0];\n const steps =\n route.legs?.flatMap((leg: any) =>\n leg.steps?.map((step: any) => ({\n distance: step.distance,\n duration: step.duration,\n instruction: step.maneuver?.instruction || \"Continue\",\n })),\n ) || [];\n\n return {\n data: {\n distanceMeters: route.distance,\n durationSeconds: route.duration,\n geometry: route.geometry,\n steps,\n },\n requestId: req.requestId,\n sdkVersion: req.sdkVersion,\n success: true,\n type: \"SDK_ROUTING_GETROUTE_RESPONSE\",\n };\n },\n async fetchRoute(\n req: RouteRequest,\n config: RoutingBackendConfig,\n ): Promise<RouteResponse> {\n const { origin, destination, waypoints, profile, language } = req.payload;\n\n if (\n !this.isValidCoordinate(origin) ||\n !this.isValidCoordinate(destination)\n ) {\n return this.createErrorResponse(\n req,\n \"INVALID_INPUT\",\n \"Origin or destination coordinates are invalid.\",\n );\n }\n if (waypoints && !waypoints.every(this.isValidCoordinate)) {\n return this.createErrorResponse(\n req,\n \"INVALID_INPUT\",\n \"One or more waypoints are invalid.\",\n );\n }\n\n const allCoords = [origin, ...(waypoints || []), destination];\n\n try {\n if (config.backend === \"osrm\") {\n return await this.fetchOSRMRoute(\n req,\n allCoords,\n profile,\n config.baseUrl,\n );\n } else {\n return await this.fetchValhallaRoute(\n req,\n allCoords,\n profile,\n language,\n config.baseUrl,\n );\n }\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"NO_ROUTE\")) {\n return this.createErrorResponse(\n req,\n \"NO_ROUTE\",\n \"No route could be found for the given points.\",\n );\n }\n if (error instanceof TypeError) {\n return this.createErrorResponse(\n req,\n \"NETWORK_ERROR\",\n \"Failed to connect to the routing backend.\",\n );\n }\n return this.createErrorResponse(\n req,\n \"BACKEND_ERROR\",\n `Routing backend error: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n\n async fetchValhallaRoute(\n req: RouteRequest,\n coords: [number, number][],\n profile: string,\n language: string | undefined,\n baseUrl: string,\n ): Promise<RouteResponse> {\n const valhallaProfile =\n profile === \"driving\"\n ? \"auto\"\n : profile === \"walking\"\n ? \"pedestrian\"\n : \"bicycle\";\n const body = {\n costing: valhallaProfile,\n directions_options: {\n language: language || \"en-US\",\n },\n locations: coords.map((c) => ({ lat: c[1], lon: c[0] })),\n };\n\n const response = await fetch(`${baseUrl}/route`, {\n body: JSON.stringify(body),\n headers: { \"Content-Type\": \"application/json\" },\n method: \"POST\",\n });\n\n if (!response.ok) {\n throw new Error(`Valhalla Error: ${response.statusText}`);\n }\n const data = await response.json();\n\n if (!data.trip || !data.trip.legs || data.trip.legs.length === 0) {\n throw new Error(\"NO_ROUTE\");\n }\n\n const trip = data.trip;\n const decodedCoordinates = this.decodePolyline(trip.legs[0].shape, 6);\n\n const steps =\n trip.legs.flatMap((leg: any) =>\n leg.maneuvers?.map((maneuver: any) => ({\n distance: maneuver.length * 1000, // Valhalla returns km\n duration: maneuver.time,\n instruction: maneuver.instruction || \"Continue\",\n })),\n ) || [];\n\n return {\n data: {\n distanceMeters: trip.summary.length * 1000, // km to m\n durationSeconds: trip.summary.time,\n geometry: {\n coordinates: decodedCoordinates,\n type: \"LineString\",\n },\n steps,\n },\n requestId: req.requestId,\n sdkVersion: req.sdkVersion,\n success: true,\n type: \"SDK_ROUTING_GETROUTE_RESPONSE\",\n };\n },\n\n isValidCoordinate(coord: [number, number]): boolean {\n const [lng, lat] = coord;\n return lng >= -180 && lng <= 180 && lat >= -90 && lat <= 90;\n },\n};\n","{\n \"name\": \"@cloudparse/up-miniapps-sdk\",\n \"version\": \"0.6.8\",\n \"description\": \"UP Mini-App SDK for bridge communication between WebView and Host Shell\",\n \"author\": \"CloudParse Team\",\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"sideEffects\": [\n \"*.css\"\n ],\n \"engines\": {\n \"node\": \">=25.6.1\"\n },\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"browser\": \"./dist/index.browser.min.js\",\n \"types\": \"./dist/index.d.ts\",\n \"bin\": {\n \"up-sdk\": \"./bin/up-sdk.cjs\"\n },\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\",\n \"default\": \"./dist/index.js\"\n },\n \"./host\": {\n \"types\": \"./dist/host.d.ts\",\n \"import\": \"./dist/host.js\",\n \"require\": \"./dist/host.cjs\",\n \"default\": \"./dist/host.js\"\n },\n \"./components/Map\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\",\n \"default\": \"./dist/index.js\"\n },\n \"./style.css\": \"./dist/style.css\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"files\": [\n \"dist\",\n \"bin\"\n ],\n \"scripts\": {\n \"build\": \"tsc --noEmit --project tsconfig.json && tsup && npm run build:css\",\n \"build:css\": \"npx postcss src/index.css -o dist/style.css\",\n \"prebuild\": \"npm run clean\",\n \"clean\": \"rm -rf dist\",\n \"format\": \"biome format --write . --max-diagnostics 10000 --diagnostic-level error\",\n \"lint\": \"biome lint . --max-diagnostics 10000 --diagnostic-level error\",\n \"lint.fix\": \"biome check --write . --max-diagnostics 10000 --diagnostic-level error\",\n \"prepack\": \"npm run build\",\n \"storybook\": \"storybook dev -p 6006\",\n \"build-storybook\": \"storybook build\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.5.1\",\n \"@chromatic-com/storybook\": \"^5.2.1\",\n \"@mapbox/maki\": \"^8.2.0\",\n \"@storybook/addon-a11y\": \"^10.4.6\",\n \"@storybook/addon-docs\": \"^10.4.6\",\n \"@storybook/addon-mcp\": \"^0.1.3\",\n \"@storybook/addon-vitest\": \"^10.4.6\",\n \"@storybook/react-vite\": \"^10.4.6\",\n \"@tailwindcss/postcss\": \"^4.3.2\",\n \"@types/geojson\": \"^7946.0.16\",\n \"@types/react\": \"^19.2.17\",\n \"@types/react-dom\": \"^19.2.3\",\n \"@vitest/browser-playwright\": \"^4.1.10\",\n \"@vitest/coverage-v8\": \"^4.1.10\",\n \"autoprefixer\": \"^10.5.2\",\n \"playwright\": \"^1.61.1\",\n \"postcss\": \"^8.5.26\",\n \"postcss-cli\": \"^11.0.1\",\n \"storybook\": \"^10.4.6\",\n \"tailwindcss\": \"^4.3.2\",\n \"tsc-alias\": \"^1.8.17\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^5.9.3\",\n \"vitest\": \"^4.1.10\"\n },\n \"dependencies\": {\n \"@radix-ui/react-dialog\": \"^1.1.17\",\n \"@radix-ui/react-slot\": \"^1.3.0\",\n \"@vis.gl/react-maplibre\": \"^8.1.1\",\n \"class-variance-authority\": \"^0.7.1\",\n \"clsx\": \"^2.1.1\",\n \"jsqr\": \"^1.4.0\",\n \"lucide-react\": \"^1.22.0\",\n \"maplibre-gl\": \"^5.24.0\",\n \"qr-code-styling\": \"^1.9.2\",\n \"react\": \"^19.2.7\",\n \"react-dom\": \"^19.2.7\",\n \"shadcn\": \"^4.12.0\",\n \"tailwind-merge\": \"^3.6.0\"\n }\n}\n","import { Bridge } from \"@miniapps-sdk/bridge\";\nimport { renderMap } from \"@miniapps-sdk/components/MapWrapper\";\nimport { generateQrCode } from \"@miniapps-sdk/services/qrCodeService\";\nimport { decodeQrCode } from \"@miniapps-sdk/services/qrDecodeService\";\nimport type { RoutingBackendConfig } from \"@miniapps-sdk/services/routingService\";\nimport { RoutingService } from \"@miniapps-sdk/services/routingService\";\nimport {\n GlobalEvent,\n type HapticStyleType,\n type IFidelityBalance,\n type IFidelityHistoryParams,\n type IFidelityTransaction,\n type IGenerateQrCodeOptions,\n type IInitializationOptions,\n type IInitializationResponse,\n type ILocationData,\n type INetworkOptions,\n type INetworkResponse,\n type IPaymentRequest,\n type IPickImageResult,\n type ISaveImageResult,\n type IUserProfile,\n type RouteRequest,\n type RouteResponse,\n type ScrollConfig,\n type SDKEvent,\n} from \"@miniapps-sdk/types\";\nimport { version } from \"../package.json\";\n\n// ... deepFreeze function omitted ...\nfunction deepFreeze<T extends object>(obj: T): T {\n // Retrieve the property names defined on obj\n const propNames = Object.getOwnPropertyNames(obj);\n\n // Freeze properties before freezing self\n for (const name of propNames) {\n const value = (obj as Record<string, unknown>)[name];\n\n if (\n value &&\n typeof value === \"object\" &&\n !Object.isFrozen(value) &&\n // Skip freezing of native objects or circular refs if any (though not expected here)\n !(value instanceof Bridge)\n ) {\n deepFreeze(value as object);\n }\n }\n\n return Object.freeze(obj);\n}\n\n/**\n * Main SDK for UP Mini-Apps.\n * Provides access to native device features, storage, identity, and shell UI.\n */\nlet globalRoutingConfig: RoutingBackendConfig | null = null;\n// Lives outside the class body (not `this.lastKnownEnv`) because the\n// exported `sdk` singleton below is `deepFreeze()`d — assigning to an\n// instance property on a frozen object throws `TypeError: Cannot assign to\n// read only property` in strict mode. That throw happened synchronously\n// inside `initialize()`, silently rejecting every single call — every app\n// fell into its `.catch()` standalone-mode fallback, `env` never got set,\n// and `createApiService` fell back to its default URL. Not a timing race\n// at all; this was the actual cause the whole time. Same reason\n// `globalRoutingConfig` above already lives at module scope instead of as\n// an instance field.\nlet lastKnownEnv: Record<string, unknown> | null = null;\n\nexport class MiniAppSDK {\n /**\n * Map services.\n * Provides access to MapLibre-based mapping components.\n */\n public readonly maps = Object.freeze({\n /**\n * Renders a MapLibre map into a DOM element.\n * Useful for non-React environments.\n */\n render: renderMap,\n });\n /**\n * QR code generation — the single source of truth for every Mini-App.\n * Runs entirely client-side (canvas, no Host Shell round-trip) and returns\n * a base64 PNG data URI, ready for an `<img src>` or `media.saveImage()`.\n * Mini-Apps must not reimplement this on their own.\n */\n public readonly qrCode = Object.freeze({\n /**\n * Decodes a QR code from a static image (base64 data URI or URL) —\n * e.g. a photo picked via `sdk.media.pickImage()` that already\n * contains a QR code, as an alternative to the live `<QRScanner>`.\n * @param imageDataUrl A base64 data URI (e.g. from `sdk.media.pickImage()`).\n * @returns The decoded string, or `null` if no QR code was found.\n */\n decode: (imageDataUrl: string): Promise<string | null> =>\n decodeQrCode(imageDataUrl),\n /**\n * @param data The value to encode (e.g. a deep link).\n * @param options Styling/labeling options — see {@link IGenerateQrCodeOptions}.\n * @returns A base64 PNG data URI.\n */\n generate: (\n data: string,\n options?: IGenerateQrCodeOptions,\n ): Promise<string> => generateQrCode(data, options),\n });\n private bridge: Bridge;\n /**\n * Local SQLite Storage.\n * Data is persisted on the device and is isolated per Mini-App.\n */\n public readonly storage = Object.freeze({\n /** Retrieves a value by key. */\n get: (key: string): Promise<string | null> =>\n this.bridge.send(\"STORAGE_GET\", { key }),\n /** Retrieves all key-value pairs stored for this Mini-App. */\n getAll: (): Promise<Record<string, string>> =>\n this.bridge.send(\"STORAGE_GET_ALL\"),\n /** Sets a value for a specific key. */\n set: (key: string, value: string): Promise<void> =>\n this.bridge.send(\"STORAGE_SET\", { key, value }),\n });\n /**\n * Hardware-level Secure Storage.\n * Data is stored in the device's secure enclave (Keychain/Keystore) and is isolated per Mini-App.\n */\n public readonly secureStore = Object.freeze({\n /** Retrieves a value by key from secure storage. */\n get: (key: string): Promise<string | null> =>\n this.bridge.send(\"SECURE_GET\", { key }),\n /** Sets a value for a specific key in secure storage. */\n set: (key: string, value: string): Promise<void> =>\n this.bridge.send(\"SECURE_SET\", { key, value }),\n });\n /**\n * Database Storage.\n * Access to user-app specific persistent database storage.\n */\n public readonly database = Object.freeze({\n /** Retrieves the user data stored in the backend database. */\n getUserData: <T = unknown>(): Promise<T> =>\n this.bridge.send<T>(\"DATABASE_GET_USER_DATA\"),\n /** Updates the user data stored in the backend database. */\n setUserData: <T = unknown>(data: T): Promise<void> =>\n this.bridge.send<void>(\"DATABASE_SET_USER_DATA\", { data }),\n });\n /**\n * Device Location services.\n */\n public readonly location = Object.freeze({\n /**\n * Retrieves the current GPS position of the device.\n */\n getCurrentPosition: (): Promise<ILocationData> =>\n this.bridge.send(\"GET_CURRENT_POSITION\"),\n /**\n * Starts the continuous location and sensor stream.\n * @param config Optional configuration for thresholds and intervals.\n */\n startStream: (\n config?: import(\"./types\").LocationStreamConfig,\n ): Promise<void> => this.bridge.send(\"START_LOCATION_STREAM\", config),\n /**\n * Stops the continuous location and sensor stream.\n */\n stopStream: (): Promise<void> => this.bridge.send(\"STOP_LOCATION_STREAM\"),\n });\n /**\n * Identity & Profile management.\n */\n public readonly user = Object.freeze({\n /**\n * Fetch user profile data.\n * @param fields Optional list of specific fields to retrieve (e.g., ['fullName', 'username']).\n */\n getProfile: <T extends keyof IUserProfile>(\n fields?: T[],\n ): Promise<Partial<IUserProfile>> =>\n this.bridge.send(\"GET_USER_PROFILE\", { fields }),\n /**\n * Fetch profile picture as a string of the current user, or a map of profile pictures from a list of user UUIDs.\n * @param uuids Optional list of user UUIDs.\n */\n getProfilePicture: ((uuids?: string[]) => {\n return this.bridge.send(\"GET_PROFILE_PICTURE\", { uuids: uuids || [] });\n }) as {\n (): Promise<string>;\n (uuids: string[]): Promise<Record<string, string>>;\n },\n });\n /**\n * Explicit Permission Management.\n * Allows requesting access to sensitive device features or user data.\n */\n public readonly permission = Object.freeze({\n /**\n * Explicitly request access to sensitive data.\n * @param type The type of permission to request ('location', 'profile', or 'camera').\n * @param fields If requesting 'profile', the specific fields required.\n */\n request: ((type: \"location\" | \"profile\" | \"camera\", fields?: string[]) => {\n return this.bridge.send(\"REQUEST_PERMISSION\", { fields, type });\n }) as {\n (type: \"location\"): Promise<boolean>;\n (type: \"profile\", fields: (keyof IUserProfile)[]): Promise<boolean>;\n (type: \"camera\"): Promise<boolean>;\n },\n });\n /**\n * Media & Gallery integration.\n */\n public readonly media = Object.freeze({\n /**\n * Opens the device's native photo gallery picker via the Host Shell and\n * returns the chosen image as base64. Distinct permission grant from\n * `saveImage` (read vs. write access to the photo library) — the Host\n * Shell requests it independently.\n */\n pickImage: (): Promise<IPickImageResult> =>\n this.bridge.send(\"PICK_IMAGE\", {}),\n /**\n * Saves a base64-encoded image to the device's photo gallery via the Host Shell.\n * A plain browser `<a download>` does not work inside the native WebView (no\n * download manager is wired up) — this is the only way to persist an image\n * generated inside a Mini-App (e.g. a QR code) to the device.\n * @param base64 Base64-encoded image data, with or without the `data:image/...;base64,` prefix.\n * @param filename Suggested filename (without extension).\n */\n saveImage: (base64: string, filename?: string): Promise<ISaveImageResult> =>\n this.bridge.send(\"SAVE_IMAGE\", { base64, filename }),\n });\n /**\n * Payments integration.\n */\n public readonly payment = Object.freeze({\n /**\n * Triggers the native payment flow.\n * @param payload Amount, currency, and itemized list for the payment.\n */\n request: (\n payload: IPaymentRequest,\n ): Promise<{ success: true; transactionId: string }> =>\n this.bridge.send(\"PAYMENT_REQUEST\", payload),\n });\n /**\n * Live Activities & Notifications.\n * Allows the Mini-App to display real-time updates in the host shell.\n */\n public readonly activity = Object.freeze({\n /**\n * Starts a new live activity.\n * @param id Unique identifier for the activity.\n * @param title Display title for the activity.\n * @param status Initial status message.\n */\n start: (id: string, title: string, status: string): Promise<void> =>\n this.bridge.send(\"START_ACTIVITY\", { id, status, title }),\n });\n /**\n * Haptic feedback.\n */\n public readonly haptic = Object.freeze({\n /**\n * Triggers a haptic vibration on the device.\n * @param style The style of haptic feedback (e.g., 'light', 'medium', 'heavy', 'success', 'warning', 'error').\n */\n trigger: (style: HapticStyleType): Promise<void> =>\n this.bridge.send(\"TRIGGER_HAPTIC\", { style }),\n });\n /**\n * Network Proxy.\n * Allows the Mini-App to make network requests through the host shell to bypass CORS or use host-level authentication.\n */\n public readonly network = Object.freeze({\n /**\n * Performs a network request via the host shell.\n * @param options Request method, URL, headers, and body.\n */\n request: async <T = unknown>(\n options: INetworkOptions,\n ): Promise<INetworkResponse<T>> => {\n return this.bridge.send(\"NETWORK_REQUEST\", options);\n },\n });\n /**\n * Navigation and Journey controls.\n * Allows programmatically starting itineraries and managing navigation state.\n */\n public readonly navigation = Object.freeze({\n /**\n * Aborts the current navigation journey.\n */\n abort: (): void => {\n this.bridge.handleNativeMessage({\n eventName: \"SDK_NAVIGATION_ABORT\",\n type: \"EVENT\",\n });\n },\n /**\n * Creates a new itinerary preview.\n * @param options Destination and routing options.\n */\n createJourney: (options: {\n destination: [number, number];\n origin?: [number, number];\n profile?: \"driving\" | \"cycling\" | \"walking\";\n }): void => {\n this.bridge.handleNativeMessage({\n eventName: \"SDK_NAVIGATION_CREATE\",\n payload: { ...options, mode: \"preview\" },\n type: \"EVENT\",\n });\n },\n /**\n * Starts the active navigation (active guidance).\n */\n start: (): void => {\n this.bridge.handleNativeMessage({\n eventName: \"SDK_NAVIGATION_START\",\n type: \"EVENT\",\n });\n },\n });\n /**\n * Fidelity & Rewards program integration.\n */\n public readonly fidelity = Object.freeze({\n /** Returns current fidelity balance. */\n getFidelityBalance: (): Promise<IFidelityBalance> =>\n this.bridge.send(\"GET_FIDELITY_BALANCE\"),\n /**\n * Retrieves fidelity transaction history.\n * @param params Filtering and pagination parameters.\n */\n getFidelityHistory: (\n params?: IFidelityHistoryParams,\n ): Promise<IFidelityTransaction[]> =>\n this.bridge.send(\"GET_FIDELITY_HISTORY\", params),\n /**\n * Triggers the native fidelity history view.\n * @param options.isDark Theme to render the native view in. Pass the\n * mini-app's current theme explicitly — the native history screen is a\n * standalone view and does not read it from `updateContext`.\n */\n showHistory: (options?: { isDark?: boolean }): Promise<void> =>\n this.bridge.send(\"SHOW_FIDELITY_HISTORY\", options),\n /**\n * Authorize spending fidelity points (FPoints) via Two-Phase Authorization.\n * @param intentUuid UUID generated by your backend for the transaction.\n */\n spendFPoints: (\n intentUuid: string,\n ): Promise<{ success: boolean; transactionId: string }> =>\n this.bridge.send(\"SPEND_FPOINTS\", { intentUuid }),\n });\n /**\n * UI and Navigation controls.\n */\n public readonly ui = Object.freeze({\n /** Closes the Mini-App and returns to the host shell. */\n exit: (): Promise<void> => this.bridge.send(\"EXIT\"),\n /**\n * Configures native scroll behaviors like Pull-to-Refresh and Infinite Scroll.\n * @param config Scroll configuration for top/bottom detection.\n */\n setScrollConfig: (config: ScrollConfig): Promise<void> =>\n this.bridge.send(\"SET_SCROLL_CONFIG\", config),\n });\n /**\n * Debug controls\n */\n public readonly debug = Object.freeze({\n /**\n * Log to the shell app\n * @param message\n */\n log: (...message: unknown[]) => this.bridge.send(\"DEBUG_LOG\", { message }),\n });\n /**\n * Routing integration (OSRM / Valhalla).\n * Provides access to route calculation and rendering on the host map.\n */\n public readonly routing = Object.freeze({\n /**\n * Clears the currently rendered route.\n */\n clearRoute: (): Promise<void> => {\n const requestId = crypto.randomUUID\n ? crypto.randomUUID()\n : Math.random().toString(36).substring(2);\n return this.bridge.send(\"SDK_ROUTING_CLEARROUTE\", {\n requestId,\n sdkVersion: version,\n });\n },\n\n /**\n * Draws the calculated route on the host map.\n * @param routeData The route data returned by getRoute.\n */\n drawRoute: (\n routeData: NonNullable<RouteResponse[\"data\"]>,\n ): Promise<void> => {\n const requestId = crypto.randomUUID\n ? crypto.randomUUID()\n : Math.random().toString(36).substring(2);\n return this.bridge.send(\"SDK_ROUTING_DRAWROUTE\", {\n payload: { routeData },\n requestId,\n sdkVersion: version,\n });\n },\n /**\n * Calculates a route between points.\n * @param payload Request payload containing origin, destination, and options.\n */\n getRoute: async (\n payload: RouteRequest[\"payload\"],\n ): Promise<NonNullable<RouteResponse[\"data\"]>> => {\n // Create a unique requestId\n const requestId = crypto.randomUUID\n ? crypto.randomUUID()\n : Math.random().toString(36).substring(2);\n\n const request: RouteRequest = {\n payload,\n requestId,\n sdkVersion: version,\n type: \"SDK_ROUTING_GETROUTE\",\n };\n\n // If a direct backend is configured, bypass the bridge\n if (globalRoutingConfig) {\n const response = await RoutingService.fetchRoute(\n request,\n globalRoutingConfig,\n );\n if (response.success && response.data) {\n return response.data;\n }\n throw new Error(response.error?.message || \"Routing failed\");\n }\n\n // Otherwise, use the bridge\n return this.bridge.send(\"SDK_ROUTING_GETROUTE\", {\n payload,\n requestId,\n sdkVersion: version,\n });\n },\n });\n\n constructor() {\n this.bridge = new Bridge();\n\n // Keep lastKnownEnv current for the lifetime of this SDK instance,\n // independent of whatever the consumer app does with the same event.\n this.bridge.on<{ env?: Record<string, unknown> }>(\n GlobalEvent.UPDATE_CONTEXT,\n (data) => {\n if (data?.env) lastKnownEnv = data.env;\n },\n );\n\n // Bind methods to this instance to preserve context if pulled out\n this.initialize = this.initialize.bind(this);\n this.getEnv = this.getEnv.bind(this);\n this.on = this.on.bind(this);\n this.off = this.off.bind(this);\n }\n\n /**\n * Configures global SDK settings.\n */\n public config(options: { routingBackend?: RoutingBackendConfig }): void {\n if (options.routingBackend) {\n globalRoutingConfig = options.routingBackend;\n }\n }\n\n /**\n * Updates the global context shared between the Mini-App and the native shell.\n * Useful for synchronizing state like theme preferences, UI flags, or custom app-specific context.\n * @param context Partial context object to merge into the existing shell context.\n */\n public updateContext(context: Record<string, unknown>): Promise<void> {\n return this.bridge.send(\"UPDATE_CONTEXT\", context);\n }\n\n /**\n * The starting point for the Mini-App. Must be called before any other SDK methods.\n * @param options The options to provide to the shell app\n */\n public async initialize(\n options: IInitializationOptions,\n ): Promise<IInitializationResponse> {\n const res = await this.bridge.send<IInitializationResponse>(\n \"INITIALIZE\",\n options,\n );\n if (res?.env) lastKnownEnv = res.env;\n return res;\n }\n\n /**\n * Returns the last known `env` (shell-provided config like `backendUrl`),\n * refreshed automatically by `initialize()` and every `UPDATE_CONTEXT`\n * push — read this instead of caching your own copy of `env` values.\n * Returns `null` before the first successful `initialize()`/context push.\n */\n public getEnv<\n T extends Record<string, unknown> = Record<string, unknown>,\n >(): T | null {\n return lastKnownEnv as T | null;\n }\n\n /**\n * Registers a callback for a specific event from the native shell.\n * @param event The name of the event to listen for.\n * @param callback The function to execute when the event is triggered.\n * @returns A function to unregister the listener.\n */\n public on<T = unknown>(\n event: SDKEvent,\n callback: (data: T) => void,\n ): () => void {\n return this.bridge.on<T>(event as string, callback);\n }\n\n /**\n * Unregisters a previously registered event listener.\n * @param event The name of the event.\n * @param callback The callback function to remove.\n */\n public off<T = unknown>(event: SDKEvent, callback: (data: T) => void): void {\n this.bridge.off<T>(event as string, callback);\n }\n}\n\n/**\n * Singleton instance of the MiniAppSDK.\n * Frozen to prevent tampering.\n */\nexport const sdk = deepFreeze(new MiniAppSDK());\n","import { MockLocationContext } from \"@miniapps-sdk/components/Map/MockLocationContext\";\nimport { Button } from \"@miniapps-sdk/components/ui/button\";\nimport { sdk } from \"@miniapps-sdk/sdk\";\nimport { GeolocationEvent } from \"@miniapps-sdk/types\";\nimport type React from \"react\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nexport interface BridgeMockerProps {\n /** Optional appId to return in INITIALIZE response */\n appId?: string;\n /** Initial simulated location [lng, lat] */\n initialLocation?: [number, number];\n /** Whether the simulated user should be moving */\n isMoving?: boolean;\n /** An array of coordinates to follow. If provided, overrides random movement. */\n simulationPath?: [number, number][];\n /** Speed multiplier for the simulation interval. Default is 1. Higher is faster. */\n simulationSpeed?: number;\n /** Mock JWT token for NETWORK_REQUEST mocking */\n mockJWTToken?: string;\n children: React.ReactNode;\n}\n\nconst AVATAR_MOUTH_VARIANTS = [\n \"variant03\",\n \"variant07\",\n \"variant08\",\n \"variant09\",\n \"variant10\",\n \"variant11\",\n \"variant12\",\n \"variant13\",\n \"variant14\",\n \"variant15\",\n \"variant16\",\n \"variant21\",\n \"variant22\",\n \"variant23\",\n \"variant25\",\n \"variant26\",\n \"variant27\",\n \"variant28\",\n \"variant29\",\n \"variant30\",\n].join(\",\");\n\nconst AVATAR_EYES_VARIANTS = [\"variant03\", \"variant04\", \"variant05\"].join(\",\");\n\n/**\n * Fast, non-cryptographic string hash (djb2 variant), same as shell's\n * `hashToShortSeed` (up/shell/src/utils/avatar.ts) — keeps the mocked\n * avatar's seed-to-image mapping identical to what the real host app\n * would render for the same uuid.\n */\nfunction hashToShortSeed(input: string): string {\n let hash = 5381;\n for (let i = 0; i < input.length; i++) {\n hash = (hash * 33) ^ input.charCodeAt(i);\n }\n return (hash >>> 0).toString(36);\n}\n\n/**\n * Mirrors the shell's `getAvatarUrl` (up/shell/src/utils/avatar.ts,\n * notionists-neutral, png) so mocked profile pictures match what the real\n * host app returns.\n */\nfunction getMockAvatarUrl(seed: string): string {\n const shortSeed = hashToShortSeed(seed);\n return `https://api.dicebear.com/10.x/notionists-neutral/png?seed=${shortSeed}&mouth=${AVATAR_MOUTH_VARIANTS}&eyes=${AVATAR_EYES_VARIANTS}&glassesProbability=50`;\n}\n\n/** Decodes a JWT's payload without verifying its signature — this is dev-only\n * mock tooling reading a token the caller already trusts enough to hand to\n * `mockJWTToken`, not a security boundary. Returns null on any malformed\n * input rather than throwing, since callers treat \"no usable claims\" and\n * \"no token at all\" identically (fall through to the hardcoded default\n * profile below). */\nfunction decodeMockJWTPayload(token: string): Record<string, unknown> | null {\n try {\n const raw = token.startsWith(\"Bearer \") ? token.slice(7) : token;\n const base64Url = raw.split(\".\")[1];\n const base64 = base64Url.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const jsonPayload = decodeURIComponent(\n atob(base64)\n .split(\"\")\n .map((c) => `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`)\n .join(\"\"),\n );\n\n return JSON.parse(jsonPayload);\n } catch {\n return null;\n }\n}\n\n/**\n * Builds the mocked profile object INITIALIZE/GET_USER_PROFILE return, from\n * `mockJWTToken`'s own claims when present and decodable, falling back to a\n * fixed placeholder (\"Smart Caveman\") otherwise. This is the single place a\n * dev/mock profile is derived from a token — every `up-miniapps-*` app used\n * to each hand-roll its own JWT-decode-and-override for this (parsing\n * `VITE_DEV_TOKEN` client-side, then discarding whatever this mock returned\n * in favor of that), which meant two devices/tabs sharing one token-bearing\n * build always collapsed onto whatever ONE profile that app's own decode\n * produced — real per-device distinctness only ever came from the token\n * actually differing, never from anything the mock itself did. Deriving it\n * here instead means a consuming app can simply trust `res.profile`/\n * `sdk.user.getProfile()` like it already must in production, with no\n * separate mock-aware code path to keep in sync or accidentally trust over a\n * real shell-provided profile.\n */\nfunction buildMockProfile(mockJWTToken: string | undefined) {\n const claims = mockJWTToken ? decodeMockJWTPayload(mockJWTToken) : null;\n const uuid = (claims?.sub as string | undefined) || \"mock-user-42\";\n const fullName =\n (claims?.name as string | undefined) ||\n (claims?.username as string | undefined) ||\n \"Smart Caveman\";\n const username = (claims?.username as string | undefined) || \"smart_caveman\";\n const [firstName, ...lastNameParts] = fullName.split(\" \");\n return {\n admin: true,\n countryCode: \"FR\",\n createdAt: new Date().toISOString(),\n email: \"caveman@up.app\",\n firstName: firstName || \"Smart\",\n fullName,\n lastName: lastNameParts.join(\" \") || \"Caveman\",\n localNumber: \"0600000000\",\n ups: 100,\n username,\n uuid,\n xp: 500,\n };\n}\n\n/**\n * Calculates bearing between two points\n */\nconst getBearing = (p1: [number, number], p2: [number, number]) => {\n const lat1 = (p1[1] * Math.PI) / 180;\n const lat2 = (p2[1] * Math.PI) / 180;\n const dLon = ((p2[0] - p1[0]) * Math.PI) / 180;\n const y = Math.sin(dLon) * Math.cos(lat2);\n const x =\n Math.cos(lat1) * Math.sin(lat2) -\n Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon);\n return ((Math.atan2(y, x) * 180) / Math.PI + 360) % 360;\n};\n\n/**\n * A utility component for Storybook that intercepts SDK bridge calls,\n * simulates the behavior of the native shell app.\n *\n * NOTE: Logs are now handled by the standalone DebugConsole component.\n */\nexport const BridgeMocker: React.FC<BridgeMockerProps> = ({\n appId,\n initialLocation = [6.1258, 45.9058], // Annecy default\n isMoving = false,\n simulationPath,\n simulationSpeed = 1,\n mockJWTToken,\n children,\n}) => {\n const [autoMove, setAutoMove] = useState(isMoving);\n const [location, setLocation] = useState<[number, number]>(initialLocation);\n const [heading, setHeading] = useState<number>(0);\n const [speedMultiplier, setSpeedMultiplier] = useState(simulationSpeed);\n const [isReady, setIsReady] = useState(false);\n const [isMinimized, setIsMinimized] = useState(true);\n const [radiusMeters, setRadiusMeters] = useState(0);\n const [radiusUnit, setRadiusUnit] = useState<\"m\" | \"km\">(\"m\");\n const [isPlacingLocation, setIsPlacingLocation] = useState(false);\n\n const streamIntervalRef = useRef<any | null>(null);\n const pathIndexRef = useRef<number>(0);\n const activeConfigRef = useRef<any>(null); // Keep track of the last START_LOCATION_STREAM config\n\n // Refs for interval to read latest state without rebinding\n const stateRef = useRef({\n autoMove,\n heading,\n location,\n mockJWTToken,\n pushLocationUpdate: () => {},\n setHeading,\n setLocation,\n simulationPath,\n speedMultiplier,\n });\n\n const pushLocationUpdateFor = useCallback(\n (coords: [number, number], headingDeg: number) => {\n const currentState = stateRef.current;\n const payload = {\n accelerometer: null,\n heading: {\n accuracy: 3,\n magneticHeading: headingDeg,\n trueHeading: headingDeg,\n },\n location: {\n coords: {\n accuracy: 10,\n altitude: 0,\n altitudeAccuracy: null,\n heading: headingDeg,\n latitude: coords[1],\n longitude: coords[0],\n speed: currentState.autoMove\n ? 1.5 * currentState.speedMultiplier\n : 0,\n },\n timestamp: Date.now(),\n },\n timestamp: Date.now(),\n };\n\n (window as any).__MiniAppBridge?.onNativeMessage({\n eventName: GeolocationEvent.LOCATION_STREAM_UPDATE,\n payload,\n type: \"EVENT\",\n });\n },\n [],\n );\n\n const pushLocationUpdate = useCallback(() => {\n const currentState = stateRef.current;\n pushLocationUpdateFor(currentState.location, currentState.heading);\n }, [pushLocationUpdateFor]);\n\n // \"Drop location here\" — used both by the map-click placement mode and\n // could be reused for a future \"teleport to point\" input. Pushes the\n // update from the given coords directly instead of reading stateRef\n // (which lags one render behind a same-tick setLocation call).\n const placeLocation = useCallback(\n (coords: [number, number]) => {\n setLocation(coords);\n setIsPlacingLocation(false);\n pushLocationUpdateFor(coords, stateRef.current.heading);\n },\n [pushLocationUpdateFor],\n );\n\n useEffect(() => {\n stateRef.current = {\n autoMove,\n heading,\n location,\n mockJWTToken,\n pushLocationUpdate,\n setHeading,\n setLocation,\n simulationPath,\n speedMultiplier,\n };\n }, [\n location,\n heading,\n autoMove,\n pushLocationUpdate,\n simulationPath,\n speedMultiplier,\n mockJWTToken,\n ]);\n\n // Sync prop changes\n useEffect(() => {\n setAutoMove(isMoving);\n }, [isMoving]);\n\n useEffect(() => {\n setSpeedMultiplier(simulationSpeed);\n }, [simulationSpeed]);\n\n // Reset path index if path changes\n useEffect(() => {\n if (simulationPath && simulationPath.length > 0) {\n pathIndexRef.current = 0;\n setLocation(simulationPath[0]); // Snap to start of new path\n }\n }, [simulationPath]);\n\n // Handle dynamic interval restart when speed changes\n // biome-ignore lint/correctness/useExhaustiveDependencies: We intentionally only want to re-trigger when speedMultiplier changes, not on every config change\n useEffect(() => {\n if (streamIntervalRef.current && activeConfigRef.current) {\n // Re-trigger startStream to apply new speed\n (sdk as any).bridge.send(\n \"START_LOCATION_STREAM\",\n activeConfigRef.current,\n );\n }\n }, [speedMultiplier]);\n\n // Setup interception synchronously before children render\n useEffect(() => {\n const bridge = (sdk as any).bridge;\n const originalSend = bridge.send.bind(bridge);\n\n const stopStream = () => {\n if (streamIntervalRef.current) {\n clearInterval(streamIntervalRef.current);\n streamIntervalRef.current = null;\n }\n activeConfigRef.current = null;\n };\n\n const startStream = (config?: any) => {\n stopStream();\n activeConfigRef.current = config || {};\n\n const baseInterval = config?.interval || 500;\n const interval = Math.max(\n 10,\n baseInterval / stateRef.current.speedMultiplier,\n );\n\n streamIntervalRef.current = setInterval(() => {\n const state = stateRef.current;\n\n if (state.autoMove) {\n if (state.simulationPath && state.simulationPath.length > 0) {\n // Path following logic\n if (pathIndexRef.current < state.simulationPath.length - 1) {\n const currentPoint = state.simulationPath[pathIndexRef.current];\n const nextPoint = state.simulationPath[pathIndexRef.current + 1];\n\n pathIndexRef.current += 1;\n const newHeading = getBearing(currentPoint, nextPoint);\n\n state.setHeading(newHeading);\n state.setLocation(nextPoint);\n } else {\n // Reached end of path\n state.setLocation(\n state.simulationPath[state.simulationPath.length - 1],\n );\n }\n } else {\n // Random drift\n state.setLocation((prev) => [\n prev[0] + (Math.random() - 0.5) * 0.0001,\n prev[1] + (Math.random() - 0.5) * 0.0001,\n ]);\n }\n }\n\n state.pushLocationUpdate();\n }, interval);\n };\n\n const simulateNetworkRequest = async (payload: any) => {\n const {\n url,\n method = \"GET\",\n headers: incomingHeaders = {},\n body,\n } = payload;\n const state = stateRef.current;\n\n const headers = new Headers(incomingHeaders);\n\n if (state.mockJWTToken) {\n headers.set(\n \"Authorization\",\n `Bearer ${state.mockJWTToken.replace(\"Bearer \", \"\")}`,\n );\n }\n\n if (body && typeof body === \"object\" && !headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n\n try {\n const response = await fetch(url, {\n body: body\n ? typeof body === \"string\"\n ? body\n : JSON.stringify(body)\n : undefined,\n headers,\n method,\n });\n\n const contentType = response.headers.get(\"content-type\");\n let responseData: any;\n\n if (contentType?.includes(\"application/json\")) {\n responseData = await response.json();\n } else {\n responseData = await response.text();\n }\n\n const headersObj: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n headersObj[key] = value;\n });\n\n return {\n data: responseData,\n headers: headersObj,\n status: response.status,\n statusText: response.statusText,\n };\n } catch (error: any) {\n throw {\n error: error.message || \"Network request failed\",\n status: 0,\n };\n }\n };\n\n // Intercept bridge calls globally\n bridge.send = async (type: string, payload: any) => {\n // 1. Mandatory Lifecycle\n if (type === \"INITIALIZE\") {\n return Promise.resolve({\n appId, // Legacy support\n context: { theme: \"dark\" }, // Legacy support\n description: \"Mocked for Dev\",\n env: {},\n insets: { bottom: 0, left: 0, right: 0, top: 0 },\n name: \"Vite Dev (Mock)\",\n params: {},\n profile: buildMockProfile(stateRef.current.mockJWTToken),\n success: true,\n userData: {},\n uuid: appId || \"mock-app-id\",\n version: \"1.0.0\",\n });\n }\n\n // 2. Location\n if (type === \"GET_CURRENT_POSITION\") {\n const state = stateRef.current;\n return Promise.resolve({\n coords: {\n accuracy: 10,\n altitude: 0,\n altitudeAccuracy: 0,\n heading: state.heading,\n latitude: state.location[1],\n longitude: state.location[0],\n speed: state.autoMove ? 1.5 * state.speedMultiplier : 0,\n },\n timestamp: Date.now(),\n });\n }\n if (type === \"START_LOCATION_STREAM\") {\n startStream(payload);\n return Promise.resolve();\n }\n if (type === \"STOP_LOCATION_STREAM\") {\n stopStream();\n return Promise.resolve();\n }\n\n // 3. Network\n if (type === \"NETWORK_REQUEST\") {\n return simulateNetworkRequest(payload);\n }\n\n // 4. Storage & Identity Mocks\n if (type === \"STORAGE_GET\" || type === \"SECURE_GET\") {\n return Promise.resolve(localStorage.getItem(`mock_sdk_${payload.key}`));\n }\n if (type === \"STORAGE_SET\" || type === \"SECURE_SET\") {\n localStorage.setItem(`mock_sdk_${payload.key}`, payload.value);\n return Promise.resolve();\n }\n if (type === \"GET_USER_PROFILE\") {\n return Promise.resolve(buildMockProfile(stateRef.current.mockJWTToken));\n }\n if (type === \"GET_PROFILE_PICTURE\") {\n const uuids = payload?.uuids || [];\n if (uuids.length === 0) {\n return Promise.resolve(getMockAvatarUrl(\"dummy\"));\n }\n const map: Record<string, string> = {};\n for (const uuid of uuids) {\n map[uuid] = getMockAvatarUrl(uuid);\n }\n return Promise.resolve(map);\n }\n\n // 5. Fidelity & Payment Mocks\n if (type === \"GET_FIDELITY_BALANCE\") {\n return Promise.resolve({ balance: 1337, currency: \"FPoints\" });\n }\n if (type === \"PAYMENT_REQUEST\") {\n return Promise.resolve({\n success: true,\n transactionId: `tx_${Math.random().toString(36).slice(2)}`,\n });\n }\n\n // 6. UI & Haptic (No-ops)\n if (\n type === \"TRIGGER_HAPTIC\" ||\n type === \"EXIT\" ||\n type === \"UPDATE_CONTEXT\"\n ) {\n return Promise.resolve({ success: true });\n }\n\n return originalSend(type, payload);\n };\n\n setIsReady(true);\n\n return () => {\n stopStream();\n bridge.send = originalSend;\n };\n }, [appId]);\n\n const radiusInMeters =\n radiusUnit === \"km\" ? radiusMeters * 1000 : radiusMeters;\n\n const mockLocationContextValue = useMemo(\n () => ({\n isPlacingLocation,\n placeLocation,\n radiusMeters: radiusInMeters,\n }),\n [isPlacingLocation, placeLocation, radiusInMeters],\n );\n\n if (!isReady) return null;\n\n return (\n <div className=\"relative w-full h-full\">\n {/* Wrapped Story */}\n <div className=\"w-full h-full\">\n <MockLocationContext.Provider value={mockLocationContextValue}>\n {children}\n </MockLocationContext.Provider>\n </div>\n\n {isMinimized ? (\n <Button\n 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!\"\n onClick={() => setIsMinimized(false)}\n title=\"Open Simulation Controls\"\n type=\"button\"\n variant=\"ghost\"\n >\n <svg\n className=\"group-hover:scale-110 transition-transform\"\n fill=\"none\"\n height=\"14\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2\"\n viewBox=\"0 0 24 24\"\n width=\"14\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M21 4H3\" />\n <path d=\"M10 8H3\" />\n <path d=\"M21 12H3\" />\n <path d=\"M10 16H3\" />\n <path d=\"M21 20H3\" />\n <circle cx=\"14\" cy=\"8\" r=\"2\" />\n <circle cx=\"14\" cy=\"16\" r=\"2\" />\n </svg>\n </Button>\n ) : (\n <div\n 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\"\n style={{ zIndex: 9998 }}\n >\n {/* Header */}\n <div\n 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\"\n onClick={() => setIsMinimized(true)}\n >\n <span className=\"font-bold text-slate-100 flex items-center gap-2\">\n <span className=\"text-lg\">🛠️</span> Simulation Controls\n </span>\n <Button\n className=\"text-slate-500 hover:text-white p-0 h-auto hover:bg-transparent cursor-pointer\"\n type=\"button\"\n variant=\"ghost\"\n >\n ▼\n </Button>\n </div>\n\n <div className=\"p-4 flex flex-col gap-3\">\n <div className=\"flex justify-between items-center\">\n <label className=\"flex items-center gap-2 cursor-pointer\">\n <input\n checked={autoMove}\n className=\"accent-blue-500 w-4 h-4\"\n onChange={(e) => setAutoMove(e.target.checked)}\n type=\"checkbox\"\n />\n <span className=\"text-slate-200 font-bold\">\n Auto-Move {simulationPath ? \"(Path)\" : \"(Random)\"}\n </span>\n </label>\n\n <div className=\"flex items-center gap-2\">\n <span className=\"text-[10px] text-slate-500\">Speed:</span>\n <select\n 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]\"\n onChange={(e) => setSpeedMultiplier(Number(e.target.value))}\n value={speedMultiplier}\n >\n {[1, 2, 5, 10, 50, 100, 250].map((s) => (\n <option key={s} value={s}>\n {s}x\n </option>\n ))}\n </select>\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 gap-2\">\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-[10px] text-slate-500 text-left\">\n Lng\n </span>\n <input\n className=\"bg-slate-800 border border-slate-700 rounded px-2 py-1 text-white focus:outline-none focus:border-blue-500\"\n onChange={(e) => {\n const lng = parseFloat(e.target.value) || 0;\n setLocation([lng, location[1]]);\n pushLocationUpdate();\n }}\n step=\"0.001\"\n type=\"number\"\n value={location[0]}\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-[10px] text-slate-500 text-left\">\n Lat\n </span>\n <input\n className=\"bg-slate-800 border border-slate-700 rounded px-2 py-1 text-white focus:outline-none focus:border-blue-500\"\n onChange={(e) => {\n const lat = parseFloat(e.target.value) || 0;\n setLocation([location[0], lat]);\n pushLocationUpdate();\n }}\n step=\"0.001\"\n type=\"number\"\n value={location[1]}\n />\n </div>\n <div className=\"flex flex-col gap-1 col-span-2\">\n <span className=\"text-[10px] text-slate-500\">\n Heading (Degrees)\n </span>\n <input\n className=\"w-full accent-blue-500\"\n max=\"360\"\n min=\"0\"\n onChange={(e) => {\n setHeading(parseInt(e.target.value, 10));\n pushLocationUpdate();\n }}\n type=\"range\"\n value={heading}\n />\n <div className=\"text-right text-slate-400\">{heading}°</div>\n </div>\n </div>\n\n <Button\n className={`w-full rounded px-2 py-1.5 text-[10px] font-bold border cursor-pointer ${\n isPlacingLocation\n ? \"bg-blue-500/20 border-blue-500 text-blue-300\"\n : \"bg-slate-800 border-slate-700 text-slate-200 hover:bg-slate-700\"\n }`}\n onClick={() => setIsPlacingLocation((prev) => !prev)}\n type=\"button\"\n variant=\"ghost\"\n >\n {isPlacingLocation\n ? \"📍 Click the map to drop location…\"\n : \"📍 Drop location on map\"}\n </Button>\n\n <div className=\"flex flex-col gap-1 border-t border-slate-800 pt-3\">\n <div className=\"flex justify-between items-center\">\n <span className=\"text-[10px] text-slate-500\">Scan Radius</span>\n <div className=\"flex items-center gap-1\">\n <input\n 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\"\n min=\"0\"\n onChange={(e) =>\n setRadiusMeters(Math.max(0, Number(e.target.value) || 0))\n }\n type=\"number\"\n value={radiusMeters}\n />\n <select\n 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\"\n onChange={(e) =>\n setRadiusUnit(e.target.value as \"m\" | \"km\")\n }\n value={radiusUnit}\n >\n <option value=\"m\">m</option>\n <option value=\"km\">km</option>\n </select>\n </div>\n </div>\n <input\n className=\"w-full accent-blue-500\"\n max={radiusUnit === \"km\" ? 10 : 500}\n min=\"0\"\n onChange={(e) => setRadiusMeters(Number(e.target.value))}\n step={radiusUnit === \"km\" ? 0.1 : 5}\n type=\"range\"\n value={radiusMeters}\n />\n <div className=\"text-right text-slate-400\">\n {radiusMeters === 0\n ? \"hidden\"\n : `${radiusMeters}${radiusUnit} radius around user`}\n </div>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n};\n","import { Button } from \"@miniapps-sdk/components/ui/button\";\nimport { sdk } from \"@miniapps-sdk/sdk\";\nimport { GeolocationEvent } from \"@miniapps-sdk/types\";\nimport type React from \"react\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nexport interface DebugConsoleProps {\n /**\n * Whether to show the console initially.\n * Can also be controlled via the 'debug' prop on SDKProvider.\n */\n isOpen?: boolean;\n /**\n * Optional callback when the console is closed.\n */\n onClose?: () => void;\n}\n\ninterface LogEntry {\n id: string;\n time: string;\n label: string;\n content: string;\n}\n\n/**\n * A standalone debug console that intercepts and displays all Bridge communication.\n * Useful for debugging both in mock mode (BridgeMocker) and on real devices.\n */\nexport const DebugConsole: React.FC<DebugConsoleProps> = ({\n isOpen: initialOpen = false,\n onClose,\n}) => {\n const [showConsole, setShowConsole] = useState(initialOpen);\n const [logs, setLogs] = useState<LogEntry[]>([]);\n const scrollRef = useRef<HTMLDivElement>(null);\n\n // Sync with prop\n useEffect(() => {\n setShowConsole(initialOpen);\n }, [initialOpen]);\n\n const clearLogs = () => setLogs([]);\n\n const addLog = useCallback((label: string, data: any) => {\n // Skip location stream updates as they are too noisy\n if (label.includes(GeolocationEvent.LOCATION_STREAM_UPDATE)) return;\n\n const entry: LogEntry = {\n content: typeof data === \"string\" ? data : JSON.stringify(data, null, 2),\n id: Math.random().toString(36).slice(2),\n label,\n time: new Date().toLocaleTimeString(),\n };\n\n setLogs((prev) => [entry, ...prev].slice(0, 100));\n }, []);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n // 1. Intercept OUTGOING calls (SDK -> Shell)\n const bridge = (sdk as any).bridge;\n const originalSend = bridge.send.bind(bridge);\n\n bridge.send = async (type: string, payload: any) => {\n addLog(`OUT: ${type}`, payload);\n return originalSend(type, payload);\n };\n\n // 2. Intercept INCOMING messages (Shell -> SDK)\n const originalHandle = bridge.handleNativeMessage.bind(bridge);\n bridge.handleNativeMessage = (envelope: any) => {\n const type =\n envelope.eventName || envelope.event || envelope.type || \"MSG\";\n if (typeof type === \"string\") {\n addLog(`IN: ${type}`, envelope.payload || envelope.value || envelope);\n originalHandle(envelope);\n }\n };\n\n return () => {\n bridge.send = originalSend;\n bridge.handleNativeMessage = originalHandle;\n };\n }, [addLog]);\n\n if (!showConsole) {\n return (\n <Button\n 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!\"\n onClick={() => setShowConsole(true)}\n title=\"Open Debug Console\"\n type=\"button\"\n variant=\"ghost\"\n >\n <svg\n className=\"group-hover:scale-110 transition-transform\"\n fill=\"none\"\n height=\"14\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2\"\n viewBox=\"0 0 24 24\"\n width=\"14\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"m8 2 1.88 1.88\" />\n <path d=\"M14.12 3.88 16 2\" />\n <path d=\"M9 7.13v-1a3.003 3.003 0 1 1 6 0v1\" />\n <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\" />\n <path d=\"M12 20v-9\" />\n <path d=\"M6.53 9C4.6 8.8 3 7.1 3 5\" />\n <path d=\"M6 13H2\" />\n <path d=\"M3 21c0-2.1 1.7-3.9 3.8-4\" />\n <path d=\"M20.97 5c0 2.1-1.6 3.8-3.5 4\" />\n <path d=\"M22 13h-4\" />\n <path d=\"M17.2 17c2.1.1 3.8 1.9 3.8 4\" />\n </svg>\n </Button>\n );\n }\n\n return (\n <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\">\n <div className=\"flex items-center justify-between mb-2\">\n <span className=\"text-[10px] font-bold uppercase tracking-widest text-slate-400 flex items-center gap-2\">\n <span className=\"w-2 h-2 rounded-full bg-emerald-500 animate-pulse\" />\n UP SDK Debug Console\n </span>\n <div className=\"flex gap-4\">\n <Button\n className=\"text-[10px] text-slate-500 font-bold uppercase hover:text-slate-300 hover:bg-transparent transition-colors p-0 h-auto cursor-pointer\"\n onClick={clearLogs}\n type=\"button\"\n variant=\"ghost\"\n >\n Clear\n </Button>\n <Button\n className=\"text-[10px] text-pink-500 font-bold uppercase hover:text-pink-400 hover:bg-transparent transition-colors p-0 h-auto cursor-pointer\"\n onClick={() => {\n setShowConsole(false);\n if (onClose) onClose();\n }}\n type=\"button\"\n variant=\"ghost\"\n >\n Close\n </Button>\n </div>\n </div>\n <div\n 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\"\n ref={scrollRef}\n >\n {logs.length === 0 ? (\n <div className=\"text-slate-600 italic text-center py-8\">\n No logs yet. Interacting with the SDK will show events here.\n </div>\n ) : (\n logs.map((log) => (\n <div\n className=\"mb-3 pb-3 border-b border-slate-900/50 last:border-0 last:mb-0 last:pb-0\"\n key={log.id}\n >\n <div className=\"flex gap-2 text-slate-500 mb-1 items-center\">\n <span className=\"text-[8px]\">{log.time}</span>\n <span className=\"font-bold text-white uppercase text-[8px] bg-slate-800 px-1.5 py-0.5 rounded leading-none\">\n {log.label}\n </span>\n </div>\n <pre className=\"whitespace-pre-wrap break-all opacity-90\">\n {log.content}\n </pre>\n </div>\n ))\n )}\n </div>\n </div>\n );\n};\n","import type React from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\n\n// Mimics React Native's <RefreshControl> inside a <SectionList>/<ScrollView>:\n// drag down from the very top of the list past a threshold, release, and\n// `onRefresh` fires while an indicator sits in the space the pull opened up.\n//\n// Built on the Pointer Events API, via a native (non-JSX) addEventListener\n// in a useEffect rather than onPointerDown/Move/Up JSX props — confirmed\n// live on a real Android WebView (chrome://inspect + CDP-injected touch\n// events, not desktop mouse emulation) that React's synthetic pointermove\n// prop only ever receives the FIRST move of a gesture inside a\n// react-native-webview host. A native\n// `addEventListener('pointermove', fn, {passive:false})` is the fix for\n// that part.\n//\n// That fix alone was still not enough: on Android WebView, ANY element with\n// `touch-action` permitting native panning on an axis (e.g. `pan-y`) hands\n// gesture ownership to native compositor-thread scrolling after the first\n// move on that axis — regardless of preventDefault(), and regardless of\n// react-native-webview's `nestedScrollEnabled` prop or any native ancestor\n// gesture handler. Confirmed via CDP touch injection: `touch-action: pan-y`\n// → 1 move event delivered for the whole gesture; `touch-action: none` →\n// every move event delivered. So this component sets `touch-action: none`\n// and, as a direct consequence, has to drive ALL scrolling itself — native\n// touch scroll is fully disabled on this element once native panning isn't\n// permitted on any axis. See `handlePointerMove`'s two branches: \"pull\"\n// (scrollTop is 0 and the gesture is dragging down) grows the refresh\n// indicator; \"scroll\" (everything else) sets `el.scrollTop` directly from\n// the per-move delta, plus a simple friction-decay fling on release so a\n// fast swipe still keeps moving after the finger lifts, closer to native\n// scroll feel.\n//\n// `touchAction: \"none\"` means this element claims 100% of touch handling\n// for its whole subtree — a `children` tree that itself contains a\n// touch-gesture-driven component (a horizontal swiper/carousel, a slider, a\n// map) will have that child's own gestures broken, since a descendant's own\n// `touch-action` can't reclaim a gesture an ancestor's JS is already\n// calling preventDefault() on every move. Don't nest another gesture-driven\n// component (e.g. `SwipeCarousel`) inside `PullToRefresh`.\nexport interface PullToRefreshIndicatorState {\n /** 0 (no pull) to 1 (at/past the trigger threshold). */\n progress: number;\n isRefreshing: boolean;\n}\n\nexport interface PullToRefreshProps {\n onRefresh: () => Promise<void> | void;\n children: React.ReactNode;\n className?: string;\n disabled?: boolean;\n /** Visual (post-resistance) px of pull required to trigger a refresh. Default 64. */\n pullThreshold?: number;\n /** Visual cap so the indicator never drags further than this. Default 96. */\n maxPull?: number;\n /** Fully replaces the default indicator — e.g. a brand-specific spinner/logo. */\n renderIndicator?: (state: PullToRefreshIndicatorState) => React.ReactNode;\n}\n\nconst DEFAULT_PULL_THRESHOLD = 64;\nconst DEFAULT_MAX_PULL = 96;\nconst RESISTANCE = 0.5; // finger has to travel 2px for every 1px of visual pull\nconst DRAG_DEADZONE = 8; // raw px of downward movement before this counts as a drag, not a tap\nconst FLING_FRICTION = 0.95; // velocity multiplier applied every animation frame\nconst FLING_MIN_VELOCITY = 0.02; // px/ms below which the fling animation stops\n\nfunction DefaultIndicator({\n progress,\n isRefreshing,\n}: PullToRefreshIndicatorState) {\n // Inline styles on purpose, not Tailwind classes: this component ships\n // compiled into consuming apps' bundles, and there's no guarantee a\n // consumer's own Tailwind build scans this package's dist output for\n // class names to generate CSS for. Inline styles render correctly\n // regardless of the consumer's build pipeline. Apps that want their own\n // themed indicator should pass `renderIndicator` instead of fighting\n // these styles.\n return (\n <div\n style={{\n alignItems: \"center\",\n background: \"rgba(24, 24, 27, 0.9)\",\n border: \"1px solid rgba(255, 255, 255, 0.1)\",\n borderRadius: 9999,\n boxShadow: \"0 4px 16px -4px rgba(0, 0, 0, 0.5)\",\n display: \"flex\",\n height: 28,\n justifyContent: \"center\",\n width: 28,\n }}\n >\n <svg\n height={14}\n style={{\n animation: isRefreshing\n ? \"up-sdk-ptr-spin 0.8s linear infinite\"\n : undefined,\n color: isRefreshing ? \"#a78bfa\" : \"#a1a1aa\",\n transform: isRefreshing ? undefined : `rotate(${progress * 360}deg)`,\n }}\n viewBox=\"0 0 24 24\"\n width={14}\n >\n <title>Refreshing</title>\n <path\n d=\"M21 12a9 9 0 1 1-2.64-6.36\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeWidth={2.5}\n />\n </svg>\n <style>\n {\"@keyframes up-sdk-ptr-spin { to { transform: rotate(360deg); } }\"}\n </style>\n </div>\n );\n}\n\nexport const PullToRefresh = ({\n onRefresh,\n children,\n className = \"\",\n disabled = false,\n pullThreshold = DEFAULT_PULL_THRESHOLD,\n maxPull = DEFAULT_MAX_PULL,\n renderIndicator,\n}: PullToRefreshProps) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const startYRef = useRef<number | null>(null);\n const lastYRef = useRef(0);\n const lastMoveTimeRef = useRef(0);\n const velocityRef = useRef(0); // px/ms, positive = finger moving down\n const pointerIdRef = useRef<number | null>(null);\n const isPullingRef = useRef(false);\n const pullDistanceRef = useRef(0);\n const flingRafRef = useRef<number | null>(null);\n const [pullDistance, setPullDistance] = useState(0);\n const [isRefreshing, setIsRefreshing] = useState(false);\n // Mirrors pointerIdRef into render-visible state, purely so the indicator\n // can tell \"collapsing because the finger reversed mid-drag\" (must be\n // instant, no CSS transition — it's happening in the same frame as a\n // manual scrollTop update) apart from \"collapsing after release\" (gets\n // the eased transition). See the pointermove/pointerup handlers below.\n const [isTracking, setIsTracking] = useState(false);\n // Native listeners are attached once and read these via refs, not state,\n // to avoid re-subscribing (or going stale) on every render.\n const disabledRef = useRef(disabled);\n disabledRef.current = disabled;\n const onRefreshRef = useRef(onRefresh);\n onRefreshRef.current = onRefresh;\n const pullThresholdRef = useRef(pullThreshold);\n pullThresholdRef.current = pullThreshold;\n const maxPullRef = useRef(maxPull);\n maxPullRef.current = maxPull;\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n\n const updatePullDistance = (value: number) => {\n pullDistanceRef.current = value;\n setPullDistance(value);\n };\n\n const stopFling = () => {\n if (flingRafRef.current !== null) {\n cancelAnimationFrame(flingRafRef.current);\n flingRafRef.current = null;\n }\n };\n\n const resetTracking = () => {\n pointerIdRef.current = null;\n startYRef.current = null;\n isPullingRef.current = false;\n setIsTracking(false);\n updatePullDistance(0);\n };\n\n const runFling = () => {\n velocityRef.current *= FLING_FRICTION;\n if (Math.abs(velocityRef.current) < FLING_MIN_VELOCITY) {\n flingRafRef.current = null;\n return;\n }\n // ~1 frame at 60fps; direction: positive velocity (finger moved down)\n // should keep scrolling up the same way a move did, i.e. decrease\n // scrollTop — mirrors the sign used in handlePointerMove below.\n el.scrollTop -= velocityRef.current * 16;\n if (\n el.scrollTop <= 0 ||\n el.scrollTop >= el.scrollHeight - el.clientHeight\n ) {\n flingRafRef.current = null;\n return;\n }\n flingRafRef.current = requestAnimationFrame(runFling);\n };\n\n const handlePointerDown = (e: PointerEvent) => {\n if (disabledRef.current) return;\n if (pointerIdRef.current !== null) return; // a pointer is already tracked\n stopFling();\n pointerIdRef.current = e.pointerId;\n startYRef.current = e.clientY;\n lastYRef.current = e.clientY;\n lastMoveTimeRef.current = performance.now();\n velocityRef.current = 0;\n isPullingRef.current = false;\n setIsTracking(true);\n try {\n el.setPointerCapture(e.pointerId);\n } catch {\n // Non-fatal — see handlePointerCancel's abort path.\n }\n };\n\n const handlePointerMove = (e: PointerEvent) => {\n if (startYRef.current === null || e.pointerId !== pointerIdRef.current) {\n return;\n }\n const totalDelta = e.clientY - startYRef.current;\n if (!isPullingRef.current && Math.abs(totalDelta) < DRAG_DEADZONE) {\n // Sub-pixel jitter a real touchscreen produces during an ordinary\n // tap — do nothing yet, don't commit to pull-vs-scroll.\n return;\n }\n\n const now = performance.now();\n const stepDelta = e.clientY - lastYRef.current;\n const dt = Math.max(now - lastMoveTimeRef.current, 1);\n velocityRef.current = stepDelta / dt;\n lastYRef.current = e.clientY;\n lastMoveTimeRef.current = now;\n\n // Must run synchronously on this genuinely non-passive listener for\n // every move — see the top-of-file comment for why `touch-action` is\n // 'none' and why that means this element owns 100% of its own\n // scrolling now, not just the pull gesture.\n if (e.cancelable) e.preventDefault();\n\n const atTop = el.scrollTop <= 0;\n if (atTop && totalDelta > 0) {\n // Pull-to-refresh zone: at the very top, dragging down.\n isPullingRef.current = true;\n updatePullDistance(\n Math.min(\n Math.max(totalDelta - DRAG_DEADZONE, 0) * RESISTANCE,\n maxPullRef.current,\n ),\n );\n return;\n }\n\n // Otherwise this is a normal scroll — this element fully owns it\n // since native touch-driven scrolling is disabled by touch-action:\n // none, so drive scrollTop directly from the per-move delta.\n if (isPullingRef.current) {\n // Was pulling, finger reversed direction back above the top edge —\n // collapse the indicator before resuming normal scroll.\n isPullingRef.current = false;\n updatePullDistance(0);\n }\n el.scrollTop -= stepDelta;\n };\n\n const handlePointerEnd = (e: PointerEvent) => {\n if (startYRef.current === null || e.pointerId !== pointerIdRef.current) {\n return;\n }\n const wasPulling = isPullingRef.current;\n pointerIdRef.current = null;\n startYRef.current = null;\n isPullingRef.current = false;\n setIsTracking(false);\n\n if (!wasPulling) {\n // Release a normal scroll with residual velocity into a short\n // decaying fling, closer to native momentum scrolling.\n if (Math.abs(velocityRef.current) > FLING_MIN_VELOCITY) {\n stopFling();\n flingRafRef.current = requestAnimationFrame(runFling);\n }\n return;\n }\n\n const shouldRefresh = pullDistanceRef.current >= pullThresholdRef.current;\n if (!shouldRefresh) {\n updatePullDistance(0);\n return;\n }\n setIsRefreshing(true);\n updatePullDistance(pullThresholdRef.current);\n Promise.resolve(onRefreshRef.current())\n .catch((err) => {\n // A failed refresh still has to release the gesture back to the\n // user — silently swallowing the error here would otherwise leave\n // an unhandled rejection and the user with no feedback at all\n // (the indicator would just vanish as if it had worked).\n console.error(\"Pull-to-refresh failed:\", err);\n })\n .finally(() => {\n setIsRefreshing(false);\n updatePullDistance(0);\n });\n };\n\n const handlePointerCancel = (e: PointerEvent) => {\n // Only abort if this cancel is for the pointer we're actually\n // tracking — a second finger resting on the screen (or any other\n // pointer the OS/browser decides to cancel independently) must not\n // wipe out an unrelated, still-active drag.\n if (e.pointerId !== pointerIdRef.current) return;\n stopFling();\n resetTracking();\n };\n\n el.addEventListener(\"pointerdown\", handlePointerDown);\n el.addEventListener(\"pointermove\", handlePointerMove, { passive: false });\n el.addEventListener(\"pointerup\", handlePointerEnd);\n el.addEventListener(\"pointercancel\", handlePointerCancel);\n return () => {\n stopFling();\n el.removeEventListener(\"pointerdown\", handlePointerDown);\n el.removeEventListener(\"pointermove\", handlePointerMove);\n el.removeEventListener(\"pointerup\", handlePointerEnd);\n el.removeEventListener(\"pointercancel\", handlePointerCancel);\n };\n }, []);\n\n const indicatorHeight = isRefreshing ? pullThreshold : pullDistance;\n const progress = Math.min(indicatorHeight / pullThreshold, 1);\n // Only the post-release collapse gets the eased transition. A collapse\n // that happens while still tracking a pointer (finger reversed direction\n // mid-drag, back above the top edge) has to be instant — it's happening\n // in the same frame as a manual `el.scrollTop` mutation, and animating\n // the indicator's height while content is simultaneously being scrolled\n // directly produces a visible stutter.\n const isSettling = pullDistance === 0 && !isRefreshing && !isTracking;\n\n return (\n <div\n className={`up-sdk-pull-to-refresh ${className}`}\n ref={containerRef}\n style={{\n overflowY: \"auto\",\n overscrollBehavior: \"none\",\n touchAction: \"none\",\n }}\n >\n {/* Hides the native scrollbar without depending on the consumer's own\n CSS/Tailwind setup (see the DefaultIndicator comment above for why\n this component avoids relying on the consumer's build pipeline). */}\n <style>\n {\n \".up-sdk-pull-to-refresh::-webkit-scrollbar { display: none; } .up-sdk-pull-to-refresh { scrollbar-width: none; -ms-overflow-style: none; }\"\n }\n </style>\n <div\n style={{\n alignItems: \"center\",\n display: \"flex\",\n height: indicatorHeight,\n justifyContent: \"center\",\n overflow: \"hidden\",\n transition: isSettling ? \"height 0.2s ease-out\" : \"none\",\n userSelect: \"none\",\n width: \"100%\",\n }}\n >\n {renderIndicator ? (\n renderIndicator({ isRefreshing, progress })\n ) : (\n <DefaultIndicator isRefreshing={isRefreshing} progress={progress} />\n )}\n </div>\n {children}\n </div>\n );\n};\n","import { sdk } from \"@miniapps-sdk/sdk\";\nimport jsQR from \"jsqr\";\nimport { useEffect, useRef, useState } from \"react\";\n\nexport interface QRScannerProps {\n /** Called once with the decoded string the moment a QR code is detected. Scanning stops immediately after. */\n onScan: (data: string) => void;\n /** Called with a user-facing error message (camera permission denied, no camera, etc.). */\n onError?: (message: string) => void;\n /** Additional className for the outer container (sizing/positioning — the component fills it). */\n className?: string;\n}\n\n/**\n * Camera-based QR code scanner — the single source of truth for every\n * Mini-App. Handles camera permission (via `sdk.permission.request`),\n * `getUserMedia` stream lifecycle, and the jsQR decode loop internally.\n * Mini-Apps must not reimplement this on their own — that duplication is\n * exactly what made this logic drift and painful to fix consistently across\n * apps.\n *\n * Renders its own default \"scan frame\" chrome (bordered square + scan-line\n * animation via inline styles, so it works with zero external CSS). Pass\n * `className` to control size/position; the video feed fills the container.\n */\nexport function QRScanner({ onScan, onError, className = \"\" }: QRScannerProps) {\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const canvasRef = useRef<HTMLCanvasElement | null>(null);\n const streamRef = useRef<MediaStream | null>(null);\n const tickRequestRef = useRef<number | null>(null);\n const hasScannedRef = useRef(false);\n const [isReady, setIsReady] = useState(false);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: onScan/onError are read via closure but intentionally excluded — they're expected to be stable per mount, and re-running this effect on every render identity change would restart the camera stream.\n useEffect(() => {\n let cancelled = false;\n hasScannedRef.current = false;\n\n const cleanup = () => {\n if (tickRequestRef.current) {\n cancelAnimationFrame(tickRequestRef.current);\n tickRequestRef.current = null;\n }\n if (streamRef.current) {\n for (const track of streamRef.current.getTracks()) {\n track.stop();\n }\n streamRef.current = null;\n }\n };\n\n const tick = () => {\n if (cancelled || hasScannedRef.current) return;\n const video = videoRef.current;\n const canvas = canvasRef.current;\n if (!video || video.readyState !== video.HAVE_ENOUGH_DATA || !canvas) {\n tickRequestRef.current = requestAnimationFrame(tick);\n return;\n }\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n tickRequestRef.current = requestAnimationFrame(tick);\n return;\n }\n canvas.height = video.videoHeight;\n canvas.width = video.videoWidth;\n ctx.drawImage(video, 0, 0, canvas.width, canvas.height);\n const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n const code = jsQR(imageData.data, imageData.width, imageData.height, {\n inversionAttempts: \"dontInvert\",\n });\n if (code?.data) {\n hasScannedRef.current = true;\n cleanup();\n onScan(code.data);\n return;\n }\n tickRequestRef.current = requestAnimationFrame(tick);\n };\n\n const start = async () => {\n try {\n const granted = await sdk.permission.request(\"camera\");\n if (!granted) {\n onError?.(\"Permission caméra refusée par l'utilisateur.\");\n return;\n }\n if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {\n onError?.(\n \"L'accès à la caméra requiert une connexion sécurisée (HTTPS) ou n'est pas supporté par ce navigateur.\",\n );\n return;\n }\n const stream = await navigator.mediaDevices.getUserMedia({\n video: { facingMode: \"environment\" },\n });\n if (cancelled) {\n for (const track of stream.getTracks()) track.stop();\n return;\n }\n streamRef.current = stream;\n const video = videoRef.current;\n if (!video) return;\n video.srcObject = stream;\n video.setAttribute(\"playsinline\", \"true\");\n await video.play();\n if (cancelled) return;\n setIsReady(true);\n tickRequestRef.current = requestAnimationFrame(tick);\n } catch (err) {\n console.error(\"QRScanner: camera access failed:\", err);\n onError?.(\"Accès caméra refusé ou non disponible sur cet appareil.\");\n }\n };\n\n start();\n\n return () => {\n cancelled = true;\n cleanup();\n };\n }, []);\n\n return (\n <div\n className={className}\n style={{\n alignItems: \"center\",\n display: \"flex\",\n justifyContent: \"center\",\n overflow: \"hidden\",\n position: \"relative\",\n }}\n >\n {/* biome-ignore lint/a11y/useMediaCaption: live camera feed, no captions apply */}\n <video\n playsInline\n ref={videoRef}\n style={{ height: \"100%\", objectFit: \"cover\", width: \"100%\" }}\n />\n <canvas ref={canvasRef} style={{ display: \"none\" }} />\n {isReady && (\n <div\n style={{\n border: \"2px dashed rgba(255,255,255,0.8)\",\n borderRadius: 12,\n bottom: \"10%\",\n left: \"10%\",\n pointerEvents: \"none\",\n position: \"absolute\",\n right: \"10%\",\n top: \"10%\",\n }}\n />\n )}\n </div>\n );\n}\n","import type React from \"react\";\nimport { createContext, useContext, useMemo } from \"react\";\nimport { BridgeMocker, type BridgeMockerProps } from \"./BridgeMocker\";\nimport { DebugConsole } from \"./DebugConsole\";\n\ninterface SDKContextValue {\n isMocked: boolean;\n}\n\nconst SDKContext = createContext<SDKContextValue>({ isMocked: false });\n\n/**\n * Hook to check if the SDK is currently running in mock mode (browser)\n * or native mode (shell app).\n */\nexport const useIsMocked = () => useContext(SDKContext).isMocked;\n\nexport interface SDKProviderProps\n extends Partial<Omit<BridgeMockerProps, \"children\">> {\n children: React.ReactNode;\n /**\n * If true, shows the standalone DebugConsole for bridge traffic.\n */\n debug?: boolean;\n}\n\n/**\n * A wrapper component that automatically enables the BridgeMocker\n * when running outside the native shell app.\n */\nexport const SDKProvider: React.FC<SDKProviderProps> = ({\n children,\n debug = false,\n ...mockerProps\n}) => {\n const isMocked =\n typeof window !== \"undefined\" &&\n !(\n (window as any).__UP_REACT_NATIVE_APP__ === true ||\n !!(window as any).ReactNativeWebView\n );\n\n const value = useMemo(() => ({ isMocked }), [isMocked]);\n\n const content = (\n <>\n {children}\n {(debug || isMocked) && <DebugConsole />}\n </>\n );\n\n if (isMocked) {\n return (\n <SDKContext.Provider value={value}>\n <BridgeMocker {...mockerProps}>{content}</BridgeMocker>\n </SDKContext.Provider>\n );\n }\n\n return <SDKContext.Provider value={value}>{content}</SDKContext.Provider>;\n};\n","import {\n type ReactNode,\n type TouchEvent as ReactTouchEvent,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\n\n// Homemade swipe carousel: the \"swiper\" library's own touch listeners fight\n// React Native WebView's native gesture handling (missed touchmove events,\n// stuck drags). This uses plain React touch events, which the WebView\n// delivers reliably.\n\nexport type SwipeAxisPriority = \"horizontal\" | \"vertical\";\n\nexport interface SwipeCarouselItem {\n id: string;\n content: ReactNode;\n className?: string;\n}\n\nexport interface SwipeCarouselVerticalDragConfig {\n /** Which way the active slide may be dragged. Default \"down\". */\n direction?: \"down\" | \"up\" | \"both\";\n /** px past which releasing fires onDismiss. Default 200. */\n dismissThreshold?: number;\n /** px/ms past which releasing fires onDismiss regardless of distance. Default 0.5. */\n dismissVelocity?: number;\n /**\n * Vertical tracking only starts when the touch begins inside an element\n * matching this selector AND that element is scrolled to its top\n * (scrollTop <= 2) — lets normal content scrolling take priority\n * otherwise. Default `[data-swipe-scroll-root]`; mark the scrollable\n * content root inside each slide with that attribute.\n */\n scrollRootSelector?: string;\n /** Fires on every move once vertical drag is engaged, with the raw px offset (already past the small dead-zone), and once more with `(0, false)` on release. */\n onDragChange?: (deltaY: number, isDragging: boolean) => void;\n /** Fires once, on release, when the drag crossed the dismiss threshold. */\n onDismiss?: () => void;\n}\n\nexport interface SwipeCarouselProps {\n items: SwipeCarouselItem[];\n activeId: string | null;\n onActiveChange: (id: string) => void;\n /** How many slides fit across the viewport (1.1 == active slide + a sliver of its neighbor). */\n peek?: number;\n gap?: number;\n className?: string;\n itemClassName?: string;\n /**\n * Once a touch moves past the direction-lock threshold, the dominant axis\n * (bigger |dx| vs |dy|) wins the WHOLE gesture — the other axis is frozen\n * for the rest of that touch, so a horizontal swipe can't also drag the\n * slide down and vice versa. `axisPriority` only breaks an exact tie at\n * that decision point. Default \"horizontal\".\n */\n axisPriority?: SwipeAxisPriority;\n /** Enables swipe-to-dismiss on the ACTIVE slide only (e.g. drag-down-to-close a detail sheet). Omit for a pure horizontal carousel. */\n verticalDrag?: SwipeCarouselVerticalDragConfig;\n /** Slides kept MOUNTED on each side of the active one, so a 100+ item list stays cheap and the next swipe target is already in the DOM. Default 2 (5 slides mounted total). */\n overscan?: number;\n /**\n * Slides kept VISIBLE (opacity) on each side of the active one — must be\n * <= `overscan`. Slides beyond this stay mounted (for an instant, already-\n * positioned reveal once they enter range) but invisible, so their\n * shadow/blur styling can't bleed into the visible strip. Default 1.\n */\n visibleOverscan?: number;\n}\n\nconst DIRECTION_LOCK_THRESHOLD_PX = 8;\nconst SWIPE_DISTANCE_THRESHOLD_PX = 40;\nconst SWIPE_VELOCITY_THRESHOLD = 0.4; // px/ms\nconst EDGE_RESISTANCE = 0.35;\nconst SNAP_EASING = \"cubic-bezier(0.16, 1, 0.3, 1)\";\nconst SNAP_DURATION_MS = 300;\nconst VERTICAL_DEAD_ZONE_PX = 15;\nconst DEFAULT_VERTICAL_DISMISS_THRESHOLD_PX = 200;\nconst DEFAULT_VERTICAL_DISMISS_VELOCITY = 0.5; // px/ms\nconst DEFAULT_OVERSCAN = 2;\nconst DEFAULT_VISIBLE_OVERSCAN = 1;\nconst DEFAULT_SCROLL_ROOT_SELECTOR = \"[data-swipe-scroll-root]\";\nconst SNAP_TRANSITION = `transform ${SNAP_DURATION_MS}ms ${SNAP_EASING}`;\n\ninterface TouchState {\n startX: number;\n startY: number;\n lastX: number;\n lastY: number;\n lastT: number;\n velocityX: number;\n velocityY: number;\n verticalAllowed: boolean;\n // \"passthrough\" = neither axis claims the gesture (e.g. a vertical\n // content-scroll attempt while verticalDrag is disabled/not allowed) —\n // native scrolling is left alone for the rest of the touch.\n lockedAxis: \"x\" | \"y\" | \"passthrough\" | null;\n}\n\nexport const SwipeCarousel = ({\n items,\n activeId,\n onActiveChange,\n peek = 1.1,\n gap = 10,\n className,\n itemClassName,\n axisPriority = \"horizontal\",\n verticalDrag,\n overscan = DEFAULT_OVERSCAN,\n visibleOverscan = DEFAULT_VISIBLE_OVERSCAN,\n}: SwipeCarouselProps) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const [containerWidth, setContainerWidth] = useState(0);\n const [dragX, setDragX] = useState(0);\n const [dragY, setDragY] = useState(0);\n const [isDraggingX, setIsDraggingX] = useState(false);\n const [isDraggingY, setIsDraggingY] = useState(false);\n const touchStateRef = useRef<TouchState | null>(null);\n\n // Authoritative index, advanced synchronously on release instead of\n // waiting for `activeId` to round-trip back through the parent's state —\n // a rapid second swipe starting before that round-trip lands would\n // otherwise read a stale index off `activeId` and could undo the first\n // swipe (or \"roll back\" instead of advancing).\n const [internalIndex, setInternalIndex] = useState(() =>\n Math.max(\n 0,\n items.findIndex((item) => item.id === activeId),\n ),\n );\n // Tracks the last `activeId` prop value we've already reacted to — NOT\n // what we last emitted via `onActiveChange`. That distinction matters: if\n // a consumer's `onActiveChange` ever ignores/gates the call, this must\n // never claim the prop changed when it didn't, or it would silently\n // revert the optimistic `commitIndex()` update the next time this effect\n // re-runs (e.g. because `items` got a new reference).\n const prevActiveIdRef = useRef(activeId);\n\n const [timingWaiting, setTimingWaiting] = useState(true);\n\n useEffect(() => {\n const timer = setTimeout(() => {\n setTimingWaiting(false);\n }, 1000);\n return () => clearTimeout(timer);\n }, []);\n\n useEffect(() => {\n if (activeId !== prevActiveIdRef.current) {\n const idx = items.findIndex((item) => item.id === activeId);\n if (idx !== -1) setInternalIndex(idx);\n prevActiveIdRef.current = activeId;\n }\n }, [activeId, items]);\n\n const activeIndex = Math.min(\n Math.max(internalIndex, 0),\n Math.max(items.length - 1, 0),\n );\n\n useLayoutEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n const update = () => setContainerWidth(el.clientWidth);\n update();\n const observer = new ResizeObserver(update);\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\n\n const slideWidth = containerWidth / peek;\n const step = slideWidth + gap;\n const baseOffset = (containerWidth - slideWidth) / 2;\n const translateX = baseOffset - activeIndex * step + dragX;\n\n const commitIndex = (nextIndex: number) => {\n setInternalIndex(nextIndex);\n const nextItem = items[nextIndex];\n if (nextItem && nextItem.id !== activeId) onActiveChange(nextItem.id);\n };\n\n const handleTouchStart = (e: ReactTouchEvent<HTMLDivElement>) => {\n const touch = e.targetTouches[0];\n if (!touch) return;\n\n let verticalAllowed = false;\n if (verticalDrag) {\n const selector =\n verticalDrag.scrollRootSelector ?? DEFAULT_SCROLL_ROOT_SELECTOR;\n const scrollRoot = (e.target as HTMLElement).closest<HTMLElement>(\n selector,\n );\n verticalAllowed = !scrollRoot || scrollRoot.scrollTop <= 2;\n }\n\n touchStateRef.current = {\n lastT: e.timeStamp,\n lastX: touch.clientX,\n lastY: touch.clientY,\n lockedAxis: null,\n startX: touch.clientX,\n startY: touch.clientY,\n velocityX: 0,\n velocityY: 0,\n verticalAllowed,\n };\n };\n\n const handleTouchMove = (e: ReactTouchEvent<HTMLDivElement>) => {\n const touch = e.targetTouches[0];\n const state = touchStateRef.current;\n if (!touch || !state) return;\n\n const rawDx = touch.clientX - state.startX;\n const rawDy = touch.clientY - state.startY;\n\n if (!state.lockedAxis) {\n if (\n Math.abs(rawDx) < DIRECTION_LOCK_THRESHOLD_PX &&\n Math.abs(rawDy) < DIRECTION_LOCK_THRESHOLD_PX\n ) {\n return;\n }\n // Whichever axis is dominant wins the whole gesture from here on —\n // ties go to axisPriority. If vertical wins but dragging isn't\n // actually usable right now (disabled, or mid-content-scroll), don't\n // lock into the carousel either: leave the gesture alone so native\n // scrolling keeps working.\n const horizontalWins =\n Math.abs(rawDx) > Math.abs(rawDy) ||\n (Math.abs(rawDx) === Math.abs(rawDy) && axisPriority === \"horizontal\");\n if (horizontalWins) {\n state.lockedAxis = \"x\";\n } else if (verticalDrag && state.verticalAllowed) {\n state.lockedAxis = \"y\";\n } else {\n state.lockedAxis = \"passthrough\";\n }\n }\n\n if (state.lockedAxis === \"passthrough\") return;\n\n const dt = e.timeStamp - state.lastT;\n if (dt > 0) {\n state.velocityX = (touch.clientX - state.lastX) / dt;\n state.velocityY = (touch.clientY - state.lastY) / dt;\n }\n state.lastX = touch.clientX;\n state.lastY = touch.clientY;\n state.lastT = e.timeStamp;\n\n if (state.lockedAxis === \"x\") {\n if (!isDraggingX) setIsDraggingX(true);\n const atStart = activeIndex === 0 && rawDx > 0;\n const atEnd = activeIndex === items.length - 1 && rawDx < 0;\n setDragX(atStart || atEnd ? rawDx * EDGE_RESISTANCE : rawDx);\n } else if (verticalDrag) {\n const direction = verticalDrag.direction ?? \"down\";\n let clamped = rawDy;\n if (direction === \"down\") clamped = Math.max(0, rawDy);\n if (direction === \"up\") clamped = Math.min(0, rawDy);\n const beyondDeadZone =\n Math.sign(clamped) *\n Math.max(0, Math.abs(clamped) - VERTICAL_DEAD_ZONE_PX);\n\n if (!isDraggingY) setIsDraggingY(true);\n setDragY(beyondDeadZone);\n verticalDrag.onDragChange?.(beyondDeadZone, true);\n }\n\n if (e.cancelable) {\n // React attaches touchmove as passive by default, so this is often a\n // no-op in practice; real scroll suppression comes from the\n // container's `touch-pan-y` CSS, not this call.\n e.preventDefault();\n }\n };\n\n const endDrag = () => {\n const state = touchStateRef.current;\n touchStateRef.current = null;\n setIsDraggingX(false);\n setIsDraggingY(false);\n\n if (!state) {\n setDragX(0);\n setDragY(0);\n return;\n }\n\n if (state.lockedAxis === \"x\") {\n const horizontalTriggered =\n Math.abs(dragX) > SWIPE_DISTANCE_THRESHOLD_PX ||\n Math.abs(state.velocityX) > SWIPE_VELOCITY_THRESHOLD;\n if (horizontalTriggered) {\n const nextIndex =\n dragX < 0\n ? Math.min(items.length - 1, activeIndex + 1)\n : Math.max(0, activeIndex - 1);\n commitIndex(nextIndex);\n }\n } else if (state.lockedAxis === \"y\") {\n const verticalThreshold =\n verticalDrag?.dismissThreshold ?? DEFAULT_VERTICAL_DISMISS_THRESHOLD_PX;\n const verticalVelocityThreshold =\n verticalDrag?.dismissVelocity ?? DEFAULT_VERTICAL_DISMISS_VELOCITY;\n // `dragY` is already direction-clamped (stays 0 when dragged the\n // \"wrong\" way), but the raw `velocityY` isn't — a fast flick in the\n // disallowed direction has real negative/positive velocity and would\n // otherwise trip the velocity fallback and dismiss anyway. Clamp it\n // the same way dragY itself is clamped in handleTouchMove.\n const direction = verticalDrag?.direction ?? \"down\";\n const directionalVelocityY =\n direction === \"down\"\n ? Math.max(0, state.velocityY)\n : direction === \"up\"\n ? Math.max(0, -state.velocityY)\n : Math.abs(state.velocityY);\n const verticalTriggered =\n Math.abs(dragY) > verticalThreshold ||\n directionalVelocityY > verticalVelocityThreshold;\n if (verticalTriggered) verticalDrag?.onDismiss?.();\n }\n\n setDragX(0);\n setDragY(0);\n verticalDrag?.onDragChange?.(0, false);\n };\n\n // NOTE: jumping `activeId` externally to an item outside this window (more\n // than `overscan` away from the previous active index) unmounts the old\n // slide immediately rather than animating past it — the snap transition\n // still runs on the track transform, but there's nothing left to slide\n // past, so it reads as a pop/cut instead of a smooth pass-through. Fine\n // for \"jump to a specific item while closed\", not for scrubbing far\n // across a huge list while open.\n const windowStart = Math.max(0, activeIndex - overscan);\n const windowEnd = Math.min(items.length - 1, activeIndex + overscan);\n\n return (\n <div\n className={`relative overflow-hidden touch-pan-y ${className ?? \"\"}`}\n onTouchCancel={endDrag}\n onTouchEnd={endDrag}\n onTouchMove={handleTouchMove}\n onTouchStart={handleTouchStart}\n ref={containerRef}\n >\n <div\n className=\"relative h-full\"\n style={{\n transform: `translateX(${translateX}px)`,\n transition: isDraggingX || timingWaiting ? \"none\" : SNAP_TRANSITION,\n willChange: \"transform\",\n }}\n >\n {items.map((item, index) => {\n if (index < windowStart || index > windowEnd) return null;\n const isActive = index === activeIndex;\n const verticalOffset = isActive ? dragY : 0;\n const distance = Math.abs(index - activeIndex);\n // Mounted (for an instant, already-positioned reveal) but\n // invisible beyond visibleOverscan — at this `peek`, an unhidden\n // ±2 slide's shadow/blur bled into the visible strip and read as\n // jitter behind the active card.\n const isVisible = distance <= visibleOverscan;\n return (\n <div\n className={`absolute top-0 left-0 h-full shrink-0 ${itemClassName ?? \"\"} ${item.className ?? \"\"}`}\n key={item.id}\n style={{\n opacity: isVisible ? 1 : 0,\n pointerEvents: isVisible ? undefined : \"none\",\n transform: `translateX(${index * step}px) translateY(${verticalOffset}px)`,\n transition:\n (isActive && isDraggingY) || timingWaiting\n ? \"none\"\n : SNAP_TRANSITION,\n width: `${slideWidth}px`,\n // Layer by distance from the active slide (not DOM/index\n // order) so it always paints above its neighbors on BOTH\n // sides symmetrically — with `peek` this close, unstyled\n // z-index left neighbor bleed (shadow/blur) showing through\n // asymmetrically depending on swipe direction.\n zIndex: overscan + 1 - distance,\n }}\n >\n {item.content}\n </div>\n );\n })}\n </div>\n </div>\n );\n};\n","import type { RoutingBackendConfig } from \"@miniapps-sdk/services/routingService\";\nimport { RoutingService } from \"@miniapps-sdk/services/routingService\";\nimport type {\n DrawRouteRequest,\n RouteRequest,\n RouteResponse,\n} from \"@miniapps-sdk/types/routing\";\nimport type { Map } from \"maplibre-gl\";\n\n/**\n * Handles a route request from the mini-app and fetches data from the configured backend.\n */\nexport async function handleRouteRequest(\n req: RouteRequest,\n config: RoutingBackendConfig,\n): Promise<RouteResponse> {\n return RoutingService.fetchRoute(req, config);\n}\n\n/**\n * Host-side map rendering logic for routes.\n */\nexport function handleDrawRoute(\n map: Map,\n miniAppId: string,\n req: DrawRouteRequest,\n) {\n const sourceId = `sdk-route-${miniAppId}`;\n const casingLayerId = `sdk-route-casing-${miniAppId}`;\n const lineLayerId = `sdk-route-line-${miniAppId}`;\n\n const geojson = {\n features: [\n {\n geometry: req.payload.routeData.geometry,\n properties: {},\n type: \"Feature\",\n },\n ],\n type: \"FeatureCollection\",\n };\n\n const source = map.getSource(sourceId);\n if (source) {\n // @ts-expect-error - maplibre-gl types might not expose setData nicely on generic source\n (source as maplibregl.GeoJSONSource).setData(geojson);\n } else {\n map.addSource(sourceId, {\n data: geojson as any,\n type: \"geojson\",\n });\n\n map.addLayer({\n id: casingLayerId,\n layout: {\n \"line-cap\": \"round\",\n \"line-join\": \"round\",\n },\n paint: {\n \"line-color\": \"#111111\",\n \"line-opacity\": 0.8,\n \"line-width\": 8,\n },\n source: sourceId,\n type: \"line\",\n });\n\n map.addLayer({\n id: lineLayerId,\n layout: {\n \"line-cap\": \"round\",\n \"line-join\": \"round\",\n },\n paint: {\n \"line-color\": \"#3b82f6\", // Bright blue\n \"line-width\": 4,\n },\n source: sourceId,\n type: \"line\",\n });\n }\n}\n\nexport function handleClearRoute(map: Map, miniAppId: string) {\n const sourceId = `sdk-route-${miniAppId}`;\n const casingLayerId = `sdk-route-casing-${miniAppId}`;\n const lineLayerId = `sdk-route-line-${miniAppId}`;\n\n if (map.getLayer(lineLayerId)) map.removeLayer(lineLayerId);\n if (map.getLayer(casingLayerId)) map.removeLayer(casingLayerId);\n if (map.getSource(sourceId)) map.removeSource(sourceId);\n}\n","import { sdk } from \"@miniapps-sdk/sdk\";\nimport type { INetworkResponse } from \"@miniapps-sdk/types\";\n\nexport interface CreateApiServiceOptions {\n /**\n * Backend URL to use before the shell has ever supplied one via\n * `initialize()`/`UPDATE_CONTEXT`, or if a boot ever completes without\n * one (e.g. a degraded/standalone fallback). Should be the app's real\n * production backend, typically read from a build-time env var baked\n * via `.env.production` — never a local dev address, since that value\n * is what actually reaches the network if the live one is ever missing.\n */\n defaultBaseUrl: string;\n /** Same fallback role as `defaultBaseUrl`, for `wsUrl` instead of `baseUrl`. Optional — omit if this app derives its WS URL from `baseUrl` itself. */\n defaultWsBackendUrl?: string;\n}\n\nexport interface ApiServiceClient {\n /** Current backend URL — see `getBaseUrl`'s doc comment below for the full resolution order. */\n readonly baseUrl: string;\n /** Current WebSocket backend URL, same resolution order as `baseUrl` but reading the dedicated ws fields instead. `undefined` if neither the shell nor `defaultWsBackendUrl` ever supplied one. */\n readonly wsUrl: string | undefined;\n\n get<T = unknown>(path: string): Promise<INetworkResponse<T>>;\n\n post<T = unknown>(path: string, body?: unknown): Promise<INetworkResponse<T>>;\n\n patch<T = unknown>(\n path: string,\n body?: unknown,\n ): Promise<INetworkResponse<T>>;\n\n delete(path: string): Promise<INetworkResponse<void>>;\n\n graphqlQuery<T = unknown>(\n query: string,\n variables?: Record<string, unknown>,\n ): Promise<INetworkResponse<{ data: T; errors?: { message: string }[] }>>;\n}\n\nfunction buildUrl(baseUrl: string, path: string): string {\n if (path.startsWith(\"http://\") || path.startsWith(\"https://\")) {\n return path;\n }\n\n let cleanBase = baseUrl.trim();\n while (cleanBase.endsWith(\"/\")) {\n cleanBase = cleanBase.slice(0, -1);\n }\n\n let cleanPath = path.trim();\n if (!cleanPath.startsWith(\"/\")) {\n cleanPath = `/${cleanPath}`;\n }\n\n // Prevent duplicate /api/v1 prefix\n const baseEndsWithV1 = cleanBase.endsWith(\"/api/v1\");\n const pathStartsWithV1 =\n cleanPath.startsWith(\"/api/v1/\") || cleanPath === \"/api/v1\";\n\n if (baseEndsWithV1 && pathStartsWithV1) {\n const strippedPath = cleanPath.slice(7);\n return `${cleanBase}${strippedPath}`;\n }\n\n return `${cleanBase}${cleanPath}`;\n}\n\n/**\n * Set synchronously by the host shell (`MiniAppContainer`'s early-injection\n * script) before this WebView's own bundle even starts parsing — the\n * earliest possible source for the backend URL, well before any bridge\n * round-trip (including `sdk.initialize()`) could complete. Checked first,\n * ahead of `sdk.getEnv()`, so a slow/lost bridge round-trip can never leave\n * a request without the right URL.\n */\nfunction getEarlyBackendUrl(kind: \"http\" | \"ws\"): string | undefined {\n if (typeof window === \"undefined\") return undefined;\n const early = (\n window as unknown as {\n __UP_BACKEND_URLS__?: { http?: string | null; ws?: string | null };\n }\n ).__UP_BACKEND_URLS__;\n return early?.[kind] ?? undefined;\n}\n\n/**\n * Creates a small REST/GraphQL client that always proxies through\n * `sdk.network.request` and always resolves the backend URL LIVE — from\n * `window.__UP_BACKEND_URLS__` (earliest, synchronous, see\n * `getEarlyBackendUrl` above), then `sdk.getEnv()` (updated by\n * `initialize()`/`UPDATE_CONTEXT`) — never from a value cached at some\n * earlier point in the boot sequence. This is the fix for a real,\n * repeatedly reproduced bug: apps used to assign a mutable `baseUrl` field\n * imperatively from `initialize()`'s response / `UPDATE_CONTEXT`; if that\n * one assignment was ever skipped (e.g. the underlying bridge request\n * losing its response — see `Bridge.send`'s retry, which reduces but does\n * not entirely eliminate that risk) the field stayed wrong for the rest of\n * the session, silently sending requests to `defaultBaseUrl` instead.\n * Reading fresh here means the very next call after either source is\n * populated self-heals automatically, and there is no second, independent\n * copy of the URL that can go stale.\n *\n * Response shape is the raw `INetworkResponse<T>` (status/data/headers) —\n * this stays a thin transport client; app-specific response unwrapping,\n * error-message translation, etc. belong in each app's own thin wrapper\n * around this, not here.\n */\nexport function createApiService(\n options: CreateApiServiceOptions,\n): ApiServiceClient {\n const getBaseUrl = (): string =>\n getEarlyBackendUrl(\"http\") ||\n (sdk.getEnv()?.backendUrl as string | undefined) ||\n options.defaultBaseUrl;\n\n const getWsUrl = (): string | undefined =>\n getEarlyBackendUrl(\"ws\") ||\n (sdk.getEnv()?.wsBackendUrl as string | undefined) ||\n options.defaultWsBackendUrl;\n\n return {\n get baseUrl(): string {\n return getBaseUrl();\n },\n\n delete: (path) =>\n sdk.network.request({\n method: \"DELETE\",\n url: buildUrl(getBaseUrl(), path),\n }),\n\n get: (path) =>\n sdk.network.request({\n headers: { \"Content-Type\": \"application/json\" },\n method: \"GET\",\n url: buildUrl(getBaseUrl(), path),\n }),\n\n graphqlQuery: (query, variables = {}) =>\n sdk.network.request({\n body: { query, variables },\n headers: { \"Content-Type\": \"application/json\" },\n method: \"POST\",\n url: buildUrl(getBaseUrl(), \"/graphql\"),\n }),\n\n patch: (path, body) =>\n sdk.network.request({\n body,\n headers: { \"Content-Type\": \"application/json\" },\n method: \"PATCH\",\n url: buildUrl(getBaseUrl(), path),\n }),\n\n post: (path, body) =>\n sdk.network.request({\n body,\n headers: { \"Content-Type\": \"application/json\" },\n method: \"POST\",\n url: buildUrl(getBaseUrl(), path),\n }),\n\n get wsUrl(): string | undefined {\n return getWsUrl();\n },\n };\n}\n","import { isRunningInsideNativeShell } from \"@miniapps-sdk/utils/environment\";\nimport type { ApiServiceClient } from \"./apiService\";\n\nexport interface WsMessage {\n event?: string;\n\n [key: string]: unknown;\n}\n\n/**\n * `\"open\"` is the only state where the wire connection is actually live —\n * `\"connecting\"` covers both the initial handshake and every reconnect\n * backoff wait, `\"closed\"` covers not-yet-started and lost-and-not-yet-\n * retried. A consumer that wants a poll-based fallback (only meaningful\n * while genuinely disconnected) should treat anything other than `\"open\"`\n * as \"poll\".\n */\nexport type WsConnectionStatus = \"connecting\" | \"open\" | \"closed\";\n\ninterface BaseWsServiceOptions<TMessage extends WsMessage> {\n /**\n * The REST client from `createApiService` — reused here for two things:\n * its live `wsUrl` (so this shares the exact same URL resolution as\n * every REST/GraphQL call, no separate copy to go stale), and its\n * `post()` to mint a short-lived WS auth ticket in production (see\n * `ticketPath` below).\n */\n api: Pick<ApiServiceClient, \"post\" | \"wsUrl\">;\n /**\n * REST path (relative, via `api.post`) that mints a short-lived,\n * single-use ticket for the WS handshake — a mini-app's JS never holds\n * its own real bearer token in production (`sdk.network.request` proxies\n * every REST/GraphQL call through the native host shell, which injects\n * auth on its own side; a raw browser `WebSocket` has no equivalent\n * bridge and no way to set a custom header, so it authenticates via a\n * ticket fetched over that same working REST path instead). Expected to\n * return `{ ticket: string }`. Defaults to `\"/ws-ticket\"`, matching the\n * established backend convention (see up-miniapps-backend's\n * `GetWSTicket`). Pass `null` to disable ticket auth entirely — only\n * appropriate for a mini-app whose backend has no ws-ticket route yet,\n * or a genuinely public route (see `requireAuth` below).\n */\n ticketPath?: string | null;\n /**\n * Raw JWT to use when NOT running inside the native shell (standalone\n * dev browser) — the consuming app reads its own build-time\n * `import.meta.env.VITE_DEV_TOKEN` and passes it here; the SDK itself\n * has no access to a consuming app's Vite env (this package is bundled\n * by tsup, not Vite). Only ever used outside the shell — a ticket is\n * always preferred when `isRunningInsideNativeShell()` is true.\n */\n devToken?: string | null;\n /**\n * Overrides the resolved WS URL outright, for a mini-app whose WS\n * gateway genuinely lives somewhere `api.wsUrl` doesn't cover. Most\n * consumers should leave this unset and rely on `api.wsUrl`.\n */\n baseUrl?: string;\n /**\n * Extra static query params appended to every connection URL. Browsers\n * (and this WebView) give a raw `WebSocket` no custom-header API — a\n * query param is the closest equivalent, e.g. for a custom auth scheme\n * on top of the ticket/token this already sends.\n */\n query?: Record<string, string>;\n /**\n * When unset/`true` (the default), `connect()` refuses — warns and\n * delays rather than opening an unauthenticated socket — if neither a\n * ticket nor `devToken` is available. This is a deliberate safety net:\n * a channel-scoped app (ticket-authorized per-room access) accidentally\n * shipping with no auth configured would silently become an open room,\n * not a loud failure.\n *\n * Set to `false` only for a backend route that's genuinely public with\n * no per-connection identity at all — e.g. up-miniapps-by-night's `/ws`,\n * which has no auth middleware by design, broadcasts the same public\n * data to every connection, and has no rooms to gate. `connect()` then\n * opens the socket with no ticket/token query param whatsoever. Pair\n * with `ticketPath: null` (no point minting a ticket nobody checks).\n */\n requireAuth?: boolean;\n}\n\n/** Options for the channel-scoped mode — pass `channelField` to subscribe/unsubscribe to specific rooms. */\nexport interface CreateChannelWsServiceOptions<\n TMessage extends WsMessage = WsMessage,\n> extends BaseWsServiceOptions<TMessage> {\n /**\n * Name of the field on each message that identifies which \"room\"/channel\n * it belongs to (e.g. `\"groupUuid\"`, `\"gameUuid\"`). Also the field name\n * used in the `{action, [channelField]: id}` subscribe/unsubscribe wire\n * messages sent to the backend. Presence of this field is what selects\n * channel mode over broadcast mode — see `CreateBroadcastWsServiceOptions`.\n */\n channelField: string;\n}\n\n/** Options for broadcast mode — omit `channelField` for a single global socket with no room concept. */\nexport interface CreateBroadcastWsServiceOptions<\n TMessage extends WsMessage = WsMessage,\n> extends BaseWsServiceOptions<TMessage> {\n channelField?: undefined;\n}\n\nexport type CreateWsServiceOptions<TMessage extends WsMessage = WsMessage> =\n | CreateChannelWsServiceOptions<TMessage>\n | CreateBroadcastWsServiceOptions<TMessage>;\n\nexport interface WsServiceClient<TMessage extends WsMessage = WsMessage> {\n /** Opens the connection if not already open/connecting. Safe to call repeatedly. */\n connect(): Promise<void>;\n\n /** Closes the connection and cancels any pending reconnect — no further automatic reconnect happens until `connect()`/`subscribe()` is called again. */\n disconnect(): void;\n\n /**\n * Subscribes to every message for one channel id. Sends the shared\n * `{action: \"subscribe\", [channelField]: id}` wire message automatically\n * on the first subscriber for that channel (and `\"unsubscribe\"` on the\n * last one leaving), and implicitly calls `connect()`. Returns an\n * unsubscribe function. Multiple concurrent channel ids are fully\n * supported — each gets its own wire subscribe/unsubscribe message and\n * its own dispatch, independent of every other channel's subscribers.\n */\n subscribe(\n channelId: string,\n callback: (message: TMessage) => void,\n ): () => void;\n\n /**\n * Subscribes to every message this socket ever receives, regardless of\n * channel — no wire message is sent for this (there's nothing to\n * subscribe/unsubscribe to, it's just an additional tap on the same\n * stream). Runs *alongside* any active `subscribe()` channel\n * subscriptions, socket.io-style (\"join specific rooms AND listen\n * globally at once\") — a message matching an active channel id is\n * delivered to both that channel's subscribers and every `onMessage`\n * listener. Implicitly calls `connect()`. Returns an unsubscribe\n * function.\n */\n onMessage(callback: (message: TMessage) => void): () => void;\n\n /**\n * Current connection status, read synchronously — no subscription needed\n * for a one-off check.\n */\n getStatus(): WsConnectionStatus;\n\n /**\n * Subscribes to connection status transitions. Fires once immediately\n * with the current status on subscribe, then again on every change.\n * Returns an unsubscribe function. Intended for a consumer that wants a\n * poll-based fallback only while genuinely disconnected (see\n * `WsConnectionStatus`'s own doc comment) — driving that off `onMessage`\n * pings alone can't distinguish \"connected but quiet\" from \"never\n * connected\".\n */\n onStatusChange(callback: (status: WsConnectionStatus) => void): () => void;\n}\n\nexport interface BroadcastWsServiceClient<\n TMessage extends WsMessage = WsMessage,\n> {\n /** Opens the connection if not already open/connecting. Safe to call repeatedly. */\n connect(): Promise<void>;\n\n /** Closes the connection and cancels any pending reconnect. */\n disconnect(): void;\n\n /**\n * Subscribes to every message this socket ever receives — there's no\n * room/channel concept in broadcast mode, so no subscribe/unsubscribe\n * wire message is ever sent; the backend just pushes to every connected\n * client. Implicitly calls `connect()`. Returns an unsubscribe function.\n */\n onMessage(callback: (message: TMessage) => void): () => void;\n\n /** Current connection status, read synchronously. See `WsConnectionStatus`. */\n getStatus(): WsConnectionStatus;\n\n /** Subscribes to connection status transitions. See `WsServiceClient.onStatusChange`. */\n onStatusChange(callback: (status: WsConnectionStatus) => void): () => void;\n}\n\n/**\n * Creates a reconnecting, (usually) authenticated WebSocket client — the WS\n * counterpart to `createApiService`. Centralizes exactly what every\n * `up-miniapps-*` app was independently hand-rolling with small drifting\n * bugs (one app's WS URL was captured once at construction and never\n * recomputed for the whole session; another always used a dev-only token\n * even in production, so it could never actually authenticate on a real\n * device): live URL resolution, ticket-based production auth with a\n * standalone-dev-token fallback, and exponential-backoff reconnect.\n *\n * Two modes, selected by whether `channelField` is present:\n * - **Channel mode** (`channelField` set): room-scoped pub/sub, matches\n * up-miniapps-split/up-miniapps-cursor's group/game-room shape. Returns a\n * `WsServiceClient` with `subscribe(channelId, cb)` — multiple concurrent\n * channel ids are fully supported — PLUS `onMessage(cb)`, a catch-all that\n * runs alongside any active channel subscriptions (socket.io-style: join\n * specific rooms and listen globally at the same time, on one socket).\n * - **Broadcast mode** (`channelField` omitted): one global socket, no\n * rooms, no subscribe/unsubscribe wire protocol — every message goes to\n * every listener. Matches up-miniapps-by-night's public live-update feed\n * (reactions/flash/favorite counts), which has no per-room access to gate\n * in the first place. Returns a `BroadcastWsServiceClient` with only\n * `onMessage(cb)` (no `subscribe` — there's no channel id to subscribe to).\n *\n * Deliberately stays a thin transport in both modes, same boundary as\n * `createApiService`: message *content* interpretation (e.g. treating one\n * event name as carrying real payload while every other message is a bare\n * cache-invalidation ping) belongs in each app's own thin wrapper around\n * this, not here — apps differ enough in what they consider safe to expose\n * over WS that baking that policy into the SDK would be the wrong\n * boundary.\n */\nexport function createWsService<TMessage extends WsMessage = WsMessage>(\n options: CreateChannelWsServiceOptions<TMessage>,\n): WsServiceClient<TMessage>;\nexport function createWsService<TMessage extends WsMessage = WsMessage>(\n options: CreateBroadcastWsServiceOptions<TMessage>,\n): BroadcastWsServiceClient<TMessage>;\nexport function createWsService<TMessage extends WsMessage = WsMessage>(\n options: CreateWsServiceOptions<TMessage>,\n): WsServiceClient<TMessage> | BroadcastWsServiceClient<TMessage> {\n const channelField = options.channelField;\n\n let ws: WebSocket | null = null;\n // Only populated/read in channel mode (via subscribe()).\n const subscriptions = new Map<string, Set<(message: TMessage) => void>>();\n // Populated/read via onMessage() in BOTH modes — the sole listener set in\n // broadcast mode, and an always-on catch-all running alongside\n // `subscriptions` in channel mode (see onMessage's own doc comment on\n // WsServiceClient).\n const globalListeners = new Set<(message: TMessage) => void>();\n let reconnectTimeout: ReturnType<typeof setTimeout> | null = null;\n let reconnectDelay = 1000;\n let isConnecting = false;\n let status: WsConnectionStatus = \"closed\";\n const statusListeners = new Set<(status: WsConnectionStatus) => void>();\n\n const setStatus = (next: WsConnectionStatus) => {\n if (status === next) return;\n status = next;\n for (const cb of statusListeners) cb(status);\n };\n\n const getWsUrl = (): string => options.baseUrl || options.api.wsUrl || \"\";\n\n const sendAction = (\n action: \"subscribe\" | \"unsubscribe\",\n channelId: string,\n ) => {\n if (ws?.readyState === WebSocket.OPEN) {\n // channelField is always defined here — sendAction is only ever\n // called from channel-mode code paths.\n ws.send(JSON.stringify({ action, [channelField as string]: channelId }));\n }\n };\n\n const scheduleReconnect = () => {\n if (reconnectTimeout) clearTimeout(reconnectTimeout);\n reconnectTimeout = setTimeout(() => {\n reconnectDelay = Math.min(reconnectDelay * 2, 30000);\n connect();\n }, reconnectDelay);\n };\n\n const connect = async (): Promise<void> => {\n if (\n ws?.readyState === WebSocket.OPEN ||\n ws?.readyState === WebSocket.CONNECTING ||\n isConnecting\n ) {\n return;\n }\n isConnecting = true;\n setStatus(\"connecting\");\n\n try {\n const wsUrl = getWsUrl();\n if (!wsUrl) {\n console.warn(\n \"[WS] No WebSocket backend URL available, connection delayed.\",\n );\n isConnecting = false;\n setStatus(\"closed\");\n return;\n }\n\n let authParams: Record<string, string> = {};\n if (isRunningInsideNativeShell() && options.ticketPath !== null) {\n const ticketResponse = await options.api.post<{ ticket: string }>(\n options.ticketPath ?? \"/ws-ticket\",\n );\n authParams = { ticket: ticketResponse.data.ticket };\n } else if (options.devToken) {\n const rawJwt = options.devToken.startsWith(\"Bearer \")\n ? options.devToken.slice(7)\n : options.devToken;\n authParams = { token: rawJwt };\n } else if (options.requireAuth === false) {\n // Explicitly opted out of auth (see requireAuth's own doc comment)\n // — connect with no ticket/token query param at all.\n } else {\n console.warn(\"[WS] No auth available, connection delayed.\");\n isConnecting = false;\n setStatus(\"closed\");\n return;\n }\n\n const params = new URLSearchParams({ ...options.query, ...authParams });\n const query = params.toString();\n ws = new WebSocket(query ? `${wsUrl}?${query}` : wsUrl);\n\n ws.onopen = () => {\n isConnecting = false;\n setStatus(\"open\");\n reconnectDelay = 1000;\n if (channelField) {\n for (const channelId of subscriptions.keys()) {\n sendAction(\"subscribe\", channelId);\n }\n }\n };\n\n ws.onmessage = (event) => {\n try {\n const payload = JSON.parse(event.data) as TMessage;\n if (channelField) {\n const channelId = payload[channelField];\n if (typeof channelId === \"string\") {\n const callbacks = subscriptions.get(channelId);\n if (callbacks) {\n for (const cb of callbacks) cb(payload);\n }\n }\n }\n // Every onMessage listener always runs, in both modes — the sole\n // dispatch path in broadcast mode, an additional catch-all on top\n // of the channel dispatch above in channel mode.\n for (const cb of globalListeners) cb(payload);\n } catch (err) {\n console.error(\"[WS] Failed to parse message:\", err);\n }\n };\n\n ws.onclose = () => {\n isConnecting = false;\n setStatus(\"closed\");\n scheduleReconnect();\n };\n\n ws.onerror = (err) => {\n console.error(\"[WS] error:\", err);\n isConnecting = false;\n ws?.close();\n };\n } catch (err) {\n console.error(\"[WS] Failed to establish connection:\", err);\n isConnecting = false;\n setStatus(\"closed\");\n scheduleReconnect();\n }\n };\n\n const disconnect = () => {\n if (reconnectTimeout) {\n clearTimeout(reconnectTimeout);\n reconnectTimeout = null;\n }\n if (ws) {\n ws.onclose = null;\n ws.close();\n ws = null;\n }\n setStatus(\"closed\");\n };\n\n const getStatus = (): WsConnectionStatus => status;\n\n const onStatusChange = (\n callback: (status: WsConnectionStatus) => void,\n ): (() => void) => {\n statusListeners.add(callback);\n callback(status);\n return () => {\n statusListeners.delete(callback);\n };\n };\n\n const subscribe = (\n channelId: string,\n callback: (message: TMessage) => void,\n ): (() => void) => {\n const isNewChannel = !subscriptions.has(channelId);\n if (isNewChannel) subscriptions.set(channelId, new Set());\n subscriptions.get(channelId)?.add(callback);\n if (isNewChannel) sendAction(\"subscribe\", channelId);\n connect();\n\n return () => {\n const set = subscriptions.get(channelId);\n if (!set) return;\n set.delete(callback);\n if (set.size === 0) {\n subscriptions.delete(channelId);\n sendAction(\"unsubscribe\", channelId);\n }\n };\n };\n\n const onMessage = (callback: (message: TMessage) => void): (() => void) => {\n globalListeners.add(callback);\n connect();\n return () => {\n globalListeners.delete(callback);\n };\n };\n\n if (channelField) {\n return {\n connect,\n disconnect,\n getStatus,\n onMessage,\n onStatusChange,\n subscribe,\n };\n }\n return { connect, disconnect, getStatus, onMessage, onStatusChange };\n}\n"],"mappings":"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","names":["Map","import_class_variance_authority","React","import_jsx_runtime","Content","import_react","import_jsx_runtime","containerH","fullPx","peekPx","targetState","autoMaxPx","autoPx","React","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","resolveHeightToPixels","import_react","import_jsx_runtime","UIEvent","GeolocationEvent","GlobalEvent","import_react","import_react","import_react","import_react","import_jsx_runtime","import_react_maplibre","import_react","import_jsx_runtime","import_react_maplibre","import_react","import_jsx_runtime","import_react_maplibre","import_jsx_runtime","import_react_maplibre","import_jsx_runtime","import_react_maplibre","import_react","import_jsx_runtime","mapLibreChildren","React","menuContentFromChildren","MapLibre","Map","import_react","React","Map","QRCodeStyling","loadImage","jsQR","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_jsqr","import_react","import_jsx_runtime","jsQR","import_react","import_jsx_runtime","import_react","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/components/Map/MockLocationContext.tsx","../src/lib/utils.ts","../src/components/ui/button.tsx","../src/utils/environment.ts","../src/bridge.ts","../src/components/ui/sheet.tsx","../src/components/Map/components/MapDrawer.tsx","../src/components/ui/card.tsx","../src/components/Map/components/MapEtaPanel.tsx","../src/components/Map/components/MapRightControls.tsx","../src/components/Map/components/MobileBottomDrawer.tsx","../src/components/Map/MapContext.tsx","../src/components/Map/components/MapControls.tsx","../src/components/Map/components/MapMenu.tsx","../src/types/types.ts","../src/components/Map/hooks/useUserLocation.ts","../src/components/Map/hooks/useLiveRouting.ts","../src/components/Map/hooks/useJourney.ts","../src/components/Map/hooks/useTrimmedRoute.ts","../src/components/Map/layers/RouteLayer.tsx","../src/components/Map/utils/geoCircle.ts","../src/components/Map/layers/MockRadiusLayer.tsx","../src/components/Map/layers/POILayers.tsx","../src/components/Map/layers/POIMarkers.tsx","../src/components/Map/layers/UserLocationLayer.tsx","../src/components/Map/Map.tsx","../src/components/MapWrapper.tsx","../src/services/qrCodeService.ts","../src/services/qrDecodeService.ts","../src/services/routingService.ts","../package.json","../src/sdk.ts","../src/components/BridgeMocker.tsx","../src/components/DebugConsole.tsx","../src/components/PullToRefresh.tsx","../src/components/QRScanner.tsx","../src/components/SDKProvider.tsx","../src/components/SwipeCarousel.tsx","../src/hooks/useTapAction.ts","../src/host/routingHandler.ts","../src/services/apiService.ts","../src/services/wsService.ts"],"sourcesContent":["export * from \"@miniapps-sdk/components\";\nexport * from \"@miniapps-sdk/hooks/useTapAction\";\nexport * from \"@miniapps-sdk/host\";\nexport { MiniAppSDK, sdk } from \"@miniapps-sdk/sdk\";\nexport * from \"@miniapps-sdk/services/apiService\";\nexport * from \"@miniapps-sdk/services/wsService\";\nexport * from \"@miniapps-sdk/types\";\n\nimport { sdk } from \"@miniapps-sdk/sdk\";\n\nexport default sdk;\n","import { createContext, useContext } from \"react\";\n\nexport interface MockLocationContextType {\n /** Radius in meters to draw around the mocked user location. 0 hides it. */\n radiusMeters: number;\n /** When true, the next map click drops the mocked location there instead\n * of firing the app's own onClick/onMapClickMiss handlers. */\n isPlacingLocation: boolean;\n /** Called by the Map when a click lands while isPlacingLocation is true. */\n placeLocation: (coords: [number, number]) => void;\n}\n\n/**\n * Bridges BridgeMocker (owns the mocked location/radius state, rendered as\n * a sibling dev panel outside the map's DOM tree) and the Map component\n * (needs to read that state to draw the radius overlay and intercept\n * \"drop location here\" clicks) without prop-drilling through every\n * consumer app's own Map usage.\n */\nexport const MockLocationContext =\n createContext<MockLocationContextType | null>(null);\n\nexport const useMockLocation = (): MockLocationContextType | null =>\n useContext(MockLocationContext);\n","import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import { cn } from \"@miniapps-sdk/lib/utils\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport * as React from \"react\";\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n defaultVariants: {\n size: \"default\",\n variant: \"default\",\n },\n variants: {\n size: {\n default: \"h-10 px-4 py-2\",\n icon: \"h-10 w-10\",\n lg: \"h-11 rounded-md px-8\",\n sm: \"h-9 rounded-md px-3\",\n },\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n outline:\n \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n },\n },\n },\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n className={cn(buttonVariants({ className, size, variant }))}\n ref={ref}\n {...props}\n />\n );\n },\n);\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants };\n","/**\n * Detects whether this WebView is actually running inside the native UP\n * shell, vs. a plain standalone browser (dev server, `vite preview`, a\n * bare tab someone opened the built HTML in directly). Deliberately a\n * runtime check against injected globals, not a build-mode flag like\n * Vite's `import.meta.env.PROD` — a production-mode standalone preview is\n * still not inside the shell, and `import.meta.env` isn't even reliably\n * available inside this package to begin with (this SDK is bundled by\n * tsup, not Vite, so Vite's compile-time env replacement never runs here).\n */\nexport function isRunningInsideNativeShell(): boolean {\n if (typeof window === \"undefined\") return false;\n const w = window as unknown as {\n __UP_REACT_NATIVE_APP__?: boolean;\n ReactNativeWebView?: unknown;\n };\n return w.__UP_REACT_NATIVE_APP__ === true || !!w.ReactNativeWebView;\n}\n","import type { IAchievement, IBridgeEnvelope } from \"@miniapps-sdk/types\";\nimport { isRunningInsideNativeShell } from \"@miniapps-sdk/utils/environment\";\n\n/** Distinguishes a lost-in-transit timeout from a definitive host rejection — see `Bridge.send`'s retry logic. */\nexport class BridgeTimeoutError extends Error {}\n\n/**\n * Plausible fake Achievements for standalone/Storybook dev (no native\n * shell) — mirrors what `up/backend`'s Achievement store would return for a\n * few sample slugs. Kept here rather than per-story so `sdk.achievement`/\n * `sdk.achievements` behave sensibly for ANY consumer running standalone,\n * not just this SDK's own Storybook (see `handleMockMessage`'s own doc\n * comment on why every bridge method should have a real mock instead of a\n * silent no-op).\n */\n// Deliberately no `imageUrl` on any of these — every consuming app's own\n// achievement UI falls back to its own real logo asset when `imageUrl` is\n// unset (that's the actual, already-implemented product behavior, not a\n// mock-only shortcut), so mocking a generic/fake image here would show a\n// misleading placeholder that doesn't exist in any real app's own branding.\n// Leaving it unset is what makes the mock path render exactly like the real\n// one for this field.\nconst MOCK_ACHIEVEMENTS: IAchievement[] = [\n {\n completed: true,\n description: \"Complete your first navigation journey.\",\n playerActionCount: 1,\n priority: 1,\n slug: \"first-journey\",\n title: \"First Steps\",\n totalActionCount: 1,\n upReward: 20,\n xpReward: 40,\n },\n {\n completed: false,\n description: \"Discover 5 points of interest around Annecy.\",\n playerActionCount: 3,\n priority: 2,\n slug: \"explore-5-pois\",\n title: \"Explorer\",\n totalActionCount: 5,\n upReward: 50,\n xpReward: 100,\n },\n {\n completed: false,\n description: \"Scan 10 QR codes at partner venues.\",\n playerActionCount: 4,\n priority: 3,\n slug: \"scan-10-qrcodes\",\n title: \"Code Breaker\",\n totalActionCount: 10,\n upReward: 80,\n xpReward: 150,\n },\n];\n\n/** Mock for `GET_ACHIEVEMENT` — returns the matching sample slug, or a\n * freshly-minted zero-progress Achievement for any unknown slug so a\n * consumer testing standalone with its own real slugs still gets a\n * well-shaped response instead of `undefined`. */\nfunction mockAchievement(slug: string | undefined): IAchievement {\n const found = MOCK_ACHIEVEMENTS.find((a) => a.slug === slug);\n if (found) return found;\n return {\n completed: false,\n description: \"Mocked achievement (no native shell attached).\",\n playerActionCount: 0,\n priority: 1,\n slug: slug || \"unknown-achievement\",\n title: slug || \"Unknown Achievement\",\n totalActionCount: 1,\n upReward: 0,\n xpReward: 0,\n };\n}\n\n/** Mock for `GET_ACHIEVEMENTS`. */\nfunction mockAchievements(): IAchievement[] {\n return MOCK_ACHIEVEMENTS;\n}\n\n/**\n * The Bridge handles low-level communication between the Mini-App WebView\n * and the Native Host Shell (iOS/Android).\n *\n * It manages asynchronous request-response cycles via callbacks and\n * supports subscription to pushed events from the native environment.\n */\nexport class Bridge {\n private callbacks = new Map<\n string,\n {\n resolve: (val: unknown) => void;\n reject: (err: unknown) => void;\n timeout: ReturnType<typeof setTimeout>;\n }\n >();\n private eventListeners = new Map<string, ((data: any) => void)[]>();\n\n /**\n * Registers a global listener for messages coming from the native shell.\n * Also listens for standard browser `message` events to support multiple\n * communication channels (e.g., React Native WebView postMessage).\n */\n constructor() {\n if (typeof window !== \"undefined\") {\n const bridgeReceiver = Object.freeze({\n onNativeMessage: (envelope: IBridgeEnvelope) =>\n this.handleNativeMessage(envelope),\n });\n\n // Use defineProperty to bind the receiver, allowing reconfiguration for HMR environments\n if (typeof (window as any).__MiniAppBridge === \"undefined\") {\n Object.defineProperty(window, \"__MiniAppBridge\", {\n configurable: true, // MUST be true for React StrictMode / HMR unmount/remount cycles\n value: bridgeReceiver,\n writable: false,\n });\n }\n\n window.addEventListener(\"message\", (event) => {\n // SECURITY: Filter events. If inside a mobile shell, the origin of native postMessage\n // varies by platform (e.g., file://, or specific app schemes).\n // For production, this should be restricted to the expected host origin.\n if (!event.data) return;\n\n try {\n const data =\n typeof event.data === \"string\"\n ? JSON.parse(event.data)\n : event.data;\n\n // SECURITY: Basic envelope validation\n if (\n data &&\n typeof data === \"object\" &&\n (data.callbackId || data.event || data.eventName)\n ) {\n this.handleNativeMessage(data);\n }\n } catch (_e) {\n // Ignore non-JSON or malformed messages\n }\n });\n }\n }\n\n /**\n * Subscribes to a pushed event from the native shell.\n *\n * @param event The event name to listen for.\n * @param callback Function to execute when the event occurs.\n * @returns An unsubscription function.\n */\n public on<T = unknown>(event: string, callback: (data: T) => void) {\n let listeners = this.eventListeners.get(event);\n if (!listeners) {\n listeners = [];\n this.eventListeners.set(event, listeners);\n }\n listeners.push(callback);\n return () => this.off(event, callback);\n }\n\n /**\n * Unsubscribes a specific callback from an event.\n *\n * @param event The event name.\n * @param callback The callback function to remove.\n */\n public off<T = unknown>(event: string, callback: (data: T) => void) {\n const listeners = this.eventListeners.get(event);\n if (!listeners) return;\n this.eventListeners.set(\n event,\n listeners.filter((cb) => cb !== callback),\n );\n }\n\n /**\n * Sends a message to the native shell and waits for a response.\n *\n * @template T The expected response type.\n * @param type The action type (e.g., \"GET_LOCATION\").\n * @param payload Data associated with the action.\n * @param timeoutMs Time in milliseconds to wait for a response before rejecting.\n * @param retries Number of additional attempts if a request times out (default 1 — one retry).\n * Exists because the response for a request can be lost in transit — e.g. the host's\n * injected response script running before this WebView's own `message` listener has\n * attached, worse under rapid mount/unmount cycles — with no application-visible symptom\n * other than the full 30s timeout. A blind retry self-heals that class of loss without\n * needing to diagnose which specific transport race dropped the original message; every\n * call site benefits automatically instead of each consumer app hand-rolling its own\n * retry-after-catch logic (which previously only covered `initialize()`, and imperfectly).\n * @returns A promise that resolves with the native response.\n */\n public send<T = unknown>(\n type: string,\n payload?: unknown,\n timeoutMs = 30000,\n retries = 1,\n ): Promise<T> {\n if (!this.isNative()) {\n return this.handleMockMessage(type, payload);\n }\n\n return this.sendOnce<T>(type, payload, timeoutMs).catch((err) => {\n // Only retry an actual lost-in-transit timeout — never a definitive\n // rejection the host already answered (e.g. a security-origin block,\n // or any other application-level `success: false`). Retrying those\n // is pointless (the same deterministic input produces the same\n // deterministic \"no\") and, with zero backoff between attempts, can\n // turn one legitimate rejection into a tight retry storm if a caller\n // up the stack also reacts to the failure by re-triggering the same\n // request.\n if (retries <= 0 || !(err instanceof BridgeTimeoutError)) throw err;\n return this.send<T>(type, payload, timeoutMs, retries - 1);\n });\n }\n\n /**\n * Internal handler for all incoming messages from the native shell.\n * Matches incoming payloads to either pending callbacks or event listeners.\n *\n * @internal\n * @param envelope The message envelope received from native code.\n */\n public handleNativeMessage(envelope: IBridgeEnvelope) {\n if (!envelope || typeof envelope !== \"object\") return;\n\n // 1. Handle Response Callbacks\n const callbackId = envelope.callbackId;\n if (callbackId && typeof callbackId === \"string\") {\n const callback = this.callbacks.get(callbackId);\n if (callback) {\n clearTimeout(callback.timeout);\n const { resolve, reject } = callback;\n\n if (envelope.success === false || envelope.error) {\n reject(envelope.error || \"Unknown error\");\n } else {\n resolve(envelope.value ?? envelope.payload ?? envelope);\n }\n\n this.callbacks.delete(callbackId);\n return;\n }\n }\n\n // 2. Handle Pushed Events\n const eventName = envelope.eventName || envelope.event;\n if (eventName) {\n // If using the new protocol with type=\"EVENT\", ensure we only process if type matches\n if (envelope.type === \"EVENT\" || !envelope.type || envelope.event) {\n const listeners = this.eventListeners.get(eventName);\n if (listeners) {\n for (const listener of listeners) {\n try {\n listener(envelope.payload || envelope.value);\n } catch (e) {\n console.error(`Error in event listener for ${eventName}:`, e);\n }\n }\n }\n }\n }\n }\n\n /**\n * Internal handler for mock message processing, overrideable in test environments.\n *\n * Every mini-app that calls a bridge method also has to run standalone in a plain\n * browser (dev, and this vault's own Chrome-based verification) with no native shell\n * attached — `isNative()` is false, so `send()` never round-trips through the real\n * host at all. Before this switch existed, EVERY unhandled type here resolved with\n * plain `undefined` (see the `default` branch below), which silently broke any caller\n * checking a result shape like `{success: boolean}` — `undefined?.success` reads as\n * `false`, not \"no answer\", so e.g. `sdk.media.saveImage()` looked like a real\n * permission-denied rejection in the browser instead of \"there's no native shell\n * here to ask.\" Add a `case` here — instead of leaving every mini-app to\n * individually special-case \"what happens when I call this with no shell attached\" —\n * whenever a bridge method's mock behavior should be more than a no-op.\n */\n protected handleMockMessage(type: string, payload: unknown): Promise<any> {\n switch (type) {\n case \"SAVE_IMAGE\":\n return this.mockSaveImage(\n payload as { base64: string; filename?: string },\n );\n case \"GET_ACHIEVEMENT\":\n return Promise.resolve(\n mockAchievement((payload as { slug: string })?.slug),\n );\n case \"GET_ACHIEVEMENTS\":\n return Promise.resolve(mockAchievements());\n default:\n console.warn(\n `[Bridge] Mock mode active: Unhandled message type ${type}`,\n );\n return Promise.resolve();\n }\n }\n\n /**\n * Standalone-browser stand-in for the native `SAVE_IMAGE` handler: triggers a real\n * browser download (an `<a download>` click) instead of writing to a device photo\n * library, which doesn't exist here. Resolves `{success: true}` on a real trigger so\n * every mini-app's own `result?.success` check gets the same shape/semantics as the\n * real native response — no per-app \"am I in mock mode\" branching needed. Consumers\n * can still keep their own `catch` fallback for the genuinely different case of a\n * native shell that's missing its WebView bridge (see `sendOnce`'s own rejection\n * path) — that's a real native edge case, not mocking, and this method never runs\n * for it (`send()` only reaches `handleMockMessage` when `!isNative()`).\n */\n private mockSaveImage(payload: {\n base64: string;\n filename?: string;\n }): Promise<{ success: boolean }> {\n if (typeof document === \"undefined\") {\n return Promise.resolve({ success: false });\n }\n\n try {\n const href = payload.base64.startsWith(\"data:\")\n ? payload.base64\n : `data:image/png;base64,${payload.base64}`;\n\n const link = document.createElement(\"a\");\n link.href = href;\n link.download = payload.filename\n ? `${payload.filename}.png`\n : \"image.png\";\n document.body.appendChild(link);\n link.click();\n link.remove();\n\n return Promise.resolve({ success: true });\n } catch (err) {\n console.warn(\"[Bridge] Mock SAVE_IMAGE download failed:\", err);\n return Promise.resolve({ success: false });\n }\n }\n\n private sendOnce<T = unknown>(\n type: string,\n payload: unknown,\n timeoutMs: number,\n ): Promise<T> {\n return new Promise((resolve, reject) => {\n const callbackId = `${type}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\n const timeout = setTimeout(() => {\n if (this.callbacks.has(callbackId)) {\n this.callbacks.delete(callbackId);\n reject(new BridgeTimeoutError(`Bridge request timeout: ${type}`));\n }\n }, timeoutMs);\n\n this.callbacks.set(callbackId, {\n reject,\n resolve: resolve as (val: unknown) => void,\n timeout,\n });\n\n const message = {\n callbackId,\n payload,\n type,\n };\n\n const win = window as unknown as {\n ReactNativeWebView?: { postMessage: (msg: string) => void };\n };\n\n if (win.ReactNativeWebView?.postMessage) {\n win.ReactNativeWebView.postMessage(JSON.stringify(message));\n } else {\n clearTimeout(timeout);\n this.callbacks.delete(callbackId);\n reject(new Error(\"Bridge not available\"));\n }\n });\n }\n\n /**\n * Determine environment. Check flag or cache result.\n */\n private isNative(): boolean {\n return isRunningInsideNativeShell();\n }\n}\n","import { cn } from \"@miniapps-sdk/lib/utils\";\nimport * as SheetPrimitive from \"@radix-ui/react-dialog\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { X } from \"lucide-react\";\nimport * as React from \"react\";\n\nconst Sheet = SheetPrimitive.Root;\n\nconst SheetTrigger = SheetPrimitive.Trigger;\n\nconst SheetClose = SheetPrimitive.Close;\n\nconst SheetPortal = SheetPrimitive.Portal;\n\nconst SheetOverlay = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Overlay\n className={cn(\n \"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className,\n )}\n {...props}\n ref={ref}\n />\n));\nSheetOverlay.displayName = SheetPrimitive.Overlay.displayName;\n\nconst sheetVariants = cva(\n \"z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500\",\n {\n defaultVariants: {\n side: \"right\",\n },\n variants: {\n side: {\n bottom:\n \"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom\",\n left: \"inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm\",\n right:\n \"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm\",\n top: \"inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top\",\n },\n },\n },\n);\n\ninterface SheetContentProps\n extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,\n VariantProps<typeof sheetVariants> {\n portal?: boolean;\n}\n\nconst SheetContent = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Content>,\n SheetContentProps\n>(({ side = \"right\", className, children, portal = true, ...props }, ref) => {\n const Content = (\n <SheetPrimitive.Content\n className={cn(\n sheetVariants({ side }),\n portal ? \"fixed\" : \"absolute\",\n className,\n )}\n ref={ref}\n {...props}\n >\n {children}\n <SheetPrimitive.Close className=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-105 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary\">\n <X className=\"h-4 w-4\" />\n <span className=\"sr-only\">Close</span>\n </SheetPrimitive.Close>\n </SheetPrimitive.Content>\n );\n\n if (!portal) {\n return Content;\n }\n\n return (\n <SheetPortal>\n <SheetOverlay />\n {Content}\n </SheetPortal>\n );\n});\nSheetContent.displayName = SheetPrimitive.Content.displayName;\n\nconst SheetHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-2 text-center sm:text-left\",\n className,\n )}\n {...props}\n />\n);\nSheetHeader.displayName = \"SheetHeader\";\n\nconst SheetFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n className,\n )}\n {...props}\n />\n);\nSheetFooter.displayName = \"SheetFooter\";\n\nconst SheetTitle = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Title\n className={cn(\"text-lg font-semibold text-foreground\", className)}\n ref={ref}\n {...props}\n />\n));\nSheetTitle.displayName = SheetPrimitive.Title.displayName;\n\nconst SheetDescription = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Description\n className={cn(\"text-sm text-muted-foreground\", className)}\n ref={ref}\n {...props}\n />\n));\nSheetDescription.displayName = SheetPrimitive.Description.displayName;\n\nexport {\n Sheet,\n SheetClose,\n SheetContent,\n SheetDescription,\n SheetFooter,\n SheetHeader,\n SheetOverlay,\n SheetPortal,\n SheetTitle,\n SheetTrigger,\n};\n","import type { MenuItem } from \"@miniapps-sdk/components/Map/types\";\nimport { Button } from \"@miniapps-sdk/components/ui/button\";\nimport {\n Sheet,\n SheetContent,\n SheetHeader,\n SheetTitle,\n} from \"@miniapps-sdk/components/ui/sheet\";\nimport type React from \"react\";\nimport { forwardRef, useImperativeHandle, useRef, useState } from \"react\";\n\n/**\n * Landscape/left-side menu drawer (Radix `Sheet`-based slide-in panel).\n *\n * The portrait bottom-sheet variant lives in `MobileBottomDrawer.tsx`\n * (built on `react-modal-sheet`) — this file now only covers `side=\"left\"`.\n */\nexport type DrawerState = \"closed\" | \"peek\" | \"full\" | \"auto\";\n\nexport interface MapDrawerProps {\n menuItems: MenuItem[];\n state: DrawerState;\n onChangeState: (state: DrawerState) => void;\n menuContent?: React.ReactNode;\n\n // Scroll to top button customization\n showScrollToTopButton?: boolean;\n scrollToTopThreshold?: number;\n}\n\nexport const MapDrawer = forwardRef<HTMLDivElement, MapDrawerProps>(\n (\n {\n menuItems,\n state,\n onChangeState,\n menuContent,\n showScrollToTopButton = true,\n scrollToTopThreshold = 300,\n },\n ref,\n ) => {\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n\n useImperativeHandle(\n ref,\n () => scrollContainerRef.current as HTMLDivElement,\n );\n\n const [showScrollTop, setShowScrollTop] = useState(false);\n\n const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {\n const scrollTop = e.currentTarget.scrollTop;\n setShowScrollTop(state !== \"closed\" && scrollTop > scrollToTopThreshold);\n };\n\n // Backdrop visible (and tap-outside-to-close active) whenever the panel\n // is open — unlike the bottom sheet's peek/full/auto split, the left\n // drawer only has an open/closed distinction.\n const isBackdropActive = state !== \"closed\";\n const backdropStyles = isBackdropActive\n ? \"opacity-100 pointer-events-auto\"\n : \"opacity-0 pointer-events-none\";\n\n return (\n <>\n <style>{`\n .no-scrollbar {\n -ms-overflow-style: none;\n scrollbar-width: none;\n }\n .no-scrollbar::-webkit-scrollbar {\n display: none;\n }\n `}</style>\n\n {/* Backdrop overlay for closing on outside tap */}\n <div\n className={`absolute inset-0 bg-black/45 backdrop-blur-[1px] transition-opacity duration-300 z-30 ${backdropStyles}`}\n onClick={() => onChangeState(\"closed\")}\n />\n\n {state === \"closed\" && (\n <Button\n 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!\"\n onClick={() => onChangeState(\"full\")}\n variant=\"ghost\"\n >\n <svg\n fill=\"none\"\n height=\"24\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2\"\n viewBox=\"0 0 24 24\"\n width=\"24\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <line x1=\"4\" x2=\"20\" y1=\"12\" y2=\"12\" />\n <line x1=\"4\" x2=\"20\" y1=\"6\" y2=\"6\" />\n <line x1=\"4\" x2=\"20\" y1=\"18\" y2=\"18\" />\n </svg>\n </Button>\n )}\n <Sheet\n onOpenChange={(open) => onChangeState(open ? \"full\" : \"closed\")}\n open={state !== \"closed\"}\n >\n <SheetContent\n 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\"\n portal={false}\n side=\"left\"\n >\n <SheetHeader className=\"pb-3 border-b border-white/10 mb-2 text-left\">\n <SheetTitle className=\"text-sm font-bold tracking-wider text-zinc-400 uppercase\">\n Menu\n </SheetTitle>\n </SheetHeader>\n\n <div\n className=\"flex-1 overflow-y-auto no-scrollbar pr-2\"\n onScroll={handleScroll}\n ref={scrollContainerRef}\n >\n {menuContent ? (\n menuContent\n ) : (\n <div className=\"flex flex-col gap-1.5\">\n {menuItems.map((item) => (\n <Button\n 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 ${\n item.disabled\n ? \"opacity-45 cursor-not-allowed pointer-events-none\"\n : \"\"\n }`}\n disabled={item.disabled}\n key={item.id}\n onClick={() => {\n if (!item.disabled) {\n item.onPress();\n onChangeState(\"closed\");\n }\n }}\n variant=\"ghost\"\n >\n <div className=\"relative flex items-center justify-center w-8 h-8 rounded-lg bg-white/5 text-zinc-300\">\n {item.icon}\n {item.badge !== undefined && (\n <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\">\n {item.badge}\n </span>\n )}\n </div>\n <span className=\"text-sm font-medium tracking-wide flex-1\">\n {item.label}\n </span>\n </Button>\n ))}\n </div>\n )}\n </div>\n\n {showScrollToTopButton && showScrollTop && (\n <Button\n 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!\"\n onClick={() => {\n scrollContainerRef.current?.scrollTo({\n behavior: \"smooth\",\n top: 0,\n });\n }}\n variant=\"ghost\"\n >\n <svg\n fill=\"none\"\n height=\"20\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2.5\"\n viewBox=\"0 0 24 24\"\n width=\"20\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <polyline points=\"18 15 12 9 6 15\"></polyline>\n </svg>\n </Button>\n )}\n </SheetContent>\n </Sheet>\n </>\n );\n },\n);\n\nMapDrawer.displayName = \"MapDrawer\";\n","import { cn } from \"@miniapps-sdk/lib/utils\";\nimport * as React from \"react\";\n\nconst Card = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n className={cn(\n \"rounded-lg border bg-card text-card-foreground shadow-sm\",\n className,\n )}\n ref={ref}\n {...props}\n />\n));\nCard.displayName = \"Card\";\n\nconst CardHeader = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n className={cn(\"flex flex-col space-y-1.5 p-6\", className)}\n ref={ref}\n {...props}\n />\n));\nCardHeader.displayName = \"CardHeader\";\n\nconst CardTitle = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n className={cn(\n \"text-2xl font-semibold leading-none tracking-tight\",\n className,\n )}\n ref={ref}\n {...props}\n />\n));\nCardTitle.displayName = \"CardTitle\";\n\nconst CardDescription = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n className={cn(\"text-sm text-muted-foreground\", className)}\n ref={ref}\n {...props}\n />\n));\nCardDescription.displayName = \"CardDescription\";\n\nconst CardContent = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div className={cn(\"p-6 pt-0\", className)} ref={ref} {...props} />\n));\nCardContent.displayName = \"CardContent\";\n\nconst CardFooter = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n className={cn(\"flex items-center p-6 pt-0\", className)}\n ref={ref}\n {...props}\n />\n));\nCardFooter.displayName = \"CardFooter\";\n\nexport {\n Card,\n CardContent,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n};\n","import type { EtaData } from \"@miniapps-sdk/components/Map/types\";\nimport { Button } from \"@miniapps-sdk/components/ui/button\";\nimport { Card, CardContent } from \"@miniapps-sdk/components/ui/card\";\nimport type React from \"react\";\n\nexport interface MapEtaPanelProps {\n etaData: EtaData;\n layoutMode: \"closed-banner\" | \"open-card\" | \"floating-card\";\n onHeaderClick?: () => void;\n style?: React.CSSProperties;\n isDragging?: boolean;\n}\n\nexport const MapEtaPanel: React.FC<MapEtaPanelProps> = ({\n etaData,\n layoutMode,\n onHeaderClick,\n style,\n isDragging = false,\n}) => {\n if (layoutMode === \"closed-banner\") {\n return (\n <div className=\"w-full h-10 flex items-center justify-between px-4 pb-2 pt-1 border-b border-white/5 bg-zinc-950/15 relative overflow-hidden\">\n <div\n className=\"flex items-center gap-2 cursor-pointer flex-1\"\n onClick={onHeaderClick}\n >\n <span className=\"w-2 h-2 rounded-full bg-emerald-500 animate-pulse\" />\n <span className=\"text-xs font-bold text-emerald-400\">\n {etaData.etaMins} min ({etaData.distanceRemainingKm.toFixed(1)} km)\n </span>\n </div>\n {etaData.onAbort && (\n <Button\n className=\"px-1 py-1 text-[10px] font-black bg-red-500/20 text-red-400 hover:bg-red-500/30 border border-red-500/25 active:scale-95 rounded-md transition-all cursor-pointer pointer-events-auto h-auto p-0!\"\n onClick={(e) => {\n e.stopPropagation();\n etaData.onAbort?.();\n }}\n variant=\"ghost\"\n >\n <svg\n className=\"lucide lucide-x\"\n fill=\"none\"\n height=\"18\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2.5\"\n viewBox=\"0 0 24 24\"\n width=\"18\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M18 6 6 18\"></path>\n <path d=\"m6 6 12 12\"></path>\n </svg>\n </Button>\n )}\n {etaData.progress !== undefined && (\n <div className=\"absolute bottom-0 left-0 right-0 h-[2px] bg-white/5\">\n <div\n className=\"h-full bg-cyan-400\"\n style={{ width: `${etaData.progress}%` }}\n />\n </div>\n )}\n </div>\n );\n }\n\n if (layoutMode === \"open-card\") {\n return (\n <Card className=\"mx-4 mt-2 p-4 bg-white/5 border border-white/10 rounded-xl flex flex-col text-card-foreground\">\n <div className=\"flex items-center justify-between mb-2\">\n <div className=\"flex items-center gap-2\">\n <span className=\"w-2 h-2 rounded-full bg-emerald-500 animate-pulse\" />\n <span className=\"text-[10px] font-bold text-emerald-400 uppercase tracking-wider\">\n {etaData.label || \"Journey Active\"}\n </span>\n </div>\n {etaData.onAbort && (\n <Button\n className=\"px-1 py-1 text-xs font-bold bg-red-500/20 text-red-400 hover:bg-red-500/30 border border-red-500/30 active:scale-95 rounded-lg transition-all cursor-pointer pointer-events-auto h-auto p-0!\"\n onClick={etaData.onAbort}\n variant=\"ghost\"\n >\n <svg\n className=\"lucide lucide-x\"\n fill=\"none\"\n height=\"18\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2.5\"\n viewBox=\"0 0 24 24\"\n width=\"18\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M18 6 6 18\"></path>\n <path d=\"m6 6 12 12\"></path>\n </svg>\n </Button>\n )}\n </div>\n\n <CardContent className=\"p-0 flex flex-col\">\n <div className=\"grid grid-cols-2 divide-x divide-white/10 py-1.5 mb-2.5\">\n <div className=\"text-center\">\n <div className=\"text-xl font-black text-white leading-none\">\n {etaData.etaMins}\n <span className=\"text-xs text-zinc-400 font-normal\"> min</span>\n </div>\n <div className=\"text-[8px] text-zinc-500 font-bold uppercase tracking-wider mt-1\">\n Time Remaining\n </div>\n </div>\n <div className=\"text-center\">\n <div className=\"text-xl font-black text-white leading-none\">\n {etaData.distanceRemainingKm.toFixed(1)}\n <span className=\"text-xs text-zinc-400 font-normal\"> km</span>\n </div>\n <div className=\"text-[8px] text-zinc-500 font-bold uppercase tracking-wider mt-1\">\n Distance Remaining\n </div>\n </div>\n </div>\n\n {etaData.progress !== undefined && (\n <div className=\"mb-3\">\n <div className=\"flex justify-between text-[9px] font-bold text-zinc-400 mb-1\">\n <span>Progress</span>\n <span>{Math.round(etaData.progress)}%</span>\n </div>\n <div className=\"h-1 bg-white/10 rounded-full overflow-hidden\">\n <div\n className=\"h-full bg-cyan-400 rounded-full\"\n style={{ width: `${etaData.progress}%` }}\n />\n </div>\n </div>\n )}\n\n {etaData.mode === \"preview\" && etaData.onStart && (\n <Button\n className=\"w-full py-2.5 text-xs font-bold bg-cyan-500 text-black hover:bg-cyan-400 hover:text-black active:scale-95 rounded-lg transition-all cursor-pointer h-auto\"\n onClick={etaData.onStart}\n variant=\"ghost\"\n >\n Start Guidance\n </Button>\n )}\n </CardContent>\n </Card>\n );\n }\n\n // floating-card (centered at bottom of map)\n return (\n <Card\n className={`absolute left-1/2 -translate-x-1/2 z-40 w-[calc(100%-2rem)] max-w-[320px] sm:max-w-[380px] bg-zinc-950/85 backdrop-blur-md border border-white/10 rounded-2xl shadow-2xl p-3 sm:p-4 flex flex-col pointer-events-auto select-none text-card-foreground ${\n isDragging ? \"transition-none\" : \"transition-all duration-300 ease-out\"\n }`}\n style={style}\n >\n <div className=\"flex items-center justify-between mb-2 sm:mb-3\">\n <div className=\"flex items-center gap-2\">\n <span className=\"w-1.5 h-1.5 sm:w-2 sm:h-2 rounded-full bg-emerald-500 animate-pulse\" />\n <span className=\"text-[9px] sm:text-[10px] font-bold text-emerald-400 uppercase tracking-wider\">\n {etaData.label || \"Guidance Active\"}\n </span>\n </div>\n {etaData.onAbort && (\n <Button\n className=\"px-1 py-1 text-[10px] sm:text-xs font-bold bg-red-500/20 text-red-400 hover:bg-red-500/30 border border-red-500/30 active:scale-95 rounded-lg transition-all cursor-pointer h-auto p-0!\"\n onClick={etaData.onAbort}\n variant=\"ghost\"\n >\n <svg\n className=\"lucide lucide-x\"\n fill=\"none\"\n height=\"18\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2.5\"\n viewBox=\"0 0 24 24\"\n width=\"18\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M18 6 6 18\"></path>\n <path d=\"m6 6 12 12\"></path>\n </svg>\n </Button>\n )}\n </div>\n\n <CardContent className=\"p-0 flex flex-col\">\n <div className=\"grid grid-cols-2 divide-x divide-white/10 py-0.5 sm:py-1 mb-2 sm:mb-3\">\n <div className=\"text-center\">\n <div className=\"text-base sm:text-lg font-black text-white leading-none\">\n {etaData.etaMins}\n <span className=\"text-[10px] sm:text-xs text-zinc-400 font-normal\">\n {\" \"}\n min\n </span>\n </div>\n </div>\n <div className=\"text-center\">\n <div className=\"text-base sm:text-lg font-black text-white leading-none\">\n {etaData.distanceRemainingKm.toFixed(1)}\n <span className=\"text-[10px] sm:text-xs text-zinc-400 font-normal\">\n {\" \"}\n km\n </span>\n </div>\n </div>\n </div>\n\n {etaData.progress !== undefined && (\n <div>\n <div className=\"flex justify-between text-[8px] sm:text-[9px] font-bold text-zinc-400 mb-1\">\n <span>Progress</span>\n <span>{Math.round(etaData.progress)}%</span>\n </div>\n <div className=\"h-1 sm:h-1.5 bg-white/10 rounded-full overflow-hidden\">\n <div\n className=\"h-full bg-cyan-400 rounded-full\"\n style={{ width: `${etaData.progress}%` }}\n />\n </div>\n </div>\n )}\n\n {etaData.mode === \"preview\" && etaData.onStart && (\n <Button\n className=\"mt-2.5 sm:mt-3 py-1.5 sm:py-2 text-[11px] sm:text-xs font-bold bg-cyan-500 text-black hover:bg-cyan-400 hover:text-black active:scale-95 rounded-lg transition-all cursor-pointer h-auto\"\n onClick={etaData.onStart}\n variant=\"ghost\"\n >\n Start Guidance\n </Button>\n )}\n </CardContent>\n </Card>\n );\n};\n","import type { CenterCallbackParams } from \"@miniapps-sdk/components\";\nimport type {\n CustomControl,\n EtaData,\n} from \"@miniapps-sdk/components/Map/types\";\nimport { Button } from \"@miniapps-sdk/components/ui/button\";\nimport type { ViewState } from \"@vis.gl/react-maplibre\";\nimport type React from \"react\";\nimport type { DrawerState } from \"./MapDrawer\";\n\nexport interface MapRightControlsProps {\n customControls?: CustomControl[];\n etaBarHeight: number;\n onRecenter: (params?: CenterCallbackParams) => void;\n isMapCentered: boolean;\n mapBearing: number;\n mapPitch: number;\n onResetBearing: (params?: CenterCallbackParams) => void;\n drawerState: DrawerState;\n side: \"left\" | \"bottom\";\n etaData?: EtaData;\n initialViewState?: Partial<ViewState>;\n\n isDragging: boolean;\n clampedDragOffset: number;\n\n // Custom button overrides passed down from facade\n customRecenterButton?: React.ReactNode;\n customCompassButton?: React.ReactNode;\n\n // Drawer customization\n drawerPeekHeight?: string | number;\n\n // Safe area insets\n insets?: { top: number; bottom: number; left: number; right: number };\n\n // Extra bottom offset (px) independent of ETA/drawer state — e.g. to clear\n // a fixed center-screen button that would otherwise overlap the stack.\n bottomOffset?: number;\n}\n\nexport const MapRightControls: React.FC<MapRightControlsProps> = ({\n customControls = [],\n etaBarHeight,\n onRecenter,\n isMapCentered,\n mapBearing,\n mapPitch,\n onResetBearing,\n initialViewState,\n drawerState,\n side,\n etaData,\n isDragging,\n clampedDragOffset,\n customRecenterButton,\n customCompassButton,\n drawerPeekHeight,\n insets = { bottom: 0, left: 0, right: 0, top: 0 },\n bottomOffset = 0,\n}) => {\n const aboveControls = customControls.filter(\n (c) => c.position === \"above-recenter\",\n );\n const belowControls = customControls.filter(\n (c) => c.position === \"below-recenter\",\n );\n\n const isCompassVisible =\n Math.abs(mapBearing) >= 0.5 || Math.abs(mapPitch) >= 0.5;\n\n // Since ETA is floating outside the drawer, the closed drawer height is always 32px (the handle).\n const closedHeightOffset = \"32px\";\n\n // If ETA is active, shift controls up by etaBarHeight to avoid overlapping the centered floating ETA card.\n // Note: when drawer is closed, etaBarHeight already includes bottom inset passed from MapControls\n const activeEtaHeight = etaData\n ? etaBarHeight\n : drawerState === \"closed\"\n ? insets.bottom\n : 0;\n\n const peekStyle =\n typeof drawerPeekHeight === \"number\"\n ? `${drawerPeekHeight}px`\n : drawerPeekHeight || \"15%\";\n\n // Compute bottom positioning offset:\n // If drawer is closed: sits above closed height + active ETA bar height (or inset) + margin\n // If drawer is peek: sits above peek height sheet + active ETA bar height + margin\n const controlsBottom =\n side === \"bottom\"\n ? drawerState === \"closed\"\n ? `calc(${closedHeightOffset} + 1rem + ${activeEtaHeight}px + ${bottomOffset}px - var(--drag-offset, 0px))`\n : `calc(${peekStyle} + 1rem + ${etaData ? etaBarHeight : 0}px + ${bottomOffset}px - var(--drag-offset, 0px))`\n : `calc(1rem + ${insets.bottom}px + ${bottomOffset}px)`;\n\n // Hide right-side controls entirely when drawer is fully open in bottom mode\n const isControlsVisible = side !== \"bottom\" || drawerState !== \"full\";\n\n return (\n <div\n className={`absolute right-4 z-30 flex flex-col items-center gap-3 select-none pointer-events-none ${\n isDragging ? \"transition-none\" : \"transition-all duration-300 ease-out\"\n } ${\n isControlsVisible\n ? \"opacity-100 scale-100 pointer-events-auto\"\n : \"opacity-0 scale-75 pointer-events-none\"\n }`}\n style={{\n bottom: controlsBottom,\n }}\n >\n {/* ABOVE-RECENTER CUSTOM CONTROLS */}\n {aboveControls.length > 0 && (\n <div className=\"flex flex-col gap-2 pointer-events-auto\">\n {aboveControls.map((control) => (\n <div className=\"relative group flex items-center\" key={control.id}>\n {/* Tooltip */}\n {control.tooltip && (\n <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\">\n {control.tooltip}\n </div>\n )}\n\n {/* Action Button */}\n <Button\n 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 ${\n control.activeState\n ? \"ring-2 ring-cyan-400 ring-offset-2 ring-offset-zinc-950\"\n : \"\"\n }`}\n onClick={control.onPress}\n variant=\"ghost\"\n >\n {control.icon}\n </Button>\n </div>\n ))}\n </div>\n )}\n\n {/* COMPASS (OVERRIDDEN OR DEFAULT HIDDEN NORTH-UP) */}\n {isCompassVisible &&\n (customCompassButton ? (\n <div className=\"pointer-events-auto\">{customCompassButton}</div>\n ) : (\n <div className=\"pointer-events-auto\">\n <Button\n 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 duration-300 p-0! hover:bg-zinc-900 hover:text-white ${\n isCompassVisible\n ? \"opacity-100 pointer-events-auto\"\n : \"opacity-0 pointer-events-none h-0 w-0 border-none m-0 p-0 overflow-hidden\"\n }`}\n onClick={() =>\n onResetBearing({ pitch: initialViewState?.pitch ?? 0 })\n }\n style={{\n transform: isCompassVisible\n ? \"scale(1) rotate(0deg)\"\n : \"scale(0.7) rotate(0deg)\",\n }}\n title=\"Reset bearing to North\"\n variant=\"ghost\"\n >\n <svg\n className=\"w-7 h-7 transition-transform duration-75 ease-out\"\n fill=\"none\"\n style={{\n transform: `rotate(${-mapBearing}deg)`,\n }}\n viewBox=\"0 0 24 24\"\n >\n {/* Outer ring */}\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"9.5\"\n stroke=\"white\"\n strokeOpacity=\"0.2\"\n strokeWidth=\"1\"\n />\n {/* North Indicator Needle (Red) */}\n <path d=\"M12 4.5L15 12H9L12 4.5Z\" fill=\"#ef4444\" />\n {/* South Indicator Needle (White) */}\n <path d=\"M12 19.5L9 12H15L12 19.5Z\" fill=\"#f4f4f5\" />\n {/* Pivot Center Point */}\n <circle cx=\"12\" cy=\"12\" fill=\"#18181b\" r=\"1.5\" />\n </svg>\n </Button>\n </div>\n ))}\n\n {/* RECENTER BUTTON (OVERRIDDEN OR DEFAULT) */}\n {customRecenterButton ? (\n <div className=\"pointer-events-auto\">{customRecenterButton}</div>\n ) : (\n <div className=\"pointer-events-auto\">\n <Button\n 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 ${\n isMapCentered\n ? \"ring-2 ring-cyan-400 ring-offset-2 ring-offset-zinc-950\"\n : \"\"\n }`}\n onClick={() => onRecenter()}\n title=\"Recenter Map\"\n variant=\"ghost\"\n >\n {isMapCentered ? (\n /* Filled active lock state */\n <svg\n className=\"w-6 h-6 text-cyan-400\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.2\"\n viewBox=\"0 0 24 24\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n <circle cx=\"12\" cy=\"12\" fill=\"currentColor\" r=\"3\" />\n <line x1=\"12\" x2=\"12\" y1=\"2\" y2=\"4\" />\n <line x1=\"12\" x2=\"12\" y1=\"20\" y2=\"22\" />\n <line x1=\"2\" x2=\"4\" y1=\"12\" y2=\"12\" />\n <line x1=\"20\" x2=\"22\" y1=\"12\" y2=\"12\" />\n </svg>\n ) : (\n /* Outlined drifted state */\n <svg\n className=\"w-6 h-6 text-zinc-300\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n viewBox=\"0 0 24 24\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n <line x1=\"12\" x2=\"12\" y1=\"2\" y2=\"4\" />\n <line x1=\"12\" x2=\"12\" y1=\"20\" y2=\"22\" />\n <line x1=\"2\" x2=\"4\" y1=\"12\" y2=\"12\" />\n <line x1=\"20\" x2=\"22\" y1=\"12\" y2=\"12\" />\n </svg>\n )}\n </Button>\n </div>\n )}\n\n {/* BELOW-RECENTER CUSTOM CONTROLS */}\n {belowControls.length > 0 && (\n <div className=\"flex flex-col gap-2 pointer-events-auto\">\n {belowControls.map((control) => (\n <div className=\"relative group flex items-center\" key={control.id}>\n {/* Tooltip */}\n {control.tooltip && (\n <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\">\n {control.tooltip}\n </div>\n )}\n\n {/* Action Button */}\n <Button\n 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 ${\n control.activeState\n ? \"ring-2 ring-cyan-400 ring-offset-2 ring-offset-zinc-950\"\n : \"\"\n }`}\n onClick={control.onPress}\n variant=\"ghost\"\n >\n {control.icon}\n </Button>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n};\n","import type { DrawerState, MenuItem } from \"@miniapps-sdk/components/Map/types\";\nimport { Button } from \"@miniapps-sdk/components/ui/button\";\nimport { interpolate, useTransform } from \"motion/react\";\nimport type React from \"react\";\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { Sheet, type SheetRef } from \"react-modal-sheet\";\n\nconst resolveHeightToPixels = (\n height: string | number,\n containerHeight: number,\n): number => {\n if (typeof height === \"number\") {\n return height;\n }\n if (height.endsWith(\"%\")) {\n return (parseFloat(height) / 100) * containerHeight;\n }\n return parseFloat(height);\n};\n\nconst HANDLE_HEIGHT_PX = 32;\n\n// react-modal-sheet's default snap/spring-back animation is a stiff 200ms\n// easeOut — fine for a full open/close, but a released drag that DIDN'T\n// reach the next snap point (springing back to where it started) reads as\n// an abrupt jump at that speed. A longer duration + a gentler, more\n// \"settling\" curve (close to iOS's own sheet deceleration) makes every\n// snap — reached or not — read as a smooth slide instead of a teleport.\nconst SHEET_TWEEN_CONFIG = {\n duration: 0.4,\n ease: [0.32, 0.72, 0, 1] as [number, number, number, number],\n};\n// Raised from the library's default 1200px/s: a small, fast flick no\n// longer forces a jump past the nearest snap point — the drag has to be\n// more deliberate before it \"commits\" past where the finger actually let\n// go, matching the ask for the snapping itself to feel less harsh/twitchy.\nconst SHEET_DRAG_VELOCITY_THRESHOLD = 1700;\n\nexport interface MobileBottomDrawerProps {\n menuItems: MenuItem[];\n state: DrawerState;\n onChangeState: (state: DrawerState) => void;\n\n // Drawer customization\n drawerPeekHeight?: string | number;\n drawerFullHeight?: string | number;\n /** Max height the \"auto\" state can grow to. Default \"100%\". */\n drawerAutoMaxHeight?: string | number;\n /**\n * Height (px) used to resolve percentage-based drawer heights. Defaults to\n * the live window height — the sheet itself always renders relative to\n * the viewport (like a native bottom sheet / the Apple Maps demo this is\n * modeled on), so this only affects the peek/full/auto height MATH, not\n * where the sheet is actually positioned on screen.\n */\n containerHeight?: number;\n menuContent?: React.ReactNode;\n enableTouchDrag?: boolean;\n /** Show/hide the drag-handle header. Default true. */\n handleVisible?: boolean;\n /** Fires whenever the measured \"auto\" content height changes (px). */\n onAutoContentHeightChange?: (px: number) => void;\n\n showScrollToTopButton?: boolean;\n scrollToTopThreshold?: number;\n\n safeAreaInsets?: { top: number; bottom: number; left: number; right: number };\n}\n\n/**\n * Bottom sheet drawer built on `react-modal-sheet`, matching that library's\n * Apple Maps example: snap points, native-feeling drag (handled entirely by\n * the library, incl. scroll-edge-aware drag handoff), a drag-linked backdrop\n * fade, and a persistent handle sliver in the \"closed\" state.\n */\nexport const MobileBottomDrawer = forwardRef<\n HTMLDivElement,\n MobileBottomDrawerProps\n>(\n (\n {\n menuItems,\n state,\n onChangeState,\n drawerPeekHeight,\n drawerFullHeight,\n drawerAutoMaxHeight,\n containerHeight,\n menuContent,\n enableTouchDrag = true,\n handleVisible = true,\n onAutoContentHeightChange,\n showScrollToTopButton = true,\n scrollToTopThreshold = 300,\n safeAreaInsets = { bottom: 0, left: 0, right: 0, top: 0 },\n },\n ref,\n ) => {\n const scrollRef = useRef<HTMLDivElement>(null);\n useImperativeHandle(ref, () => scrollRef.current as HTMLDivElement);\n\n const headerRef = useRef<HTMLDivElement>(null);\n const contentWrapperRef = useRef<HTMLDivElement>(null);\n\n const [viewportHeight, setViewportHeight] = useState(\n () =>\n containerHeight ??\n (typeof window !== \"undefined\" ? window.innerHeight : 800),\n );\n\n useEffect(() => {\n if (containerHeight) {\n setViewportHeight(containerHeight);\n return;\n }\n if (typeof window === \"undefined\") return;\n const update = () => setViewportHeight(window.innerHeight);\n update();\n window.addEventListener(\"resize\", update);\n return () => window.removeEventListener(\"resize\", update);\n }, [containerHeight]);\n\n // Measures the real \"auto\" content height (handle/header + rendered\n // content), live, so \"auto\" never clips or over-guesses — same\n // approach the previous implementation used, minus the manual math\n // react-modal-sheet's own layout now handles for us.\n const [autoContentPx, setAutoContentPx] = useState(0);\n useEffect(() => {\n const contentEl = contentWrapperRef.current;\n if (!contentEl) return;\n\n const measure = () => {\n const headerHeight = handleVisible\n ? (headerRef.current?.offsetHeight ?? 0)\n : 0;\n const px = headerHeight + contentEl.scrollHeight;\n setAutoContentPx(px);\n onAutoContentHeightChange?.(px);\n };\n\n measure();\n const ro = new ResizeObserver(measure);\n ro.observe(contentEl);\n return () => ro.disconnect();\n }, [handleVisible, onAutoContentHeightChange]);\n\n const closedPx =\n (handleVisible ? HANDLE_HEIGHT_PX : 0) + safeAreaInsets.bottom;\n const peekPx = resolveHeightToPixels(\n drawerPeekHeight ?? \"15%\",\n viewportHeight,\n );\n const autoMaxPx = resolveHeightToPixels(\n drawerAutoMaxHeight ?? \"100%\",\n viewportHeight,\n );\n const autoPx = Math.min(autoMaxPx, Math.max(autoContentPx, closedPx + 1));\n\n // react-modal-sheet REQUIRES snapPoints[0] === 0 and snapPoints[last]\n // === 1 (1 meaning \"fully open\", 100% of the sheet's own intrinsic\n // height) — if you don't provide those exactly, it silently mutates\n // your array (unshift(0)/push(1)) to force it, which desyncs any index\n // math you built against your own array. So \"full\" IS that literal 1\n // here (same as the upstream Apple Maps example's own top snap point,\n // `drawerFullHeight` no longer applies — matching the demo exactly\n // beats a configurable-but-fighting-the-library \"85%\" full state), and\n // we always supply our own leading 0 so the library never needs to\n // correct anything behind our back.\n const { snapPoints, snapLabels, backdropOutput } = useMemo(() => {\n const normalize = (raw: number) =>\n raw > 0 && raw <= 1 ? raw * viewportHeight : raw;\n\n const unsorted: { label: DrawerState; raw: number }[] = [\n { label: \"closed\", raw: 0 },\n { label: \"closed\", raw: closedPx },\n { label: \"peek\", raw: peekPx },\n { label: \"auto\", raw: autoPx },\n { label: \"full\", raw: 1 },\n ];\n const entries = unsorted.sort(\n (a, b) => normalize(a.raw) - normalize(b.raw),\n );\n\n // On a tie (e.g. a long \"auto\" content height clamped to the same\n // 100% ceiling as \"full\"'s literal 1), keep the LATER-declared\n // label, not the first — our seed order below is\n // [closed, closed, peek, auto, full], so ties resolve in that same\n // priority. Losing \"full\" here (dedup used to keep whichever\n // collided entry sorted first) silently dropped it from the array\n // and left `state === \"full\"` unable to find its own index at all.\n const deduped: { label: DrawerState; raw: number }[] = [];\n for (const entry of entries) {\n const prev = deduped[deduped.length - 1];\n if (\n prev &&\n Math.abs(normalize(prev.raw) - normalize(entry.raw)) < 0.5\n ) {\n deduped[deduped.length - 1] = entry;\n continue;\n }\n deduped.push(entry);\n }\n\n return {\n backdropOutput: deduped.map((d) =>\n d.label === \"full\" || d.label === \"auto\" ? 1 : 0,\n ),\n snapLabels: deduped.map((d) => d.label),\n snapPoints: deduped.map((d) => d.raw),\n };\n }, [closedPx, peekPx, autoPx, viewportHeight]);\n\n // Last match, not first: index 0 is always the mandatory hidden anchor\n // (also labeled \"closed\") — the real, visible \"closed\" sliver is\n // whichever later index carries the same label (or the same index, if\n // `closedPx` collapsed to exactly 0 and they deduped into one entry).\n const currentIndex = Math.max(0, snapLabels.lastIndexOf(state));\n\n // react-modal-sheet's `initialSnap` only applies once, inside a\n // one-shot \"opening\" animation fired from an internal isOpen-driven\n // state machine — it does nothing at all for later `state` prop\n // changes anyway, so we drive every position change (including the\n // first) through the same explicit imperative `snapTo` instead.\n //\n // That call races the library's OWN internal height measurement\n // though: `sheetRef.current.snapPoints` is `[]` until its ResizeObserver\n // on the container has reported a real height, and `snapTo` silently\n // no-ops (just a console.warn) against an empty array — confirmed via\n // direct instrumentation, both calls on mount landed with\n // `snapPoints: []`. Since nothing else re-triggers this effect once our\n // own `currentIndex` settles, a snapTo that lands in that dead window\n // never gets retried and the sheet is stuck wherever it happened to\n // mount. Poll (bounded, rAF-paced) until the library's own snapPoints\n // are actually populated before calling snapTo.\n const sheetRef = useRef<SheetRef>(null);\n useEffect(() => {\n let cancelled = false;\n let attempts = 0;\n\n const trySnap = () => {\n if (cancelled) return;\n const ref = sheetRef.current;\n if (ref && ref.snapPoints.length > 0) {\n ref.snapTo(currentIndex);\n return;\n }\n attempts += 1;\n if (attempts > 60) return; // ~1s at 60fps — give up, something else is wrong\n requestAnimationFrame(trySnap);\n };\n\n trySnap();\n return () => {\n cancelled = true;\n };\n }, [currentIndex]);\n\n const handleSnap = useCallback(\n (index: number) => {\n const label = snapLabels[index] ?? \"closed\";\n if (label !== state) onChangeState(label);\n },\n [snapLabels, state, onChangeState],\n );\n\n const handleHandleClick = () => {\n if (state === \"closed\") {\n onChangeState(\"peek\");\n } else if (state === \"peek\") {\n onChangeState(\"full\");\n } else if (state === \"auto\") {\n onChangeState(\"closed\");\n } else {\n onChangeState(\"peek\");\n }\n };\n\n const [showScrollTop, setShowScrollTop] = useState(false);\n useEffect(() => {\n const el = scrollRef.current;\n if (!el) return;\n const onScroll = () => {\n setShowScrollTop(\n state !== \"closed\" && el.scrollTop > scrollToTopThreshold,\n );\n };\n el.addEventListener(\"scroll\", onScroll);\n return () => el.removeEventListener(\"scroll\", onScroll);\n }, [state, scrollToTopThreshold]);\n\n useEffect(() => {\n if (state === \"closed\") setShowScrollTop(false);\n }, [state]);\n\n const dragDisabled = !enableTouchDrag;\n\n return (\n <>\n <style>{`\n .no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }\n .no-scrollbar::-webkit-scrollbar { display: none; }\n `}</style>\n\n <Sheet\n disableDismiss\n disableDrag={dragDisabled}\n dragVelocityThreshold={SHEET_DRAG_VELOCITY_THRESHOLD}\n initialSnap={currentIndex}\n isOpen\n onClose={() => onChangeState(\"closed\")}\n onSnap={handleSnap}\n ref={sheetRef}\n snapPoints={snapPoints}\n tweenConfig={SHEET_TWEEN_CONFIG}\n >\n <Sheet.Container\n className=\"!bg-zinc-950/85 !backdrop-blur-md !border !border-white/10 !border-b-0 !rounded-t-2xl !shadow-2xl \"\n style={{ paddingBottom: safeAreaInsets.bottom }}\n >\n {handleVisible && (\n <Sheet.Header\n className=\"!bg-transparent cursor-pointer hover:!bg-white/5 transition-colors\"\n onClick={handleHandleClick}\n ref={headerRef}\n />\n )}\n\n <Sheet.Content\n className=\"!bg-transparent\"\n disableDrag={(info) =>\n dragDisabled || info.scrollPosition === \"middle\"\n }\n // Below the tallest snap point, content isn't scrollable at\n // all — same trick the upstream Apple Maps example uses.\n // react-modal-sheet's SheetContent sets `touch-action:\n // pan-down` on the scroller whenever it's a live scroll\n // area, which lets the browser's native scroll handling\n // compete with (and usually win over) the sheet's own drag\n // gesture for upward pans — dragging the list up from peek\n // would get eaten by \"scrolling\" a list that has nowhere\n // left to scroll, instead of expanding the sheet. With\n // scroll disabled here, content has nothing to compete for:\n // it's a pure drag target until you're actually at the top.\n disableScroll={(info) =>\n !dragDisabled && info.currentSnap !== snapPoints.length - 1\n }\n scrollClassName=\"no-scrollbar\"\n scrollRef={scrollRef}\n >\n <div className=\"px-4 pb-4 pt-2 relative\" ref={contentWrapperRef}>\n {menuContent ? (\n menuContent\n ) : (\n <div className=\"flex flex-col gap-1\">\n {menuItems.map((item) => (\n <Button\n 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 ${\n item.disabled\n ? \"opacity-45 cursor-not-allowed pointer-events-none\"\n : \"\"\n }`}\n disabled={item.disabled}\n key={item.id}\n onClick={() => {\n if (!item.disabled) {\n item.onPress();\n onChangeState(\"closed\");\n }\n }}\n variant=\"ghost\"\n >\n <div className=\"relative flex items-center justify-center w-8 h-8 rounded-lg bg-white/5 text-zinc-300\">\n {item.icon}\n {item.badge !== undefined && (\n <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\">\n {item.badge}\n </span>\n )}\n </div>\n <span className=\"text-sm font-medium tracking-wide\">\n {item.label}\n </span>\n </Button>\n ))}\n </div>\n )}\n </div>\n\n {showScrollToTopButton && showScrollTop && (\n <Button\n 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!\"\n onClick={() => {\n scrollRef.current?.scrollTo({ behavior: \"smooth\", top: 0 });\n }}\n variant=\"ghost\"\n >\n <svg\n fill=\"none\"\n height=\"20\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2.5\"\n viewBox=\"0 0 24 24\"\n width=\"20\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <polyline points=\"18 15 12 9 6 15\" />\n </svg>\n </Button>\n )}\n </Sheet.Content>\n </Sheet.Container>\n\n <DrawerBackdrop\n active={state === \"full\" || state === \"auto\"}\n onTap={() => onChangeState(\"closed\")}\n output={backdropOutput}\n />\n </Sheet>\n </>\n );\n },\n);\n\nMobileBottomDrawer.displayName = \"MobileBottomDrawer\";\n\n/**\n * Drag-linked backdrop fade, same technique as react-modal-sheet's own\n * Apple Maps example: interpolate opacity from the sheet's raw `y` motion\n * value across each snap point, rather than a plain state-keyed CSS class,\n * so the dim follows the finger 1:1 during a drag instead of snapping in\n * only after the gesture settles.\n */\nfunction DrawerBackdrop({\n active,\n output,\n onTap,\n}: {\n active: boolean;\n output: number[];\n onTap: () => void;\n}) {\n const { y, snapPoints } = Sheet.useContext();\n\n const opacity = useTransform(y, (value) => {\n if (snapPoints.length === 0 || output.length !== snapPoints.length) {\n return 0;\n }\n const mix = interpolate(\n snapPoints.map((point) => point.snapValueY),\n output,\n );\n return mix(value) * 0.45;\n });\n\n // react-modal-sheet's Sheet.Backdrop sets `pointer-events: auto` across\n // the FULL VIEWPORT the moment it's given an onTap/onClick handler — not\n // conditionally on its opacity/visibility. Passing `onTap` unconditionally\n // (as the upstream Apple Maps example does, where the backdrop is the\n // ONLY interactive layer outside the sheet) silently swallowed every\n // click anywhere on the page whenever the sheet wasn't fully open here,\n // because there IS other interactive UI outside the sheet (map controls,\n // this story's own buttons). Only wire it up while the backdrop is\n // actually meant to be interactive.\n return (\n <Sheet.Backdrop\n className=\"!bg-black !backdrop-blur-[1px]\"\n onTap={active ? onTap : undefined}\n style={{ opacity }}\n />\n );\n}\n","import type { DrawerState, EtaData } from \"@miniapps-sdk/components/Map/types\";\nimport type React from \"react\";\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nexport interface MapInsets {\n top: number;\n bottom: number;\n left: number;\n right: number;\n}\n\nexport interface MapControlsState {\n isFollowing: boolean;\n setIsFollowing: (following: boolean) => void;\n centerOnUser: (params?: CenterCallbackParams) => void;\n /**\n * Fly the camera to an arbitrary [lng, lat] — e.g. jumping to a venue\n * selected from a list. Unlike calling the raw MapLibre instance's own\n * `flyTo` directly, this also disables follow-mode and locks out the\n * \"recenter on the user\" live-location tracking for the duration of the\n * animation, so a GPS update arriving mid-flight doesn't immediately snap\n * the camera back to the user and undo it (this exact bug — flyTo only\n * \"worked\" after the first manual pan, which is what actually disabled\n * follow-mode — is why this exists instead of every consumer reaching\n * into the MapLibre instance themselves).\n */\n flyTo: (coords: [number, number], params?: FlyToParams) => void;\n bearing: number;\n setBearing: (bearing: number) => void;\n pitch: number;\n setPitch: (pitch: number) => void;\n resetBearing: (params?: CenterCallbackParams) => void;\n\n // Navigation details and controls presence state\n etaData?: EtaData;\n setEtaData: (data?: EtaData) => void;\n hasControls: boolean;\n setHasControls: (hasControls: boolean) => void;\n\n // Drawer state controls\n drawerState: DrawerState;\n setDrawerState: (state: DrawerState) => void;\n /** Stable ref to the drawer's scrollable container. Always available. */\n drawerContentRef: React.RefObject<HTMLDivElement | null>;\n /**\n * Show/hide the drawer's drag-handle bar programmatically — e.g. hide it\n * while `menuContent` is itself a full-bleed swipeable detail view (its\n * own drag handle/affordance would double up with the drawer's). Defaults\n * to `true`. Remember to restore it (e.g. in a `useEffect` cleanup) when\n * the content that needed it hidden unmounts.\n */\n drawerHandleVisible: boolean;\n setDrawerHandleVisible: (visible: boolean) => void;\n\n // Safe area insets (e.g. for mobile home indicators/notches)\n insets: MapInsets;\n setInsets: (insets: Partial<MapInsets>) => void;\n}\n\nexport interface CenterCallbackParams {\n pitch?: number;\n /**\n * Optional bearing to animate to in the same motion as the center/zoom/pitch\n * change. Pass this instead of calling `resetBearing()` right after\n * `centerOnUser()` — two separate flyTo/easeTo calls on the same camera\n * race each other (both touch pitch) and read as sluggish, multi-second\n * drift instead of one clean fast motion.\n */\n bearing?: number;\n}\n\nexport interface FlyToParams {\n zoom?: number;\n pitch?: number;\n bearing?: number;\n /** ms. Defaults to MapLibre's own distance-based duration if omitted. */\n duration?: number;\n}\n\ninterface MapControlsContextType extends MapControlsState {\n // Internal registration callbacks for the Map component to hook up its controls\n _registerCenterCallback: (\n cb: (params?: CenterCallbackParams) => void,\n ) => void;\n _registerResetBearingCallback: (\n cb: (params?: CenterCallbackParams) => void,\n ) => void;\n _registerFlyToCallback: (\n cb: (coords: [number, number], params?: FlyToParams) => void,\n ) => void;\n}\n\nexport const MapControlsContext = createContext<MapControlsContextType | null>(\n null,\n);\n\nexport const SDKMapProvider: React.FC<{ children: React.ReactNode }> = ({\n children,\n}) => {\n const [isFollowing, setIsFollowing] = useState(true);\n const [bearing, setBearingState] = useState(0);\n const [pitch, setPitchState] = useState(0);\n const [drawerState, setDrawerStateInternal] = useState<DrawerState>(\"closed\");\n\n // Stable ref created by the provider to ensure it's always available to hook users\n const drawerContentRef = useRef<HTMLDivElement>(null);\n\n const setDrawerState = useCallback((val: DrawerState) => {\n setDrawerStateInternal(val);\n }, []);\n\n const [drawerHandleVisible, setDrawerHandleVisibleState] = useState(true);\n const setDrawerHandleVisible = useCallback((val: boolean) => {\n setDrawerHandleVisibleState((prev) => (prev === val ? prev : val));\n }, []);\n\n // Use stable handlers for hasControls\n const [hasControls, setHasControlsState] = useState(false);\n const setHasControls = useCallback((val: boolean) => {\n setHasControlsState((prev) => (prev === val ? prev : val));\n }, []);\n\n // Use shallow comparison for etaData setter to prevent update loops\n const [etaData, setEtaDataState] = useState<EtaData | undefined>(undefined);\n const setEtaData = useCallback((newData?: EtaData) => {\n setEtaDataState((prev) => {\n if (!prev && !newData) return prev;\n if (!prev || !newData) return newData;\n if (\n prev.etaMins === newData.etaMins &&\n prev.distanceRemainingKm === newData.distanceRemainingKm &&\n prev.label === newData.label &&\n prev.progress === newData.progress &&\n prev.mode === newData.mode &&\n prev.isCalculating === newData.isCalculating &&\n prev.error === newData.error\n ) {\n return prev;\n }\n return newData;\n });\n }, []);\n\n const [insets, setInsetsState] = useState<MapInsets>({\n bottom: 0,\n left: 0,\n right: 0,\n top: 0,\n });\n\n const setInsets = useCallback((newInsets: Partial<MapInsets>) => {\n setInsetsState((prev) => ({ ...prev, ...newInsets }));\n }, []);\n\n const centerCallbackRef = useRef<\n ((params?: CenterCallbackParams) => void) | null\n >(null);\n const resetBearingCallbackRef = useRef<\n ((params?: CenterCallbackParams) => void) | null\n >(null);\n const flyToCallbackRef = useRef<\n ((coords: [number, number], params?: FlyToParams) => void) | null\n >(null);\n\n const centerOnUser = useCallback((params?: CenterCallbackParams) => {\n if (centerCallbackRef.current) {\n centerCallbackRef.current(params);\n }\n }, []);\n\n const resetBearing = useCallback((params?: CenterCallbackParams) => {\n if (resetBearingCallbackRef.current) {\n resetBearingCallbackRef.current(params);\n }\n }, []);\n\n const flyTo = useCallback(\n (coords: [number, number], params?: FlyToParams) => {\n if (flyToCallbackRef.current) {\n flyToCallbackRef.current(coords, params);\n }\n },\n [],\n );\n\n const _registerCenterCallback = useCallback(\n (cb: (params?: CenterCallbackParams) => void) => {\n centerCallbackRef.current = cb;\n },\n [],\n );\n\n const _registerResetBearingCallback = useCallback(\n (cb: (params?: CenterCallbackParams) => void) => {\n resetBearingCallbackRef.current = cb;\n },\n [],\n );\n\n const _registerFlyToCallback = useCallback(\n (cb: (coords: [number, number], params?: FlyToParams) => void) => {\n flyToCallbackRef.current = cb;\n },\n [],\n );\n\n const setBearing = useCallback((b: number) => {\n setBearingState(b);\n }, []);\n\n const setPitch = useCallback((p: number) => {\n setPitchState(p);\n }, []);\n\n // Memoize context value to block redundant re-renders of listeners\n const contextValue = useMemo(\n () => ({\n _registerCenterCallback,\n _registerFlyToCallback,\n _registerResetBearingCallback,\n bearing,\n centerOnUser,\n drawerContentRef,\n drawerHandleVisible,\n drawerState,\n etaData,\n flyTo,\n hasControls,\n insets,\n isFollowing,\n pitch,\n resetBearing,\n setBearing,\n setDrawerHandleVisible,\n setDrawerState,\n setEtaData,\n setHasControls,\n setInsets,\n setIsFollowing,\n setPitch,\n }),\n [\n _registerCenterCallback,\n _registerFlyToCallback,\n _registerResetBearingCallback,\n bearing,\n centerOnUser,\n drawerHandleVisible,\n drawerState,\n etaData,\n flyTo,\n hasControls,\n isFollowing,\n pitch,\n resetBearing,\n setBearing,\n setDrawerHandleVisible,\n setDrawerState,\n setEtaData,\n setHasControls,\n setPitch,\n insets,\n setInsets,\n ],\n );\n\n return (\n <MapControlsContext.Provider value={contextValue}>\n {children}\n </MapControlsContext.Provider>\n );\n};\n\nexport const useMapControls = (): MapControlsState => {\n const context = useContext(MapControlsContext);\n if (!context) {\n throw new Error(\"useMapControls must be used within a MapControlsProvider\");\n }\n return context;\n};\n","import { MapDrawer } from \"@miniapps-sdk/components/Map/components/MapDrawer\";\nimport { MapEtaPanel } from \"@miniapps-sdk/components/Map/components/MapEtaPanel\";\nimport { MapRightControls } from \"@miniapps-sdk/components/Map/components/MapRightControls\";\nimport { MobileBottomDrawer } from \"@miniapps-sdk/components/Map/components/MobileBottomDrawer\";\nimport {\n type CenterCallbackParams,\n MapControlsContext,\n} from \"@miniapps-sdk/components/Map/MapContext\";\nimport type {\n CustomControl,\n DrawerState,\n EtaData,\n MenuItem,\n} from \"@miniapps-sdk/components/Map/types\";\nimport type { ViewState } from \"@vis.gl/react-maplibre\";\nimport type React from \"react\";\nimport { useCallback, useContext, useEffect, useRef, useState } from \"react\";\n\nconst resolveHeightToPixels = (\n height: string | number,\n containerHeight: number,\n): number => {\n if (typeof height === \"number\") {\n return height;\n }\n if (height.endsWith(\"%\")) {\n return (parseFloat(height) / 100) * containerHeight;\n }\n return parseFloat(height);\n};\n\nexport interface MapControlsProps {\n // Drawer\n menuItems?: MenuItem[];\n drawerSide?: \"left\" | \"bottom\"; // default: 'left' on landscape, 'bottom' on portrait\n defaultState?: DrawerState; // default: 'closed'\n menuContent?: React.ReactNode;\n children?: React.ReactNode;\n\n // Controls\n customControls?: CustomControl[];\n etaBarHeight?: number; // px — keeps controls above ETA bar\n onRecenter?: (params?: CenterCallbackParams) => void;\n isMapCentered?: boolean;\n mapBearing?: number; // degrees — drives compass visibility and rotation\n initialViewState?: Partial<ViewState>;\n\n // Compass\n onResetBearing?: (params?: CenterCallbackParams) => void;\n\n // Integrated ETA details\n etaData?: EtaData;\n\n // Custom button overrides\n customRecenterButton?: React.ReactNode;\n customCompassButton?: React.ReactNode;\n\n // Drawer customization\n drawerPeekHeight?: string | number;\n drawerFullHeight?: string | number;\n /**\n * Max height the \"auto\" drawer state (sized to fit `menuContent`) can\n * grow to. Default \"100%\" — the full available map container height\n * (i.e. effectively 100vh), NOT `drawerFullHeight` (85% by default),\n * so auto-sized content isn't clipped just because it's taller than the\n * manual \"full\" state's height.\n */\n drawerAutoMaxHeight?: string | number;\n drawerContentRef?: React.Ref<HTMLDivElement>;\n\n // Touch drag customization\n enableTouchDrag?: boolean;\n\n // Scroll to top button customization\n showScrollToTopButton?: boolean;\n scrollToTopThreshold?: number;\n\n // Extra bottom offset (px) for the right-side floating controls stack,\n // independent of ETA/drawer state — e.g. to clear a fixed center-screen\n // action button that would otherwise sit under it.\n controlsBottomOffset?: number;\n\n // Internal flag to avoid registry update loops\n isInternal?: boolean;\n}\n\nexport const MapControls: React.FC<MapControlsProps> = ({\n menuItems = [],\n drawerSide,\n customControls = [],\n etaBarHeight = 100,\n onRecenter: propRecenter,\n isMapCentered: propMapCentered,\n mapBearing: propMapBearing,\n onResetBearing: propResetBearing,\n etaData,\n customRecenterButton,\n defaultState,\n initialViewState,\n customCompassButton,\n drawerPeekHeight,\n drawerFullHeight,\n drawerAutoMaxHeight,\n drawerContentRef,\n menuContent,\n children,\n enableTouchDrag = false,\n showScrollToTopButton = true,\n scrollToTopThreshold = 300,\n controlsBottomOffset = 0,\n isInternal = false,\n}) => {\n const mapContext = useContext(MapControlsContext);\n\n const contextRef = mapContext?.drawerContentRef;\n\n // Combine property ref and context ref into a single sync callback\n const mergedRef = useCallback(\n (node: HTMLDivElement | null) => {\n // Sync prop ref\n if (drawerContentRef) {\n if (typeof drawerContentRef === \"function\") {\n drawerContentRef(node);\n } else {\n (drawerContentRef as any).current = node;\n }\n }\n // Sync context ref (always an object ref from provider)\n if (contextRef) {\n (contextRef as any).current = node;\n }\n },\n [drawerContentRef, contextRef],\n );\n\n // Local fallback if context is not available (e.g. isolated storybook without provider)\n const [localDrawerState, setLocalDrawerState] = useState<DrawerState>(\n defaultState ?? \"closed\",\n );\n\n const drawerState = mapContext ? mapContext.drawerState : localDrawerState;\n const setDrawerState = useCallback(\n (state: DrawerState) => {\n if (mapContext) {\n mapContext.setDrawerState(state);\n } else {\n setLocalDrawerState(state);\n }\n },\n [mapContext],\n );\n\n // Sync defaultState into context on mount if provided\n // biome-ignore lint/correctness/useExhaustiveDependencies: only run on mount to set initial state\n useEffect(() => {\n if (defaultState && mapContext) {\n mapContext.setDrawerState(defaultState);\n }\n }, []);\n\n const [side, setSide] = useState<\"left\" | \"bottom\">(\"left\");\n const containerRef = useRef<HTMLDivElement>(null);\n const [mapHeight, setMapHeight] = useState(600);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: containerRef is stable and parent is resolved once on mount\n useEffect(() => {\n const parent = containerRef.current?.parentElement;\n if (!parent) return;\n\n const updateHeight = () => {\n setMapHeight(parent.getBoundingClientRect().height);\n };\n\n updateHeight();\n\n const observer = new ResizeObserver(updateHeight);\n observer.observe(parent);\n\n return () => {\n observer.disconnect();\n };\n }, []);\n\n // Set registry flag\n const setHasControls = mapContext?.setHasControls;\n useEffect(() => {\n if (setHasControls && !isInternal) {\n setHasControls(true);\n return () => setHasControls(false);\n }\n }, [setHasControls, isInternal]);\n\n // Fallbacks using context properties if props are not explicitly passed\n const isMapCentered =\n propMapCentered !== undefined\n ? propMapCentered\n : mapContext\n ? mapContext.isFollowing\n : true;\n\n const mapBearing =\n propMapBearing !== undefined\n ? propMapBearing\n : mapContext\n ? mapContext.bearing\n : 0;\n\n const onRecenter = (params?: CenterCallbackParams) => {\n if (propRecenter) {\n propRecenter(params);\n } else if (mapContext) {\n mapContext.centerOnUser(params);\n }\n };\n\n const onResetBearing = (params?: CenterCallbackParams) => {\n if (propResetBearing) {\n propResetBearing(params);\n } else if (mapContext) {\n mapContext.resetBearing(params);\n }\n };\n\n const mapPitch = mapContext ? mapContext.pitch : 0;\n\n // Resolve etaData from context if not explicitly passed as a prop\n const resolvedEtaData = etaData !== undefined ? etaData : mapContext?.etaData;\n\n // Mirrors the bottom drawer's own \"auto\" content measurement so THIS\n // component's height math (used for the ETA card fade/position) doesn't\n // fall back to a nonsensical fixed guess for an \"auto\"-sized sheet.\n const [autoContentPx, setAutoContentPx] = useState(0);\n\n // Handle responsive layout detection for orientation matching\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const checkLayout = () => {\n if (drawerSide) {\n setSide(drawerSide);\n } else {\n // Landscape: left drawer panel, Portrait: bottom sheet panel\n if (window.innerWidth < 768) {\n setSide(\"bottom\");\n } else {\n setSide(\"left\");\n }\n }\n };\n\n checkLayout();\n window.addEventListener(\"resize\", checkLayout);\n return () => window.removeEventListener(\"resize\", checkLayout);\n }, [drawerSide]);\n\n // The bottom sheet (MobileBottomDrawer, built on react-modal-sheet) now\n // owns its own drag/snap animation internally — ETA card and right-side\n // controls key off the settled `drawerState` (CSS-transitioned) instead\n // of a live per-frame drag offset hoisted up from the drawer.\n const isDragging = false;\n const clampedDragOffset = 0;\n\n // Resolve height limits\n const fullPx = resolveHeightToPixels(drawerFullHeight || \"85%\", mapHeight);\n const peekPx = resolveHeightToPixels(drawerPeekHeight || \"15%\", mapHeight);\n const autoMaxPx = resolveHeightToPixels(\n drawerAutoMaxHeight || \"100%\",\n mapHeight,\n );\n const autoPx = Math.min(autoMaxPx, autoContentPx);\n const bottomInset = mapContext?.insets.bottom || 0;\n const handleVisible = mapContext ? mapContext.drawerHandleVisible : true;\n\n // Calculate dynamic drawer height and opacity for portrait bottom sheet\n let baseHeight = handleVisible ? 32 : 0;\n if (drawerState === \"peek\") {\n baseHeight = peekPx;\n } else if (drawerState === \"full\") {\n baseHeight = fullPx;\n } else if (drawerState === \"auto\") {\n baseHeight = autoPx;\n }\n\n const currentDrawerHeight = baseHeight;\n\n // Smoothly fade out opacity between peek height and 35% of the distance to full\n const startFadeHeight = peekPx + 20; // start fading just above peek\n const endFadeHeight = peekPx + (fullPx - peekPx) * 0.35; // fully faded out at 35% progress\n\n let etaOpacity = 1;\n let etaBottomStyle: string | number = \"1rem\";\n\n if (side === \"bottom\") {\n if (currentDrawerHeight <= startFadeHeight) {\n etaOpacity = 1;\n } else if (currentDrawerHeight >= endFadeHeight) {\n etaOpacity = 0;\n } else {\n const fraction =\n (currentDrawerHeight - startFadeHeight) /\n (endFadeHeight - startFadeHeight);\n etaOpacity = 1 - fraction;\n }\n\n // Add inset if closed, otherwise drawer already pushed up\n const effectiveInset = drawerState === \"closed\" ? bottomInset : 0;\n etaBottomStyle = `calc(${baseHeight + effectiveInset + 16}px - var(--drag-offset, 0px))`;\n } else {\n // Landscape / Left drawer side\n etaOpacity = drawerState === \"full\" ? 0 : 1;\n etaBottomStyle = `calc(1rem + ${bottomInset}px)`;\n }\n\n return (\n <>\n <div ref={containerRef} style={{ display: \"none\" }} />\n\n {/* Dynamic Slide-out Menu Drawer */}\n {side === \"bottom\" ? (\n <MobileBottomDrawer\n containerHeight={mapHeight}\n drawerAutoMaxHeight={drawerAutoMaxHeight}\n drawerFullHeight={drawerFullHeight}\n drawerPeekHeight={drawerPeekHeight}\n enableTouchDrag={enableTouchDrag}\n handleVisible={handleVisible}\n menuContent={children || menuContent}\n menuItems={menuItems}\n onAutoContentHeightChange={setAutoContentPx}\n onChangeState={setDrawerState}\n ref={mergedRef}\n safeAreaInsets={mapContext?.insets}\n scrollToTopThreshold={scrollToTopThreshold}\n showScrollToTopButton={showScrollToTopButton}\n state={drawerState}\n />\n ) : (\n <MapDrawer\n menuContent={children || menuContent}\n menuItems={menuItems}\n onChangeState={setDrawerState}\n ref={mergedRef}\n scrollToTopThreshold={scrollToTopThreshold}\n showScrollToTopButton={showScrollToTopButton}\n state={drawerState}\n />\n )}\n\n {/* Floating Controls stacked on the right side */}\n <MapRightControls\n bottomOffset={controlsBottomOffset}\n clampedDragOffset={clampedDragOffset}\n customCompassButton={customCompassButton}\n customControls={customControls}\n customRecenterButton={customRecenterButton}\n drawerPeekHeight={drawerPeekHeight}\n drawerState={drawerState}\n etaBarHeight={\n etaBarHeight + (drawerState === \"closed\" ? bottomInset : 0)\n }\n etaData={resolvedEtaData}\n initialViewState={initialViewState}\n insets={mapContext?.insets}\n isDragging={isDragging}\n isMapCentered={isMapCentered}\n mapBearing={mapBearing}\n mapPitch={mapPitch}\n onRecenter={() => onRecenter()}\n onResetBearing={onResetBearing}\n side={side}\n />\n\n {/* Floating Bottom ETA Card (Landscape or Portrait peek/closed) */}\n {resolvedEtaData && (\n <MapEtaPanel\n etaData={resolvedEtaData}\n isDragging={isDragging}\n layoutMode=\"floating-card\"\n style={{\n bottom: etaBottomStyle,\n opacity: etaOpacity,\n pointerEvents: etaOpacity > 0.1 ? \"auto\" : \"none\",\n transition: isDragging\n ? \"none\"\n : \"bottom 250ms ease-in-out, opacity 300ms ease-out\",\n }}\n />\n )}\n </>\n );\n};\n\nexport type { DrawerState };\n","import { MapControlsContext } from \"@miniapps-sdk/components/Map/MapContext\";\nimport type React from \"react\";\nimport { useContext } from \"react\";\n\nexport interface MapMenuProps {\n children?: React.ReactNode;\n}\n\nexport const MapMenu: React.FC<MapMenuProps> = ({ children }) => {\n return <div className=\"flex flex-col gap-1.5\">{children}</div>;\n};\n\nexport interface MapMenuItemProps {\n id: string;\n label: string;\n icon?: React.ReactNode;\n onPress?: () => void;\n badge?: string | number;\n disabled?: boolean;\n children?: React.ReactNode;\n}\n\nexport const MapMenuItem: React.FC<MapMenuItemProps> = ({\n id,\n label,\n icon,\n onPress,\n badge,\n disabled = false,\n children,\n}) => {\n const context = useContext(MapControlsContext);\n\n const handleClick = (e: React.MouseEvent) => {\n if (disabled) return;\n if (onPress) onPress();\n if (context && context.setDrawerState) {\n context.setDrawerState(\"closed\");\n }\n };\n\n return (\n <button\n className={`flex items-center gap-3 w-full py-3 px-3.5 rounded-xl text-left cursor-pointer transition-all duration-150 ${\n disabled\n ? \"opacity-45 cursor-not-allowed pointer-events-none\"\n : \"hover:bg-white/5 active:bg-white/10 text-white\"\n }`}\n disabled={disabled}\n onClick={handleClick}\n type=\"button\"\n >\n {icon && (\n <div className=\"relative flex items-center justify-center w-8 h-8 rounded-lg bg-white/5 text-zinc-300\">\n {icon}\n {badge !== undefined && (\n <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\">\n {badge}\n </span>\n )}\n </div>\n )}\n <div className=\"flex-1 flex flex-col justify-center\">\n <span className=\"text-sm font-medium tracking-wide flex-1\">\n {label}\n </span>\n {children}\n </div>\n </button>\n );\n};\n\nMapMenu.displayName = \"MapMenu\";\nMapMenuItem.displayName = \"MapMenuItem\";\n\nexport interface MapMenuTitleProps {\n children: React.ReactNode;\n className?: string;\n showDivider?: boolean;\n}\n\nexport const MapMenuTitle: React.FC<MapMenuTitleProps> = ({\n children,\n showDivider = true,\n className = \"\",\n}) => {\n return (\n <div\n 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\" : \"\"}`}\n >\n {children}\n </div>\n );\n};\nMapMenuTitle.displayName = \"MapMenuTitle\";\n\nexport interface MapMenuDividerProps {\n className?: string;\n}\n\nexport const MapMenuDivider: React.FC<MapMenuDividerProps> = ({\n className = \"\",\n}) => {\n return <div className={`h-[1px] bg-white/10 my-3 mx-3.5 ${className}`} />;\n};\nMapMenuDivider.displayName = \"MapMenuDivider\";\n\nexport interface MapMenuFooterProps {\n children: React.ReactNode;\n className?: string;\n}\n\nexport const MapMenuFooter: React.FC<MapMenuFooterProps> = ({\n children,\n className = \"\",\n}) => {\n return (\n <div\n className={`mt-auto pt-4 border-t border-white/10 px-3.5 text-xs text-zinc-500 font-medium ${className}`}\n >\n {children}\n </div>\n );\n};\nMapMenuFooter.displayName = \"MapMenuFooter\";\n","import type {\n CornerDotType,\n CornerSquareType,\n DotType,\n ErrorCorrectionLevel,\n Gradient,\n ShapeType,\n} from \"qr-code-styling\";\n\n/**\n * UP Mini-App SDK Types\n */\n\n/**\n * Represents the user's profile information.\n */\nexport interface IUserProfile {\n /** Unique identifier for the user. */\n uuid: string;\n /** Full legal name of the user. */\n fullName: string;\n /** First name of the user. */\n firstName: string;\n /** Last name of the user. */\n lastName: string;\n /** Primary email address. */\n email?: string;\n /** Chosen username within the UP ecosystem. */\n username?: string;\n /** ISO country code (e.g., \"FR\", \"US\"). */\n countryCode: string;\n /** Phone number without country code. */\n localNumber: string;\n /** How the user's account was created/registered. */\n registrationType: \"up\" | \"apple\" | \"google\";\n /** Admin status. */\n admin: boolean;\n /** UP points balance. */\n ups: number;\n /** Experience points balance. */\n xp: number;\n /** ISO timestamp of user creation. */\n createdAt: string;\n /** ISO timestamp of last password update. */\n lastPasswordUpdate?: string;\n /** URL to profile picture. */\n avatarUrl?: string;\n /** UUID of profile picture. */\n avatarUuid?: string;\n /** URL to user badge. */\n badgeUrl?: string;\n /** UUID of user badge. */\n badgeUuid?: string;\n /** URL to user profile theme. */\n themeUrl?: string;\n /** UUID of user profile theme. */\n themeUuid?: string;\n}\n\n/**\n * Geographic location data.\n */\nexport interface ILocationData {\n coords: {\n /** Latitude in decimal degrees. */\n latitude: number;\n /** Longitude in decimal degrees. */\n longitude: number;\n /** Altitude in meters above the WGS 84 reference ellipsoid, or null if not available. */\n altitude: number | null;\n /** Accuracy of the latitude and longitude properties in meters. */\n accuracy: number | null;\n /** Accuracy of the altitude property in meters. */\n altitudeAccuracy: number | null;\n /** The direction in which the device is traveling, in degrees (0-360). */\n heading: number | null;\n /** The velocity of the device in meters per second. */\n speed: number | null;\n };\n /** The time at which the location was retrieved (Unix timestamp). */\n timestamp: number;\n}\n\n/**\n * Request payload for triggering a payment flow.\n */\nexport interface IPaymentRequest {\n /** The specific amount to charge. */\n amount: number;\n /** ISO currency code (e.g., \"EUR\", \"USD\"). */\n currency: string;\n /** Total amount including taxes/fees. */\n total: number;\n /** Itemized breakdown of the purchase. */\n items: Array<{\n /** Name or description of the item. */\n item: string;\n /** Price per unit. */\n price?: number;\n /** Number of units. */\n quantity?: number;\n }>;\n}\n\n/**\n * Style of haptic feedback.\n */\nexport type HapticStyleType =\n | \"light\"\n | \"medium\"\n | \"heavy\"\n | \"rigid\"\n | \"soft\"\n | \"success\"\n | \"warning\"\n | \"error\";\n\n/**\n * Network Proxy Types\n */\n\n/**\n * The HTTP method to use as request method\n */\nexport type NetworkMethodType = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n/**\n * Configuration for network proxy requests.\n */\nexport interface INetworkOptions {\n /** Full URL for the request. */\n url: string;\n /** HTTP method to use. */\n method: NetworkMethodType;\n /** Request body for POST/PUT/PATCH. */\n body?: unknown;\n /** Custom HTTP headers. */\n headers?: Record<string, string>;\n}\n\n/**\n * Response from a network proxy request.\n */\nexport interface INetworkResponse<T = unknown> {\n /** HTTP status code. */\n status: number;\n /** Response data payload. */\n data: T;\n /** Response headers. */\n headers: Headers;\n}\n\n/**\n * Fidelity & Rewards Types\n */\n\n/**\n * Fidelity program balance information.\n */\nexport interface IFidelityBalance {\n /** Current point or currency balance. */\n balance: number;\n /** Name or symbol of the fidelity currency (e.g., \"FPoints\"). */\n currency: string;\n}\n\n/**\n * Parameters for retrieving fidelity transaction history.\n */\nexport interface IFidelityHistoryParams {\n /** Maximum number of records to return. */\n limit?: number;\n\n /** Cursor for pagination; null for the first page. */\n cursor?: string | null;\n}\n\n/** Type of transaction: credit (add) or debit (remove). */\nexport type FidelityTransactionTypeType = \"credit\" | \"debit\";\n\n/**\n * A single fidelity program transaction.\n */\nexport interface IFidelityTransaction {\n /** Unique identifier for the transaction. */\n id: string;\n /** Amount of the transaction. */\n amount: number;\n /** Human-readable description. */\n description: string;\n /** ISO 8601 date string. */\n date: string;\n /** Type of transaction */\n type: FidelityTransactionTypeType;\n}\n\n/**\n * Achievement Types\n */\n\n/**\n * A player's progress towards a single named Achievement. The Hub tracks a\n * raw in-app action count per Achievement `slug` (reported server-to-server\n * by each mini-app's own backend — never by this SDK, see `sdk.achievement`/\n * `sdk.achievements` doc comments in `sdk.ts`) and auto-credits UP+XP once\n * `playerActionCount` reaches `totalActionCount`. This is a read-only view\n * for rendering progress (e.g. a progress bar) — there is no \"claim\" step.\n */\nexport interface IAchievement {\n /** Unique slug identifying the Achievement (e.g. \"explore-5-pois\"). */\n slug: string;\n /** Display title. */\n title: string;\n /** Display description. */\n description: string;\n /** The player's current raw in-app action count towards this Achievement. */\n playerActionCount: number;\n /** The action count required to complete this Achievement. */\n totalActionCount: number;\n /** UP points credited automatically once completed. */\n upReward: number;\n /** XP credited automatically once completed. */\n xpReward: number;\n /** Whether `playerActionCount` has reached `totalActionCount`. */\n completed: boolean;\n /** Optional illustration/icon URL. */\n imageUrl?: string;\n /**\n * Progression order among this mini-app's own Achievements — lower comes\n * first (1 = first Achievement a player should complete). Achievements\n * unlock sequentially: only the lowest-`priority` not-yet-`completed`\n * Achievement is actionable, every higher-`priority` one stays locked\n * until it completes. Ties are allowed (no uniqueness enforced).\n */\n priority: number;\n}\n\n/**\n * The initialization options required to set up the Mini-App SDK.\n */\nexport type IInitializationOptions = {\n /**\n * The Mini-App's own dark/light theme preference, applied by the host\n * immediately from the INITIALIZE payload — pass it here instead of a\n * separate `sdk.updateContext({isDark})` call right after `initialize()`\n * resolves, which left the host rendering its own theme for the whole\n * round-trip before flipping to the Mini-App's real one.\n */\n isDark?: boolean;\n};\n\n/**\n * The post initialization response\n */\nexport interface IInitializationResponse<\n Env extends Record<string, unknown> = Record<string, unknown>,\n UserData extends Record<string, unknown> = Record<string, unknown>,\n Params extends Record<string, unknown> = Record<string, unknown>,\n> {\n /** The name of the mini app */\n name: string;\n /** The uuid of the mini app */\n uuid: string;\n /** The description of the mini app */\n description: string;\n /** The authors of the mini app */\n authors?: string;\n /** The current version in the registry */\n version?: string;\n /** The scoped profile based on the requested fields during initialization or the getUserProfile call */\n profile: Partial<IUserProfile | null>;\n /** The environment variables defined for the mini app in the shell's backend */\n env: Env;\n /** The user data passed during the initialization or the setUserData call */\n userData: UserData;\n /** The params passed during the initialization */\n params: Params;\n /** The edge insets of the mini app, representing the padding around the mini app's view within the Host Shell. */\n insets: IEdgeInsets;\n}\n\n/**\n * Events emitted by the UI module.\n */\nexport enum UIEvent {\n /** Triggered when the user performs a native \"Pull-to-Refresh\". */\n TOP_SCROLL_MORE = \"TOP_SCROLL_MORE\",\n /** Triggered when the user scrolls near the bottom of the page (within 200px threshold). */\n BOTTOM_SCROLL_MORE = \"BOTTOM_SCROLL_MORE\",\n /** Triggered when the user performs a native back gesture or presses the native back button. */\n BACK_GESTURE = \"BACK_GESTURE\",\n}\n\n/**\n * Events emitted by the Geolocation module.\n */\nexport enum GeolocationEvent {\n /** Triggered when the user's location is updated (legacy polling). */\n LOCATION_UPDATE = \"LOCATION_UPDATE\",\n /** Triggered by the continuous location stream. */\n LOCATION_STREAM_UPDATE = \"LOCATION_STREAM_UPDATE\",\n}\n\n/**\n * Configuration options for the location stream.\n */\nexport interface LocationStreamConfig {\n /** Polling cycle rate in milliseconds. Default: 250 */\n interval?: number;\n /** Distance change in meters to trigger an update. Default: 5 */\n distanceFilter?: number;\n /** Heading change in degrees to trigger an update. Default: 5 */\n headingThreshold?: number;\n /** Accelerometer delta in G-force to trigger an update. Default: 0.1 */\n accelerometerThreshold?: number;\n}\n\nexport interface StreamLocationData {\n coords: {\n latitude: number;\n longitude: number;\n altitude: number | null;\n accuracy: number | null;\n altitudeAccuracy: number | null;\n heading: number | null;\n speed: number | null;\n };\n timestamp: number;\n}\n\nexport interface StreamHeadingData {\n magneticHeading: number;\n trueHeading: number;\n accuracy: number;\n}\n\nexport interface StreamAccelerometerData {\n x: number;\n y: number;\n z: number;\n}\n\nexport interface StreamUpdatePayload {\n location: StreamLocationData;\n heading: StreamHeadingData;\n accelerometer: StreamAccelerometerData | null;\n timestamp: number;\n}\n\n/**\n * Global events emitted by the Host Shell that may affect the mini-app's context.\n */\nexport enum GlobalEvent {\n /** Triggered when the Host Shell sends an update event to the mini-app, indicating changes in context. */\n UPDATE_CONTEXT = \"UPDATE_CONTEXT\",\n}\n\n/**\n * Union type for all SDK events, allowing for both known enums and custom strings.\n * The (string & {}) pattern preserves IntelliSense for enum members.\n */\nexport type SDKEvent = UIEvent | GeolocationEvent | GlobalEvent | (string & {});\n\n/**\n * Configuration for native scroll interactions managed by the Host Shell.\n */\nexport interface ScrollConfig {\n /** Configuration for Pull-to-Refresh (Top). */\n topScrollMore?: {\n /** Show/hide the native RefreshControl. */\n enabled: boolean;\n /** Set to true to show the loading spinner, false to hide it. */\n refreshing?: boolean;\n };\n /** Configuration for Infinite Scroll (Bottom). */\n bottomScrollMore?: {\n /** Enable/disable bottom scroll detection. */\n enabled: boolean;\n /** If false, detection stops and the indicator is hidden. */\n hasMore?: boolean;\n /** Set to true to show the bottom ActivityIndicator. */\n loadingMore?: boolean;\n };\n}\n\n/**\n * Result of a `sdk.media.saveImage` call.\n */\nexport interface ISaveImageResult {\n /** Whether the image was saved successfully. */\n success: boolean;\n}\n\n/**\n * Result of a `sdk.media.pickImage` call.\n */\nexport interface IPickImageResult {\n /** Whether an image was picked (false if permission was denied or the user canceled the picker). */\n success: boolean;\n /** Base64-encoded image data as a full data URI (e.g. `data:image/jpeg;base64,...`). Only set when `success` is true. */\n base64?: string;\n /** MIME type of the picked image (e.g. `image/jpeg`). Only set when `success` is true. */\n mimeType?: string;\n}\n\n/**\n * Options for `sdk.qrCode.generate`.\n */\nexport interface IGenerateQrCodeOptions {\n /** Square size of the QR code itself, in px. Default 512. */\n size?: number;\n /**\n * Mini-app name shown as a \"UP - <appName>\" label above the QR code (e.g.\n * the `name` field from `sdk.initialize()`'s response). Ignored if `label`\n * is also set. Omit both for no label.\n */\n appName?: string;\n /**\n * Explicit label text, overriding the \"UP - <appName>\" auto-format. Pass\n * an empty string (or omit both this and `appName`) for no label.\n */\n label?: string;\n /** Dot/corner color. Default a neutral dark gray — kept theme-agnostic since this SDK serves every mini-app, not just one product's brand. */\n color?: string;\n /** Background color behind the QR (and the label, if any). Default white. */\n backgroundColor?: string;\n /** Optional center logo, as a URL or base64 data URI. */\n logo?: string;\n /** Overall QR frame shape. Default \"square\". */\n shape?: ShapeType;\n /** Quiet-zone margin around the raw QR modules, in px. Default 0. */\n margin?: number;\n /** Error correction level — higher tolerates more damage/logo overlap at the cost of density. Default \"Q\". */\n errorCorrectionLevel?: ErrorCorrectionLevel;\n /** Dot module style. Default \"extra-rounded\". */\n dotsType?: DotType;\n /** Gradient for the dots — overrides `color` for the dots when set. */\n dotsGradient?: Gradient;\n /** Corner square (the 3 big position markers) style. Default \"extra-rounded\". */\n cornersSquareType?: CornerSquareType;\n /** Corner square color override. Defaults to `color`. */\n cornersSquareColor?: string;\n /** Gradient for the corner squares — overrides the corner square color when set. */\n cornersSquareGradient?: Gradient;\n /** Corner dot (the small dot inside each position marker) style. Default \"dot\". */\n cornersDotType?: CornerDotType;\n /** Corner dot color override. Defaults to `color`. */\n cornersDotColor?: string;\n /** Gradient for the corner dots — overrides the corner dot color when set. */\n cornersDotGradient?: Gradient;\n /** Gradient for the background — overrides `backgroundColor` when set. */\n backgroundGradient?: Gradient;\n /** Hide the QR dots directly behind the logo. Default true when `logo` is set. */\n hideBackgroundDots?: boolean;\n /** Logo size, as a fraction of the QR width (0-1). Default 0.4. */\n logoSize?: number;\n /** Blank margin around the logo, in px. Default 4. */\n logoMargin?: number;\n /**\n * Extra padding, in px, wrapped around the ENTIRE generated image (the QR\n * code plus the label band, if any) — same `backgroundColor` fill on all\n * four sides. Distinct from `margin`, which is `qr-code-styling`'s own\n * internal quiet-zone around just the QR modules. Default 32.\n */\n outerPadding?: number;\n /**\n * The final generated image is ALWAYS a square (padded on the shorter\n * side to force it, even when a label band makes the QR+label content\n * taller than it is wide) — this is the corner radius applied to that\n * square, as a PERCENTAGE of its side length (0-50, like CSS\n * `border-radius: N%` on a square element), not raw px. The area outside\n * the rounded corners is left transparent, not `backgroundColor`-filled.\n * Set to 0 for sharp corners, 50 for a full circle. Default 6.\n */\n borderRadius?: number;\n}\n\n/**\n * Edge insets representing padding or margins around a component, typically used for layout purposes.\n */\nexport interface IEdgeInsets {\n top: number;\n right: number;\n bottom: number;\n left: number;\n}\n\n/**\n * The context state of the mini-app, which includes dynamic properties provided by the Host Shell, such as edge insets for layout adjustments. This type can be extended with additional properties as needed.\n */\nexport type IContextState = Record<string, any> & {\n insets: IEdgeInsets;\n};\n","import { sdk } from \"@miniapps-sdk/sdk\";\nimport { GeolocationEvent } from \"@miniapps-sdk/types\";\nimport { useEffect, useState } from \"react\";\n\nexport interface UserLocationState {\n coords: [number, number] | null;\n heading: number | null;\n accuracy: number | null;\n}\n\n/**\n * Smoothing factor for interpolation.\n * Higher = faster/snappier (less lag, more jitter)\n * Lower = smoother/slower (more lag, zero jitter)\n */\nconst LERP_FACTOR = 0.12;\n\nconst EMPTY_STATE: UserLocationState = {\n accuracy: null,\n coords: null,\n heading: null,\n};\n\nfunction mapPayload(payload: any): UserLocationState {\n const coords = payload.location?.coords || payload.coords;\n const headingData = payload.heading;\n\n const newCoords: [number, number] | null = coords\n ? [coords.longitude, coords.latitude]\n : null;\n\n let heading = null;\n if (headingData?.trueHeading !== undefined && headingData.trueHeading >= 0) {\n heading = headingData.trueHeading;\n } else if (\n headingData?.magneticHeading !== undefined &&\n headingData.magneticHeading >= 0\n ) {\n heading = headingData.magneticHeading;\n } else if (headingData?.heading !== null && headingData?.heading >= 0) {\n heading = headingData.heading;\n }\n\n return {\n accuracy: coords?.accuracy || null,\n coords: newCoords,\n heading,\n };\n}\n\n/**\n * Module-level singleton: the native GPS stream (sdk.location.startStream /\n * stopStream) and its RAF interpolation loop are shared by EVERY\n * useUserLocation() call in the app, not one per call site.\n *\n * Bug fixed 2026-08-26: this hook is called concurrently from several\n * independent places at once (this SDK's own Map.tsx for the user-location\n * marker, plus each consumer app's own screens/buttons — up-miniapps-explore\n * alone had 4 concurrent instances). Each instance used to own a fully\n * independent stream lifecycle with NO reference counting — every mount\n * called the native startStream() and every unmount called the native\n * stopStream(), both GLOBAL signals to the host shell. Whenever any ONE\n * instance unmounted (e.g. a consumer remounting its map subtree on a\n * retry-after-timeout flow) while others stayed mounted, its stopStream()\n * could race ahead of another instance's startStream() (both are\n * independent async bridge round-trips with no ordering guarantee across\n * instances) and silently kill GPS delivery for the whole app — nothing\n * surfaces an error, every remaining consumer just stops receiving\n * location updates and freezes on the last known position. Fixed by\n * owning the stream here: it starts once, on the first mount across the\n * whole app, and stops only when the LAST consumer unmounts.\n */\nlet refCount = 0;\n// Bumped every time startSharedStream() runs. Guards the async\n// getCurrentPosition() fetch below, which has no cancellation of its own —\n// without this, a promise from a PREVIOUS stream generation (e.g. the one\n// torn down by a retry-remount) can resolve after stopSharedStream() has\n// already reset targetState, or worse, after a brand-new generation has\n// already fetched fresh data — clobbering it with stale coordinates.\nlet generation = 0;\nconst subscribers = new Set<(state: UserLocationState) => void>();\nlet targetState: UserLocationState = { ...EMPTY_STATE };\nlet currentInterpolated: {\n coords: [number, number] | null;\n heading: number | null;\n} = { coords: null, heading: null };\nlet rafId: number | null = null;\nlet unsubscribeStream: (() => void) | null = null;\nlet unsubscribeLegacy: (() => void) | null = null;\n\nfunction getSnapshot(): UserLocationState {\n return {\n accuracy: targetState.accuracy,\n coords: currentInterpolated.coords ? [...currentInterpolated.coords] : null,\n heading: currentInterpolated.heading,\n };\n}\n\nfunction notify() {\n const snapshot = getSnapshot();\n for (const callback of subscribers) callback(snapshot);\n}\n\nfunction animate() {\n let changed = false;\n\n // 1. Interpolate Coords\n if (targetState.coords) {\n if (!currentInterpolated.coords) {\n currentInterpolated.coords = [...targetState.coords];\n changed = true;\n } else {\n const [tLng, tLat] = targetState.coords;\n const [cLng, cLat] = currentInterpolated.coords;\n\n const nLng = cLng + (tLng - cLng) * LERP_FACTOR;\n const nLat = cLat + (tLat - cLat) * LERP_FACTOR;\n\n // Only update if difference is significant to save cycles\n if (Math.abs(nLng - cLng) > 1e-7 || Math.abs(nLat - cLat) > 1e-7) {\n currentInterpolated.coords = [nLng, nLat];\n changed = true;\n }\n }\n }\n\n // 2. Interpolate Heading (Shortest Path)\n if (targetState.heading !== null) {\n if (currentInterpolated.heading === null) {\n currentInterpolated.heading = targetState.heading;\n changed = true;\n } else {\n const target = targetState.heading;\n const current = currentInterpolated.heading;\n\n // Find shortest delta (handle 0/360 wrap)\n let delta = target - current;\n if (delta > 180) delta -= 360;\n if (delta < -180) delta += 360;\n\n const nHeading = current + delta * LERP_FACTOR;\n // Normalize to [0, 360)\n const normalized = ((nHeading % 360) + 360) % 360;\n\n if (Math.abs(delta) > 0.1) {\n currentInterpolated.heading = normalized;\n changed = true;\n }\n }\n }\n\n if (changed) notify();\n\n rafId = requestAnimationFrame(animate);\n}\n\nfunction startSharedStream() {\n rafId = requestAnimationFrame(animate);\n\n generation++;\n const thisGeneration = generation;\n\n // Initial fetch\n sdk.location\n .getCurrentPosition()\n .then((data) => {\n if (thisGeneration !== generation) return;\n targetState = mapPayload(data);\n })\n .catch((e) => console.warn(\"Initial location fetch failed\", e));\n\n unsubscribeStream = sdk.on(\n GeolocationEvent.LOCATION_STREAM_UPDATE,\n (payload: any) => {\n targetState = mapPayload(payload);\n },\n );\n\n unsubscribeLegacy = sdk.on(\n GeolocationEvent.LOCATION_UPDATE,\n (payload: any) => {\n targetState = mapPayload(payload);\n },\n );\n\n sdk.location\n .startStream({\n distanceFilter: 1,\n headingThreshold: 2,\n })\n .catch((e) => console.warn(\"Failed to start location stream\", e));\n}\n\nfunction stopSharedStream() {\n generation++;\n if (rafId !== null) cancelAnimationFrame(rafId);\n rafId = null;\n unsubscribeStream?.();\n unsubscribeLegacy?.();\n unsubscribeStream = null;\n unsubscribeLegacy = null;\n sdk.location.stopStream().catch(() => {});\n targetState = { ...EMPTY_STATE };\n currentInterpolated = { coords: null, heading: null };\n}\n\nexport const useUserLocation = () => {\n const [locationState, setLocationState] =\n useState<UserLocationState>(getSnapshot);\n\n useEffect(() => {\n refCount++;\n if (refCount === 1) {\n startSharedStream();\n } else {\n // Stream is already live — sync immediately instead of this consumer\n // starting from a blank state and waiting for the next RAF tick.\n setLocationState(getSnapshot());\n }\n\n subscribers.add(setLocationState);\n\n return () => {\n subscribers.delete(setLocationState);\n refCount--;\n if (refCount === 0) {\n stopSharedStream();\n }\n };\n }, []);\n\n return locationState;\n};\n","import { useUserLocation } from \"@miniapps-sdk/components/Map/hooks/useUserLocation\";\nimport { sdk } from \"@miniapps-sdk/sdk\";\nimport type { RouteResponse } from \"@miniapps-sdk/types\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nexport interface LiveRoutingOptions {\n /** Origin coordinates [lng, lat]. If not provided, uses device location. */\n origin?: [number, number] | null;\n /** Destination coordinates [lng, lat] */\n destination: [number, number] | null;\n /** Transport profile. Defaults to 'driving'. */\n profile?: \"driving\" | \"cycling\" | \"walking\";\n /** Minimum distance in meters the user must move before recalculating path geometry. Defaults to 50. */\n recalculateThreshold?: number;\n /** Whether live routing is active. */\n enabled?: boolean;\n /** Initial mode: 'preview' or 'navigation'. Defaults to 'preview'. */\n initialMode?: \"preview\" | \"navigation\";\n}\n\nexport interface LiveRoutingResult {\n /** The calculated route data from the last API call */\n route: RouteResponse[\"data\"] | null;\n /** Real-time distance to destination in meters */\n currentDistanceMeters: number | null;\n /** The initial total distance when the destination was first set */\n totalDistance: number | null;\n /** Whether a new calculation is in progress */\n isCalculating: boolean;\n /** Any error message from the routing service */\n error: string | null;\n /** Force a manual recalculation */\n recalculate: () => void;\n /** Current mode: 'preview' (overview) or 'navigation' (active guidance) */\n mode: \"preview\" | \"navigation\";\n /** Start active navigation (switch mode to 'navigation') */\n start: () => void;\n}\n\nexport const useLiveRouting = ({\n origin: manualOrigin,\n destination,\n profile = \"driving\",\n recalculateThreshold = 50,\n enabled = true,\n initialMode = \"preview\",\n}: LiveRoutingOptions): LiveRoutingResult => {\n const [route, setRoute] = useState<RouteResponse[\"data\"] | null>(null);\n const [totalDistance, setTotalDistance] = useState<number | null>(null);\n const [isCalculating, setIsCalculating] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [mode, setMode] = useState<\"preview\" | \"navigation\">(initialMode);\n\n const userLocationState = useUserLocation();\n // calculationOrigin: used for the route API call (can be a fixed start point)\n // trackingLocation: always live GPS — used for real-time distance/progress tracking\n const calculationOrigin = manualOrigin || userLocationState.coords;\n const trackingLocation = userLocationState.coords || manualOrigin;\n\n const lastCalcOrigin = useRef<[number, number] | null>(null);\n const lastCalcDest = useRef<[number, number] | null>(null);\n const isRequestInProgress = useRef(false);\n // Tracks the destination we've already reset `mode` for — separate from\n // lastCalcDest (which only updates once the async calculate() resolves),\n // so the mode reset happens exactly once per new destination instead of\n // repeating on every subsequent effect re-run (e.g. every GPS tick) while\n // the route calculation is still in flight.\n const lastResetDestKey = useRef<string | null>(null);\n\n // Helper to calculate distance between two points (Haversine)\n const getDistance = useCallback(\n (p1: [number, number], p2: [number, number]) => {\n const R = 6371e3; // meters\n const φ1 = (p1[1] * Math.PI) / 180;\n const φ2 = (p2[1] * Math.PI) / 180;\n const Δφ = ((p2[1] - p1[1]) * Math.PI) / 180;\n const Δλ = ((p2[0] - p1[0]) * Math.PI) / 180;\n\n const a =\n Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +\n Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ / 2) * Math.sin(Δλ / 2);\n const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n\n return R * c;\n },\n [],\n );\n\n // Real-time distance calculation along route coordinates.\n // ALWAYS uses trackingLocation (live GPS), never the fixed manualOrigin,\n // so it updates as the user physically moves.\n const currentDistanceMeters = useMemo(() => {\n if (!trackingLocation || !route || route.geometry.coordinates.length < 2) {\n if (trackingLocation && destination) {\n return getDistance(trackingLocation, destination);\n }\n return null;\n }\n\n const coords = route.geometry.coordinates as [number, number][];\n\n // Find the coordinate on the route closest to the user's live position\n let minDistSq = Infinity;\n let closestIndex = 0;\n\n const getDistSq = (p1: [number, number], p2: [number, number]) =>\n (p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2;\n\n for (let i = 0; i < coords.length; i++) {\n const d = getDistSq(trackingLocation, coords[i] as [number, number]);\n if (d < minDistSq) {\n minDistSq = d;\n closestIndex = i;\n }\n }\n\n // Sum distance along remaining route segments starting from the user's exact position\n const remainingCoords = coords.slice(closestIndex + 1);\n let dist = 0;\n let prev: [number, number] = trackingLocation;\n for (const coord of remainingCoords) {\n dist += getDistance(prev, coord as [number, number]);\n prev = coord as [number, number];\n }\n return dist;\n }, [trackingLocation, route, destination, getDistance]);\n\n const calculate = useCallback(\n async (\n origin: [number, number],\n dest: [number, number],\n isNewDest: boolean,\n ) => {\n if (isRequestInProgress.current) return;\n\n isRequestInProgress.current = true;\n setIsCalculating(true);\n\n try {\n const data = await sdk.routing.getRoute({\n destination: dest,\n origin,\n profile,\n });\n\n setRoute(data);\n setError(null);\n\n if (isNewDest) {\n const coords = data.geometry.coordinates;\n let sum = 0;\n for (let i = 0; i < coords.length - 1; i++) {\n sum += getDistance(\n coords[i] as [number, number],\n coords[i + 1] as [number, number],\n );\n }\n setTotalDistance(sum);\n }\n\n lastCalcOrigin.current = origin;\n lastCalcDest.current = dest;\n } catch (err: any) {\n setError(err.message || \"Failed to fetch route\");\n } finally {\n setIsCalculating(false);\n isRequestInProgress.current = false;\n }\n },\n [profile, getDistance],\n );\n\n useEffect(() => {\n if (initialMode === \"navigation\") {\n setMode(\"navigation\");\n }\n }, [initialMode]);\n\n useEffect(() => {\n if (!enabled || !destination || !calculationOrigin) {\n if (!enabled || !destination) {\n setRoute(null);\n setTotalDistance(null);\n lastCalcOrigin.current = null;\n lastCalcDest.current = null;\n lastResetDestKey.current = null;\n // A journey that's disabled/cleared (e.g. cancelled) must always\n // come back in preview mode next time — never resume mid-navigation.\n setMode(initialMode);\n }\n return;\n }\n\n const destChanged =\n !lastCalcDest.current ||\n lastCalcDest.current[0] !== destination[0] ||\n lastCalcDest.current[1] !== destination[1];\n\n // A new destination is a brand-new journey — always start it in preview.\n // Gated on a key separate from lastCalcDest (which only updates once the\n // async calculate() resolves) so this fires exactly once per destination,\n // not on every subsequent effect re-run while destChanged is still true.\n const destKey = `${destination[0]},${destination[1]}`;\n if (lastResetDestKey.current !== destKey) {\n lastResetDestKey.current = destKey;\n setMode(initialMode);\n }\n\n if (destChanged) {\n calculate(calculationOrigin, destination, true);\n } else if (lastCalcOrigin.current) {\n // Recalculate route geometry only if user drifted far from last calc origin\n const livePos = trackingLocation || calculationOrigin;\n const dist = getDistance(livePos, lastCalcOrigin.current);\n if (dist > recalculateThreshold) {\n calculate(livePos, destination, false);\n }\n } else {\n calculate(calculationOrigin, destination, true);\n }\n }, [\n calculationOrigin,\n trackingLocation,\n destination,\n enabled,\n initialMode,\n recalculateThreshold,\n calculate,\n getDistance,\n ]);\n\n return {\n currentDistanceMeters,\n error,\n isCalculating,\n mode,\n recalculate: () =>\n calculationOrigin &&\n destination &&\n calculate(calculationOrigin, destination, false),\n route,\n start: () => setMode(\"navigation\"),\n totalDistance,\n };\n};\n\n/**\n * A simple hook to fetch a route once between two points.\n * Does not automatically recalculate or track user location.\n */\nexport const useRoute = (\n origin: [number, number] | null,\n destination: [number, number] | null,\n profile: \"driving\" | \"cycling\" | \"walking\" = \"driving\",\n) => {\n const [route, setRoute] = useState<RouteResponse[\"data\"] | null>(null);\n const [isCalculating, setIsCalculating] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!origin || !destination) {\n setRoute(null);\n return;\n }\n\n const fetchRoute = async () => {\n setIsCalculating(true);\n try {\n const data = await sdk.routing.getRoute({\n destination,\n origin,\n profile,\n });\n setRoute(data);\n setError(null);\n } catch (err: any) {\n setError(err.message || \"Failed to fetch route\");\n } finally {\n setIsCalculating(false);\n }\n };\n\n fetchRoute();\n }, [origin, destination, profile]);\n\n return { error, isCalculating, route };\n};\n","import {\n type LiveRoutingOptions,\n useLiveRouting,\n} from \"@miniapps-sdk/components/Map/hooks/useLiveRouting\";\nimport { sdk } from \"@miniapps-sdk/sdk\";\nimport type { RouteResponse } from \"@miniapps-sdk/types\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\ntype NavMode = \"preview\" | \"navigation\";\n\nexport interface DeclarativeJourneyOptions {\n /** Destination coordinates [lng, lat] */\n destination: [number, number] | null;\n /** Transport profile. Defaults to 'driving'. */\n profile?: LiveRoutingOptions[\"profile\"];\n /** Minimum distance in meters the user must move before recalculating path geometry. Defaults to 50. */\n recalculateThreshold?: number;\n /** Optional manual origin. Defaults to real-time user location. */\n origin?: [number, number] | null;\n /** Initial mode. 'preview' shows the route overview, 'navigation' starts active guidance. Defaults to 'preview'. */\n mode?: NavMode;\n}\n\nexport interface UseJourneyOptions {\n /**\n * Declarative journey configuration. If provided, this hook manages route\n * calculation/tracking itself — equivalent to the `navigation` prop on `<Map/>`.\n * Omit this to instead drive the journey imperatively via `sdk.navigation.*`\n * (createJourney/start/abort), e.g. from elsewhere in the app or from `<Map/>` itself.\n */\n navigation?: DeclarativeJourneyOptions;\n /** Called whenever the journey is cancelled/aborted. */\n onAbort?: () => void;\n /** Called whenever the mode changes (e.g. preview -> navigation). */\n onModeChange?: (mode: NavMode) => void;\n}\n\nexport interface UseJourneyResult {\n /** Whether a journey (preview or navigation) is currently active. */\n isActive: boolean;\n /** Current mode: 'preview' (route overview) or 'navigation' (active guidance). */\n mode: NavMode;\n /** The calculated route geometry/data, or null if none. */\n route: RouteResponse[\"data\"] | null;\n /** Whether a route calculation is in flight. */\n isCalculating: boolean;\n /** Routing error message, if any. */\n error: string | null;\n /** Real-time remaining distance to destination, in meters. */\n distanceRemainingMeters: number | null;\n /** Real-time remaining distance to destination, in kilometers. */\n distanceRemainingKm: number;\n /** The total distance of the route when the destination was first set, in meters. */\n totalDistanceMeters: number | null;\n /** Estimated remaining time, in minutes, scaled proportionally to remaining distance. */\n etaMinutes: number;\n /** Journey completion progress, 0-100. */\n progress: number;\n /** Switch from 'preview' to active 'navigation' guidance. */\n start: () => void;\n /** Cancel the journey entirely. Always returns to 'preview' the next time a journey starts. */\n cancel: () => void;\n /** Force a manual route recalculation. */\n recalculate: () => void;\n}\n\n/**\n * Everything related to a map journey — preview, active navigation, and ETA —\n * exposed as plain data and actions so devs can build their own preview/journey\n * panel instead of using the SDK's built-in one.\n *\n * Stays in sync with `<Map/>`'s built-in navigation UI: both this hook and\n * `<Map/>` react to the same `sdk.navigation.*` imperative events, so you can\n * use `useJourney()` to drive a fully custom UI while `<Map/>` handles the\n * route line/camera, or use it standalone with the `navigation` option.\n */\nexport const useJourney = (\n options: UseJourneyOptions = {},\n): UseJourneyResult => {\n const { navigation, onAbort, onModeChange } = options;\n\n const [progNav, setProgNav] = useState<{\n destination: [number, number] | null;\n origin?: [number, number] | null;\n profile?: LiveRoutingOptions[\"profile\"];\n mode?: NavMode;\n recalculateThreshold?: number;\n } | null>(null);\n const [isAborted, setIsAborted] = useState(false);\n\n useEffect(() => {\n const unsubCreate = sdk.on(\"SDK_NAVIGATION_CREATE\", (payload: any) => {\n setIsAborted(false);\n setProgNav(payload);\n });\n const unsubStart = sdk.on(\"SDK_NAVIGATION_START\", () => {\n setIsAborted(false);\n setProgNav((prev) => (prev ? { ...prev, mode: \"navigation\" } : null));\n });\n const unsubAbort = sdk.on(\"SDK_NAVIGATION_ABORT\", () => {\n setIsAborted(true);\n setProgNav(null);\n });\n\n return () => {\n unsubCreate();\n unsubStart();\n unsubAbort();\n };\n }, []);\n\n const effectiveOptions = progNav || navigation;\n\n const internalNav = useLiveRouting({\n destination: effectiveOptions?.destination || null,\n enabled: !isAborted && !!effectiveOptions?.destination,\n initialMode: effectiveOptions?.mode || \"preview\",\n origin: effectiveOptions?.origin,\n profile: effectiveOptions?.profile || \"driving\",\n recalculateThreshold: effectiveOptions?.recalculateThreshold || 50,\n });\n\n // Reset isAborted whenever a genuinely new destination comes in — a fresh\n // journey should never inherit the aborted flag from a previous one.\n const prevDest = useRef<[number, number] | null | undefined>(null);\n const currentDest = effectiveOptions?.destination;\n useEffect(() => {\n if (\n currentDest &&\n (!prevDest.current ||\n prevDest.current[0] !== currentDest[0] ||\n prevDest.current[1] !== currentDest[1])\n ) {\n setIsAborted(false);\n }\n prevDest.current = currentDest;\n }, [currentDest]);\n\n const onModeChangeRef = useRef(onModeChange);\n onModeChangeRef.current = onModeChange;\n useEffect(() => {\n onModeChangeRef.current?.(internalNav.mode);\n }, [internalNav.mode]);\n\n const isActive = !isAborted && !!effectiveOptions?.destination;\n\n const distanceRemainingMeters = isActive\n ? internalNav.currentDistanceMeters\n : null;\n const totalDistanceMeters = isActive ? internalNav.totalDistance : null;\n const routeDurationSeconds = internalNav.route?.durationSeconds ?? null;\n\n const remainingMeters = distanceRemainingMeters ?? 0;\n const distanceRemainingKm = remainingMeters / 1000;\n\n const etaMinutes = (() => {\n if (\n !routeDurationSeconds ||\n !totalDistanceMeters ||\n !distanceRemainingMeters\n )\n return 0;\n const ratio = distanceRemainingMeters / totalDistanceMeters;\n return Math.ceil((routeDurationSeconds * ratio) / 60);\n })();\n\n const progress =\n totalDistanceMeters && totalDistanceMeters > 0\n ? Math.min(\n 100,\n Math.max(\n 0,\n ((totalDistanceMeters - remainingMeters) / totalDistanceMeters) *\n 100,\n ),\n )\n : 0;\n\n const cancel = useCallback(() => {\n setIsAborted(true);\n setProgNav(null);\n sdk.navigation.abort();\n if (onAbort) onAbort();\n }, [onAbort]);\n\n const start = useCallback(() => {\n sdk.navigation.start();\n internalNav.start();\n }, [internalNav.start]);\n\n return {\n cancel,\n distanceRemainingKm,\n distanceRemainingMeters,\n error: isActive ? internalNav.error : null,\n etaMinutes,\n isActive,\n isCalculating: isActive ? internalNav.isCalculating : false,\n mode: isActive ? internalNav.mode : \"preview\",\n progress,\n recalculate: internalNav.recalculate,\n route: isActive ? internalNav.route : null,\n start,\n totalDistanceMeters,\n };\n};\n","import { useMemo } from \"react\";\n\n/**\n * Slices a LineString to start at the point closest to the provided coordinates.\n * This removes the \"already traveled\" portion of the route.\n */\nexport const useTrimmedRoute = (\n route: GeoJSON.LineString | undefined,\n userLocation: [number, number] | null,\n): GeoJSON.LineString | undefined => {\n return useMemo(() => {\n if (!route || !userLocation || route.coordinates.length < 2) return route;\n\n const coords = route.coordinates as [number, number][];\n\n // 1. Find the index of the segment closest to the user\n let minDistance = Infinity;\n let closestIndex = 0;\n\n const getDistSq = (p1: [number, number], p2: [number, number]) => {\n return (p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2;\n };\n\n // We search for the point in the original geometry closest to the user\n for (let i = 0; i < coords.length; i++) {\n const dist = getDistSq(userLocation, coords[i]);\n if (dist < minDistance) {\n minDistance = dist;\n closestIndex = i;\n }\n }\n\n // 2. Slice the route from that point onwards\n // We also prepend the ACTUAL user location to ensure the line starts exactly at the blue dot\n const remainingCoords = coords.slice(closestIndex + 1);\n\n return {\n coordinates: [userLocation, ...remainingCoords],\n type: \"LineString\",\n };\n }, [route, userLocation]);\n};\n","import { Layer, Source } from \"@vis.gl/react-maplibre\";\nimport type React from \"react\";\n\nexport interface RouteLayerProps {\n /** The route geometry as a GeoJSON LineString */\n geometry?: GeoJSON.LineString;\n /** Color of the route line. Defaults to #3b82f6 (blue-500). */\n color?: string;\n /** Width of the route line. Defaults to 5. */\n width?: number;\n /** Opacity of the route line. Defaults to 0.8. */\n opacity?: number;\n}\n\nexport const RouteLayer: React.FC<RouteLayerProps> = ({\n geometry,\n color = \"#3b82f6\",\n width = 5,\n opacity = 0.8,\n}) => {\n if (!geometry) return null;\n\n const data: GeoJSON.Feature<GeoJSON.LineString> = {\n geometry,\n properties: {},\n type: \"Feature\",\n };\n\n return (\n <Source data={data} id=\"sdk-route-source\" type=\"geojson\">\n <Layer\n id=\"sdk-route-layer-casing\"\n paint={{\n \"line-blur\": 1,\n \"line-color\": \"#ffffff\",\n \"line-opacity\": opacity,\n \"line-width\": width + 2,\n }}\n type=\"line\"\n />\n <Layer\n id=\"sdk-route-layer\"\n layout={{\n \"line-cap\": \"round\",\n \"line-join\": \"round\",\n }}\n paint={{\n \"line-color\": color,\n \"line-opacity\": opacity,\n \"line-width\": width,\n }}\n type=\"line\"\n />\n </Source>\n );\n};\n","const EARTH_RADIUS_METERS = 6371000;\n\n/**\n * Builds an approximate geodesic circle polygon (GeoJSON) around a\n * [lng, lat] center for a given radius in meters. Used to render a\n * real-world-scaled radius overlay (e.g. the mock geolocation \"scan\n * radius\" helper) on the map — a fixed-pixel circle would not scale\n * correctly across zoom levels or latitudes.\n */\nexport const buildGeoCircle = (\n center: [number, number],\n radiusMeters: number,\n points = 64,\n): GeoJSON.Feature<GeoJSON.Polygon> => {\n const [lng, lat] = center;\n const latRad = (lat * Math.PI) / 180;\n const coordinates: [number, number][] = [];\n\n for (let i = 0; i <= points; i++) {\n const angle = (i / points) * 2 * Math.PI;\n const dLat =\n ((radiusMeters * Math.cos(angle)) / EARTH_RADIUS_METERS) *\n (180 / Math.PI);\n const dLng =\n ((radiusMeters * Math.sin(angle)) /\n (EARTH_RADIUS_METERS * Math.cos(latRad))) *\n (180 / Math.PI);\n coordinates.push([lng + dLng, lat + dLat]);\n }\n\n return {\n geometry: {\n coordinates: [coordinates],\n type: \"Polygon\",\n },\n properties: {},\n type: \"Feature\",\n };\n};\n","import { buildGeoCircle } from \"@miniapps-sdk/components/Map/utils/geoCircle\";\nimport { Layer, Source } from \"@vis.gl/react-maplibre\";\nimport type React from \"react\";\nimport { useMemo } from \"react\";\n\nexport interface MockRadiusLayerProps {\n center: [number, number];\n radiusMeters: number;\n color?: string;\n}\n\n/**\n * Dev-only visual aid drawn around the mocked user location, showing the\n * real-world distance (in meters) configured in the BridgeMocker's radius\n * slider — useful to eyeball whether a point-of-interest sits within a\n * \"scan\" radius (e.g. Explore's /explore/scan unlock distance) before\n * wiring up real GPS.\n */\nexport const MockRadiusLayer: React.FC<MockRadiusLayerProps> = ({\n center,\n radiusMeters,\n // Neutral gray, not any one app's accent color — this debug aid is shared\n // across every mini-app (each with its own, different palette), so it\n // shouldn't default to a color that reads as \"part of the app\" (was\n // #39ff88, a neon green/yellow left over from an earlier shared theme,\n // reported as looking like an unwanted yellow border around the user's\n // position marker in up-miniapps-explore, which has since moved to a\n // pastel palette with no neon accents at all).\n color = \"#e2e8f0\",\n}) => {\n const data = useMemo(\n () => buildGeoCircle(center, radiusMeters),\n [center, radiusMeters],\n );\n\n return (\n <Source data={data} id=\"sdk-mock-radius-source\" type=\"geojson\">\n <Layer\n id=\"sdk-mock-radius-fill\"\n paint={{\n \"fill-color\": color,\n \"fill-opacity\": 0.12,\n }}\n type=\"fill\"\n />\n <Layer\n id=\"sdk-mock-radius-outline\"\n paint={{\n \"line-color\": color,\n \"line-dasharray\": [2, 2],\n \"line-width\": 2,\n }}\n type=\"line\"\n />\n </Source>\n );\n};\n","import type { POI } from \"@miniapps-sdk/components/Map/types\";\nimport { Layer, Source, useMap } from \"@vis.gl/react-maplibre\";\nimport type React from \"react\";\nimport { useEffect, useMemo, useState } from \"react\";\n\n/**\n * Utility to render an emoji to ImageData for use as a MapLibre icon\n */\nfunction createEmojiIcon(emoji: string, size = 64): ImageData {\n const canvas = document.createElement(\"canvas\");\n canvas.width = size;\n canvas.height = size;\n const ctx = canvas.getContext(\"2d\")!;\n ctx.font = `${size * 0.75}px serif`;\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n ctx.fillText(emoji, size / 2, size / 2);\n return ctx.getImageData(0, 0, size, size);\n}\n\nexport const POILayers: React.FC<{\n pois: POI[];\n}> = ({ pois }) => {\n const [loadedImages, setLoadedImages] = useState<number>(0);\n const { current: map } = useMap();\n\n // Filter for GL-mode POIs - stable memoized list\n const glPois = useMemo(\n () => pois.filter((p) => !p.displayMode || p.displayMode === \"gl\"),\n [pois],\n );\n\n useEffect(() => {\n if (!map) return;\n const glMap = map.getMap();\n\n // Built-in default emoji icons\n const defaults = [\n { emoji: \"🍺\", name: \"sdk-default-bar\" },\n { emoji: \"🍽️\", name: \"sdk-default-restaurant\" },\n { emoji: \"📍\", name: \"sdk-default-poi\" },\n ];\n\n defaults.forEach((def) => {\n if (!glMap.hasImage(def.name)) {\n glMap.addImage(def.name, createEmojiIcon(def.emoji), { pixelRatio: 2 });\n }\n });\n\n // Handle custom image URLs and custom emojis\n let updates = 0;\n glPois.forEach((poi) => {\n // 1. Custom URL Image\n if (poi.imageUrl) {\n const name = `custom-url-${poi.id}`;\n if (!glMap.hasImage(name)) {\n (glMap.loadImage as any)(poi.imageUrl, (error: any, image: any) => {\n if (!error && image) {\n if (!glMap.hasImage(name)) {\n glMap.addImage(name, image);\n setLoadedImages((prev) => prev + 1);\n }\n }\n });\n }\n }\n\n // 2. Custom Emoji Icon\n if (poi.emoji) {\n const name = `custom-emoji-${poi.emoji}`;\n if (!glMap.hasImage(name)) {\n glMap.addImage(name, createEmojiIcon(poi.emoji), { pixelRatio: 2 });\n updates++;\n }\n }\n });\n\n if (updates > 0) {\n setLoadedImages((prev) => prev + updates);\n }\n }, [map, glPois]);\n\n const geojson: any = useMemo(\n () => ({\n features: glPois.map((poi) => ({\n geometry: {\n coordinates: [poi.longitude, poi.latitude],\n type: \"Point\" as const,\n },\n properties: {\n ...poi,\n // Selection logic for the icon in GL\n \"sdk-icon\": poi.imageUrl\n ? `custom-url-${poi.id}`\n : poi.spriteName\n ? poi.spriteName\n : poi.emoji\n ? `custom-emoji-${poi.emoji}`\n : poi.type === \"bar\"\n ? \"sdk-default-bar\"\n : poi.type === \"restaurant\"\n ? \"sdk-default-restaurant\"\n : \"sdk-default-poi\",\n },\n type: \"Feature\" as const,\n })),\n type: \"FeatureCollection\" as const,\n }),\n [glPois],\n );\n\n return (\n <Source data={geojson} id=\"sdk-pois\" type=\"geojson\">\n <Layer\n id=\"sdk-poi-layer\"\n layout={{\n \"icon-allow-overlap\": true,\n \"icon-image\": [\"get\", \"sdk-icon\"],\n \"icon-size\": 1,\n \"text-anchor\": \"top\",\n \"text-field\": [\n \"step\",\n [\"zoom\"],\n \"\", // Show nothing when zoomed out\n 14,\n [\"get\", \"name\"], // Show name when zoomed in\n ],\n \"text-font\": [\"Open Sans Bold\"],\n \"text-offset\": [0, 1.5],\n \"text-optional\": true,\n \"text-size\": 11,\n }}\n paint={{\n \"icon-opacity\": [\"interpolate\", [\"linear\"], [\"zoom\"], 11, 0, 12, 1],\n \"text-color\": \"#ffffff\",\n \"text-halo-color\": \"#000000\",\n \"text-halo-width\": 1,\n \"text-opacity\": [\"interpolate\", [\"linear\"], [\"zoom\"], 13.5, 0, 14, 1],\n }}\n type=\"symbol\"\n />\n </Source>\n );\n};\n","import type { POI } from \"@miniapps-sdk/components/Map/types\";\nimport { Marker } from \"@vis.gl/react-maplibre\";\nimport type React from \"react\";\n\nexport const POIMarkers: React.FC<{\n pois: POI[];\n onClick?: (poi: POI) => void;\n}> = ({ pois, onClick }) => {\n // Filter for Marker-mode POIs\n const markerPois = pois.filter((p) => p.displayMode === \"marker\");\n\n if (markerPois.length === 0) return null;\n\n return (\n <>\n {markerPois.map((poi) => (\n <Marker\n anchor=\"bottom\"\n key={poi.id}\n latitude={poi.latitude}\n longitude={poi.longitude}\n onClick={(e) => {\n e.originalEvent.stopPropagation();\n if (onClick) onClick(poi);\n }}\n >\n {poi.markerComponent ? (\n poi.markerComponent\n ) : (\n <div\n style={{\n cursor: \"pointer\",\n filter: \"drop-shadow(0 4px 6px rgba(0,0,0,0.1))\",\n transform: \"transition-transform duration-200 hover:scale-110\",\n }}\n >\n <div\n style={{\n alignItems: \"center\",\n backgroundColor: poi.type === \"bar\" ? \"#f97316\" : \"#10b981\",\n border: \"2px solid white\",\n borderRadius: \"50%\",\n display: \"flex\",\n height: \"32px\",\n justifyContent: \"center\",\n width: \"32px\",\n }}\n >\n {poi.emoji ? (\n <span style={{ fontSize: \"16px\" }}>{poi.emoji}</span>\n ) : (\n <div\n style={{\n backgroundColor: \"white\",\n borderRadius: \"50%\",\n height: \"8px\",\n width: \"8px\",\n }}\n ></div>\n )}\n </div>\n {/* Pin Tail */}\n <div\n style={{\n borderLeft: \"6px solid transparent\",\n borderRight: \"6px solid transparent\",\n borderTop: `8px solid ${poi.type === \"bar\" ? \"#f97316\" : \"#10b981\"}`,\n height: 0,\n margin: \"-2px auto 0\",\n width: 0,\n }}\n ></div>\n </div>\n )}\n </Marker>\n ))}\n </>\n );\n};\n","import { Marker } from \"@vis.gl/react-maplibre\";\nimport type React from \"react\";\n\nexport interface UserLocationLayerProps {\n /**\n * The location to display.\n */\n forcedLocation: [number, number] | null;\n /**\n * The user's heading (bearing) in degrees.\n */\n heading?: number | null;\n}\n\nexport const UserLocationLayer: React.FC<UserLocationLayerProps> = ({\n forcedLocation,\n heading,\n}) => {\n if (!forcedLocation) return null;\n\n return (\n <Marker\n anchor=\"center\"\n latitude={forcedLocation[1]}\n longitude={forcedLocation[0]}\n >\n <div\n style={{\n alignItems: \"center\",\n display: \"flex\",\n justifyContent: \"center\",\n position: \"relative\",\n }}\n >\n {/* Pulse Animation */}\n <div\n style={{\n animation: \"pulse 2s infinite\",\n backgroundColor: \"rgba(59, 130, 246, 0.4)\",\n borderRadius: \"50%\",\n height: \"40px\",\n position: \"absolute\",\n width: \"40px\",\n }}\n ></div>\n\n {/* Heading Indicator (Cone/Arrow) */}\n {heading !== undefined && heading !== null && (\n <div\n style={{\n height: \"60px\",\n position: \"absolute\",\n transform: `rotate(${heading}deg)`,\n width: \"60px\",\n zIndex: 0,\n }}\n >\n <svg\n style={{ height: \"100%\", width: \"100%\" }}\n viewBox=\"0 0 100 100\"\n >\n <defs>\n <radialGradient\n cx=\"50%\"\n cy=\"50%\"\n fx=\"50%\"\n fy=\"50%\"\n id=\"grad1\"\n r=\"50%\"\n >\n <stop\n offset=\"0%\"\n style={{\n stopColor: \"rgba(37, 99, 235, 0.6)\",\n stopOpacity: 1,\n }}\n />\n <stop\n offset=\"100%\"\n style={{\n stopColor: \"rgba(37, 99, 235, 0)\",\n stopOpacity: 0,\n }}\n />\n </radialGradient>\n </defs>\n {/* Visual Direction Cone */}\n <path\n d=\"M 50 50 L 35 0 A 50 50 0 0 1 65 0 Z\"\n fill=\"url(#grad1)\"\n />\n </svg>\n </div>\n )}\n\n {/* Main Blue Dot */}\n <div\n style={{\n alignItems: \"center\",\n backgroundColor: \"white\",\n borderRadius: \"50%\",\n boxShadow:\n \"0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 0 0 2px rgba(37, 99, 235, 0.2)\",\n display: \"flex\",\n height: \"20px\",\n justifyContent: \"center\",\n width: \"20px\",\n zIndex: 1,\n }}\n >\n <div\n style={{\n backgroundColor: \"#2563eb\",\n border: \"2px solid white\",\n borderRadius: \"50%\",\n height: \"12px\",\n width: \"12px\",\n }}\n ></div>\n </div>\n <style>{`@keyframes pulse { 0% { transform: scale(0.95); opacity: 0.7; } 70% { transform: scale(1.5); opacity: 0; } 100% { transform: scale(0.95); opacity: 0; } }`}</style>\n </div>\n </Marker>\n );\n};\n","import { MapControls } from \"@miniapps-sdk/components/Map/components/MapControls\";\nimport {\n MapMenu,\n MapMenuDivider,\n MapMenuFooter,\n MapMenuItem,\n MapMenuTitle,\n} from \"@miniapps-sdk/components/Map/components/MapMenu\";\nimport { useJourney } from \"@miniapps-sdk/components/Map/hooks/useJourney\";\nimport { useTrimmedRoute } from \"@miniapps-sdk/components/Map/hooks/useTrimmedRoute\";\nimport { useUserLocation } from \"@miniapps-sdk/components/Map/hooks/useUserLocation\";\nimport { MockRadiusLayer } from \"@miniapps-sdk/components/Map/layers/MockRadiusLayer\";\nimport { POILayers } from \"@miniapps-sdk/components/Map/layers/POILayers\";\nimport { POIMarkers } from \"@miniapps-sdk/components/Map/layers/POIMarkers\";\nimport { RouteLayer } from \"@miniapps-sdk/components/Map/layers/RouteLayer\";\nimport { UserLocationLayer } from \"@miniapps-sdk/components/Map/layers/UserLocationLayer\";\nimport {\n type CenterCallbackParams,\n type FlyToParams,\n MapControlsContext,\n SDKMapProvider,\n} from \"@miniapps-sdk/components/Map/MapContext\";\nimport { MockLocationContext } from \"@miniapps-sdk/components/Map/MockLocationContext\";\nimport type { MapProps, POI } from \"@miniapps-sdk/components/Map/types\";\nimport type { MapRef } from \"@vis.gl/react-maplibre\";\nimport { Map as MapLibre, MapProvider } from \"@vis.gl/react-maplibre\";\nimport React, {\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport \"maplibre-gl/dist/maplibre-gl.css\";\n\nconst MapInternal: React.FC<MapProps> = ({\n initialViewState = {\n latitude: 45.90583599233422,\n longitude: 6.12589018919138,\n zoom: 12,\n },\n style = {},\n mapStyle = \"https://tiles.cloudparse.fr/style/up_dark_matter\",\n className = \"\",\n maxBounds,\n children,\n onClick,\n onMapClickMiss,\n onContextMenu,\n interactiveLayerIds = [],\n onLoad,\n showUserLocation = true,\n followUser: initialFollowUser = false,\n lockToUser = false,\n showUserLocationButton = true,\n renderUserLocation,\n pois = [],\n onPoiClick,\n route: externalRoute,\n showNavigationUI: externalShowNavigationUI,\n navigationData: externalNavigationData,\n onNavigationAbort,\n onNavigationModeChange,\n navigation,\n showControls = true,\n menuItems,\n menuContent,\n drawerState: propDrawerState,\n drawerContentRef,\n controlProps = {},\n enableTouchDrag = false,\n}) => {\n const mapControls = useContext(MapControlsContext);\n const mockLocation = useContext(MockLocationContext);\n\n const mapRef = useRef<MapRef | null>(null);\n\n // Get user location state (data only)\n const userLocationState = useUserLocation();\n\n // Journey state (preview/navigation/eta) — used only when `navigation` prop\n // or the imperative sdk.navigation.* API drives this Map. See useJourney()\n // for the standalone public hook devs can use to build their own UI.\n const journey = useJourney({\n navigation,\n onModeChange: navigation ? onNavigationModeChange : undefined,\n });\n\n const hasIntegratedNav = journey.isActive;\n\n // Merge external and internal data\n const navigationData = hasIntegratedNav\n ? {\n currentDistanceMeters: journey.distanceRemainingMeters,\n mode: journey.mode,\n route: journey.route,\n start: journey.start,\n totalDistance: journey.totalDistanceMeters,\n }\n : externalNavigationData;\n const route = hasIntegratedNav ? journey.route?.geometry : externalRoute;\n const showNavigationUI = hasIntegratedNav\n ? externalShowNavigationUI !== false && navigation?.showUI !== false\n : externalShowNavigationUI;\n\n const mode = navigationData?.mode || \"preview\";\n const resolvedInitialFollow = mapControls\n ? mapControls.isFollowing\n : initialFollowUser;\n\n // Synchronous refs for the render loop to avoid React state batching race conditions\n const isFollowingRef = useRef(resolvedInitialFollow);\n const isFlyingRef = useRef(false);\n // Shared across EVERY camera-animation call site in this component\n // (initial-follow flyTo, navigation-lock flyTo, handleCenterOnUser,\n // handleFlyTo) — guards the lock-release against a later call\n // superseding an earlier one still mid-flight: without a SHARED counter,\n // an earlier call's release firing after a later call has already\n // started would clear isFlyingRef mid-animation of the later one,\n // letting a GPS tick fight it (the exact bug this locking exists to\n // prevent). A counter scoped to just one call site isn't enough — any\n // two of these can interleave (e.g. selecting a venue while navigation\n // auto-starts).\n const flyingGenerationRef = useRef(0);\n const lockFlying = useCallback(() => {\n isFlyingRef.current = true;\n return ++flyingGenerationRef.current;\n }, []);\n const releaseFlyingIfCurrent = useCallback((flightId: number) => {\n if (flyingGenerationRef.current === flightId) {\n isFlyingRef.current = false;\n }\n }, []);\n\n // We use the context directly for UI updates if it exists, otherwise we fallback to a local state\n const [localIsFollowingUI, setLocalIsFollowingUI] = useState(\n resolvedInitialFollow,\n );\n const isFollowingUI = mapControls\n ? mapControls.isFollowing\n : localIsFollowingUI;\n\n const setIsFollowingCtx = mapControls?.setIsFollowing;\n\n const setFollowMode = useCallback(\n (follow: boolean) => {\n isFollowingRef.current = follow;\n\n // Update local UI state as a fallback\n setLocalIsFollowingUI(follow);\n\n // Update context UI state\n if (setIsFollowingCtx) {\n setIsFollowingCtx(follow);\n }\n },\n [setIsFollowingCtx],\n );\n\n // Sync context state changes into the local ref (if external client called setFollowMode)\n useEffect(() => {\n if (mapControls && mapControls.isFollowing !== isFollowingRef.current) {\n isFollowingRef.current = mapControls.isFollowing;\n }\n }, [mapControls?.isFollowing, mapControls]);\n\n const mergedInteractiveLayerIds = [...interactiveLayerIds];\n if (pois.length > 0 && !mergedInteractiveLayerIds.includes(\"sdk-poi-layer\")) {\n mergedInteractiveLayerIds.push(\"sdk-poi-layer\");\n }\n\n const prevInitialFollow = useRef(initialFollowUser);\n // Reactive follow state sync from props\n useEffect(() => {\n if (initialFollowUser !== prevInitialFollow.current) {\n setFollowMode(initialFollowUser);\n prevInitialFollow.current = initialFollowUser;\n\n if (initialFollowUser && userLocationState.coords && mapRef.current) {\n const flightId = lockFlying();\n mapRef.current.flyTo({\n center: userLocationState.coords,\n duration: 1000,\n essential: true,\n zoom: Math.max(mapRef.current.getZoom(), 16),\n });\n setTimeout(() => {\n releaseFlyingIfCurrent(flightId);\n }, 1050);\n }\n }\n }, [\n initialFollowUser,\n setFollowMode,\n userLocationState.coords,\n lockFlying,\n releaseFlyingIfCurrent,\n ]);\n\n const lastAutoLockedRouteRef = useRef<any>(null);\n const lastModeRef = useRef<string | null>(null);\n\n // Auto-lock camera or fit bounds depending on mode\n useEffect(() => {\n if (!route || !mapRef.current) {\n if (!route) lastAutoLockedRouteRef.current = null;\n return;\n }\n\n const isNewRoute = route !== lastAutoLockedRouteRef.current;\n const modeChanged = lastModeRef.current !== mode;\n\n if (mode === \"navigation\") {\n if (modeChanged || isNewRoute) {\n // Only (re-)lock the camera when navigation just started or the\n // route just changed — not on every re-run of this effect (it also\n // depends on userLocationState.coords, which changes on every GPS\n // tick). Otherwise a manual pan/rotate during active navigation\n // would get re-locked on the very next location update.\n setFollowMode(true);\n }\n if (\n (modeChanged || isNewRoute) &&\n userLocationState.coords &&\n mapRef.current\n ) {\n const flightId = lockFlying();\n mapRef.current.flyTo({\n center: userLocationState.coords,\n duration: 1000,\n essential: true,\n zoom: 17, // Zoomed in on user for active guidance\n });\n setTimeout(() => {\n releaseFlyingIfCurrent(flightId);\n }, 1050);\n }\n } else if (mode === \"preview\" && isNewRoute) {\n setFollowMode(false);\n // Fit bounds to show entire route\n const coords = route.coordinates;\n if (coords.length > 0) {\n const bounds = coords.reduce(\n (acc, coord) => {\n return [\n [Math.min(acc[0][0], coord[0]), Math.min(acc[0][1], coord[1])],\n [Math.max(acc[1][0], coord[0]), Math.max(acc[1][1], coord[1])],\n ];\n },\n [\n [coords[0][0], coords[0][1]],\n [coords[0][0], coords[0][1]],\n ],\n );\n\n mapRef.current.fitBounds(\n [bounds[0][0], bounds[0][1], bounds[1][0], bounds[1][1]],\n { padding: 100, speed: 1.2 },\n );\n }\n }\n\n lastAutoLockedRouteRef.current = route;\n lastModeRef.current = mode;\n }, [\n route,\n mode,\n setFollowMode,\n userLocationState.coords,\n lockFlying,\n releaseFlyingIfCurrent,\n ]);\n\n // Continuous Camera Tracking\n useEffect(() => {\n // Read from the ref synchronously to guarantee we don't fight a manual interaction that just occurred\n if (\n isFollowingRef.current &&\n !isFlyingRef.current &&\n userLocationState.coords &&\n mapRef.current\n ) {\n mapRef.current.easeTo({\n center: userLocationState.coords,\n duration: 50, // Ultra-short for high-frequency interpolated stream\n easing: (t) => t,\n essential: true,\n });\n }\n }, [userLocationState.coords]);\n\n // Dynamically trim the route\n const displayRoute = useTrimmedRoute(\n route,\n showUserLocation ? userLocationState.coords : null,\n );\n\n // Compute etaData from navigationData if active\n // Extract primitives directly so useMemo dependency array can track changes\n const currentDistMeters = navigationData?.currentDistanceMeters ?? null;\n const totalDist = navigationData?.totalDistance ?? null;\n const routeDurationSeconds = navigationData?.route?.durationSeconds ?? null;\n\n // Use currentDistanceMeters (real-time along route) — never fall back to route.distanceMeters\n // (that's the total distance, which would make progress 0 or negative)\n const remainingMeters = currentDistMeters ?? 0;\n\n // ETA: scale route duration proportionally to remaining distance\n const etaMins = (() => {\n if (!routeDurationSeconds || !totalDist || !currentDistMeters) return 0;\n const ratio = currentDistMeters / totalDist;\n return Math.ceil((routeDurationSeconds * ratio) / 60);\n })();\n\n const kmRemaining = remainingMeters / 1000;\n\n const progressValue =\n totalDist && totalDist > 0\n ? Math.min(\n 100,\n Math.max(0, ((totalDist - remainingMeters) / totalDist) * 100),\n )\n : 0;\n\n // No useMemo here — primitive deps change on every location update,\n // useMemo was hiding the updates because navigationData object ref is stable\n const showEtaData =\n showNavigationUI && navigationData && route\n ? {\n distanceRemainingKm: kmRemaining,\n etaMins,\n label:\n mode === \"navigation\" ? \"Walking Guidance Active\" : \"Route Preview\",\n mode: mode,\n onAbort: () => {\n journey.cancel();\n if (onNavigationAbort) {\n onNavigationAbort();\n }\n },\n onStart: navigationData.start,\n progress: progressValue,\n }\n : undefined;\n\n // Sync etaData to context so controls can access it\n const setEtaDataCtx = mapControls?.setEtaData;\n useEffect(() => {\n if (setEtaDataCtx) {\n setEtaDataCtx(showEtaData);\n }\n }, [showEtaData, setEtaDataCtx]);\n\n // Sync propDrawerState to context so it can be controlled programmatically from Map props\n const setDrawerStateCtx = mapControls?.setDrawerState;\n useEffect(() => {\n if (setDrawerStateCtx && propDrawerState !== undefined) {\n setDrawerStateCtx(propDrawerState);\n }\n }, [propDrawerState, setDrawerStateCtx]);\n\n // No demo fallback here on purpose — a placeholder menu item used to leak\n // into real apps' UI as a visible flash whenever `menuContent`/`menuItems`\n // were momentarily empty (e.g. during a mode-switch re-render).\n const resolvedMenuItems = menuItems ?? [];\n\n const { mapLibreChildren, menuContentFromChildren } = useMemo(() => {\n const mapLibreChildren: React.ReactNode[] = [];\n const extractedMenuItems: React.ReactNode[] = [];\n\n React.Children.forEach(children, (child) => {\n if (React.isValidElement(child)) {\n const type = child.type;\n const displayName = (type as any)?.displayName || (type as any)?.name;\n const isMenu = type === MapMenu || displayName === \"MapMenu\";\n const isMenuComponent =\n isMenu ||\n type === MapMenuItem ||\n type === MapMenuTitle ||\n type === MapMenuDivider ||\n type === MapMenuFooter ||\n [\n \"MapMenuItem\",\n \"MapMenuTitle\",\n \"MapMenuDivider\",\n \"MapMenuFooter\",\n ].includes(displayName);\n\n if (isMenu) {\n React.Children.forEach(\n (child as React.ReactElement<any>).props.children,\n (nestedChild) => {\n if (nestedChild) {\n extractedMenuItems.push(nestedChild);\n }\n },\n );\n } else if (isMenuComponent) {\n extractedMenuItems.push(child);\n } else {\n mapLibreChildren.push(child);\n }\n } else {\n mapLibreChildren.push(child);\n }\n });\n\n const menuContentFromChildren =\n extractedMenuItems.length > 0 ? (\n <MapMenu>{extractedMenuItems}</MapMenu>\n ) : null;\n\n return { mapLibreChildren, menuContentFromChildren };\n }, [children]);\n\n const handleMapClick = (e: any) => {\n if (mockLocation?.isPlacingLocation) {\n mockLocation.placeLocation([e.lngLat.lng, e.lngLat.lat]);\n return;\n }\n\n const clickedFeatures = e.features || [];\n\n if (onPoiClick) {\n const poiFeature = clickedFeatures.find(\n (f: any) => f.layer.id === \"sdk-poi-layer\",\n );\n if (poiFeature) {\n onPoiClick(poiFeature.properties as POI);\n return;\n }\n }\n\n // Check if the click hit any interactive layers\n const hitInteractive = clickedFeatures.some((f: any) =>\n mergedInteractiveLayerIds.includes(f.layer.id),\n );\n\n if (!hitInteractive) {\n if (onMapClickMiss) {\n onMapClickMiss(e);\n }\n }\n\n if (onClick) onClick(e);\n };\n\n const handleCenterOnUser = useCallback(\n (payload?: CenterCallbackParams) => {\n if (userLocationState.coords && mapRef.current) {\n setFollowMode(true);\n const flightId = lockFlying(); // Lock continuous tracking during the cinematic flyTo\n\n mapRef.current.flyTo({\n center: userLocationState.coords,\n duration: 1000,\n essential: true,\n pitch: payload?.pitch || 0,\n zoom: Math.max(mapRef.current.getZoom(), 16),\n ...(payload?.bearing !== undefined\n ? { bearing: payload.bearing }\n : {}),\n });\n\n // Release the lock when flyTo completes\n setTimeout(() => {\n releaseFlyingIfCurrent(flightId);\n }, 1050);\n }\n },\n [\n userLocationState.coords,\n setFollowMode,\n lockFlying,\n releaseFlyingIfCurrent,\n ],\n );\n\n const handleFlyTo = useCallback(\n (coords: [number, number], params?: FlyToParams) => {\n const map = mapRef.current;\n if (!map) return;\n // Disable follow-mode AND lock out the continuous-tracking effect for\n // the duration of the animation — otherwise a live location update\n // arriving mid-flight immediately snaps the camera back onto the\n // user, undoing this flyTo (this only \"worked\" after the user first\n // manually panned the map, since panning is what disables follow).\n setFollowMode(false);\n const flightId = lockFlying();\n\n map.flyTo({\n center: coords,\n essential: true,\n pitch: params?.pitch ?? 0,\n zoom: params?.zoom ?? map.getZoom(),\n // Omit entirely (rather than defaulting to a fixed number) when\n // not given, so MapLibre computes its own distance-based duration.\n ...(params?.duration !== undefined\n ? { duration: params.duration }\n : {}),\n ...(params?.bearing !== undefined ? { bearing: params.bearing } : {}),\n });\n\n // Release tied to the actual animation completing (fires on\n // interruption too, e.g. a second flyTo cutting this one short) —\n // not a guessed timeout, which can't know the real duration once it's\n // MapLibre's own distance-based default.\n map.once(\"moveend\", () => releaseFlyingIfCurrent(flightId));\n },\n [setFollowMode, lockFlying, releaseFlyingIfCurrent],\n );\n\n const handleResetBearing = useCallback((params?: CenterCallbackParams) => {\n if (mapRef.current) {\n mapRef.current.easeTo({\n bearing: 0,\n duration: 500,\n essential: true,\n pitch: params?.pitch ?? 0,\n });\n }\n }, []);\n\n // Register callbacks to context so controls can trigger centering and resets\n useEffect(() => {\n if (mapControls) {\n mapControls._registerCenterCallback(handleCenterOnUser);\n mapControls._registerResetBearingCallback(handleResetBearing);\n mapControls._registerFlyToCallback(handleFlyTo);\n }\n }, [mapControls, handleCenterOnUser, handleResetBearing, handleFlyTo]);\n\n const handleMove = useCallback(() => {\n if (mapRef.current && mapControls) {\n mapControls.setBearing(mapRef.current.getBearing());\n mapControls.setPitch(mapRef.current.getPitch());\n }\n }, [mapControls]);\n\n // Instantly halt animations and drop tracking on manual input — unless\n // `lockToUser` is set, in which case following is an authoritative lock\n // (e.g. a GPS-driven tracker/game) rather than a one-time initial default,\n // and manual pointer interaction must not silently disable it (previously\n // the camera stopped following on the very first drag/wheel/touch event\n // and never recovered without an explicit recenter call).\n const handleUserInteraction = () => {\n if (lockToUser) return;\n\n if (isFollowingRef.current) {\n setFollowMode(false);\n if (mapRef.current) {\n mapRef.current.stop(); // Stops any ongoing easeTo immediately\n }\n }\n };\n\n return (\n <div\n className={`w-full h-full overflow-hidden relative ${mockLocation?.isPlacingLocation ? \"cursor-crosshair\" : \"\"} ${className}`}\n style={style}\n >\n <MapLibre\n attributionControl={false}\n initialViewState={initialViewState}\n interactiveLayerIds={mergedInteractiveLayerIds}\n mapStyle={mapStyle}\n maxBounds={maxBounds}\n onClick={handleMapClick}\n onContextMenu={onContextMenu}\n onDragStart={handleUserInteraction}\n onLoad={(e) => {\n if (onLoad) onLoad(e);\n if (initialFollowUser && userLocationState.coords && mapRef.current) {\n mapRef.current.jumpTo({\n center: userLocationState.coords,\n zoom: 16,\n });\n }\n }}\n onMouseDown={handleUserInteraction}\n onMove={handleMove}\n onRotateStart={handleUserInteraction}\n onTouchStart={handleUserInteraction}\n onWheel={handleUserInteraction}\n ref={mapRef}\n >\n {showUserLocation &&\n userLocationState.coords &&\n (renderUserLocation ? (\n renderUserLocation({\n coords: userLocationState.coords,\n heading: userLocationState.heading,\n })\n ) : (\n <UserLocationLayer\n forcedLocation={userLocationState.coords}\n heading={userLocationState.heading}\n />\n ))}\n\n {mockLocation &&\n mockLocation.radiusMeters > 0 &&\n userLocationState.coords && (\n <MockRadiusLayer\n center={userLocationState.coords}\n radiusMeters={mockLocation.radiusMeters}\n />\n )}\n\n {displayRoute && <RouteLayer geometry={displayRoute} />}\n\n {pois.length > 0 && (\n <>\n <POILayers pois={pois} />\n <POIMarkers onClick={onPoiClick} pois={pois} />\n </>\n )}\n {mapLibreChildren}\n </MapLibre>\n {showControls && mapControls && !mapControls.hasControls && (\n <MapControls\n drawerContentRef={drawerContentRef}\n enableTouchDrag={enableTouchDrag}\n etaData={showEtaData}\n initialViewState={initialViewState}\n isInternal={true}\n menuContent={menuContent || menuContentFromChildren}\n menuItems={resolvedMenuItems}\n {...controlProps}\n />\n )}\n </div>\n );\n};\n\nconst SDKMapProviderWrapper: React.FC<{ children: React.ReactNode }> = ({\n children,\n}) => {\n const context = useContext(MapControlsContext);\n if (context) {\n return <>{children}</>;\n }\n return <SDKMapProvider>{children}</SDKMapProvider>;\n};\n\nexport const Map: React.FC<MapProps> = (props) => {\n return (\n <SDKMapProviderWrapper>\n <MapProvider>\n <MapInternal {...props} />\n </MapProvider>\n </SDKMapProviderWrapper>\n );\n};\n","import { Map, type MapProps } from \"@miniapps-sdk/components/Map\";\nimport React from \"react\";\nimport { createRoot } from \"react-dom/client\";\n\n/**\n * Renders the Map component into a DOM element.\n * Useful for non-React environments (UMD/IIFE).\n *\n * @param containerId The ID of the HTML element where the map should be rendered.\n * @param props The props to pass to the Map component.\n * @returns The React root instance.\n */\nexport function renderMap(containerId: string, props: MapProps = {}) {\n const container = document.getElementById(containerId);\n if (!container) {\n throw new Error(`Container with id \"${containerId}\" not found.`);\n }\n\n const root = createRoot(container);\n root.render(React.createElement(Map, props));\n return root;\n}\n","import type { IGenerateQrCodeOptions } from \"@miniapps-sdk/types\";\nimport QRCodeStyling from \"qr-code-styling\";\n\nconst DEFAULT_SIZE = 512;\nconst DEFAULT_COLOR = \"#18181b\";\nconst DEFAULT_BACKGROUND = \"#ffffff\";\nconst DEFAULT_BORDER_RADIUS_PERCENT = 6;\nconst DEFAULT_LOGO_IMAGE =\n \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAAAXNSR0IB2cksfwAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB+oIBggpDsP9ZQ0AACAASURBVHja7L15tG3rVRf4m3ufc+6953bv3Zc83ktCBQgh9OkEAwgYQEKgpEBURB02Y6ChRALRSBqsGAgEIyKOoIJWY6FWjeGowbCaIVKWHVJhlF1ZqNiVFgUlMQl5zb339HvvNeuPtZu1vjW7b+1zX+65Z84x9jjn7LPWt9bXzjl/swOSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkh4IUQ5B0nkTf/9X7jBNnibC06DJbezuvxRXblzD3v4emsXjaBY3wHwFwLRdhctlyKsVSe3v4aVLxa/S/RRY+tR+zd1r2LiXhWevvqaiHePZq3duGmB2BsxO5Wu5GKv12LHzDKGvLLxvr93O7zdudS4m+RpvbM17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\";\nconst LABEL_FONT = \"600 %PXpx -apple-system, BlinkMacSystemFont, sans-serif\";\nconst LABEL_AREA_RATIO = 0.175; // fraction of `size` reserved for the label band, when present\nconst LABEL_PADDING_RATIO = -0.04;\n\n/**\n * Generates a styled QR code entirely client-side (canvas, no native bridge\n * round-trip needed — this never touches the Host Shell) and returns it as a\n * base64 PNG data URI, ready to hand straight to an `<img src>` or to\n * `sdk.media.saveImage()`.\n *\n * This is the SDK's single source of truth for QR code generation — mini-apps\n * must not reimplement this (canvas rasterization, styling, labeling) on\n * their own; that duplication is exactly what led every mini-app to drift\n * and made shared fixes/style updates painful to roll out consistently.\n */\nexport async function generateQrCode(\n data: string,\n options: IGenerateQrCodeOptions = {},\n): Promise<string> {\n const size = options.size ?? DEFAULT_SIZE;\n const color = options.color ?? DEFAULT_COLOR;\n const backgroundColor = options.backgroundColor ?? DEFAULT_BACKGROUND;\n const label =\n options.label || (options.appName ? `${options.appName} by UP` : \"\");\n\n // qr-code-styling merges its own default `imageOptions` with whatever's\n // passed in — but an explicitly-present `imageOptions: undefined` key\n // (e.g. from `options.logo ? {...} : undefined`) overwrites that default\n // during the merge instead of falling back to it, and the library reads\n // `imageOptions.hideBackgroundDots` unconditionally during rendering even\n // when there's no `image` — so `imageOptions: undefined` throws\n // (\"Cannot read properties of undefined\"), not just no-ops. The `image`\n // and `imageOptions` keys must be entirely ABSENT from the options object\n // when there's no logo, not present with an undefined value — hence the\n // conditional spread instead of a ternary-to-undefined.\n const qr = new QRCodeStyling({\n backgroundOptions: {\n color: backgroundColor,\n ...(options.backgroundGradient\n ? { gradient: options.backgroundGradient }\n : {}),\n },\n cornersDotOptions: {\n color: options.cornersDotColor ?? color,\n type: options.cornersDotType ?? \"extra-rounded\",\n ...(options.cornersDotGradient\n ? { gradient: options.cornersDotGradient }\n : {}),\n },\n cornersSquareOptions: {\n color: options.cornersSquareColor ?? color,\n type: options.cornersSquareType ?? \"extra-rounded\",\n ...(options.cornersSquareGradient\n ? { gradient: options.cornersSquareGradient }\n : {}),\n },\n data,\n dotsOptions: {\n color,\n type: options.dotsType ?? \"extra-rounded\",\n ...(options.dotsGradient ? { gradient: options.dotsGradient } : {}),\n },\n height: size,\n margin: options.margin ?? 0,\n qrOptions: {\n errorCorrectionLevel: options.errorCorrectionLevel ?? \"Q\",\n mode: \"Byte\",\n typeNumber: 0,\n },\n shape: options.shape ?? \"square\",\n type: \"canvas\",\n width: size,\n ...(options.logo !== null\n ? {\n image: options.logo ?? DEFAULT_LOGO_IMAGE,\n imageOptions: {\n hideBackgroundDots: options.hideBackgroundDots ?? true,\n imageSize: options.logoSize ?? 0.3,\n margin: options.logoMargin ?? 0,\n },\n }\n : {}),\n });\n\n const qrBlob = await qr.getRawData(\"png\");\n if (!qrBlob || !(qrBlob instanceof Blob)) {\n throw new Error(\"Failed to generate QR code image\");\n }\n const qrDataUrl = await blobToDataUrl(qrBlob);\n const outerPadding = options.outerPadding ?? 32;\n const borderRadiusPercent =\n options.borderRadius ?? DEFAULT_BORDER_RADIUS_PERCENT;\n\n const composed = label\n ? await composeWithLabel(qrDataUrl, label, size, backgroundColor, color)\n : qrDataUrl;\n\n return finalizeImage(\n composed,\n outerPadding,\n borderRadiusPercent,\n backgroundColor,\n );\n}\n\nconst blobToDataUrl = (blob: Blob): Promise<string> =>\n new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onloadend = () => resolve(reader.result as string);\n reader.onerror = reject;\n reader.readAsDataURL(blob);\n });\n\nconst loadImage = (src: string): Promise<HTMLImageElement> =>\n new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => resolve(img);\n img.onerror = reject;\n img.src = src;\n });\n\n/**\n * Draws the QR code onto a taller canvas with the label text centered above\n * it, and returns the composite as a base64 PNG data URI.\n */\nasync function composeWithLabel(\n qrDataUrl: string,\n label: string,\n size: number,\n backgroundColor: string,\n textColor: string,\n): Promise<string> {\n const qrImage = await loadImage(qrDataUrl);\n const labelAreaHeight = Math.round(size * LABEL_AREA_RATIO);\n const padding = Math.round(size * LABEL_PADDING_RATIO);\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = size;\n canvas.height = size + labelAreaHeight;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n // No 2D canvas context available — degrade to the unlabeled QR rather\n // than fail the whole generation over a cosmetic addition.\n return qrDataUrl;\n }\n\n ctx.fillStyle = backgroundColor;\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n\n const fontSize = Math.round(labelAreaHeight * 0.45);\n ctx.fillStyle = textColor;\n ctx.font = LABEL_FONT.replace(\"%PX\", String(fontSize));\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n ctx.fillText(\n label,\n canvas.width / 2,\n labelAreaHeight / 2 + padding / 2,\n canvas.width - padding * 2,\n );\n\n ctx.drawImage(qrImage, 0, labelAreaHeight, size, size);\n\n return canvas.toDataURL(\"image/png\");\n}\n\n/**\n * Traces a rounded-rectangle path on `ctx` without filling/stroking it —\n * caller decides (`.fill()`, `.clip()`, etc).\n */\nfunction traceRoundedRectPath(\n ctx: CanvasRenderingContext2D,\n x: number,\n y: number,\n width: number,\n height: number,\n radius: number,\n): void {\n ctx.beginPath();\n ctx.moveTo(x + radius, y);\n ctx.arcTo(x + width, y, x + width, y + height, radius);\n ctx.arcTo(x + width, y + height, x, y + height, radius);\n ctx.arcTo(x, y + height, x, y, radius);\n ctx.arcTo(x, y, x + width, y, radius);\n ctx.closePath();\n}\n\n/**\n * Forces the already-composed image (QR code, or QR code + label — the\n * latter is TALLER than it is wide, since the label band only adds height)\n * into a final SQUARE canvas: `outerPadding` is added on all four sides,\n * then the shorter dimension is padded further (content re-centered) so the\n * result is always `side × side`, never a rectangle. `borderRadius` is a\n * PERCENTAGE (0-50) of that final square's side, matching how CSS\n * `border-radius: N%` behaves on a square element — not raw px — so the\n * roundedness scales correctly with `size`/`outerPadding` instead of\n * looking sharper on a bigger QR and blobbier on a smaller one. The area\n * outside the rounded corners is left transparent (not `backgroundColor`\n * filled), so the PNG itself has real rounded corners, not just a\n * same-color illusion — matters once this is composited onto anything other\n * than a plain `backgroundColor` surface (e.g. a gallery photo grid).\n */\nasync function finalizeImage(\n imageDataUrl: string,\n outerPadding: number,\n borderRadiusPercent: number,\n backgroundColor: string,\n): Promise<string> {\n const image = await loadImage(imageDataUrl);\n const paddedWidth = image.width + outerPadding * 2;\n const paddedHeight = image.height + outerPadding * 2;\n const squareSize = Math.max(paddedWidth, paddedHeight);\n const radius =\n (Math.min(Math.max(borderRadiusPercent, 0), 50) / 100) * squareSize;\n\n const needsCanvas =\n radius > 0 || paddedWidth !== squareSize || paddedHeight !== squareSize;\n if (!needsCanvas) {\n return imageDataUrl;\n }\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = squareSize;\n canvas.height = squareSize;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n // No 2D canvas context available — degrade to the un-finalized image\n // rather than fail the whole generation over a cosmetic addition.\n return imageDataUrl;\n }\n\n if (radius > 0) {\n traceRoundedRectPath(ctx, 0, 0, squareSize, squareSize, radius);\n ctx.clip();\n }\n\n ctx.fillStyle = backgroundColor;\n ctx.fillRect(0, 0, squareSize, squareSize);\n\n const offsetX = Math.round((squareSize - image.width) / 2);\n const offsetY = Math.round((squareSize - image.height) / 2);\n ctx.drawImage(image, offsetX, offsetY);\n\n return canvas.toDataURL(\"image/png\");\n}\n","import jsQR from \"jsqr\";\n\n/**\n * Decodes a QR code from a static image (base64 data URI) — the single\n * source of truth for \"scan a photo instead of the live camera\" across\n * every Mini-App. Complements `<QRScanner>` (live camera decode loop): this\n * is for a gallery-picked photo (e.g. via `sdk.media.pickImage`, which\n * always returns a base64 data URI) that already contains a QR code, not a\n * live video frame.\n *\n * Deliberately data-URI-only, not \"or URL\": a cross-origin URL taints the\n * canvas and `getImageData` throws a `SecurityError`, which would silently\n * break the \"never throws for 'no code found'\" contract below for that\n * input shape. If a URL-based variant is ever needed, it must set\n * `img.crossOrigin` AND accept that it still depends on the remote host\n * sending CORS headers — not a drop-in support of arbitrary URLs.\n *\n * Returns the decoded string, or `null` if no QR code was found in the\n * image — never throws for \"no code found\", only for a genuinely unusable\n * image (fails to load, no 2D canvas context).\n */\nexport async function decodeQrCode(\n imageDataUrl: string,\n): Promise<string | null> {\n const image = await loadImage(imageDataUrl);\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = image.naturalWidth || image.width;\n canvas.height = image.naturalHeight || image.height;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n throw new Error(\"No 2D canvas context available to decode the image.\");\n }\n\n ctx.drawImage(image, 0, 0, canvas.width, canvas.height);\n const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n const code = jsQR(imageData.data, imageData.width, imageData.height, {\n inversionAttempts: \"attemptBoth\",\n });\n\n return code?.data ?? null;\n}\n\nconst loadImage = (src: string): Promise<HTMLImageElement> =>\n new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => resolve(img);\n img.onerror = reject;\n img.src = src;\n });\n","import type { RouteRequest, RouteResponse } from \"@miniapps-sdk/types/routing\";\n\nexport interface RoutingBackendConfig {\n backend: \"osrm\" | \"valhalla\";\n baseUrl: string;\n}\n\n/**\n * Core routing service that can be used by both SDK (for direct fetching)\n * and Host (for handling bridge requests).\n */\nexport const RoutingService = {\n createErrorResponse(\n req: RouteRequest,\n code: NonNullable<RouteResponse[\"error\"]>[\"code\"],\n message: string,\n ): RouteResponse {\n return {\n error: { code, message },\n requestId: req.requestId,\n sdkVersion: req.sdkVersion,\n success: false,\n type: \"SDK_ROUTING_GETROUTE_RESPONSE\",\n };\n },\n\n decodePolyline(str: string, precision: number): [number, number][] {\n let index = 0,\n lat = 0,\n lng = 0;\n const coordinates: [number, number][] = [];\n const shift = 10 ** precision;\n\n while (index < str.length) {\n let b: any,\n shiftNum = 0,\n result = 0;\n do {\n b = str.charCodeAt(index++) - 63;\n result |= (b & 0x1f) << shiftNum;\n shiftNum += 5;\n } while (b >= 0x20);\n const dlat = result & 1 ? ~(result >> 1) : result >> 1;\n lat += dlat;\n\n shiftNum = 0;\n result = 0;\n do {\n b = str.charCodeAt(index++) - 63;\n result |= (b & 0x1f) << shiftNum;\n shiftNum += 5;\n } while (b >= 0x20);\n const dlng = result & 1 ? ~(result >> 1) : result >> 1;\n lng += dlng;\n\n coordinates.push([lng / shift, lat / shift]);\n }\n return coordinates;\n },\n\n async fetchOSRMRoute(\n req: RouteRequest,\n coords: [number, number][],\n profile: string,\n baseUrl: string,\n ): Promise<RouteResponse> {\n const coordsString = coords.map((c) => `${c[0]},${c[1]}`).join(\";\");\n const osrmProfile =\n profile === \"walking\" ? \"foot\" : profile === \"driving\" ? \"car\" : \"bike\";\n const url = `${baseUrl}/route/v1/${osrmProfile}/${coordsString}?overview=full&geometries=geojson&steps=true`;\n\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`OSRM Error: ${response.statusText}`);\n }\n const data = await response.json();\n\n if (data.code !== \"Ok\" || !data.routes || data.routes.length === 0) {\n throw new Error(\"NO_ROUTE\");\n }\n\n const route = data.routes[0];\n const steps =\n route.legs?.flatMap((leg: any) =>\n leg.steps?.map((step: any) => ({\n distance: step.distance,\n duration: step.duration,\n instruction: step.maneuver?.instruction || \"Continue\",\n })),\n ) || [];\n\n return {\n data: {\n distanceMeters: route.distance,\n durationSeconds: route.duration,\n geometry: route.geometry,\n steps,\n },\n requestId: req.requestId,\n sdkVersion: req.sdkVersion,\n success: true,\n type: \"SDK_ROUTING_GETROUTE_RESPONSE\",\n };\n },\n async fetchRoute(\n req: RouteRequest,\n config: RoutingBackendConfig,\n ): Promise<RouteResponse> {\n const { origin, destination, waypoints, profile, language } = req.payload;\n\n if (\n !this.isValidCoordinate(origin) ||\n !this.isValidCoordinate(destination)\n ) {\n return this.createErrorResponse(\n req,\n \"INVALID_INPUT\",\n \"Origin or destination coordinates are invalid.\",\n );\n }\n if (waypoints && !waypoints.every(this.isValidCoordinate)) {\n return this.createErrorResponse(\n req,\n \"INVALID_INPUT\",\n \"One or more waypoints are invalid.\",\n );\n }\n\n const allCoords = [origin, ...(waypoints || []), destination];\n\n try {\n if (config.backend === \"osrm\") {\n return await this.fetchOSRMRoute(\n req,\n allCoords,\n profile,\n config.baseUrl,\n );\n } else {\n return await this.fetchValhallaRoute(\n req,\n allCoords,\n profile,\n language,\n config.baseUrl,\n );\n }\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"NO_ROUTE\")) {\n return this.createErrorResponse(\n req,\n \"NO_ROUTE\",\n \"No route could be found for the given points.\",\n );\n }\n if (error instanceof TypeError) {\n return this.createErrorResponse(\n req,\n \"NETWORK_ERROR\",\n \"Failed to connect to the routing backend.\",\n );\n }\n return this.createErrorResponse(\n req,\n \"BACKEND_ERROR\",\n `Routing backend error: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n\n async fetchValhallaRoute(\n req: RouteRequest,\n coords: [number, number][],\n profile: string,\n language: string | undefined,\n baseUrl: string,\n ): Promise<RouteResponse> {\n const valhallaProfile =\n profile === \"driving\"\n ? \"auto\"\n : profile === \"walking\"\n ? \"pedestrian\"\n : \"bicycle\";\n const body = {\n costing: valhallaProfile,\n directions_options: {\n language: language || \"en-US\",\n },\n locations: coords.map((c) => ({ lat: c[1], lon: c[0] })),\n };\n\n const response = await fetch(`${baseUrl}/route`, {\n body: JSON.stringify(body),\n headers: { \"Content-Type\": \"application/json\" },\n method: \"POST\",\n });\n\n if (!response.ok) {\n throw new Error(`Valhalla Error: ${response.statusText}`);\n }\n const data = await response.json();\n\n if (!data.trip || !data.trip.legs || data.trip.legs.length === 0) {\n throw new Error(\"NO_ROUTE\");\n }\n\n const trip = data.trip;\n const decodedCoordinates = this.decodePolyline(trip.legs[0].shape, 6);\n\n const steps =\n trip.legs.flatMap((leg: any) =>\n leg.maneuvers?.map((maneuver: any) => ({\n distance: maneuver.length * 1000, // Valhalla returns km\n duration: maneuver.time,\n instruction: maneuver.instruction || \"Continue\",\n })),\n ) || [];\n\n return {\n data: {\n distanceMeters: trip.summary.length * 1000, // km to m\n durationSeconds: trip.summary.time,\n geometry: {\n coordinates: decodedCoordinates,\n type: \"LineString\",\n },\n steps,\n },\n requestId: req.requestId,\n sdkVersion: req.sdkVersion,\n success: true,\n type: \"SDK_ROUTING_GETROUTE_RESPONSE\",\n };\n },\n\n isValidCoordinate(coord: [number, number]): boolean {\n const [lng, lat] = coord;\n return lng >= -180 && lng <= 180 && lat >= -90 && lat <= 90;\n },\n};\n","{\n \"name\": \"@cloudparse/up-miniapps-sdk\",\n \"version\": \"0.7.3\",\n \"description\": \"UP Mini-App SDK for bridge communication between WebView and Host Shell\",\n \"author\": \"CloudParse Team\",\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"sideEffects\": [\n \"*.css\"\n ],\n \"engines\": {\n \"node\": \">=25.6.1\"\n },\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"browser\": \"./dist/index.browser.min.js\",\n \"types\": \"./dist/index.d.ts\",\n \"bin\": {\n \"up-sdk\": \"./bin/up-sdk.cjs\"\n },\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\",\n \"default\": \"./dist/index.js\"\n },\n \"./host\": {\n \"types\": \"./dist/host.d.ts\",\n \"import\": \"./dist/host.js\",\n \"require\": \"./dist/host.cjs\",\n \"default\": \"./dist/host.js\"\n },\n \"./components/Map\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\",\n \"default\": \"./dist/index.js\"\n },\n \"./style.css\": \"./dist/style.css\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"files\": [\n \"dist\",\n \"bin\"\n ],\n \"scripts\": {\n \"build\": \"tsc --noEmit --project tsconfig.json && tsup && npm run build:css\",\n \"build:css\": \"npx postcss src/index.css -o dist/style.css\",\n \"prebuild\": \"npm run clean\",\n \"clean\": \"rm -rf dist\",\n \"format\": \"biome format --write . --max-diagnostics 10000 --diagnostic-level error\",\n \"lint\": \"biome lint . --max-diagnostics 10000 --diagnostic-level error\",\n \"lint.fix\": \"biome check --write . --max-diagnostics 10000 --diagnostic-level error\",\n \"prepack\": \"npm run build\",\n \"storybook\": \"storybook dev -p 6006\",\n \"build-storybook\": \"storybook build\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.5.1\",\n \"@chromatic-com/storybook\": \"^5.2.1\",\n \"@mapbox/maki\": \"^8.2.0\",\n \"@storybook/addon-a11y\": \"^10.4.6\",\n \"@storybook/addon-docs\": \"^10.4.6\",\n \"@storybook/addon-mcp\": \"^0.1.3\",\n \"@storybook/addon-vitest\": \"^10.4.6\",\n \"@storybook/react-vite\": \"^10.4.6\",\n \"@tailwindcss/postcss\": \"^4.3.2\",\n \"@types/geojson\": \"^7946.0.16\",\n \"@types/react\": \"^19.2.17\",\n \"@types/react-dom\": \"^19.2.3\",\n \"@vitest/browser-playwright\": \"^4.1.10\",\n \"@vitest/coverage-v8\": \"^4.1.10\",\n \"autoprefixer\": \"^10.5.2\",\n \"playwright\": \"^1.61.1\",\n \"postcss\": \"^8.5.26\",\n \"postcss-cli\": \"^11.0.1\",\n \"storybook\": \"^10.4.6\",\n \"tailwindcss\": \"^4.3.2\",\n \"tsc-alias\": \"^1.8.17\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^5.9.3\",\n \"vitest\": \"^4.1.10\"\n },\n \"dependencies\": {\n \"@radix-ui/react-dialog\": \"^1.1.17\",\n \"@radix-ui/react-slot\": \"^1.3.0\",\n \"@vis.gl/react-maplibre\": \"^8.1.1\",\n \"class-variance-authority\": \"^0.7.1\",\n \"clsx\": \"^2.1.1\",\n \"jsqr\": \"^1.4.0\",\n \"lucide-react\": \"^1.22.0\",\n \"maplibre-gl\": \"^5.24.0\",\n \"motion\": \"^13.1.1\",\n \"qr-code-styling\": \"^1.9.2\",\n \"react\": \"^19.2.7\",\n \"react-dom\": \"^19.2.7\",\n \"react-modal-sheet\": \"^5.6.0\",\n \"shadcn\": \"^4.12.0\",\n \"tailwind-merge\": \"^3.6.0\"\n }\n}\n","import { Bridge } from \"@miniapps-sdk/bridge\";\nimport { renderMap } from \"@miniapps-sdk/components/MapWrapper\";\nimport { generateQrCode } from \"@miniapps-sdk/services/qrCodeService\";\nimport { decodeQrCode } from \"@miniapps-sdk/services/qrDecodeService\";\nimport type { RoutingBackendConfig } from \"@miniapps-sdk/services/routingService\";\nimport { RoutingService } from \"@miniapps-sdk/services/routingService\";\nimport {\n GlobalEvent,\n type HapticStyleType,\n type IAchievement,\n type IFidelityBalance,\n type IFidelityHistoryParams,\n type IFidelityTransaction,\n type IGenerateQrCodeOptions,\n type IInitializationOptions,\n type IInitializationResponse,\n type ILocationData,\n type INetworkOptions,\n type INetworkResponse,\n type IPaymentRequest,\n type IPickImageResult,\n type ISaveImageResult,\n type IUserProfile,\n type RouteRequest,\n type RouteResponse,\n type ScrollConfig,\n type SDKEvent,\n} from \"@miniapps-sdk/types\";\nimport { version } from \"../package.json\";\n\n// ... deepFreeze function omitted ...\nfunction deepFreeze<T extends object>(obj: T): T {\n // Retrieve the property names defined on obj\n const propNames = Object.getOwnPropertyNames(obj);\n\n // Freeze properties before freezing self\n for (const name of propNames) {\n const value = (obj as Record<string, unknown>)[name];\n\n if (\n value &&\n typeof value === \"object\" &&\n !Object.isFrozen(value) &&\n // Skip freezing of native objects or circular refs if any (though not expected here)\n !(value instanceof Bridge)\n ) {\n deepFreeze(value as object);\n }\n }\n\n return Object.freeze(obj);\n}\n\n/**\n * Main SDK for UP Mini-Apps.\n * Provides access to native device features, storage, identity, and shell UI.\n */\nlet globalRoutingConfig: RoutingBackendConfig | null = null;\n// Lives outside the class body (not `this.lastKnownEnv`) because the\n// exported `sdk` singleton below is `deepFreeze()`d — assigning to an\n// instance property on a frozen object throws `TypeError: Cannot assign to\n// read only property` in strict mode. That throw happened synchronously\n// inside `initialize()`, silently rejecting every single call — every app\n// fell into its `.catch()` standalone-mode fallback, `env` never got set,\n// and `createApiService` fell back to its default URL. Not a timing race\n// at all; this was the actual cause the whole time. Same reason\n// `globalRoutingConfig` above already lives at module scope instead of as\n// an instance field.\nlet lastKnownEnv: Record<string, unknown> | null = null;\n\nexport class MiniAppSDK {\n /**\n * Map services.\n * Provides access to MapLibre-based mapping components.\n */\n public readonly maps = Object.freeze({\n /**\n * Renders a MapLibre map into a DOM element.\n * Useful for non-React environments.\n */\n render: renderMap,\n });\n /**\n * QR code generation — the single source of truth for every Mini-App.\n * Runs entirely client-side (canvas, no Host Shell round-trip) and returns\n * a base64 PNG data URI, ready for an `<img src>` or `media.saveImage()`.\n * Mini-Apps must not reimplement this on their own.\n */\n public readonly qrCode = Object.freeze({\n /**\n * Decodes a QR code from a static image (base64 data URI or URL) —\n * e.g. a photo picked via `sdk.media.pickImage()` that already\n * contains a QR code, as an alternative to the live `<QRScanner>`.\n * @param imageDataUrl A base64 data URI (e.g. from `sdk.media.pickImage()`).\n * @returns The decoded string, or `null` if no QR code was found.\n */\n decode: (imageDataUrl: string): Promise<string | null> =>\n decodeQrCode(imageDataUrl),\n /**\n * @param data The value to encode (e.g. a deep link).\n * @param options Styling/labeling options — see {@link IGenerateQrCodeOptions}.\n * @returns A base64 PNG data URI.\n */\n generate: (\n data: string,\n options?: IGenerateQrCodeOptions,\n ): Promise<string> => generateQrCode(data, options),\n });\n private bridge: Bridge;\n /**\n * Local SQLite Storage.\n * Data is persisted on the device and is isolated per Mini-App.\n */\n public readonly storage = Object.freeze({\n /** Retrieves a value by key. */\n get: (key: string): Promise<string | null> =>\n this.bridge.send(\"STORAGE_GET\", { key }),\n /** Retrieves all key-value pairs stored for this Mini-App. */\n getAll: (): Promise<Record<string, string>> =>\n this.bridge.send(\"STORAGE_GET_ALL\"),\n /** Sets a value for a specific key. */\n set: (key: string, value: string): Promise<void> =>\n this.bridge.send(\"STORAGE_SET\", { key, value }),\n });\n /**\n * Hardware-level Secure Storage.\n * Data is stored in the device's secure enclave (Keychain/Keystore) and is isolated per Mini-App.\n */\n public readonly secureStore = Object.freeze({\n /** Retrieves a value by key from secure storage. */\n get: (key: string): Promise<string | null> =>\n this.bridge.send(\"SECURE_GET\", { key }),\n /** Sets a value for a specific key in secure storage. */\n set: (key: string, value: string): Promise<void> =>\n this.bridge.send(\"SECURE_SET\", { key, value }),\n });\n /**\n * Database Storage.\n * Access to user-app specific persistent database storage.\n */\n public readonly database = Object.freeze({\n /** Retrieves the user data stored in the backend database. */\n getUserData: <T = unknown>(): Promise<T> =>\n this.bridge.send<T>(\"DATABASE_GET_USER_DATA\"),\n /** Updates the user data stored in the backend database. */\n setUserData: <T = unknown>(data: T): Promise<void> =>\n this.bridge.send<void>(\"DATABASE_SET_USER_DATA\", { data }),\n });\n /**\n * Device Location services.\n */\n public readonly location = Object.freeze({\n /**\n * Retrieves the current GPS position of the device.\n */\n getCurrentPosition: (): Promise<ILocationData> =>\n this.bridge.send(\"GET_CURRENT_POSITION\"),\n /**\n * Starts the continuous location and sensor stream.\n * @param config Optional configuration for thresholds and intervals.\n */\n startStream: (\n config?: import(\"./types\").LocationStreamConfig,\n ): Promise<void> => this.bridge.send(\"START_LOCATION_STREAM\", config),\n /**\n * Stops the continuous location and sensor stream.\n */\n stopStream: (): Promise<void> => this.bridge.send(\"STOP_LOCATION_STREAM\"),\n });\n /**\n * Identity & Profile management.\n */\n public readonly user = Object.freeze({\n /**\n * Fetch user profile data.\n * @param fields Optional list of specific fields to retrieve (e.g., ['fullName', 'username']).\n */\n getProfile: <T extends keyof IUserProfile>(\n fields?: T[],\n ): Promise<Partial<IUserProfile>> =>\n this.bridge.send(\"GET_USER_PROFILE\", { fields }),\n /**\n * Fetch profile picture as a string of the current user, or a map of profile pictures from a list of user UUIDs.\n * @param uuids Optional list of user UUIDs.\n */\n getProfilePicture: ((uuids?: string[]) => {\n return this.bridge.send(\"GET_PROFILE_PICTURE\", { uuids: uuids || [] });\n }) as {\n (): Promise<string>;\n (uuids: string[]): Promise<Record<string, string>>;\n },\n });\n /**\n * Explicit Permission Management.\n * Allows requesting access to sensitive device features or user data.\n */\n public readonly permission = Object.freeze({\n /**\n * Explicitly request access to sensitive data.\n * @param type The type of permission to request ('location', 'profile', or 'camera').\n * @param fields If requesting 'profile', the specific fields required.\n */\n request: ((type: \"location\" | \"profile\" | \"camera\", fields?: string[]) => {\n return this.bridge.send(\"REQUEST_PERMISSION\", { fields, type });\n }) as {\n (type: \"location\"): Promise<boolean>;\n (type: \"profile\", fields: (keyof IUserProfile)[]): Promise<boolean>;\n (type: \"camera\"): Promise<boolean>;\n },\n });\n /**\n * Media & Gallery integration.\n */\n public readonly media = Object.freeze({\n /**\n * Opens the device's native photo gallery picker via the Host Shell and\n * returns the chosen image as base64. Distinct permission grant from\n * `saveImage` (read vs. write access to the photo library) — the Host\n * Shell requests it independently.\n */\n pickImage: (): Promise<IPickImageResult> =>\n this.bridge.send(\"PICK_IMAGE\", {}),\n /**\n * Saves a base64-encoded image to the device's photo gallery via the Host Shell.\n * A plain browser `<a download>` does not work inside the native WebView (no\n * download manager is wired up) — this is the only way to persist an image\n * generated inside a Mini-App (e.g. a QR code) to the device.\n * @param base64 Base64-encoded image data, with or without the `data:image/...;base64,` prefix.\n * @param filename Suggested filename (without extension).\n */\n saveImage: (base64: string, filename?: string): Promise<ISaveImageResult> =>\n this.bridge.send(\"SAVE_IMAGE\", { base64, filename }),\n });\n /**\n * Payments integration.\n */\n public readonly payment = Object.freeze({\n /**\n * Triggers the native payment flow.\n * @param payload Amount, currency, and itemized list for the payment.\n */\n request: (\n payload: IPaymentRequest,\n ): Promise<{ success: true; transactionId: string }> =>\n this.bridge.send(\"PAYMENT_REQUEST\", payload),\n });\n /**\n * Live Activities & Notifications.\n * Allows the Mini-App to display real-time updates in the host shell.\n */\n public readonly activity = Object.freeze({\n /**\n * Starts a new live activity.\n * @param id Unique identifier for the activity.\n * @param title Display title for the activity.\n * @param status Initial status message.\n */\n start: (id: string, title: string, status: string): Promise<void> =>\n this.bridge.send(\"START_ACTIVITY\", { id, status, title }),\n });\n /**\n * Haptic feedback.\n */\n public readonly haptic = Object.freeze({\n /**\n * Triggers a haptic vibration on the device.\n * @param style The style of haptic feedback (e.g., 'light', 'medium', 'heavy', 'success', 'warning', 'error').\n */\n trigger: (style: HapticStyleType): Promise<void> =>\n this.bridge.send(\"TRIGGER_HAPTIC\", { style }),\n });\n /**\n * Network Proxy.\n * Allows the Mini-App to make network requests through the host shell to bypass CORS or use host-level authentication.\n */\n public readonly network = Object.freeze({\n /**\n * Performs a network request via the host shell.\n * @param options Request method, URL, headers, and body.\n */\n request: async <T = unknown>(\n options: INetworkOptions,\n ): Promise<INetworkResponse<T>> => {\n return this.bridge.send(\"NETWORK_REQUEST\", options);\n },\n });\n /**\n * Navigation and Journey controls.\n * Allows programmatically starting itineraries and managing navigation state.\n */\n public readonly navigation = Object.freeze({\n /**\n * Aborts the current navigation journey.\n */\n abort: (): void => {\n this.bridge.handleNativeMessage({\n eventName: \"SDK_NAVIGATION_ABORT\",\n type: \"EVENT\",\n });\n },\n /**\n * Creates a new itinerary preview.\n * @param options Destination and routing options.\n */\n createJourney: (options: {\n destination: [number, number];\n origin?: [number, number];\n profile?: \"driving\" | \"cycling\" | \"walking\";\n }): void => {\n this.bridge.handleNativeMessage({\n eventName: \"SDK_NAVIGATION_CREATE\",\n payload: { ...options, mode: \"preview\" },\n type: \"EVENT\",\n });\n },\n /**\n * Starts the active navigation (active guidance).\n */\n start: (): void => {\n this.bridge.handleNativeMessage({\n eventName: \"SDK_NAVIGATION_START\",\n type: \"EVENT\",\n });\n },\n });\n /**\n * Fidelity & Points program integration.\n */\n public readonly fidelity = Object.freeze({\n /** Returns current fidelity balance. */\n getFidelityBalance: (): Promise<IFidelityBalance> =>\n this.bridge.send(\"GET_FIDELITY_BALANCE\"),\n /**\n * Retrieves fidelity transaction history.\n * @param params Filtering and pagination parameters.\n */\n getFidelityHistory: (\n params?: IFidelityHistoryParams,\n ): Promise<IFidelityTransaction[]> =>\n this.bridge.send(\"GET_FIDELITY_HISTORY\", params),\n /**\n * Triggers the native fidelity history view.\n * @param options.isDark Theme to render the native view in. Pass the\n * mini-app's current theme explicitly — the native history screen is a\n * standalone view and does not read it from `updateContext`.\n */\n showHistory: (options?: { isDark?: boolean }): Promise<void> =>\n this.bridge.send(\"SHOW_FIDELITY_HISTORY\", options),\n /**\n * Authorize spending fidelity points (FPoints) via Two-Phase Authorization.\n * @param intentUuid UUID generated by your backend for the transaction.\n */\n spendFPoints: (\n intentUuid: string,\n ): Promise<{ success: boolean; transactionId: string }> =>\n this.bridge.send(\"SPEND_FPOINTS\", { intentUuid }),\n });\n /**\n * UI and Navigation controls.\n */\n public readonly ui = Object.freeze({\n /** Closes the Mini-App and returns to the host shell. */\n exit: (): Promise<void> => this.bridge.send(\"EXIT\"),\n /**\n * Configures native scroll behaviors like Pull-to-Refresh and Infinite Scroll.\n * @param config Scroll configuration for top/bottom detection.\n */\n setScrollConfig: (config: ScrollConfig): Promise<void> =>\n this.bridge.send(\"SET_SCROLL_CONFIG\", config),\n });\n /**\n * Debug controls\n */\n public readonly debug = Object.freeze({\n /**\n * Log to the shell app\n * @param message\n */\n log: (...message: unknown[]) => this.bridge.send(\"DEBUG_LOG\", { message }),\n });\n /**\n * Routing integration (OSRM / Valhalla).\n * Provides access to route calculation and rendering on the host map.\n */\n public readonly routing = Object.freeze({\n /**\n * Clears the currently rendered route.\n */\n clearRoute: (): Promise<void> => {\n const requestId = crypto.randomUUID\n ? crypto.randomUUID()\n : Math.random().toString(36).substring(2);\n return this.bridge.send(\"SDK_ROUTING_CLEARROUTE\", {\n requestId,\n sdkVersion: version,\n });\n },\n\n /**\n * Draws the calculated route on the host map.\n * @param routeData The route data returned by getRoute.\n */\n drawRoute: (\n routeData: NonNullable<RouteResponse[\"data\"]>,\n ): Promise<void> => {\n const requestId = crypto.randomUUID\n ? crypto.randomUUID()\n : Math.random().toString(36).substring(2);\n return this.bridge.send(\"SDK_ROUTING_DRAWROUTE\", {\n payload: { routeData },\n requestId,\n sdkVersion: version,\n });\n },\n /**\n * Calculates a route between points.\n * @param payload Request payload containing origin, destination, and options.\n */\n getRoute: async (\n payload: RouteRequest[\"payload\"],\n ): Promise<NonNullable<RouteResponse[\"data\"]>> => {\n // Create a unique requestId\n const requestId = crypto.randomUUID\n ? crypto.randomUUID()\n : Math.random().toString(36).substring(2);\n\n const request: RouteRequest = {\n payload,\n requestId,\n sdkVersion: version,\n type: \"SDK_ROUTING_GETROUTE\",\n };\n\n // If a direct backend is configured, bypass the bridge\n if (globalRoutingConfig) {\n const response = await RoutingService.fetchRoute(\n request,\n globalRoutingConfig,\n );\n if (response.success && response.data) {\n return response.data;\n }\n throw new Error(response.error?.message || \"Routing failed\");\n }\n\n // Otherwise, use the bridge\n return this.bridge.send(\"SDK_ROUTING_GETROUTE\", {\n payload,\n requestId,\n sdkVersion: version,\n });\n },\n });\n\n constructor() {\n this.bridge = new Bridge();\n\n // Keep lastKnownEnv current for the lifetime of this SDK instance,\n // independent of whatever the consumer app does with the same event.\n this.bridge.on<{ env?: Record<string, unknown> }>(\n GlobalEvent.UPDATE_CONTEXT,\n (data) => {\n if (data?.env) lastKnownEnv = data.env;\n },\n );\n\n // Bind methods to this instance to preserve context if pulled out\n this.initialize = this.initialize.bind(this);\n this.getEnv = this.getEnv.bind(this);\n this.achievement = this.achievement.bind(this);\n this.achievements = this.achievements.bind(this);\n this.on = this.on.bind(this);\n this.off = this.off.bind(this);\n }\n\n /**\n * Configures global SDK settings.\n */\n public config(options: { routingBackend?: RoutingBackendConfig }): void {\n if (options.routingBackend) {\n globalRoutingConfig = options.routingBackend;\n }\n }\n\n /**\n * Updates the global context shared between the Mini-App and the native shell.\n * Useful for synchronizing state like theme preferences, UI flags, or custom app-specific context.\n * @param context Partial context object to merge into the existing shell context.\n */\n public updateContext(context: Record<string, unknown>): Promise<void> {\n return this.bridge.send(\"UPDATE_CONTEXT\", context);\n }\n\n /**\n * The starting point for the Mini-App. Must be called before any other SDK methods.\n * @param options The options to provide to the shell app\n */\n public async initialize(\n options: IInitializationOptions,\n ): Promise<IInitializationResponse> {\n const res = await this.bridge.send<IInitializationResponse>(\n \"INITIALIZE\",\n options,\n );\n if (res?.env) lastKnownEnv = res.env;\n return res;\n }\n\n /**\n * Returns the last known `env` (shell-provided config like `backendUrl`),\n * refreshed automatically by `initialize()` and every `UPDATE_CONTEXT`\n * push — read this instead of caching your own copy of `env` values.\n * Returns `null` before the first successful `initialize()`/context push.\n */\n public getEnv<\n T extends Record<string, unknown> = Record<string, unknown>,\n >(): T | null {\n return lastKnownEnv as T | null;\n }\n\n /**\n * Fetches a single Achievement's current progress by slug — read-only, for\n * rendering things like a progress bar. Progress is reported server-side\n * by the mini-app's own backend calling the Hub's M2M endpoint directly;\n * there is no corresponding \"report progress\" method on this SDK.\n * @param slug Unique slug identifying the Achievement.\n */\n public achievement(slug: string): Promise<IAchievement> {\n return this.bridge.send(\"GET_ACHIEVEMENT\", { slug });\n }\n\n /**\n * Fetches every Achievement (with current progress) visible to this\n * mini-app — read-only, same boundary as {@link MiniAppSDK.achievement}.\n */\n public achievements(): Promise<IAchievement[]> {\n return this.bridge.send(\"GET_ACHIEVEMENTS\");\n }\n\n /**\n * Registers a callback for a specific event from the native shell.\n * @param event The name of the event to listen for.\n * @param callback The function to execute when the event is triggered.\n * @returns A function to unregister the listener.\n */\n public on<T = unknown>(\n event: SDKEvent,\n callback: (data: T) => void,\n ): () => void {\n return this.bridge.on<T>(event as string, callback);\n }\n\n /**\n * Unregisters a previously registered event listener.\n * @param event The name of the event.\n * @param callback The callback function to remove.\n */\n public off<T = unknown>(event: SDKEvent, callback: (data: T) => void): void {\n this.bridge.off<T>(event as string, callback);\n }\n}\n\n/**\n * Singleton instance of the MiniAppSDK.\n * Frozen to prevent tampering.\n */\nexport const sdk = deepFreeze(new MiniAppSDK());\n","import { MockLocationContext } from \"@miniapps-sdk/components/Map/MockLocationContext\";\nimport { Button } from \"@miniapps-sdk/components/ui/button\";\nimport { sdk } from \"@miniapps-sdk/sdk\";\nimport { GeolocationEvent, type IAchievement } from \"@miniapps-sdk/types\";\nimport type React from \"react\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\n/**\n * Plausible fake Achievements for Storybook (via `SDKProvider`/`BridgeMocker`)\n * — same sample data shape as `Bridge.handleMockMessage`'s own\n * `GET_ACHIEVEMENT`/`GET_ACHIEVEMENTS` mocks (`src/bridge.ts`), kept as a\n * separate small copy here since `BridgeMocker` intercepts `bridge.send`\n * entirely and never falls through to that default handler for types it\n * recognizes — same pattern as `GET_FIDELITY_BALANCE` below.\n */\n// Deliberately no `imageUrl` on any of these — every consuming app's own\n// achievement UI falls back to its own real logo asset when `imageUrl` is\n// unset, so mocking a generic/fake image here would show a placeholder\n// that doesn't exist in any real app's own branding. See bridge.ts's own\n// `MOCK_ACHIEVEMENTS` (same data, same reasoning) for the standalone-dev\n// counterpart of this Storybook-only mock.\nconst MOCK_ACHIEVEMENTS: IAchievement[] = [\n {\n completed: true,\n description: \"Complete your first navigation journey.\",\n playerActionCount: 1,\n priority: 1,\n slug: \"first-journey\",\n title: \"First Steps\",\n totalActionCount: 1,\n upReward: 20,\n xpReward: 40,\n },\n {\n completed: false,\n description: \"Discover 5 points of interest around Annecy.\",\n playerActionCount: 3,\n priority: 2,\n slug: \"explore-5-pois\",\n title: \"Explorer\",\n totalActionCount: 5,\n upReward: 50,\n xpReward: 100,\n },\n {\n completed: false,\n description: \"Scan 10 QR codes at partner venues.\",\n playerActionCount: 4,\n priority: 3,\n slug: \"scan-10-qrcodes\",\n title: \"Code Breaker\",\n totalActionCount: 10,\n upReward: 80,\n xpReward: 150,\n },\n];\n\nexport interface BridgeMockerProps {\n /** Optional appId to return in INITIALIZE response */\n appId?: string;\n /** Initial simulated location [lng, lat] */\n initialLocation?: [number, number];\n /** Whether the simulated user should be moving */\n isMoving?: boolean;\n /** An array of coordinates to follow. If provided, overrides random movement. */\n simulationPath?: [number, number][];\n /** Speed multiplier for the simulation interval. Default is 1. Higher is faster. */\n simulationSpeed?: number;\n /** Mock JWT token for NETWORK_REQUEST mocking */\n mockJWTToken?: string;\n children: React.ReactNode;\n}\n\nconst AVATAR_MOUTH_VARIANTS = [\n \"variant03\",\n \"variant07\",\n \"variant08\",\n \"variant09\",\n \"variant10\",\n \"variant11\",\n \"variant12\",\n \"variant13\",\n \"variant14\",\n \"variant15\",\n \"variant16\",\n \"variant21\",\n \"variant22\",\n \"variant23\",\n \"variant25\",\n \"variant26\",\n \"variant27\",\n \"variant28\",\n \"variant29\",\n \"variant30\",\n].join(\",\");\n\nconst AVATAR_EYES_VARIANTS = [\"variant03\", \"variant04\", \"variant05\"].join(\",\");\n\n/**\n * Fast, non-cryptographic string hash (djb2 variant), same as shell's\n * `hashToShortSeed` (up/shell/src/utils/avatar.ts) — keeps the mocked\n * avatar's seed-to-image mapping identical to what the real host app\n * would render for the same uuid.\n */\nfunction hashToShortSeed(input: string): string {\n let hash = 5381;\n for (let i = 0; i < input.length; i++) {\n hash = (hash * 33) ^ input.charCodeAt(i);\n }\n return (hash >>> 0).toString(36);\n}\n\n/**\n * Mirrors the shell's `getAvatarUrl` (up/shell/src/utils/avatar.ts,\n * notionists-neutral, png) so mocked profile pictures match what the real\n * host app returns.\n */\nfunction getMockAvatarUrl(seed: string): string {\n const shortSeed = hashToShortSeed(seed);\n return `https://api.dicebear.com/10.x/notionists-neutral/png?seed=${shortSeed}&mouth=${AVATAR_MOUTH_VARIANTS}&eyes=${AVATAR_EYES_VARIANTS}&glassesProbability=50`;\n}\n\n/** Decodes a JWT's payload without verifying its signature — this is dev-only\n * mock tooling reading a token the caller already trusts enough to hand to\n * `mockJWTToken`, not a security boundary. Returns null on any malformed\n * input rather than throwing, since callers treat \"no usable claims\" and\n * \"no token at all\" identically (fall through to the hardcoded default\n * profile below). */\nfunction decodeMockJWTPayload(token: string): Record<string, unknown> | null {\n try {\n const raw = token.startsWith(\"Bearer \") ? token.slice(7) : token;\n const base64Url = raw.split(\".\")[1];\n const base64 = base64Url.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const jsonPayload = decodeURIComponent(\n atob(base64)\n .split(\"\")\n .map((c) => `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`)\n .join(\"\"),\n );\n\n return JSON.parse(jsonPayload);\n } catch {\n return null;\n }\n}\n\n/**\n * Builds the mocked profile object INITIALIZE/GET_USER_PROFILE return, from\n * `mockJWTToken`'s own claims when present and decodable, falling back to a\n * fixed placeholder (\"Smart Caveman\") otherwise. This is the single place a\n * dev/mock profile is derived from a token — every `up-miniapps-*` app used\n * to each hand-roll its own JWT-decode-and-override for this (parsing\n * `VITE_DEV_TOKEN` client-side, then discarding whatever this mock returned\n * in favor of that), which meant two devices/tabs sharing one token-bearing\n * build always collapsed onto whatever ONE profile that app's own decode\n * produced — real per-device distinctness only ever came from the token\n * actually differing, never from anything the mock itself did. Deriving it\n * here instead means a consuming app can simply trust `res.profile`/\n * `sdk.user.getProfile()` like it already must in production, with no\n * separate mock-aware code path to keep in sync or accidentally trust over a\n * real shell-provided profile.\n */\nfunction buildMockProfile(mockJWTToken: string | undefined) {\n const claims = mockJWTToken ? decodeMockJWTPayload(mockJWTToken) : null;\n const uuid = (claims?.sub as string | undefined) || \"mock-user-42\";\n const fullName =\n (claims?.name as string | undefined) ||\n (claims?.username as string | undefined) ||\n \"Smart Caveman\";\n const username = (claims?.username as string | undefined) || \"smart_caveman\";\n const [firstName, ...lastNameParts] = fullName.split(\" \");\n return {\n admin: true,\n countryCode: \"FR\",\n createdAt: new Date().toISOString(),\n email: \"caveman@up.app\",\n firstName: firstName || \"Smart\",\n fullName,\n lastName: lastNameParts.join(\" \") || \"Caveman\",\n localNumber: \"0600000000\",\n ups: 100,\n username,\n uuid,\n xp: 500,\n };\n}\n\n/**\n * Calculates bearing between two points\n */\nconst getBearing = (p1: [number, number], p2: [number, number]) => {\n const lat1 = (p1[1] * Math.PI) / 180;\n const lat2 = (p2[1] * Math.PI) / 180;\n const dLon = ((p2[0] - p1[0]) * Math.PI) / 180;\n const y = Math.sin(dLon) * Math.cos(lat2);\n const x =\n Math.cos(lat1) * Math.sin(lat2) -\n Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon);\n return ((Math.atan2(y, x) * 180) / Math.PI + 360) % 360;\n};\n\n/**\n * A utility component for Storybook that intercepts SDK bridge calls,\n * simulates the behavior of the native shell app.\n *\n * NOTE: Logs are now handled by the standalone DebugConsole component.\n */\nexport const BridgeMocker: React.FC<BridgeMockerProps> = ({\n appId,\n initialLocation = [6.1258, 45.9058], // Annecy default\n isMoving = false,\n simulationPath,\n simulationSpeed = 1,\n mockJWTToken,\n children,\n}) => {\n const [autoMove, setAutoMove] = useState(isMoving);\n const [location, setLocation] = useState<[number, number]>(initialLocation);\n const [heading, setHeading] = useState<number>(0);\n const [speedMultiplier, setSpeedMultiplier] = useState(simulationSpeed);\n const [isReady, setIsReady] = useState(false);\n const [isMinimized, setIsMinimized] = useState(true);\n const [radiusMeters, setRadiusMeters] = useState(0);\n const [radiusUnit, setRadiusUnit] = useState<\"m\" | \"km\">(\"m\");\n const [isPlacingLocation, setIsPlacingLocation] = useState(false);\n\n const streamIntervalRef = useRef<any | null>(null);\n const pathIndexRef = useRef<number>(0);\n const activeConfigRef = useRef<any>(null); // Keep track of the last START_LOCATION_STREAM config\n\n // Refs for interval to read latest state without rebinding\n const stateRef = useRef({\n autoMove,\n heading,\n location,\n mockJWTToken,\n pushLocationUpdate: () => {},\n setHeading,\n setLocation,\n simulationPath,\n speedMultiplier,\n });\n\n const pushLocationUpdateFor = useCallback(\n (coords: [number, number], headingDeg: number) => {\n const currentState = stateRef.current;\n const payload = {\n accelerometer: null,\n heading: {\n accuracy: 3,\n magneticHeading: headingDeg,\n trueHeading: headingDeg,\n },\n location: {\n coords: {\n accuracy: 10,\n altitude: 0,\n altitudeAccuracy: null,\n heading: headingDeg,\n latitude: coords[1],\n longitude: coords[0],\n speed: currentState.autoMove\n ? 1.5 * currentState.speedMultiplier\n : 0,\n },\n timestamp: Date.now(),\n },\n timestamp: Date.now(),\n };\n\n (window as any).__MiniAppBridge?.onNativeMessage({\n eventName: GeolocationEvent.LOCATION_STREAM_UPDATE,\n payload,\n type: \"EVENT\",\n });\n },\n [],\n );\n\n const pushLocationUpdate = useCallback(() => {\n const currentState = stateRef.current;\n pushLocationUpdateFor(currentState.location, currentState.heading);\n }, [pushLocationUpdateFor]);\n\n // \"Drop location here\" — used both by the map-click placement mode and\n // could be reused for a future \"teleport to point\" input. Pushes the\n // update from the given coords directly instead of reading stateRef\n // (which lags one render behind a same-tick setLocation call).\n const placeLocation = useCallback(\n (coords: [number, number]) => {\n setLocation(coords);\n setIsPlacingLocation(false);\n pushLocationUpdateFor(coords, stateRef.current.heading);\n },\n [pushLocationUpdateFor],\n );\n\n useEffect(() => {\n stateRef.current = {\n autoMove,\n heading,\n location,\n mockJWTToken,\n pushLocationUpdate,\n setHeading,\n setLocation,\n simulationPath,\n speedMultiplier,\n };\n }, [\n location,\n heading,\n autoMove,\n pushLocationUpdate,\n simulationPath,\n speedMultiplier,\n mockJWTToken,\n ]);\n\n // Sync prop changes\n useEffect(() => {\n setAutoMove(isMoving);\n }, [isMoving]);\n\n useEffect(() => {\n setSpeedMultiplier(simulationSpeed);\n }, [simulationSpeed]);\n\n // Reset path index if path changes\n useEffect(() => {\n if (simulationPath && simulationPath.length > 0) {\n pathIndexRef.current = 0;\n setLocation(simulationPath[0]); // Snap to start of new path\n }\n }, [simulationPath]);\n\n // Handle dynamic interval restart when speed changes\n // biome-ignore lint/correctness/useExhaustiveDependencies: We intentionally only want to re-trigger when speedMultiplier changes, not on every config change\n useEffect(() => {\n if (streamIntervalRef.current && activeConfigRef.current) {\n // Re-trigger startStream to apply new speed\n (sdk as any).bridge.send(\n \"START_LOCATION_STREAM\",\n activeConfigRef.current,\n );\n }\n }, [speedMultiplier]);\n\n // Setup interception synchronously before children render\n useEffect(() => {\n const bridge = (sdk as any).bridge;\n const originalSend = bridge.send.bind(bridge);\n\n const stopStream = () => {\n if (streamIntervalRef.current) {\n clearInterval(streamIntervalRef.current);\n streamIntervalRef.current = null;\n }\n activeConfigRef.current = null;\n };\n\n const startStream = (config?: any) => {\n stopStream();\n activeConfigRef.current = config || {};\n\n const baseInterval = config?.interval || 500;\n const interval = Math.max(\n 10,\n baseInterval / stateRef.current.speedMultiplier,\n );\n\n streamIntervalRef.current = setInterval(() => {\n const state = stateRef.current;\n\n if (state.autoMove) {\n if (state.simulationPath && state.simulationPath.length > 0) {\n // Path following logic\n if (pathIndexRef.current < state.simulationPath.length - 1) {\n const currentPoint = state.simulationPath[pathIndexRef.current];\n const nextPoint = state.simulationPath[pathIndexRef.current + 1];\n\n pathIndexRef.current += 1;\n const newHeading = getBearing(currentPoint, nextPoint);\n\n state.setHeading(newHeading);\n state.setLocation(nextPoint);\n } else {\n // Reached end of path\n state.setLocation(\n state.simulationPath[state.simulationPath.length - 1],\n );\n }\n } else {\n // Random drift\n state.setLocation((prev) => [\n prev[0] + (Math.random() - 0.5) * 0.0001,\n prev[1] + (Math.random() - 0.5) * 0.0001,\n ]);\n }\n }\n\n state.pushLocationUpdate();\n }, interval);\n };\n\n const simulateNetworkRequest = async (payload: any) => {\n const {\n url,\n method = \"GET\",\n headers: incomingHeaders = {},\n body,\n } = payload;\n const state = stateRef.current;\n\n const headers = new Headers(incomingHeaders);\n\n if (state.mockJWTToken) {\n headers.set(\n \"Authorization\",\n `Bearer ${state.mockJWTToken.replace(\"Bearer \", \"\")}`,\n );\n }\n\n if (body && typeof body === \"object\" && !headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n\n try {\n const response = await fetch(url, {\n body: body\n ? typeof body === \"string\"\n ? body\n : JSON.stringify(body)\n : undefined,\n headers,\n method,\n });\n\n const contentType = response.headers.get(\"content-type\");\n let responseData: any;\n\n if (contentType?.includes(\"application/json\")) {\n responseData = await response.json();\n } else {\n responseData = await response.text();\n }\n\n const headersObj: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n headersObj[key] = value;\n });\n\n return {\n data: responseData,\n headers: headersObj,\n status: response.status,\n statusText: response.statusText,\n };\n } catch (error: any) {\n throw {\n error: error.message || \"Network request failed\",\n status: 0,\n };\n }\n };\n\n // Intercept bridge calls globally\n bridge.send = async (type: string, payload: any) => {\n // 1. Mandatory Lifecycle\n if (type === \"INITIALIZE\") {\n return Promise.resolve({\n appId, // Legacy support\n context: { theme: \"dark\" }, // Legacy support\n description: \"Mocked for Dev\",\n env: {},\n insets: { bottom: 0, left: 0, right: 0, top: 0 },\n name: \"Vite Dev (Mock)\",\n params: {},\n profile: buildMockProfile(stateRef.current.mockJWTToken),\n success: true,\n userData: {},\n uuid: appId || \"mock-app-id\",\n version: \"1.0.0\",\n });\n }\n\n // 2. Location\n if (type === \"GET_CURRENT_POSITION\") {\n const state = stateRef.current;\n return Promise.resolve({\n coords: {\n accuracy: 10,\n altitude: 0,\n altitudeAccuracy: 0,\n heading: state.heading,\n latitude: state.location[1],\n longitude: state.location[0],\n speed: state.autoMove ? 1.5 * state.speedMultiplier : 0,\n },\n timestamp: Date.now(),\n });\n }\n if (type === \"START_LOCATION_STREAM\") {\n startStream(payload);\n return Promise.resolve();\n }\n if (type === \"STOP_LOCATION_STREAM\") {\n stopStream();\n return Promise.resolve();\n }\n\n // 3. Network\n if (type === \"NETWORK_REQUEST\") {\n return simulateNetworkRequest(payload);\n }\n\n // 4. Storage & Identity Mocks\n if (type === \"STORAGE_GET\" || type === \"SECURE_GET\") {\n return Promise.resolve(localStorage.getItem(`mock_sdk_${payload.key}`));\n }\n if (type === \"STORAGE_SET\" || type === \"SECURE_SET\") {\n localStorage.setItem(`mock_sdk_${payload.key}`, payload.value);\n return Promise.resolve();\n }\n if (type === \"GET_USER_PROFILE\") {\n return Promise.resolve(buildMockProfile(stateRef.current.mockJWTToken));\n }\n if (type === \"GET_PROFILE_PICTURE\") {\n const uuids = payload?.uuids || [];\n if (uuids.length === 0) {\n return Promise.resolve(getMockAvatarUrl(\"dummy\"));\n }\n const map: Record<string, string> = {};\n for (const uuid of uuids) {\n map[uuid] = getMockAvatarUrl(uuid);\n }\n return Promise.resolve(map);\n }\n\n // 5. Fidelity & Payment Mocks\n if (type === \"GET_FIDELITY_BALANCE\") {\n return Promise.resolve({ balance: 1337, currency: \"FPoints\" });\n }\n\n // 5b. Achievement Mocks\n if (type === \"GET_ACHIEVEMENTS\") {\n return Promise.resolve(MOCK_ACHIEVEMENTS);\n }\n if (type === \"GET_ACHIEVEMENT\") {\n const slug = payload?.slug;\n return Promise.resolve(\n MOCK_ACHIEVEMENTS.find((a) => a.slug === slug) ?? {\n completed: false,\n description: \"Mocked achievement (no native shell attached).\",\n playerActionCount: 0,\n priority: 1,\n slug: slug || \"unknown-achievement\",\n title: slug || \"Unknown Achievement\",\n totalActionCount: 1,\n upReward: 0,\n xpReward: 0,\n },\n );\n }\n if (type === \"PAYMENT_REQUEST\") {\n return Promise.resolve({\n success: true,\n transactionId: `tx_${Math.random().toString(36).slice(2)}`,\n });\n }\n\n // 6. UI & Haptic (No-ops)\n if (\n type === \"TRIGGER_HAPTIC\" ||\n type === \"EXIT\" ||\n type === \"UPDATE_CONTEXT\"\n ) {\n return Promise.resolve({ success: true });\n }\n\n return originalSend(type, payload);\n };\n\n setIsReady(true);\n\n return () => {\n stopStream();\n bridge.send = originalSend;\n };\n }, [appId]);\n\n const radiusInMeters =\n radiusUnit === \"km\" ? radiusMeters * 1000 : radiusMeters;\n\n const mockLocationContextValue = useMemo(\n () => ({\n isPlacingLocation,\n placeLocation,\n radiusMeters: radiusInMeters,\n }),\n [isPlacingLocation, placeLocation, radiusInMeters],\n );\n\n if (!isReady) return null;\n\n return (\n <div className=\"relative w-full h-full\">\n {/* Wrapped Story */}\n <div className=\"w-full h-full\">\n <MockLocationContext.Provider value={mockLocationContextValue}>\n {children}\n </MockLocationContext.Provider>\n </div>\n\n {isMinimized ? (\n <Button\n 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!\"\n onClick={() => setIsMinimized(false)}\n title=\"Open Simulation Controls\"\n type=\"button\"\n variant=\"ghost\"\n >\n <svg\n className=\"group-hover:scale-110 transition-transform\"\n fill=\"none\"\n height=\"14\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2\"\n viewBox=\"0 0 24 24\"\n width=\"14\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M21 4H3\" />\n <path d=\"M10 8H3\" />\n <path d=\"M21 12H3\" />\n <path d=\"M10 16H3\" />\n <path d=\"M21 20H3\" />\n <circle cx=\"14\" cy=\"8\" r=\"2\" />\n <circle cx=\"14\" cy=\"16\" r=\"2\" />\n </svg>\n </Button>\n ) : (\n <div\n 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\"\n style={{ zIndex: 9998 }}\n >\n {/* Header */}\n <div\n 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\"\n onClick={() => setIsMinimized(true)}\n >\n <span className=\"font-bold text-slate-100 flex items-center gap-2\">\n <span className=\"text-lg\">🛠️</span> Simulation Controls\n </span>\n <Button\n className=\"text-slate-500 hover:text-white p-0 h-auto hover:bg-transparent cursor-pointer\"\n type=\"button\"\n variant=\"ghost\"\n >\n ▼\n </Button>\n </div>\n\n <div className=\"p-4 flex flex-col gap-3\">\n <div className=\"flex justify-between items-center\">\n <label className=\"flex items-center gap-2 cursor-pointer\">\n <input\n checked={autoMove}\n className=\"accent-blue-500 w-4 h-4\"\n onChange={(e) => setAutoMove(e.target.checked)}\n type=\"checkbox\"\n />\n <span className=\"text-slate-200 font-bold\">\n Auto-Move {simulationPath ? \"(Path)\" : \"(Random)\"}\n </span>\n </label>\n\n <div className=\"flex items-center gap-2\">\n <span className=\"text-[10px] text-slate-500\">Speed:</span>\n <select\n 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]\"\n onChange={(e) => setSpeedMultiplier(Number(e.target.value))}\n value={speedMultiplier}\n >\n {[1, 2, 5, 10, 50, 100, 250].map((s) => (\n <option key={s} value={s}>\n {s}x\n </option>\n ))}\n </select>\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 gap-2\">\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-[10px] text-slate-500 text-left\">\n Lng\n </span>\n <input\n className=\"bg-slate-800 border border-slate-700 rounded px-2 py-1 text-white focus:outline-none focus:border-blue-500\"\n onChange={(e) => {\n const lng = parseFloat(e.target.value) || 0;\n setLocation([lng, location[1]]);\n pushLocationUpdate();\n }}\n step=\"0.001\"\n type=\"number\"\n value={location[0]}\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-[10px] text-slate-500 text-left\">\n Lat\n </span>\n <input\n className=\"bg-slate-800 border border-slate-700 rounded px-2 py-1 text-white focus:outline-none focus:border-blue-500\"\n onChange={(e) => {\n const lat = parseFloat(e.target.value) || 0;\n setLocation([location[0], lat]);\n pushLocationUpdate();\n }}\n step=\"0.001\"\n type=\"number\"\n value={location[1]}\n />\n </div>\n <div className=\"flex flex-col gap-1 col-span-2\">\n <span className=\"text-[10px] text-slate-500\">\n Heading (Degrees)\n </span>\n <input\n className=\"w-full accent-blue-500\"\n max=\"360\"\n min=\"0\"\n onChange={(e) => {\n setHeading(parseInt(e.target.value, 10));\n pushLocationUpdate();\n }}\n type=\"range\"\n value={heading}\n />\n <div className=\"text-right text-slate-400\">{heading}°</div>\n </div>\n </div>\n\n <Button\n className={`w-full rounded px-2 py-1.5 text-[10px] font-bold border cursor-pointer ${\n isPlacingLocation\n ? \"bg-blue-500/20 border-blue-500 text-blue-300\"\n : \"bg-slate-800 border-slate-700 text-slate-200 hover:bg-slate-700\"\n }`}\n onClick={() => setIsPlacingLocation((prev) => !prev)}\n type=\"button\"\n variant=\"ghost\"\n >\n {isPlacingLocation\n ? \"📍 Click the map to drop location…\"\n : \"📍 Drop location on map\"}\n </Button>\n\n <div className=\"flex flex-col gap-1 border-t border-slate-800 pt-3\">\n <div className=\"flex justify-between items-center\">\n <span className=\"text-[10px] text-slate-500\">Scan Radius</span>\n <div className=\"flex items-center gap-1\">\n <input\n 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\"\n min=\"0\"\n onChange={(e) =>\n setRadiusMeters(Math.max(0, Number(e.target.value) || 0))\n }\n type=\"number\"\n value={radiusMeters}\n />\n <select\n 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\"\n onChange={(e) =>\n setRadiusUnit(e.target.value as \"m\" | \"km\")\n }\n value={radiusUnit}\n >\n <option value=\"m\">m</option>\n <option value=\"km\">km</option>\n </select>\n </div>\n </div>\n <input\n className=\"w-full accent-blue-500\"\n max={radiusUnit === \"km\" ? 10 : 500}\n min=\"0\"\n onChange={(e) => setRadiusMeters(Number(e.target.value))}\n step={radiusUnit === \"km\" ? 0.1 : 5}\n type=\"range\"\n value={radiusMeters}\n />\n <div className=\"text-right text-slate-400\">\n {radiusMeters === 0\n ? \"hidden\"\n : `${radiusMeters}${radiusUnit} radius around user`}\n </div>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n};\n","import { Button } from \"@miniapps-sdk/components/ui/button\";\nimport { sdk } from \"@miniapps-sdk/sdk\";\nimport { GeolocationEvent } from \"@miniapps-sdk/types\";\nimport type React from \"react\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nexport interface DebugConsoleProps {\n /**\n * Whether to show the console initially.\n * Can also be controlled via the 'debug' prop on SDKProvider.\n */\n isOpen?: boolean;\n /**\n * Optional callback when the console is closed.\n */\n onClose?: () => void;\n}\n\ninterface LogEntry {\n id: string;\n time: string;\n label: string;\n content: string;\n}\n\n/**\n * A standalone debug console that intercepts and displays all Bridge communication.\n * Useful for debugging both in mock mode (BridgeMocker) and on real devices.\n */\nexport const DebugConsole: React.FC<DebugConsoleProps> = ({\n isOpen: initialOpen = false,\n onClose,\n}) => {\n const [showConsole, setShowConsole] = useState(initialOpen);\n const [logs, setLogs] = useState<LogEntry[]>([]);\n const scrollRef = useRef<HTMLDivElement>(null);\n\n // Sync with prop\n useEffect(() => {\n setShowConsole(initialOpen);\n }, [initialOpen]);\n\n const clearLogs = () => setLogs([]);\n\n const addLog = useCallback((label: string, data: any) => {\n // Skip location stream updates as they are too noisy\n if (label.includes(GeolocationEvent.LOCATION_STREAM_UPDATE)) return;\n\n const entry: LogEntry = {\n content: typeof data === \"string\" ? data : JSON.stringify(data, null, 2),\n id: Math.random().toString(36).slice(2),\n label,\n time: new Date().toLocaleTimeString(),\n };\n\n setLogs((prev) => [entry, ...prev].slice(0, 100));\n }, []);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n // 1. Intercept OUTGOING calls (SDK -> Shell)\n const bridge = (sdk as any).bridge;\n const originalSend = bridge.send.bind(bridge);\n\n bridge.send = async (type: string, payload: any) => {\n addLog(`OUT: ${type}`, payload);\n return originalSend(type, payload);\n };\n\n // 2. Intercept INCOMING messages (Shell -> SDK)\n const originalHandle = bridge.handleNativeMessage.bind(bridge);\n bridge.handleNativeMessage = (envelope: any) => {\n const type =\n envelope.eventName || envelope.event || envelope.type || \"MSG\";\n if (typeof type === \"string\") {\n addLog(`IN: ${type}`, envelope.payload || envelope.value || envelope);\n originalHandle(envelope);\n }\n };\n\n return () => {\n bridge.send = originalSend;\n bridge.handleNativeMessage = originalHandle;\n };\n }, [addLog]);\n\n if (!showConsole) {\n return (\n <Button\n 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!\"\n onClick={() => setShowConsole(true)}\n title=\"Open Debug Console\"\n type=\"button\"\n variant=\"ghost\"\n >\n <svg\n className=\"group-hover:scale-110 transition-transform\"\n fill=\"none\"\n height=\"14\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2\"\n viewBox=\"0 0 24 24\"\n width=\"14\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"m8 2 1.88 1.88\" />\n <path d=\"M14.12 3.88 16 2\" />\n <path d=\"M9 7.13v-1a3.003 3.003 0 1 1 6 0v1\" />\n <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\" />\n <path d=\"M12 20v-9\" />\n <path d=\"M6.53 9C4.6 8.8 3 7.1 3 5\" />\n <path d=\"M6 13H2\" />\n <path d=\"M3 21c0-2.1 1.7-3.9 3.8-4\" />\n <path d=\"M20.97 5c0 2.1-1.6 3.8-3.5 4\" />\n <path d=\"M22 13h-4\" />\n <path d=\"M17.2 17c2.1.1 3.8 1.9 3.8 4\" />\n </svg>\n </Button>\n );\n }\n\n return (\n <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\">\n <div className=\"flex items-center justify-between mb-2\">\n <span className=\"text-[10px] font-bold uppercase tracking-widest text-slate-400 flex items-center gap-2\">\n <span className=\"w-2 h-2 rounded-full bg-emerald-500 animate-pulse\" />\n UP SDK Debug Console\n </span>\n <div className=\"flex gap-4\">\n <Button\n className=\"text-[10px] text-slate-500 font-bold uppercase hover:text-slate-300 hover:bg-transparent transition-colors p-0 h-auto cursor-pointer\"\n onClick={clearLogs}\n type=\"button\"\n variant=\"ghost\"\n >\n Clear\n </Button>\n <Button\n className=\"text-[10px] text-pink-500 font-bold uppercase hover:text-pink-400 hover:bg-transparent transition-colors p-0 h-auto cursor-pointer\"\n onClick={() => {\n setShowConsole(false);\n if (onClose) onClose();\n }}\n type=\"button\"\n variant=\"ghost\"\n >\n Close\n </Button>\n </div>\n </div>\n <div\n 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\"\n ref={scrollRef}\n >\n {logs.length === 0 ? (\n <div className=\"text-slate-600 italic text-center py-8\">\n No logs yet. Interacting with the SDK will show events here.\n </div>\n ) : (\n logs.map((log) => (\n <div\n className=\"mb-3 pb-3 border-b border-slate-900/50 last:border-0 last:mb-0 last:pb-0\"\n key={log.id}\n >\n <div className=\"flex gap-2 text-slate-500 mb-1 items-center\">\n <span className=\"text-[8px]\">{log.time}</span>\n <span className=\"font-bold text-white uppercase text-[8px] bg-slate-800 px-1.5 py-0.5 rounded leading-none\">\n {log.label}\n </span>\n </div>\n <pre className=\"whitespace-pre-wrap break-all opacity-90\">\n {log.content}\n </pre>\n </div>\n ))\n )}\n </div>\n </div>\n );\n};\n","import type React from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\n\n// Mimics React Native's <RefreshControl> inside a <SectionList>/<ScrollView>:\n// drag down from the very top of the list past a threshold, release, and\n// `onRefresh` fires while an indicator sits in the space the pull opened up.\n//\n// Built on the Pointer Events API, via a native (non-JSX) addEventListener\n// in a useEffect rather than onPointerDown/Move/Up JSX props — confirmed\n// live on a real Android WebView (chrome://inspect + CDP-injected touch\n// events, not desktop mouse emulation) that React's synthetic pointermove\n// prop only ever receives the FIRST move of a gesture inside a\n// react-native-webview host. A native\n// `addEventListener('pointermove', fn, {passive:false})` is the fix for\n// that part.\n//\n// That fix alone was still not enough: on Android WebView, ANY element with\n// `touch-action` permitting native panning on an axis (e.g. `pan-y`) hands\n// gesture ownership to native compositor-thread scrolling after the first\n// move on that axis — regardless of preventDefault(), and regardless of\n// react-native-webview's `nestedScrollEnabled` prop or any native ancestor\n// gesture handler. Confirmed via CDP touch injection: `touch-action: pan-y`\n// → 1 move event delivered for the whole gesture; `touch-action: none` →\n// every move event delivered. So this component sets `touch-action: none`\n// and, as a direct consequence, has to drive ALL scrolling itself — native\n// touch scroll is fully disabled on this element once native panning isn't\n// permitted on any axis. See `handlePointerMove`'s two branches: \"pull\"\n// (scrollTop is 0 and the gesture is dragging down) grows the refresh\n// indicator; \"scroll\" (everything else) sets `el.scrollTop` directly from\n// the per-move delta, plus a simple friction-decay fling on release so a\n// fast swipe still keeps moving after the finger lifts, closer to native\n// scroll feel.\n//\n// `touchAction: \"none\"` means this element claims 100% of touch handling\n// for its whole subtree — a `children` tree that itself contains a\n// touch-gesture-driven component (a horizontal swiper/carousel, a slider, a\n// map) will have that child's own gestures broken, since a descendant's own\n// `touch-action` can't reclaim a gesture an ancestor's JS is already\n// calling preventDefault() on every move. Don't nest another gesture-driven\n// component (e.g. `SwipeCarousel`) inside `PullToRefresh`.\nexport interface PullToRefreshIndicatorState {\n /** 0 (no pull) to 1 (at/past the trigger threshold). */\n progress: number;\n isRefreshing: boolean;\n}\n\nexport interface PullToRefreshProps {\n onRefresh: () => Promise<void> | void;\n children: React.ReactNode;\n className?: string;\n disabled?: boolean;\n /** Visual (post-resistance) px of pull required to trigger a refresh. Default 64. */\n pullThreshold?: number;\n /** Visual cap so the indicator never drags further than this. Default 96. */\n maxPull?: number;\n /** Fully replaces the default indicator — e.g. a brand-specific spinner/logo. */\n renderIndicator?: (state: PullToRefreshIndicatorState) => React.ReactNode;\n}\n\nconst DEFAULT_PULL_THRESHOLD = 64;\nconst DEFAULT_MAX_PULL = 96;\nconst RESISTANCE = 0.5; // finger has to travel 2px for every 1px of visual pull\nconst DRAG_DEADZONE = 8; // raw px of downward movement before this counts as a drag, not a tap\nconst FLING_FRICTION = 0.95; // velocity multiplier applied every animation frame\nconst FLING_MIN_VELOCITY = 0.02; // px/ms below which the fling animation stops\n\nfunction DefaultIndicator({\n progress,\n isRefreshing,\n}: PullToRefreshIndicatorState) {\n // Inline styles on purpose, not Tailwind classes: this component ships\n // compiled into consuming apps' bundles, and there's no guarantee a\n // consumer's own Tailwind build scans this package's dist output for\n // class names to generate CSS for. Inline styles render correctly\n // regardless of the consumer's build pipeline. Apps that want their own\n // themed indicator should pass `renderIndicator` instead of fighting\n // these styles.\n return (\n <div\n style={{\n alignItems: \"center\",\n background: \"rgba(24, 24, 27, 0.9)\",\n border: \"1px solid rgba(255, 255, 255, 0.1)\",\n borderRadius: 9999,\n boxShadow: \"0 4px 16px -4px rgba(0, 0, 0, 0.5)\",\n display: \"flex\",\n height: 28,\n justifyContent: \"center\",\n width: 28,\n }}\n >\n <svg\n height={14}\n style={{\n animation: isRefreshing\n ? \"up-sdk-ptr-spin 0.8s linear infinite\"\n : undefined,\n color: isRefreshing ? \"#a78bfa\" : \"#a1a1aa\",\n transform: isRefreshing ? undefined : `rotate(${progress * 360}deg)`,\n }}\n viewBox=\"0 0 24 24\"\n width={14}\n >\n <title>Refreshing</title>\n <path\n d=\"M21 12a9 9 0 1 1-2.64-6.36\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeWidth={2.5}\n />\n </svg>\n <style>\n {\"@keyframes up-sdk-ptr-spin { to { transform: rotate(360deg); } }\"}\n </style>\n </div>\n );\n}\n\nexport const PullToRefresh = ({\n onRefresh,\n children,\n className = \"\",\n disabled = false,\n pullThreshold = DEFAULT_PULL_THRESHOLD,\n maxPull = DEFAULT_MAX_PULL,\n renderIndicator,\n}: PullToRefreshProps) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const startYRef = useRef<number | null>(null);\n const lastYRef = useRef(0);\n const lastMoveTimeRef = useRef(0);\n const velocityRef = useRef(0); // px/ms, positive = finger moving down\n const pointerIdRef = useRef<number | null>(null);\n const isPullingRef = useRef(false);\n const pullDistanceRef = useRef(0);\n const flingRafRef = useRef<number | null>(null);\n const [pullDistance, setPullDistance] = useState(0);\n const [isRefreshing, setIsRefreshing] = useState(false);\n // Mirrors pointerIdRef into render-visible state, purely so the indicator\n // can tell \"collapsing because the finger reversed mid-drag\" (must be\n // instant, no CSS transition — it's happening in the same frame as a\n // manual scrollTop update) apart from \"collapsing after release\" (gets\n // the eased transition). See the pointermove/pointerup handlers below.\n const [isTracking, setIsTracking] = useState(false);\n // Native listeners are attached once and read these via refs, not state,\n // to avoid re-subscribing (or going stale) on every render.\n const disabledRef = useRef(disabled);\n disabledRef.current = disabled;\n const onRefreshRef = useRef(onRefresh);\n onRefreshRef.current = onRefresh;\n const pullThresholdRef = useRef(pullThreshold);\n pullThresholdRef.current = pullThreshold;\n const maxPullRef = useRef(maxPull);\n maxPullRef.current = maxPull;\n\n // Dev safety net for the single most common way to misuse this component: because it sets\n // `touch-action: none` on itself (see the top-of-file comment), it becomes the ONLY thing\n // capable of scrolling its subtree — native touch scroll is fully disabled for that touch,\n // for every ancestor too. If this element's own box never gets a genuinely bounded height\n // (a `flex-1` ancestor missing `min-h-0`, or an ancestor using `min-h-screen`/`min-h-full` —\n // a floor, not a ceiling — instead of `h-full`/`h-screen`/`h-dvh`), it just grows to fit its\n // content instead of clipping it, so there's nothing to scroll internally either. Net result:\n // completely stuck scrolling, with pull-to-refresh itself still working (a separate top-edge\n // gesture) and masking the bug. Real incident: up-miniapps-split's GroupDetail.tsx/GroupList.tsx,\n // see the vault skill js/pull-to-refresh-scroll-chain.md for the full writeup and the fix\n // pattern. This check can't prove the layout is correct (a short screen legitimately has no\n // internal overflow), but \"taller than the viewport AND has zero internal overflow\" is a\n // reliable, low-false-positive signal that this exact misconfiguration is present.\n useEffect(() => {\n const el = containerRef.current;\n if (!el || typeof window === \"undefined\") return;\n\n const checkScrollChain = () => {\n const noInternalOverflow = el.scrollHeight <= el.clientHeight;\n const tallerThanViewport = el.clientHeight > window.innerHeight;\n if (noInternalOverflow && tallerThanViewport) {\n console.warn(\n \"[PullToRefresh] This container is taller than the viewport but has no internal \" +\n \"scroll (scrollHeight <= clientHeight). Because this component disables native \" +\n \"touch scrolling entirely (touch-action: none), scrolling is now completely \" +\n \"broken here. This almost always means either: (1) an ancestor's flex-1 item is \" +\n \"missing `min-h-0` (a flex item defaults to min-height:auto and refuses to shrink \" +\n \"below its content size), or (2) an ancestor uses `min-h-screen`/`min-h-full` (a \" +\n \"floor, not a ceiling) instead of `h-full`/`h-screen`/`h-dvh`. See the vault skill \" +\n \"js/pull-to-refresh-scroll-chain.md for the fix pattern.\",\n );\n }\n };\n\n const raf = requestAnimationFrame(checkScrollChain);\n window.addEventListener(\"resize\", checkScrollChain);\n return () => {\n cancelAnimationFrame(raf);\n window.removeEventListener(\"resize\", checkScrollChain);\n };\n }, []);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n\n const updatePullDistance = (value: number) => {\n pullDistanceRef.current = value;\n setPullDistance(value);\n };\n\n const stopFling = () => {\n if (flingRafRef.current !== null) {\n cancelAnimationFrame(flingRafRef.current);\n flingRafRef.current = null;\n }\n };\n\n const resetTracking = () => {\n pointerIdRef.current = null;\n startYRef.current = null;\n isPullingRef.current = false;\n setIsTracking(false);\n updatePullDistance(0);\n };\n\n const runFling = () => {\n velocityRef.current *= FLING_FRICTION;\n if (Math.abs(velocityRef.current) < FLING_MIN_VELOCITY) {\n flingRafRef.current = null;\n return;\n }\n // ~1 frame at 60fps; direction: positive velocity (finger moved down)\n // should keep scrolling up the same way a move did, i.e. decrease\n // scrollTop — mirrors the sign used in handlePointerMove below.\n el.scrollTop -= velocityRef.current * 16;\n if (\n el.scrollTop <= 0 ||\n el.scrollTop >= el.scrollHeight - el.clientHeight\n ) {\n flingRafRef.current = null;\n return;\n }\n flingRafRef.current = requestAnimationFrame(runFling);\n };\n\n const handlePointerDown = (e: PointerEvent) => {\n if (disabledRef.current) return;\n if (pointerIdRef.current !== null) return; // a pointer is already tracked\n stopFling();\n pointerIdRef.current = e.pointerId;\n startYRef.current = e.clientY;\n lastYRef.current = e.clientY;\n lastMoveTimeRef.current = performance.now();\n velocityRef.current = 0;\n isPullingRef.current = false;\n setIsTracking(true);\n try {\n el.setPointerCapture(e.pointerId);\n } catch {\n // Non-fatal — see handlePointerCancel's abort path.\n }\n };\n\n const handlePointerMove = (e: PointerEvent) => {\n if (startYRef.current === null || e.pointerId !== pointerIdRef.current) {\n return;\n }\n const totalDelta = e.clientY - startYRef.current;\n if (!isPullingRef.current && Math.abs(totalDelta) < DRAG_DEADZONE) {\n // Sub-pixel jitter a real touchscreen produces during an ordinary\n // tap — do nothing yet, don't commit to pull-vs-scroll.\n return;\n }\n\n const now = performance.now();\n const stepDelta = e.clientY - lastYRef.current;\n const dt = Math.max(now - lastMoveTimeRef.current, 1);\n velocityRef.current = stepDelta / dt;\n lastYRef.current = e.clientY;\n lastMoveTimeRef.current = now;\n\n // Must run synchronously on this genuinely non-passive listener for\n // every move — see the top-of-file comment for why `touch-action` is\n // 'none' and why that means this element owns 100% of its own\n // scrolling now, not just the pull gesture.\n if (e.cancelable) e.preventDefault();\n\n const atTop = el.scrollTop <= 0;\n if (atTop && totalDelta > 0) {\n // Pull-to-refresh zone: at the very top, dragging down.\n isPullingRef.current = true;\n updatePullDistance(\n Math.min(\n Math.max(totalDelta - DRAG_DEADZONE, 0) * RESISTANCE,\n maxPullRef.current,\n ),\n );\n return;\n }\n\n // Otherwise this is a normal scroll — this element fully owns it\n // since native touch-driven scrolling is disabled by touch-action:\n // none, so drive scrollTop directly from the per-move delta.\n if (isPullingRef.current) {\n // Was pulling, finger reversed direction back above the top edge —\n // collapse the indicator before resuming normal scroll.\n isPullingRef.current = false;\n updatePullDistance(0);\n }\n el.scrollTop -= stepDelta;\n };\n\n const handlePointerEnd = (e: PointerEvent) => {\n if (startYRef.current === null || e.pointerId !== pointerIdRef.current) {\n return;\n }\n const wasPulling = isPullingRef.current;\n pointerIdRef.current = null;\n startYRef.current = null;\n isPullingRef.current = false;\n setIsTracking(false);\n\n if (!wasPulling) {\n // Release a normal scroll with residual velocity into a short\n // decaying fling, closer to native momentum scrolling.\n if (Math.abs(velocityRef.current) > FLING_MIN_VELOCITY) {\n stopFling();\n flingRafRef.current = requestAnimationFrame(runFling);\n }\n return;\n }\n\n const shouldRefresh = pullDistanceRef.current >= pullThresholdRef.current;\n if (!shouldRefresh) {\n updatePullDistance(0);\n return;\n }\n setIsRefreshing(true);\n updatePullDistance(pullThresholdRef.current);\n Promise.resolve(onRefreshRef.current())\n .catch((err) => {\n // A failed refresh still has to release the gesture back to the\n // user — silently swallowing the error here would otherwise leave\n // an unhandled rejection and the user with no feedback at all\n // (the indicator would just vanish as if it had worked).\n console.error(\"Pull-to-refresh failed:\", err);\n })\n .finally(() => {\n setIsRefreshing(false);\n updatePullDistance(0);\n });\n };\n\n const handlePointerCancel = (e: PointerEvent) => {\n // Only abort if this cancel is for the pointer we're actually\n // tracking — a second finger resting on the screen (or any other\n // pointer the OS/browser decides to cancel independently) must not\n // wipe out an unrelated, still-active drag.\n if (e.pointerId !== pointerIdRef.current) return;\n stopFling();\n resetTracking();\n };\n\n el.addEventListener(\"pointerdown\", handlePointerDown);\n el.addEventListener(\"pointermove\", handlePointerMove, { passive: false });\n el.addEventListener(\"pointerup\", handlePointerEnd);\n el.addEventListener(\"pointercancel\", handlePointerCancel);\n return () => {\n stopFling();\n el.removeEventListener(\"pointerdown\", handlePointerDown);\n el.removeEventListener(\"pointermove\", handlePointerMove);\n el.removeEventListener(\"pointerup\", handlePointerEnd);\n el.removeEventListener(\"pointercancel\", handlePointerCancel);\n };\n }, []);\n\n const indicatorHeight = isRefreshing ? pullThreshold : pullDistance;\n const progress = Math.min(indicatorHeight / pullThreshold, 1);\n // Only the post-release collapse gets the eased transition. A collapse\n // that happens while still tracking a pointer (finger reversed direction\n // mid-drag, back above the top edge) has to be instant — it's happening\n // in the same frame as a manual `el.scrollTop` mutation, and animating\n // the indicator's height while content is simultaneously being scrolled\n // directly produces a visible stutter.\n const isSettling = pullDistance === 0 && !isRefreshing && !isTracking;\n\n return (\n <div\n className={`up-sdk-pull-to-refresh ${className}`}\n ref={containerRef}\n style={{\n overflowY: \"auto\",\n overscrollBehavior: \"none\",\n touchAction: \"none\",\n }}\n >\n {/* Hides the native scrollbar without depending on the consumer's own\n CSS/Tailwind setup (see the DefaultIndicator comment above for why\n this component avoids relying on the consumer's build pipeline). */}\n <style>\n {\n \".up-sdk-pull-to-refresh::-webkit-scrollbar { display: none; } .up-sdk-pull-to-refresh { scrollbar-width: none; -ms-overflow-style: none; }\"\n }\n </style>\n <div\n style={{\n alignItems: \"center\",\n display: \"flex\",\n height: indicatorHeight,\n justifyContent: \"center\",\n overflow: \"hidden\",\n transition: isSettling ? \"height 0.2s ease-out\" : \"none\",\n userSelect: \"none\",\n width: \"100%\",\n }}\n >\n {renderIndicator ? (\n renderIndicator({ isRefreshing, progress })\n ) : (\n <DefaultIndicator isRefreshing={isRefreshing} progress={progress} />\n )}\n </div>\n {children}\n </div>\n );\n};\n","import { sdk } from \"@miniapps-sdk/sdk\";\nimport jsQR from \"jsqr\";\nimport { useEffect, useRef, useState } from \"react\";\n\nexport interface QRScannerProps {\n /** Called once with the decoded string the moment a QR code is detected. Scanning stops immediately after. */\n onScan: (data: string) => void;\n /** Called with a user-facing error message (camera permission denied, no camera, etc.). */\n onError?: (message: string) => void;\n /** Additional className for the outer container (sizing/positioning — the component fills it). */\n className?: string;\n}\n\n/**\n * Camera-based QR code scanner — the single source of truth for every\n * Mini-App. Handles camera permission (via `sdk.permission.request`),\n * `getUserMedia` stream lifecycle, and the jsQR decode loop internally.\n * Mini-Apps must not reimplement this on their own — that duplication is\n * exactly what made this logic drift and painful to fix consistently across\n * apps.\n *\n * Renders its own default \"scan frame\" chrome (bordered square + scan-line\n * animation via inline styles, so it works with zero external CSS). Pass\n * `className` to control size/position; the video feed fills the container.\n */\nexport function QRScanner({ onScan, onError, className = \"\" }: QRScannerProps) {\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const canvasRef = useRef<HTMLCanvasElement | null>(null);\n const streamRef = useRef<MediaStream | null>(null);\n const tickRequestRef = useRef<number | null>(null);\n const hasScannedRef = useRef(false);\n const [isReady, setIsReady] = useState(false);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: onScan/onError are read via closure but intentionally excluded — they're expected to be stable per mount, and re-running this effect on every render identity change would restart the camera stream.\n useEffect(() => {\n let cancelled = false;\n hasScannedRef.current = false;\n\n const cleanup = () => {\n if (tickRequestRef.current) {\n cancelAnimationFrame(tickRequestRef.current);\n tickRequestRef.current = null;\n }\n if (streamRef.current) {\n for (const track of streamRef.current.getTracks()) {\n track.stop();\n }\n streamRef.current = null;\n }\n };\n\n const tick = () => {\n if (cancelled || hasScannedRef.current) return;\n const video = videoRef.current;\n const canvas = canvasRef.current;\n if (!video || video.readyState !== video.HAVE_ENOUGH_DATA || !canvas) {\n tickRequestRef.current = requestAnimationFrame(tick);\n return;\n }\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n tickRequestRef.current = requestAnimationFrame(tick);\n return;\n }\n canvas.height = video.videoHeight;\n canvas.width = video.videoWidth;\n ctx.drawImage(video, 0, 0, canvas.width, canvas.height);\n const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n const code = jsQR(imageData.data, imageData.width, imageData.height, {\n inversionAttempts: \"dontInvert\",\n });\n if (code?.data) {\n hasScannedRef.current = true;\n cleanup();\n onScan(code.data);\n return;\n }\n tickRequestRef.current = requestAnimationFrame(tick);\n };\n\n const start = async () => {\n try {\n const granted = await sdk.permission.request(\"camera\");\n if (!granted) {\n onError?.(\"Permission caméra refusée par l'utilisateur.\");\n return;\n }\n if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {\n onError?.(\n \"L'accès à la caméra requiert une connexion sécurisée (HTTPS) ou n'est pas supporté par ce navigateur.\",\n );\n return;\n }\n const stream = await navigator.mediaDevices.getUserMedia({\n video: { facingMode: \"environment\" },\n });\n if (cancelled) {\n for (const track of stream.getTracks()) track.stop();\n return;\n }\n streamRef.current = stream;\n const video = videoRef.current;\n if (!video) return;\n video.srcObject = stream;\n video.setAttribute(\"playsinline\", \"true\");\n await video.play();\n if (cancelled) return;\n setIsReady(true);\n tickRequestRef.current = requestAnimationFrame(tick);\n } catch (err) {\n console.error(\"QRScanner: camera access failed:\", err);\n onError?.(\"Accès caméra refusé ou non disponible sur cet appareil.\");\n }\n };\n\n start();\n\n return () => {\n cancelled = true;\n cleanup();\n };\n }, []);\n\n return (\n <div\n className={className}\n style={{\n alignItems: \"center\",\n display: \"flex\",\n justifyContent: \"center\",\n overflow: \"hidden\",\n position: \"relative\",\n }}\n >\n {/* biome-ignore lint/a11y/useMediaCaption: live camera feed, no captions apply */}\n <video\n playsInline\n ref={videoRef}\n style={{ height: \"100%\", objectFit: \"cover\", width: \"100%\" }}\n />\n <canvas ref={canvasRef} style={{ display: \"none\" }} />\n {isReady && (\n <div\n style={{\n border: \"2px dashed rgba(255,255,255,0.8)\",\n borderRadius: 12,\n bottom: \"10%\",\n left: \"10%\",\n pointerEvents: \"none\",\n position: \"absolute\",\n right: \"10%\",\n top: \"10%\",\n }}\n />\n )}\n </div>\n );\n}\n","import type React from \"react\";\nimport { createContext, useContext, useMemo } from \"react\";\nimport { BridgeMocker, type BridgeMockerProps } from \"./BridgeMocker\";\nimport { DebugConsole } from \"./DebugConsole\";\n\ninterface SDKContextValue {\n isMocked: boolean;\n}\n\nconst SDKContext = createContext<SDKContextValue>({ isMocked: false });\n\n/**\n * Hook to check if the SDK is currently running in mock mode (browser)\n * or native mode (shell app).\n */\nexport const useIsMocked = () => useContext(SDKContext).isMocked;\n\nexport interface SDKProviderProps\n extends Partial<Omit<BridgeMockerProps, \"children\">> {\n children: React.ReactNode;\n /**\n * If true, shows the standalone DebugConsole for bridge traffic.\n */\n debug?: boolean;\n}\n\n/**\n * A wrapper component that automatically enables the BridgeMocker\n * when running outside the native shell app.\n */\nexport const SDKProvider: React.FC<SDKProviderProps> = ({\n children,\n debug = false,\n ...mockerProps\n}) => {\n const isMocked =\n typeof window !== \"undefined\" &&\n !(\n (window as any).__UP_REACT_NATIVE_APP__ === true ||\n !!(window as any).ReactNativeWebView\n );\n\n const value = useMemo(() => ({ isMocked }), [isMocked]);\n\n const content = (\n <>\n {children}\n {(debug || isMocked) && <DebugConsole />}\n </>\n );\n\n if (isMocked) {\n return (\n <SDKContext.Provider value={value}>\n <BridgeMocker {...mockerProps}>{content}</BridgeMocker>\n </SDKContext.Provider>\n );\n }\n\n return <SDKContext.Provider value={value}>{content}</SDKContext.Provider>;\n};\n","import {\n type ReactNode,\n type TouchEvent as ReactTouchEvent,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\n\n// Homemade swipe carousel: the \"swiper\" library's own touch listeners fight\n// React Native WebView's native gesture handling (missed touchmove events,\n// stuck drags). This uses plain React touch events, which the WebView\n// delivers reliably.\n\nexport type SwipeAxisPriority = \"horizontal\" | \"vertical\";\n\nexport interface SwipeCarouselItem {\n id: string;\n content: ReactNode;\n className?: string;\n}\n\nexport interface SwipeCarouselVerticalDragConfig {\n /** Which way the active slide may be dragged. Default \"down\". */\n direction?: \"down\" | \"up\" | \"both\";\n /** px past which releasing fires onDismiss. Default 200. */\n dismissThreshold?: number;\n /** px/ms past which releasing fires onDismiss regardless of distance. Default 0.5. */\n dismissVelocity?: number;\n /**\n * Vertical tracking only starts when the touch begins inside an element\n * matching this selector AND that element is scrolled to its top\n * (scrollTop <= 2) — lets normal content scrolling take priority\n * otherwise. Default `[data-swipe-scroll-root]`; mark the scrollable\n * content root inside each slide with that attribute.\n */\n scrollRootSelector?: string;\n /** Fires on every move once vertical drag is engaged, with the raw px offset (already past the small dead-zone), and once more with `(0, false)` on release. */\n onDragChange?: (deltaY: number, isDragging: boolean) => void;\n /** Fires once, on release, when the drag crossed the dismiss threshold. */\n onDismiss?: () => void;\n}\n\nexport interface SwipeCarouselProps {\n items: SwipeCarouselItem[];\n activeId: string | null;\n onActiveChange: (id: string) => void;\n /** How many slides fit across the viewport (1.1 == active slide + a sliver of its neighbor). */\n peek?: number;\n gap?: number;\n className?: string;\n itemClassName?: string;\n /**\n * Once a touch moves past the direction-lock threshold, the dominant axis\n * (bigger |dx| vs |dy|) wins the WHOLE gesture — the other axis is frozen\n * for the rest of that touch, so a horizontal swipe can't also drag the\n * slide down and vice versa. `axisPriority` only breaks an exact tie at\n * that decision point. Default \"horizontal\".\n */\n axisPriority?: SwipeAxisPriority;\n /** Enables swipe-to-dismiss on the ACTIVE slide only (e.g. drag-down-to-close a detail sheet). Omit for a pure horizontal carousel. */\n verticalDrag?: SwipeCarouselVerticalDragConfig;\n /** Slides kept MOUNTED on each side of the active one, so a 100+ item list stays cheap and the next swipe target is already in the DOM. Default 2 (5 slides mounted total). */\n overscan?: number;\n /**\n * Slides kept VISIBLE (opacity) on each side of the active one — must be\n * <= `overscan`. Slides beyond this stay mounted (for an instant, already-\n * positioned reveal once they enter range) but invisible, so their\n * shadow/blur styling can't bleed into the visible strip. Default 1.\n */\n visibleOverscan?: number;\n}\n\nconst DIRECTION_LOCK_THRESHOLD_PX = 8;\nconst SWIPE_DISTANCE_THRESHOLD_PX = 40;\nconst SWIPE_VELOCITY_THRESHOLD = 0.4; // px/ms\nconst EDGE_RESISTANCE = 0.35;\nconst SNAP_EASING = \"cubic-bezier(0.16, 1, 0.3, 1)\";\nconst SNAP_DURATION_MS = 300;\nconst VERTICAL_DEAD_ZONE_PX = 15;\nconst DEFAULT_VERTICAL_DISMISS_THRESHOLD_PX = 200;\nconst DEFAULT_VERTICAL_DISMISS_VELOCITY = 0.5; // px/ms\nconst DEFAULT_OVERSCAN = 2;\nconst DEFAULT_VISIBLE_OVERSCAN = 1;\nconst DEFAULT_SCROLL_ROOT_SELECTOR = \"[data-swipe-scroll-root]\";\nconst SNAP_TRANSITION = `transform ${SNAP_DURATION_MS}ms ${SNAP_EASING}`;\n\ninterface TouchState {\n startX: number;\n startY: number;\n lastX: number;\n lastY: number;\n lastT: number;\n velocityX: number;\n velocityY: number;\n verticalAllowed: boolean;\n // \"passthrough\" = neither axis claims the gesture (e.g. a vertical\n // content-scroll attempt while verticalDrag is disabled/not allowed) —\n // native scrolling is left alone for the rest of the touch.\n lockedAxis: \"x\" | \"y\" | \"passthrough\" | null;\n}\n\nexport const SwipeCarousel = ({\n items,\n activeId,\n onActiveChange,\n peek = 1.1,\n gap = 10,\n className,\n itemClassName,\n axisPriority = \"horizontal\",\n verticalDrag,\n overscan = DEFAULT_OVERSCAN,\n visibleOverscan = DEFAULT_VISIBLE_OVERSCAN,\n}: SwipeCarouselProps) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const [containerWidth, setContainerWidth] = useState(0);\n const [dragX, setDragX] = useState(0);\n const [dragY, setDragY] = useState(0);\n const [isDraggingX, setIsDraggingX] = useState(false);\n const [isDraggingY, setIsDraggingY] = useState(false);\n const touchStateRef = useRef<TouchState | null>(null);\n\n // Authoritative index, advanced synchronously on release instead of\n // waiting for `activeId` to round-trip back through the parent's state —\n // a rapid second swipe starting before that round-trip lands would\n // otherwise read a stale index off `activeId` and could undo the first\n // swipe (or \"roll back\" instead of advancing).\n const [internalIndex, setInternalIndex] = useState(() =>\n Math.max(\n 0,\n items.findIndex((item) => item.id === activeId),\n ),\n );\n // Tracks the last `activeId` prop value we've already reacted to — NOT\n // what we last emitted via `onActiveChange`. That distinction matters: if\n // a consumer's `onActiveChange` ever ignores/gates the call, this must\n // never claim the prop changed when it didn't, or it would silently\n // revert the optimistic `commitIndex()` update the next time this effect\n // re-runs (e.g. because `items` got a new reference).\n const prevActiveIdRef = useRef(activeId);\n\n const [timingWaiting, setTimingWaiting] = useState(true);\n\n useEffect(() => {\n const timer = setTimeout(() => {\n setTimingWaiting(false);\n }, 1000);\n return () => clearTimeout(timer);\n }, []);\n\n useEffect(() => {\n if (activeId !== prevActiveIdRef.current) {\n const idx = items.findIndex((item) => item.id === activeId);\n if (idx !== -1) setInternalIndex(idx);\n prevActiveIdRef.current = activeId;\n }\n }, [activeId, items]);\n\n const activeIndex = Math.min(\n Math.max(internalIndex, 0),\n Math.max(items.length - 1, 0),\n );\n\n useLayoutEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n const update = () => setContainerWidth(el.clientWidth);\n update();\n const observer = new ResizeObserver(update);\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\n\n const slideWidth = containerWidth / peek;\n const step = slideWidth + gap;\n const baseOffset = (containerWidth - slideWidth) / 2;\n const translateX = baseOffset - activeIndex * step + dragX;\n\n const commitIndex = (nextIndex: number) => {\n setInternalIndex(nextIndex);\n const nextItem = items[nextIndex];\n if (nextItem && nextItem.id !== activeId) onActiveChange(nextItem.id);\n };\n\n const handleTouchStart = (e: ReactTouchEvent<HTMLDivElement>) => {\n const touch = e.targetTouches[0];\n if (!touch) return;\n\n let verticalAllowed = false;\n if (verticalDrag) {\n const selector =\n verticalDrag.scrollRootSelector ?? DEFAULT_SCROLL_ROOT_SELECTOR;\n const scrollRoot = (e.target as HTMLElement).closest<HTMLElement>(\n selector,\n );\n verticalAllowed = !scrollRoot || scrollRoot.scrollTop <= 2;\n }\n\n touchStateRef.current = {\n lastT: e.timeStamp,\n lastX: touch.clientX,\n lastY: touch.clientY,\n lockedAxis: null,\n startX: touch.clientX,\n startY: touch.clientY,\n velocityX: 0,\n velocityY: 0,\n verticalAllowed,\n };\n };\n\n const handleTouchMove = (e: ReactTouchEvent<HTMLDivElement>) => {\n const touch = e.targetTouches[0];\n const state = touchStateRef.current;\n if (!touch || !state) return;\n\n const rawDx = touch.clientX - state.startX;\n const rawDy = touch.clientY - state.startY;\n\n if (!state.lockedAxis) {\n if (\n Math.abs(rawDx) < DIRECTION_LOCK_THRESHOLD_PX &&\n Math.abs(rawDy) < DIRECTION_LOCK_THRESHOLD_PX\n ) {\n return;\n }\n // Whichever axis is dominant wins the whole gesture from here on —\n // ties go to axisPriority. If vertical wins but dragging isn't\n // actually usable right now (disabled, or mid-content-scroll), don't\n // lock into the carousel either: leave the gesture alone so native\n // scrolling keeps working.\n const horizontalWins =\n Math.abs(rawDx) > Math.abs(rawDy) ||\n (Math.abs(rawDx) === Math.abs(rawDy) && axisPriority === \"horizontal\");\n if (horizontalWins) {\n state.lockedAxis = \"x\";\n } else if (verticalDrag && state.verticalAllowed) {\n state.lockedAxis = \"y\";\n } else {\n state.lockedAxis = \"passthrough\";\n }\n }\n\n if (state.lockedAxis === \"passthrough\") return;\n\n const dt = e.timeStamp - state.lastT;\n if (dt > 0) {\n state.velocityX = (touch.clientX - state.lastX) / dt;\n state.velocityY = (touch.clientY - state.lastY) / dt;\n }\n state.lastX = touch.clientX;\n state.lastY = touch.clientY;\n state.lastT = e.timeStamp;\n\n if (state.lockedAxis === \"x\") {\n if (!isDraggingX) setIsDraggingX(true);\n const atStart = activeIndex === 0 && rawDx > 0;\n const atEnd = activeIndex === items.length - 1 && rawDx < 0;\n setDragX(atStart || atEnd ? rawDx * EDGE_RESISTANCE : rawDx);\n } else if (verticalDrag) {\n const direction = verticalDrag.direction ?? \"down\";\n let clamped = rawDy;\n if (direction === \"down\") clamped = Math.max(0, rawDy);\n if (direction === \"up\") clamped = Math.min(0, rawDy);\n const beyondDeadZone =\n Math.sign(clamped) *\n Math.max(0, Math.abs(clamped) - VERTICAL_DEAD_ZONE_PX);\n\n if (!isDraggingY) setIsDraggingY(true);\n setDragY(beyondDeadZone);\n verticalDrag.onDragChange?.(beyondDeadZone, true);\n }\n\n if (e.cancelable) {\n // React attaches touchmove as passive by default, so this is often a\n // no-op in practice; real scroll suppression comes from the\n // container's `touch-pan-y` CSS, not this call.\n e.preventDefault();\n }\n };\n\n const endDrag = () => {\n const state = touchStateRef.current;\n touchStateRef.current = null;\n setIsDraggingX(false);\n setIsDraggingY(false);\n\n if (!state) {\n setDragX(0);\n setDragY(0);\n return;\n }\n\n if (state.lockedAxis === \"x\") {\n const horizontalTriggered =\n Math.abs(dragX) > SWIPE_DISTANCE_THRESHOLD_PX ||\n Math.abs(state.velocityX) > SWIPE_VELOCITY_THRESHOLD;\n if (horizontalTriggered) {\n const nextIndex =\n dragX < 0\n ? Math.min(items.length - 1, activeIndex + 1)\n : Math.max(0, activeIndex - 1);\n commitIndex(nextIndex);\n }\n } else if (state.lockedAxis === \"y\") {\n const verticalThreshold =\n verticalDrag?.dismissThreshold ?? DEFAULT_VERTICAL_DISMISS_THRESHOLD_PX;\n const verticalVelocityThreshold =\n verticalDrag?.dismissVelocity ?? DEFAULT_VERTICAL_DISMISS_VELOCITY;\n // `dragY` is already direction-clamped (stays 0 when dragged the\n // \"wrong\" way), but the raw `velocityY` isn't — a fast flick in the\n // disallowed direction has real negative/positive velocity and would\n // otherwise trip the velocity fallback and dismiss anyway. Clamp it\n // the same way dragY itself is clamped in handleTouchMove.\n const direction = verticalDrag?.direction ?? \"down\";\n const directionalVelocityY =\n direction === \"down\"\n ? Math.max(0, state.velocityY)\n : direction === \"up\"\n ? Math.max(0, -state.velocityY)\n : Math.abs(state.velocityY);\n const verticalTriggered =\n Math.abs(dragY) > verticalThreshold ||\n directionalVelocityY > verticalVelocityThreshold;\n if (verticalTriggered) verticalDrag?.onDismiss?.();\n }\n\n setDragX(0);\n setDragY(0);\n verticalDrag?.onDragChange?.(0, false);\n };\n\n // NOTE: jumping `activeId` externally to an item outside this window (more\n // than `overscan` away from the previous active index) unmounts the old\n // slide immediately rather than animating past it — the snap transition\n // still runs on the track transform, but there's nothing left to slide\n // past, so it reads as a pop/cut instead of a smooth pass-through. Fine\n // for \"jump to a specific item while closed\", not for scrubbing far\n // across a huge list while open.\n const windowStart = Math.max(0, activeIndex - overscan);\n const windowEnd = Math.min(items.length - 1, activeIndex + overscan);\n\n return (\n <div\n className={`relative overflow-hidden touch-pan-y ${className ?? \"\"}`}\n onTouchCancel={endDrag}\n onTouchEnd={endDrag}\n onTouchMove={handleTouchMove}\n onTouchStart={handleTouchStart}\n ref={containerRef}\n >\n <div\n className=\"relative h-full\"\n style={{\n transform: `translateX(${translateX}px)`,\n transition: isDraggingX || timingWaiting ? \"none\" : SNAP_TRANSITION,\n willChange: \"transform\",\n }}\n >\n {items.map((item, index) => {\n if (index < windowStart || index > windowEnd) return null;\n const isActive = index === activeIndex;\n const verticalOffset = isActive ? dragY : 0;\n const distance = Math.abs(index - activeIndex);\n // Mounted (for an instant, already-positioned reveal) but\n // invisible beyond visibleOverscan — at this `peek`, an unhidden\n // ±2 slide's shadow/blur bled into the visible strip and read as\n // jitter behind the active card.\n const isVisible = distance <= visibleOverscan;\n return (\n <div\n className={`absolute top-0 left-0 h-full shrink-0 ${itemClassName ?? \"\"} ${item.className ?? \"\"}`}\n key={item.id}\n style={{\n opacity: isVisible ? 1 : 0,\n pointerEvents: isVisible ? undefined : \"none\",\n transform: `translateX(${index * step}px) translateY(${verticalOffset}px)`,\n transition:\n (isActive && isDraggingY) || timingWaiting\n ? \"none\"\n : SNAP_TRANSITION,\n width: `${slideWidth}px`,\n // Layer by distance from the active slide (not DOM/index\n // order) so it always paints above its neighbors on BOTH\n // sides symmetrically — with `peek` this close, unstyled\n // z-index left neighbor bleed (shadow/blur) showing through\n // asymmetrically depending on swipe direction.\n zIndex: overscan + 1 - distance,\n }}\n >\n {item.content}\n </div>\n );\n })}\n </div>\n </div>\n );\n};\n","import type { TouchEvent } from \"react\";\nimport { useRef } from \"react\";\n\n// px of finger movement tolerated before a touch counts as a drag/swipe\n// instead of a tap.\nconst TAP_MOVE_TOLERANCE_PX = 10;\n// How long to keep suppressing a delayed native `click` for a tap already\n// handled via touchend — mirrors MapDrawer's own `suppressNextClickRef`\n// auto-clear window (see the SDK's AGENTS.md §16). Without this, a click\n// that never arrives for tap N would leave the flag armed to wrongly\n// swallow the NEXT tap on an element that doesn't unmount between taps.\nconst CLICK_SUPPRESS_WINDOW_MS = 500;\n\n// Buttons rendered inside a SwipeCarousel slide (VenueDetail/EventDetail's\n// \"Fermer\" close button) sit under a container that owns its own\n// touchstart/touchmove/touchend handling for the horizontal swipe gesture.\n// In the native WebView, the browser's synthetic `click` event following a\n// touch sequence inside that container isn't reliably delivered — the same\n// root cause already diagnosed (and fixed the same way) for the SDK's\n// MapDrawer handle-tap. Detect a plain tap directly from touchend instead of\n// depending on `click`, while still falling back to `onClick` for\n// non-touch input (desktop mouse) and de-duping if a delayed native click\n// does still arrive for the same tap.\nexport const useTapAction = (action: () => void) => {\n const startRef = useRef<{ x: number; y: number } | null>(null);\n const handledByTouchRef = useRef(false);\n\n const onTouchStart = (e: TouchEvent<HTMLElement>) => {\n const touch = e.targetTouches[0];\n startRef.current = touch ? { x: touch.clientX, y: touch.clientY } : null;\n };\n\n const onTouchEnd = (e: TouchEvent<HTMLElement>) => {\n const start = startRef.current;\n const touch = e.changedTouches[0];\n startRef.current = null;\n if (!start || !touch) return;\n\n const moved = Math.hypot(touch.clientX - start.x, touch.clientY - start.y);\n if (moved > TAP_MOVE_TOLERANCE_PX) return;\n\n handledByTouchRef.current = true;\n setTimeout(() => {\n handledByTouchRef.current = false;\n }, CLICK_SUPPRESS_WINDOW_MS);\n action();\n };\n\n const onClick = () => {\n if (handledByTouchRef.current) {\n handledByTouchRef.current = false;\n return;\n }\n action();\n };\n\n return { onClick, onTouchEnd, onTouchStart };\n};\n","import type { RoutingBackendConfig } from \"@miniapps-sdk/services/routingService\";\nimport { RoutingService } from \"@miniapps-sdk/services/routingService\";\nimport type {\n DrawRouteRequest,\n RouteRequest,\n RouteResponse,\n} from \"@miniapps-sdk/types/routing\";\nimport type { Map } from \"maplibre-gl\";\n\n/**\n * Handles a route request from the mini-app and fetches data from the configured backend.\n */\nexport async function handleRouteRequest(\n req: RouteRequest,\n config: RoutingBackendConfig,\n): Promise<RouteResponse> {\n return RoutingService.fetchRoute(req, config);\n}\n\n/**\n * Host-side map rendering logic for routes.\n */\nexport function handleDrawRoute(\n map: Map,\n miniAppId: string,\n req: DrawRouteRequest,\n) {\n const sourceId = `sdk-route-${miniAppId}`;\n const casingLayerId = `sdk-route-casing-${miniAppId}`;\n const lineLayerId = `sdk-route-line-${miniAppId}`;\n\n const geojson = {\n features: [\n {\n geometry: req.payload.routeData.geometry,\n properties: {},\n type: \"Feature\",\n },\n ],\n type: \"FeatureCollection\",\n };\n\n const source = map.getSource(sourceId);\n if (source) {\n // @ts-expect-error - maplibre-gl types might not expose setData nicely on generic source\n (source as maplibregl.GeoJSONSource).setData(geojson);\n } else {\n map.addSource(sourceId, {\n data: geojson as any,\n type: \"geojson\",\n });\n\n map.addLayer({\n id: casingLayerId,\n layout: {\n \"line-cap\": \"round\",\n \"line-join\": \"round\",\n },\n paint: {\n \"line-color\": \"#111111\",\n \"line-opacity\": 0.8,\n \"line-width\": 8,\n },\n source: sourceId,\n type: \"line\",\n });\n\n map.addLayer({\n id: lineLayerId,\n layout: {\n \"line-cap\": \"round\",\n \"line-join\": \"round\",\n },\n paint: {\n \"line-color\": \"#3b82f6\", // Bright blue\n \"line-width\": 4,\n },\n source: sourceId,\n type: \"line\",\n });\n }\n}\n\nexport function handleClearRoute(map: Map, miniAppId: string) {\n const sourceId = `sdk-route-${miniAppId}`;\n const casingLayerId = `sdk-route-casing-${miniAppId}`;\n const lineLayerId = `sdk-route-line-${miniAppId}`;\n\n if (map.getLayer(lineLayerId)) map.removeLayer(lineLayerId);\n if (map.getLayer(casingLayerId)) map.removeLayer(casingLayerId);\n if (map.getSource(sourceId)) map.removeSource(sourceId);\n}\n","import { sdk } from \"@miniapps-sdk/sdk\";\nimport type { INetworkResponse } from \"@miniapps-sdk/types\";\n\nexport interface CreateApiServiceOptions {\n /**\n * Backend URL to use before the shell has ever supplied one via\n * `initialize()`/`UPDATE_CONTEXT`, or if a boot ever completes without\n * one (e.g. a degraded/standalone fallback). Should be the app's real\n * production backend, typically read from a build-time env var baked\n * via `.env.production` — never a local dev address, since that value\n * is what actually reaches the network if the live one is ever missing.\n */\n defaultBaseUrl: string;\n /** Same fallback role as `defaultBaseUrl`, for `wsUrl` instead of `baseUrl`. Optional — omit if this app derives its WS URL from `baseUrl` itself. */\n defaultWsBackendUrl?: string;\n}\n\nexport interface ApiServiceClient {\n /** Current backend URL — see `getBaseUrl`'s doc comment below for the full resolution order. */\n readonly baseUrl: string;\n /** Current WebSocket backend URL, same resolution order as `baseUrl` but reading the dedicated ws fields instead. `undefined` if neither the shell nor `defaultWsBackendUrl` ever supplied one. */\n readonly wsUrl: string | undefined;\n\n get<T = unknown>(path: string): Promise<INetworkResponse<T>>;\n\n post<T = unknown>(path: string, body?: unknown): Promise<INetworkResponse<T>>;\n\n patch<T = unknown>(\n path: string,\n body?: unknown,\n ): Promise<INetworkResponse<T>>;\n\n delete(path: string): Promise<INetworkResponse<void>>;\n\n graphqlQuery<T = unknown>(\n query: string,\n variables?: Record<string, unknown>,\n ): Promise<INetworkResponse<{ data: T; errors?: { message: string }[] }>>;\n}\n\nfunction buildUrl(baseUrl: string, path: string): string {\n if (path.startsWith(\"http://\") || path.startsWith(\"https://\")) {\n return path;\n }\n\n let cleanBase = baseUrl.trim();\n while (cleanBase.endsWith(\"/\")) {\n cleanBase = cleanBase.slice(0, -1);\n }\n\n let cleanPath = path.trim();\n if (!cleanPath.startsWith(\"/\")) {\n cleanPath = `/${cleanPath}`;\n }\n\n // Prevent duplicate /api/v1 prefix\n const baseEndsWithV1 = cleanBase.endsWith(\"/api/v1\");\n const pathStartsWithV1 =\n cleanPath.startsWith(\"/api/v1/\") || cleanPath === \"/api/v1\";\n\n if (baseEndsWithV1 && pathStartsWithV1) {\n const strippedPath = cleanPath.slice(7);\n return `${cleanBase}${strippedPath}`;\n }\n\n return `${cleanBase}${cleanPath}`;\n}\n\n/**\n * Set synchronously by the host shell (`MiniAppContainer`'s early-injection\n * script) before this WebView's own bundle even starts parsing — the\n * earliest possible source for the backend URL, well before any bridge\n * round-trip (including `sdk.initialize()`) could complete. Checked first,\n * ahead of `sdk.getEnv()`, so a slow/lost bridge round-trip can never leave\n * a request without the right URL.\n */\nfunction getEarlyBackendUrl(kind: \"http\" | \"ws\"): string | undefined {\n if (typeof window === \"undefined\") return undefined;\n const early = (\n window as unknown as {\n __UP_BACKEND_URLS__?: { http?: string | null; ws?: string | null };\n }\n ).__UP_BACKEND_URLS__;\n return early?.[kind] ?? undefined;\n}\n\n/**\n * Creates a small REST/GraphQL client that always proxies through\n * `sdk.network.request` and always resolves the backend URL LIVE — from\n * `window.__UP_BACKEND_URLS__` (earliest, synchronous, see\n * `getEarlyBackendUrl` above), then `sdk.getEnv()` (updated by\n * `initialize()`/`UPDATE_CONTEXT`) — never from a value cached at some\n * earlier point in the boot sequence. This is the fix for a real,\n * repeatedly reproduced bug: apps used to assign a mutable `baseUrl` field\n * imperatively from `initialize()`'s response / `UPDATE_CONTEXT`; if that\n * one assignment was ever skipped (e.g. the underlying bridge request\n * losing its response — see `Bridge.send`'s retry, which reduces but does\n * not entirely eliminate that risk) the field stayed wrong for the rest of\n * the session, silently sending requests to `defaultBaseUrl` instead.\n * Reading fresh here means the very next call after either source is\n * populated self-heals automatically, and there is no second, independent\n * copy of the URL that can go stale.\n *\n * Response shape is the raw `INetworkResponse<T>` (status/data/headers) —\n * this stays a thin transport client; app-specific response unwrapping,\n * error-message translation, etc. belong in each app's own thin wrapper\n * around this, not here.\n */\nexport function createApiService(\n options: CreateApiServiceOptions,\n): ApiServiceClient {\n const getBaseUrl = (): string =>\n getEarlyBackendUrl(\"http\") ||\n (sdk.getEnv()?.backendUrl as string | undefined) ||\n options.defaultBaseUrl;\n\n const getWsUrl = (): string | undefined =>\n getEarlyBackendUrl(\"ws\") ||\n (sdk.getEnv()?.wsBackendUrl as string | undefined) ||\n options.defaultWsBackendUrl;\n\n return {\n get baseUrl(): string {\n return getBaseUrl();\n },\n\n delete: (path) =>\n sdk.network.request({\n method: \"DELETE\",\n url: buildUrl(getBaseUrl(), path),\n }),\n\n get: (path) =>\n sdk.network.request({\n headers: { \"Content-Type\": \"application/json\" },\n method: \"GET\",\n url: buildUrl(getBaseUrl(), path),\n }),\n\n graphqlQuery: (query, variables = {}) =>\n sdk.network.request({\n body: { query, variables },\n headers: { \"Content-Type\": \"application/json\" },\n method: \"POST\",\n url: buildUrl(getBaseUrl(), \"/graphql\"),\n }),\n\n patch: (path, body) =>\n sdk.network.request({\n body,\n headers: { \"Content-Type\": \"application/json\" },\n method: \"PATCH\",\n url: buildUrl(getBaseUrl(), path),\n }),\n\n post: (path, body) =>\n sdk.network.request({\n body,\n headers: { \"Content-Type\": \"application/json\" },\n method: \"POST\",\n url: buildUrl(getBaseUrl(), path),\n }),\n\n get wsUrl(): string | undefined {\n return getWsUrl();\n },\n };\n}\n","import { isRunningInsideNativeShell } from \"@miniapps-sdk/utils/environment\";\nimport type { ApiServiceClient } from \"./apiService\";\n\nexport interface WsMessage {\n event?: string;\n\n [key: string]: unknown;\n}\n\n/**\n * `\"open\"` is the only state where the wire connection is actually live —\n * `\"connecting\"` covers both the initial handshake and every reconnect\n * backoff wait, `\"closed\"` covers not-yet-started and lost-and-not-yet-\n * retried. A consumer that wants a poll-based fallback (only meaningful\n * while genuinely disconnected) should treat anything other than `\"open\"`\n * as \"poll\".\n */\nexport type WsConnectionStatus = \"connecting\" | \"open\" | \"closed\";\n\ninterface BaseWsServiceOptions<TMessage extends WsMessage> {\n /**\n * The REST client from `createApiService` — reused here for two things:\n * its live `wsUrl` (so this shares the exact same URL resolution as\n * every REST/GraphQL call, no separate copy to go stale), and its\n * `post()` to mint a short-lived WS auth ticket in production (see\n * `ticketPath` below).\n */\n api: Pick<ApiServiceClient, \"post\" | \"wsUrl\">;\n /**\n * REST path (relative, via `api.post`) that mints a short-lived,\n * single-use ticket for the WS handshake — a mini-app's JS never holds\n * its own real bearer token in production (`sdk.network.request` proxies\n * every REST/GraphQL call through the native host shell, which injects\n * auth on its own side; a raw browser `WebSocket` has no equivalent\n * bridge and no way to set a custom header, so it authenticates via a\n * ticket fetched over that same working REST path instead). Expected to\n * return `{ ticket: string }`. Defaults to `\"/ws-ticket\"`, matching the\n * established backend convention (see up-miniapps-backend's\n * `GetWSTicket`). Pass `null` to disable ticket auth entirely — only\n * appropriate for a mini-app whose backend has no ws-ticket route yet,\n * or a genuinely public route (see `requireAuth` below).\n */\n ticketPath?: string | null;\n /**\n * Raw JWT to use when NOT running inside the native shell (standalone\n * dev browser) — the consuming app reads its own build-time\n * `import.meta.env.VITE_DEV_TOKEN` and passes it here; the SDK itself\n * has no access to a consuming app's Vite env (this package is bundled\n * by tsup, not Vite). Only ever used outside the shell — a ticket is\n * always preferred when `isRunningInsideNativeShell()` is true.\n */\n devToken?: string | null;\n /**\n * Overrides the resolved WS URL outright, for a mini-app whose WS\n * gateway genuinely lives somewhere `api.wsUrl` doesn't cover. Most\n * consumers should leave this unset and rely on `api.wsUrl`.\n */\n baseUrl?: string;\n /**\n * Extra static query params appended to every connection URL. Browsers\n * (and this WebView) give a raw `WebSocket` no custom-header API — a\n * query param is the closest equivalent, e.g. for a custom auth scheme\n * on top of the ticket/token this already sends.\n */\n query?: Record<string, string>;\n /**\n * When unset/`true` (the default), `connect()` refuses — warns and\n * delays rather than opening an unauthenticated socket — if neither a\n * ticket nor `devToken` is available. This is a deliberate safety net:\n * a channel-scoped app (ticket-authorized per-room access) accidentally\n * shipping with no auth configured would silently become an open room,\n * not a loud failure.\n *\n * Set to `false` only for a backend route that's genuinely public with\n * no per-connection identity at all — e.g. up-miniapps-by-night's `/ws`,\n * which has no auth middleware by design, broadcasts the same public\n * data to every connection, and has no rooms to gate. `connect()` then\n * opens the socket with no ticket/token query param whatsoever. Pair\n * with `ticketPath: null` (no point minting a ticket nobody checks).\n */\n requireAuth?: boolean;\n}\n\n/** Options for the channel-scoped mode — pass `channelField` to subscribe/unsubscribe to specific rooms. */\nexport interface CreateChannelWsServiceOptions<\n TMessage extends WsMessage = WsMessage,\n> extends BaseWsServiceOptions<TMessage> {\n /**\n * Name of the field on each message that identifies which \"room\"/channel\n * it belongs to (e.g. `\"groupUuid\"`, `\"gameUuid\"`). Also the field name\n * used in the `{action, [channelField]: id}` subscribe/unsubscribe wire\n * messages sent to the backend. Presence of this field is what selects\n * channel mode over broadcast mode — see `CreateBroadcastWsServiceOptions`.\n */\n channelField: string;\n}\n\n/** Options for broadcast mode — omit `channelField` for a single global socket with no room concept. */\nexport interface CreateBroadcastWsServiceOptions<\n TMessage extends WsMessage = WsMessage,\n> extends BaseWsServiceOptions<TMessage> {\n channelField?: undefined;\n}\n\nexport type CreateWsServiceOptions<TMessage extends WsMessage = WsMessage> =\n | CreateChannelWsServiceOptions<TMessage>\n | CreateBroadcastWsServiceOptions<TMessage>;\n\nexport interface WsServiceClient<TMessage extends WsMessage = WsMessage> {\n /** Opens the connection if not already open/connecting. Safe to call repeatedly. */\n connect(): Promise<void>;\n\n /** Closes the connection and cancels any pending reconnect — no further automatic reconnect happens until `connect()`/`subscribe()` is called again. */\n disconnect(): void;\n\n /**\n * Subscribes to every message for one channel id. Sends the shared\n * `{action: \"subscribe\", [channelField]: id}` wire message automatically\n * on the first subscriber for that channel (and `\"unsubscribe\"` on the\n * last one leaving), and implicitly calls `connect()`. Returns an\n * unsubscribe function. Multiple concurrent channel ids are fully\n * supported — each gets its own wire subscribe/unsubscribe message and\n * its own dispatch, independent of every other channel's subscribers.\n */\n subscribe(\n channelId: string,\n callback: (message: TMessage) => void,\n ): () => void;\n\n /**\n * Subscribes to every message this socket ever receives, regardless of\n * channel — no wire message is sent for this (there's nothing to\n * subscribe/unsubscribe to, it's just an additional tap on the same\n * stream). Runs *alongside* any active `subscribe()` channel\n * subscriptions, socket.io-style (\"join specific rooms AND listen\n * globally at once\") — a message matching an active channel id is\n * delivered to both that channel's subscribers and every `onMessage`\n * listener. Implicitly calls `connect()`. Returns an unsubscribe\n * function.\n */\n onMessage(callback: (message: TMessage) => void): () => void;\n\n /**\n * Current connection status, read synchronously — no subscription needed\n * for a one-off check.\n */\n getStatus(): WsConnectionStatus;\n\n /**\n * Subscribes to connection status transitions. Fires once immediately\n * with the current status on subscribe, then again on every change.\n * Returns an unsubscribe function. Intended for a consumer that wants a\n * poll-based fallback only while genuinely disconnected (see\n * `WsConnectionStatus`'s own doc comment) — driving that off `onMessage`\n * pings alone can't distinguish \"connected but quiet\" from \"never\n * connected\".\n */\n onStatusChange(callback: (status: WsConnectionStatus) => void): () => void;\n}\n\nexport interface BroadcastWsServiceClient<\n TMessage extends WsMessage = WsMessage,\n> {\n /** Opens the connection if not already open/connecting. Safe to call repeatedly. */\n connect(): Promise<void>;\n\n /** Closes the connection and cancels any pending reconnect. */\n disconnect(): void;\n\n /**\n * Subscribes to every message this socket ever receives — there's no\n * room/channel concept in broadcast mode, so no subscribe/unsubscribe\n * wire message is ever sent; the backend just pushes to every connected\n * client. Implicitly calls `connect()`. Returns an unsubscribe function.\n */\n onMessage(callback: (message: TMessage) => void): () => void;\n\n /** Current connection status, read synchronously. See `WsConnectionStatus`. */\n getStatus(): WsConnectionStatus;\n\n /** Subscribes to connection status transitions. See `WsServiceClient.onStatusChange`. */\n onStatusChange(callback: (status: WsConnectionStatus) => void): () => void;\n}\n\n/**\n * Creates a reconnecting, (usually) authenticated WebSocket client — the WS\n * counterpart to `createApiService`. Centralizes exactly what every\n * `up-miniapps-*` app was independently hand-rolling with small drifting\n * bugs (one app's WS URL was captured once at construction and never\n * recomputed for the whole session; another always used a dev-only token\n * even in production, so it could never actually authenticate on a real\n * device): live URL resolution, ticket-based production auth with a\n * standalone-dev-token fallback, and exponential-backoff reconnect.\n *\n * Two modes, selected by whether `channelField` is present:\n * - **Channel mode** (`channelField` set): room-scoped pub/sub, matches\n * up-miniapps-split/up-miniapps-cursor's group/game-room shape. Returns a\n * `WsServiceClient` with `subscribe(channelId, cb)` — multiple concurrent\n * channel ids are fully supported — PLUS `onMessage(cb)`, a catch-all that\n * runs alongside any active channel subscriptions (socket.io-style: join\n * specific rooms and listen globally at the same time, on one socket).\n * - **Broadcast mode** (`channelField` omitted): one global socket, no\n * rooms, no subscribe/unsubscribe wire protocol — every message goes to\n * every listener. Matches up-miniapps-by-night's public live-update feed\n * (reactions/flash/favorite counts), which has no per-room access to gate\n * in the first place. Returns a `BroadcastWsServiceClient` with only\n * `onMessage(cb)` (no `subscribe` — there's no channel id to subscribe to).\n *\n * Deliberately stays a thin transport in both modes, same boundary as\n * `createApiService`: message *content* interpretation (e.g. treating one\n * event name as carrying real payload while every other message is a bare\n * cache-invalidation ping) belongs in each app's own thin wrapper around\n * this, not here — apps differ enough in what they consider safe to expose\n * over WS that baking that policy into the SDK would be the wrong\n * boundary.\n */\nexport function createWsService<TMessage extends WsMessage = WsMessage>(\n options: CreateChannelWsServiceOptions<TMessage>,\n): WsServiceClient<TMessage>;\nexport function createWsService<TMessage extends WsMessage = WsMessage>(\n options: CreateBroadcastWsServiceOptions<TMessage>,\n): BroadcastWsServiceClient<TMessage>;\nexport function createWsService<TMessage extends WsMessage = WsMessage>(\n options: CreateWsServiceOptions<TMessage>,\n): WsServiceClient<TMessage> | BroadcastWsServiceClient<TMessage> {\n const channelField = options.channelField;\n\n let ws: WebSocket | null = null;\n // Only populated/read in channel mode (via subscribe()).\n const subscriptions = new Map<string, Set<(message: TMessage) => void>>();\n // Populated/read via onMessage() in BOTH modes — the sole listener set in\n // broadcast mode, and an always-on catch-all running alongside\n // `subscriptions` in channel mode (see onMessage's own doc comment on\n // WsServiceClient).\n const globalListeners = new Set<(message: TMessage) => void>();\n let reconnectTimeout: ReturnType<typeof setTimeout> | null = null;\n let reconnectDelay = 1000;\n let isConnecting = false;\n let status: WsConnectionStatus = \"closed\";\n const statusListeners = new Set<(status: WsConnectionStatus) => void>();\n\n const setStatus = (next: WsConnectionStatus) => {\n if (status === next) return;\n status = next;\n for (const cb of statusListeners) cb(status);\n };\n\n const getWsUrl = (): string => options.baseUrl || options.api.wsUrl || \"\";\n\n const sendAction = (\n action: \"subscribe\" | \"unsubscribe\",\n channelId: string,\n ) => {\n if (ws?.readyState === WebSocket.OPEN) {\n // channelField is always defined here — sendAction is only ever\n // called from channel-mode code paths.\n ws.send(JSON.stringify({ action, [channelField as string]: channelId }));\n }\n };\n\n const scheduleReconnect = () => {\n if (reconnectTimeout) clearTimeout(reconnectTimeout);\n reconnectTimeout = setTimeout(() => {\n reconnectDelay = Math.min(reconnectDelay * 2, 30000);\n connect();\n }, reconnectDelay);\n };\n\n const connect = async (): Promise<void> => {\n if (\n ws?.readyState === WebSocket.OPEN ||\n ws?.readyState === WebSocket.CONNECTING ||\n isConnecting\n ) {\n return;\n }\n isConnecting = true;\n setStatus(\"connecting\");\n\n try {\n const wsUrl = getWsUrl();\n if (!wsUrl) {\n console.warn(\n \"[WS] No WebSocket backend URL available, connection delayed.\",\n );\n isConnecting = false;\n setStatus(\"closed\");\n return;\n }\n\n let authParams: Record<string, string> = {};\n if (isRunningInsideNativeShell() && options.ticketPath !== null) {\n const ticketResponse = await options.api.post<{ ticket: string }>(\n options.ticketPath ?? \"/ws-ticket\",\n );\n authParams = { ticket: ticketResponse.data.ticket };\n } else if (options.devToken) {\n const rawJwt = options.devToken.startsWith(\"Bearer \")\n ? options.devToken.slice(7)\n : options.devToken;\n authParams = { token: rawJwt };\n } else if (options.requireAuth === false) {\n // Explicitly opted out of auth (see requireAuth's own doc comment)\n // — connect with no ticket/token query param at all.\n } else {\n console.warn(\"[WS] No auth available, connection delayed.\");\n isConnecting = false;\n setStatus(\"closed\");\n return;\n }\n\n const params = new URLSearchParams({ ...options.query, ...authParams });\n const query = params.toString();\n ws = new WebSocket(query ? `${wsUrl}?${query}` : wsUrl);\n\n ws.onopen = () => {\n isConnecting = false;\n setStatus(\"open\");\n reconnectDelay = 1000;\n if (channelField) {\n for (const channelId of subscriptions.keys()) {\n sendAction(\"subscribe\", channelId);\n }\n }\n };\n\n ws.onmessage = (event) => {\n try {\n const payload = JSON.parse(event.data) as TMessage;\n if (channelField) {\n const channelId = payload[channelField];\n if (typeof channelId === \"string\") {\n const callbacks = subscriptions.get(channelId);\n if (callbacks) {\n for (const cb of callbacks) cb(payload);\n }\n }\n }\n // Every onMessage listener always runs, in both modes — the sole\n // dispatch path in broadcast mode, an additional catch-all on top\n // of the channel dispatch above in channel mode.\n for (const cb of globalListeners) cb(payload);\n } catch (err) {\n console.error(\"[WS] Failed to parse message:\", err);\n }\n };\n\n ws.onclose = () => {\n isConnecting = false;\n setStatus(\"closed\");\n scheduleReconnect();\n };\n\n ws.onerror = (err) => {\n console.error(\"[WS] error:\", err);\n isConnecting = false;\n ws?.close();\n };\n } catch (err) {\n console.error(\"[WS] Failed to establish connection:\", err);\n isConnecting = false;\n setStatus(\"closed\");\n scheduleReconnect();\n }\n };\n\n const disconnect = () => {\n if (reconnectTimeout) {\n clearTimeout(reconnectTimeout);\n reconnectTimeout = null;\n }\n if (ws) {\n ws.onclose = null;\n ws.close();\n ws = null;\n }\n setStatus(\"closed\");\n };\n\n const getStatus = (): WsConnectionStatus => status;\n\n const onStatusChange = (\n callback: (status: WsConnectionStatus) => void,\n ): (() => void) => {\n statusListeners.add(callback);\n callback(status);\n return () => {\n statusListeners.delete(callback);\n };\n };\n\n const subscribe = (\n channelId: string,\n callback: (message: TMessage) => void,\n ): (() => void) => {\n const isNewChannel = !subscriptions.has(channelId);\n if (isNewChannel) subscriptions.set(channelId, new Set());\n subscriptions.get(channelId)?.add(callback);\n if (isNewChannel) sendAction(\"subscribe\", channelId);\n connect();\n\n return () => {\n const set = subscriptions.get(channelId);\n if (!set) return;\n set.delete(callback);\n if (set.size === 0) {\n subscriptions.delete(channelId);\n sendAction(\"unsubscribe\", channelId);\n }\n };\n };\n\n const onMessage = (callback: (message: TMessage) => void): (() => void) => {\n globalListeners.add(callback);\n connect();\n return () => {\n globalListeners.delete(callback);\n };\n };\n\n if (channelField) {\n return {\n connect,\n disconnect,\n getStatus,\n onMessage,\n onStatusChange,\n subscribe,\n };\n }\n return { connect, disconnect, getStatus, onMessage, onStatusChange };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,aAAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAA0C;AAmBnC,IAAM,0BACX,4BAA8C,IAAI;AAE7C,IAAM,kBAAkB,UAC7B,yBAAW,mBAAmB;;;ACvBhC,kBAAsC;AACtC,4BAAwB;AAEjB,SAAS,MAAM,QAAsB;AAC1C,aAAO,mCAAQ,kBAAK,MAAM,CAAC;AAC7B;;;ACJA,wBAAqB;AACrB,sCAAuC;AACvC,YAAuB;AAyCjB;AAvCN,IAAM,qBAAiB;AAAA,EACrB;AAAA,EACA;AAAA,IACE,iBAAiB;AAAA,MACf,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA,UAAU;AAAA,MACR,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,MAAM;AAAA,QACN,IAAI;AAAA,QACJ,IAAI;AAAA,MACN;AAAA,MACA,SAAS;AAAA,QACP,SAAS;AAAA,QACT,aACE;AAAA,QACF,OAAO;AAAA,QACP,MAAM;AAAA,QACN,SACE;AAAA,QACF,WACE;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACF;AAQA,IAAM,SAAe;AAAA,EACnB,CAAC,EAAE,WAAW,SAAS,MAAM,UAAU,OAAO,GAAG,MAAM,GAAG,QAAQ;AAChE,UAAM,OAAO,UAAU,yBAAO;AAC9B,WACE;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,GAAG,eAAe,EAAE,WAAW,MAAM,QAAQ,CAAC,CAAC;AAAA,QAC1D;AAAA,QACC,GAAG;AAAA;AAAA,IACN;AAAA,EAEJ;AACF;AACA,OAAO,cAAc;;;AC1Cd,SAAS,6BAAsC;AACpD,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,QAAM,IAAI;AAIV,SAAO,EAAE,4BAA4B,QAAQ,CAAC,CAAC,EAAE;AACnD;;;ACbO,IAAM,qBAAN,cAAiC,MAAM;AAAC;AAkB/C,IAAM,oBAAoC;AAAA,EACxC;AAAA,IACE,WAAW;AAAA,IACX,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,UAAU;AAAA,IACV,MAAM;AAAA,IACN,OAAO;AAAA,IACP,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,WAAW;AAAA,IACX,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,UAAU;AAAA,IACV,MAAM;AAAA,IACN,OAAO;AAAA,IACP,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,WAAW;AAAA,IACX,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,UAAU;AAAA,IACV,MAAM;AAAA,IACN,OAAO;AAAA,IACP,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AACF;AAMA,SAAS,gBAAgB,MAAwC;AAC/D,QAAM,QAAQ,kBAAkB,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAC3D,MAAI,MAAO,QAAO;AAClB,SAAO;AAAA,IACL,WAAW;AAAA,IACX,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,UAAU;AAAA,IACV,MAAM,QAAQ;AAAA,IACd,OAAO,QAAQ;AAAA,IACf,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AACF;AAGA,SAAS,mBAAmC;AAC1C,SAAO;AACT;AASO,IAAM,SAAN,MAAa;AAAA,EACV,YAAY,oBAAI,IAOtB;AAAA,EACM,iBAAiB,oBAAI,IAAqC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOlE,cAAc;AACZ,QAAI,OAAO,WAAW,aAAa;AACjC,YAAM,iBAAiB,OAAO,OAAO;AAAA,QACnC,iBAAiB,CAAC,aAChB,KAAK,oBAAoB,QAAQ;AAAA,MACrC,CAAC;AAGD,UAAI,OAAQ,OAAe,oBAAoB,aAAa;AAC1D,eAAO,eAAe,QAAQ,mBAAmB;AAAA,UAC/C,cAAc;AAAA;AAAA,UACd,OAAO;AAAA,UACP,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAEA,aAAO,iBAAiB,WAAW,CAAC,UAAU;AAI5C,YAAI,CAAC,MAAM,KAAM;AAEjB,YAAI;AACF,gBAAM,OACJ,OAAO,MAAM,SAAS,WAClB,KAAK,MAAM,MAAM,IAAI,IACrB,MAAM;AAGZ,cACE,QACA,OAAO,SAAS,aACf,KAAK,cAAc,KAAK,SAAS,KAAK,YACvC;AACA,iBAAK,oBAAoB,IAAI;AAAA,UAC/B;AAAA,QACF,SAAS,IAAI;AAAA,QAEb;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,GAAgB,OAAe,UAA6B;AACjE,QAAI,YAAY,KAAK,eAAe,IAAI,KAAK;AAC7C,QAAI,CAAC,WAAW;AACd,kBAAY,CAAC;AACb,WAAK,eAAe,IAAI,OAAO,SAAS;AAAA,IAC1C;AACA,cAAU,KAAK,QAAQ;AACvB,WAAO,MAAM,KAAK,IAAI,OAAO,QAAQ;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,IAAiB,OAAe,UAA6B;AAClE,UAAM,YAAY,KAAK,eAAe,IAAI,KAAK;AAC/C,QAAI,CAAC,UAAW;AAChB,SAAK,eAAe;AAAA,MAClB;AAAA,MACA,UAAU,OAAO,CAAC,OAAO,OAAO,QAAQ;AAAA,IAC1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBO,KACL,MACA,SACA,YAAY,KACZ,UAAU,GACE;AACZ,QAAI,CAAC,KAAK,SAAS,GAAG;AACpB,aAAO,KAAK,kBAAkB,MAAM,OAAO;AAAA,IAC7C;AAEA,WAAO,KAAK,SAAY,MAAM,SAAS,SAAS,EAAE,MAAM,CAAC,QAAQ;AAS/D,UAAI,WAAW,KAAK,EAAE,eAAe,oBAAqB,OAAM;AAChE,aAAO,KAAK,KAAQ,MAAM,SAAS,WAAW,UAAU,CAAC;AAAA,IAC3D,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,oBAAoB,UAA2B;AACpD,QAAI,CAAC,YAAY,OAAO,aAAa,SAAU;AAG/C,UAAM,aAAa,SAAS;AAC5B,QAAI,cAAc,OAAO,eAAe,UAAU;AAChD,YAAM,WAAW,KAAK,UAAU,IAAI,UAAU;AAC9C,UAAI,UAAU;AACZ,qBAAa,SAAS,OAAO;AAC7B,cAAM,EAAE,SAAS,OAAO,IAAI;AAE5B,YAAI,SAAS,YAAY,SAAS,SAAS,OAAO;AAChD,iBAAO,SAAS,SAAS,eAAe;AAAA,QAC1C,OAAO;AACL,kBAAQ,SAAS,SAAS,SAAS,WAAW,QAAQ;AAAA,QACxD;AAEA,aAAK,UAAU,OAAO,UAAU;AAChC;AAAA,MACF;AAAA,IACF;AAGA,UAAM,YAAY,SAAS,aAAa,SAAS;AACjD,QAAI,WAAW;AAEb,UAAI,SAAS,SAAS,WAAW,CAAC,SAAS,QAAQ,SAAS,OAAO;AACjE,cAAM,YAAY,KAAK,eAAe,IAAI,SAAS;AACnD,YAAI,WAAW;AACb,qBAAW,YAAY,WAAW;AAChC,gBAAI;AACF,uBAAS,SAAS,WAAW,SAAS,KAAK;AAAA,YAC7C,SAAS,GAAG;AACV,sBAAQ,MAAM,+BAA+B,SAAS,KAAK,CAAC;AAAA,YAC9D;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBU,kBAAkB,MAAc,SAAgC;AACxE,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH,eAAO,KAAK;AAAA,UACV;AAAA,QACF;AAAA,MACF,KAAK;AACH,eAAO,QAAQ;AAAA,UACb,gBAAiB,SAA8B,IAAI;AAAA,QACrD;AAAA,MACF,KAAK;AACH,eAAO,QAAQ,QAAQ,iBAAiB,CAAC;AAAA,MAC3C;AACE,gBAAQ;AAAA,UACN,qDAAqD,IAAI;AAAA,QAC3D;AACA,eAAO,QAAQ,QAAQ;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaQ,cAAc,SAGY;AAChC,QAAI,OAAO,aAAa,aAAa;AACnC,aAAO,QAAQ,QAAQ,EAAE,SAAS,MAAM,CAAC;AAAA,IAC3C;AAEA,QAAI;AACF,YAAM,OAAO,QAAQ,OAAO,WAAW,OAAO,IAC1C,QAAQ,SACR,yBAAyB,QAAQ,MAAM;AAE3C,YAAM,OAAO,SAAS,cAAc,GAAG;AACvC,WAAK,OAAO;AACZ,WAAK,WAAW,QAAQ,WACpB,GAAG,QAAQ,QAAQ,SACnB;AACJ,eAAS,KAAK,YAAY,IAAI;AAC9B,WAAK,MAAM;AACX,WAAK,OAAO;AAEZ,aAAO,QAAQ,QAAQ,EAAE,SAAS,KAAK,CAAC;AAAA,IAC1C,SAAS,KAAK;AACZ,cAAQ,KAAK,6CAA6C,GAAG;AAC7D,aAAO,QAAQ,QAAQ,EAAE,SAAS,MAAM,CAAC;AAAA,IAC3C;AAAA,EACF;AAAA,EAEQ,SACN,MACA,SACA,WACY;AACZ,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,aAAa,GAAG,IAAI,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,CAAC,CAAC;AAEtF,YAAM,UAAU,WAAW,MAAM;AAC/B,YAAI,KAAK,UAAU,IAAI,UAAU,GAAG;AAClC,eAAK,UAAU,OAAO,UAAU;AAChC,iBAAO,IAAI,mBAAmB,2BAA2B,IAAI,EAAE,CAAC;AAAA,QAClE;AAAA,MACF,GAAG,SAAS;AAEZ,WAAK,UAAU,IAAI,YAAY;AAAA,QAC7B;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAED,YAAM,UAAU;AAAA,QACd;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEA,YAAM,MAAM;AAIZ,UAAI,IAAI,oBAAoB,aAAa;AACvC,YAAI,mBAAmB,YAAY,KAAK,UAAU,OAAO,CAAC;AAAA,MAC5D,OAAO;AACL,qBAAa,OAAO;AACpB,aAAK,UAAU,OAAO,UAAU;AAChC,eAAO,IAAI,MAAM,sBAAsB,CAAC;AAAA,MAC1C;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKQ,WAAoB;AAC1B,WAAO,2BAA2B;AAAA,EACpC;AACF;;;ACvYA,qBAAgC;AAChC,IAAAC,mCAAuC;AACvC,0BAAkB;AAClB,IAAAC,SAAuB;AAcrB,IAAAC,sBAAA;AAZF,IAAM,QAAuB;AAM7B,IAAM,cAA6B;AAEnC,IAAM,eAAqB,kBAGzB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAgB;AAAA,EAAf;AAAA,IACC,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA,IACJ;AAAA;AACF,CACD;AACD,aAAa,cAA6B,uBAAQ;AAElD,IAAM,oBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,iBAAiB;AAAA,MACf,MAAM;AAAA,IACR;AAAA,IACA,UAAU;AAAA,MACR,MAAM;AAAA,QACJ,QACE;AAAA,QACF,MAAM;AAAA,QACN,OACE;AAAA,QACF,KAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF;AACF;AAQA,IAAM,eAAqB,kBAGzB,CAAC,EAAE,OAAO,SAAS,WAAW,UAAU,SAAS,MAAM,GAAG,MAAM,GAAG,QAAQ;AAC3E,QAAMC,WACJ;AAAA,IAAgB;AAAA,IAAf;AAAA,MACC,WAAW;AAAA,QACT,cAAc,EAAE,KAAK,CAAC;AAAA,QACtB,SAAS,UAAU;AAAA,QACnB;AAAA,MACF;AAAA,MACA;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,QACD,8CAAgB,sBAAf,EAAqB,WAAU,4OAC9B;AAAA,uDAAC,yBAAE,WAAU,WAAU;AAAA,UACvB,6CAAC,UAAK,WAAU,WAAU,mBAAK;AAAA,WACjC;AAAA;AAAA;AAAA,EACF;AAGF,MAAI,CAAC,QAAQ;AACX,WAAOA;AAAA,EACT;AAEA,SACE,8CAAC,eACC;AAAA,iDAAC,gBAAa;AAAA,IACbA;AAAA,KACH;AAEJ,CAAC;AACD,aAAa,cAA6B,uBAAQ;AAElD,IAAM,cAAc,CAAC;AAAA,EACnB;AAAA,EACA,GAAG;AACL,MACE;AAAA,EAAC;AAAA;AAAA,IACC,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN;AAEF,YAAY,cAAc;AAE1B,IAAM,cAAc,CAAC;AAAA,EACnB;AAAA,EACA,GAAG;AACL,MACE;AAAA,EAAC;AAAA;AAAA,IACC,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN;AAEF,YAAY,cAAc;AAE1B,IAAM,aAAmB,kBAGvB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAgB;AAAA,EAAf;AAAA,IACC,WAAW,GAAG,yCAAyC,SAAS;AAAA,IAChE;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,WAAW,cAA6B,qBAAM;AAE9C,IAAM,mBAAyB,kBAG7B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAgB;AAAA,EAAf;AAAA,IACC,WAAW,GAAG,iCAAiC,SAAS;AAAA,IACxD;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,iBAAiB,cAA6B,2BAAY;;;AClI1D,IAAAC,gBAAkE;AAwD5D,IAAAC,sBAAA;AAnCC,IAAM,gBAAY;AAAA,EACvB,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,wBAAwB;AAAA,IACxB,uBAAuB;AAAA,EACzB,GACA,QACG;AACH,UAAM,yBAAqB,sBAAuB,IAAI;AAEtD;AAAA,MACE;AAAA,MACA,MAAM,mBAAmB;AAAA,IAC3B;AAEA,UAAM,CAAC,eAAe,gBAAgB,QAAI,wBAAS,KAAK;AAExD,UAAM,eAAe,CAAC,MAAqC;AACzD,YAAM,YAAY,EAAE,cAAc;AAClC,uBAAiB,UAAU,YAAY,YAAY,oBAAoB;AAAA,IACzE;AAKA,UAAM,mBAAmB,UAAU;AACnC,UAAM,iBAAiB,mBACnB,oCACA;AAEJ,WACE,8EACE;AAAA,mDAAC,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAQR;AAAA,MAGA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,yFAAyF,cAAc;AAAA,UAClH,SAAS,MAAM,cAAc,QAAQ;AAAA;AAAA,MACvC;AAAA,MAEC,UAAU,YACT;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,SAAS,MAAM,cAAc,MAAM;AAAA,UACnC,SAAQ;AAAA,UAER;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,QAAO;AAAA,cACP,QAAO;AAAA,cACP,eAAc;AAAA,cACd,gBAAe;AAAA,cACf,aAAY;AAAA,cACZ,SAAQ;AAAA,cACR,OAAM;AAAA,cACN,OAAM;AAAA,cAEN;AAAA,6DAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,gBACrC,6CAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,KAAI,IAAG,KAAI;AAAA,gBACnC,6CAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA;AAAA;AAAA,UACvC;AAAA;AAAA,MACF;AAAA,MAEF;AAAA,QAAC;AAAA;AAAA,UACC,cAAc,CAAC,SAAS,cAAc,OAAO,SAAS,QAAQ;AAAA,UAC9D,MAAM,UAAU;AAAA,UAEhB;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,QAAQ;AAAA,cACR,MAAK;AAAA,cAEL;AAAA,6DAAC,eAAY,WAAU,gDACrB,uDAAC,cAAW,WAAU,4DAA2D,kBAEjF,GACF;AAAA,gBAEA;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAU;AAAA,oBACV,UAAU;AAAA,oBACV,KAAK;AAAA,oBAEJ,wBACC,cAEA,6CAAC,SAAI,WAAU,yBACZ,oBAAU,IAAI,CAAC,SACd;AAAA,sBAAC;AAAA;AAAA,wBACC,WAAW,4LACT,KAAK,WACD,sDACA,EACN;AAAA,wBACA,UAAU,KAAK;AAAA,wBAEf,SAAS,MAAM;AACb,8BAAI,CAAC,KAAK,UAAU;AAClB,iCAAK,QAAQ;AACb,0CAAc,QAAQ;AAAA,0BACxB;AAAA,wBACF;AAAA,wBACA,SAAQ;AAAA,wBAER;AAAA,wEAAC,SAAI,WAAU,yFACZ;AAAA,iCAAK;AAAA,4BACL,KAAK,UAAU,UACd,6CAAC,UAAK,WAAU,iLACb,eAAK,OACR;AAAA,6BAEJ;AAAA,0BACA,6CAAC,UAAK,WAAU,4CACb,eAAK,OACR;AAAA;AAAA;AAAA,sBAnBK,KAAK;AAAA,oBAoBZ,CACD,GACH;AAAA;AAAA,gBAEJ;AAAA,gBAEC,yBAAyB,iBACxB;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAU;AAAA,oBACV,SAAS,MAAM;AACb,yCAAmB,SAAS,SAAS;AAAA,wBACnC,UAAU;AAAA,wBACV,KAAK;AAAA,sBACP,CAAC;AAAA,oBACH;AAAA,oBACA,SAAQ;AAAA,oBAER;AAAA,sBAAC;AAAA;AAAA,wBACC,MAAK;AAAA,wBACL,QAAO;AAAA,wBACP,QAAO;AAAA,wBACP,eAAc;AAAA,wBACd,gBAAe;AAAA,wBACf,aAAY;AAAA,wBACZ,SAAQ;AAAA,wBACR,OAAM;AAAA,wBACN,OAAM;AAAA,wBAEN,uDAAC,cAAS,QAAO,mBAAkB;AAAA;AAAA,oBACrC;AAAA;AAAA,gBACF;AAAA;AAAA;AAAA,UAEJ;AAAA;AAAA,MACF;AAAA,OACF;AAAA,EAEJ;AACF;AAEA,UAAU,cAAc;;;ACnMxB,IAAAC,SAAuB;AAMrB,IAAAC,sBAAA;AAJF,IAAM,OAAa,kBAGjB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAC;AAAA;AAAA,IACC,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,KAAK,cAAc;AAEnB,IAAM,aAAmB,kBAGvB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAC;AAAA;AAAA,IACC,WAAW,GAAG,iCAAiC,SAAS;AAAA,IACxD;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,WAAW,cAAc;AAEzB,IAAM,YAAkB,kBAGtB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAC;AAAA;AAAA,IACC,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,UAAU,cAAc;AAExB,IAAM,kBAAwB,kBAG5B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAC;AAAA;AAAA,IACC,WAAW,GAAG,iCAAiC,SAAS;AAAA,IACxD;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,gBAAgB,cAAc;AAE9B,IAAM,cAAoB,kBAGxB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,6CAAC,SAAI,WAAW,GAAG,YAAY,SAAS,GAAG,KAAW,GAAG,OAAO,CACjE;AACD,YAAY,cAAc;AAE1B,IAAM,aAAmB,kBAGvB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAC;AAAA;AAAA,IACC,WAAW,GAAG,8BAA8B,SAAS;AAAA,IACrD;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,WAAW,cAAc;;;AChDf,IAAAC,sBAAA;AAdH,IAAM,cAA0C,CAAC;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AACf,MAAM;AACJ,MAAI,eAAe,iBAAiB;AAClC,WACE,8CAAC,SAAI,WAAU,gIACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,SAAS;AAAA,UAET;AAAA,yDAAC,UAAK,WAAU,qDAAoD;AAAA,YACpE,8CAAC,UAAK,WAAU,sCACb;AAAA,sBAAQ;AAAA,cAAQ;AAAA,cAAO,QAAQ,oBAAoB,QAAQ,CAAC;AAAA,cAAE;AAAA,eACjE;AAAA;AAAA;AAAA,MACF;AAAA,MACC,QAAQ,WACP;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,SAAS,CAAC,MAAM;AACd,cAAE,gBAAgB;AAClB,oBAAQ,UAAU;AAAA,UACpB;AAAA,UACA,SAAQ;AAAA,UAER;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,MAAK;AAAA,cACL,QAAO;AAAA,cACP,QAAO;AAAA,cACP,eAAc;AAAA,cACd,gBAAe;AAAA,cACf,aAAY;AAAA,cACZ,SAAQ;AAAA,cACR,OAAM;AAAA,cACN,OAAM;AAAA,cAEN;AAAA,6DAAC,UAAK,GAAE,cAAa;AAAA,gBACrB,6CAAC,UAAK,GAAE,cAAa;AAAA;AAAA;AAAA,UACvB;AAAA;AAAA,MACF;AAAA,MAED,QAAQ,aAAa,UACpB,6CAAC,SAAI,WAAU,uDACb;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO,EAAE,OAAO,GAAG,QAAQ,QAAQ,IAAI;AAAA;AAAA,MACzC,GACF;AAAA,OAEJ;AAAA,EAEJ;AAEA,MAAI,eAAe,aAAa;AAC9B,WACE,8CAAC,QAAK,WAAU,iGACd;AAAA,oDAAC,SAAI,WAAU,0CACb;AAAA,sDAAC,SAAI,WAAU,2BACb;AAAA,uDAAC,UAAK,WAAU,qDAAoD;AAAA,UACpE,6CAAC,UAAK,WAAU,mEACb,kBAAQ,SAAS,kBACpB;AAAA,WACF;AAAA,QACC,QAAQ,WACP;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,SAAS,QAAQ;AAAA,YACjB,SAAQ;AAAA,YAER;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,MAAK;AAAA,gBACL,QAAO;AAAA,gBACP,QAAO;AAAA,gBACP,eAAc;AAAA,gBACd,gBAAe;AAAA,gBACf,aAAY;AAAA,gBACZ,SAAQ;AAAA,gBACR,OAAM;AAAA,gBACN,OAAM;AAAA,gBAEN;AAAA,+DAAC,UAAK,GAAE,cAAa;AAAA,kBACrB,6CAAC,UAAK,GAAE,cAAa;AAAA;AAAA;AAAA,YACvB;AAAA;AAAA,QACF;AAAA,SAEJ;AAAA,MAEA,8CAAC,eAAY,WAAU,qBACrB;AAAA,sDAAC,SAAI,WAAU,2DACb;AAAA,wDAAC,SAAI,WAAU,eACb;AAAA,0DAAC,SAAI,WAAU,8CACZ;AAAA,sBAAQ;AAAA,cACT,6CAAC,UAAK,WAAU,qCAAoC,kBAAI;AAAA,eAC1D;AAAA,YACA,6CAAC,SAAI,WAAU,oEAAmE,4BAElF;AAAA,aACF;AAAA,UACA,8CAAC,SAAI,WAAU,eACb;AAAA,0DAAC,SAAI,WAAU,8CACZ;AAAA,sBAAQ,oBAAoB,QAAQ,CAAC;AAAA,cACtC,6CAAC,UAAK,WAAU,qCAAoC,iBAAG;AAAA,eACzD;AAAA,YACA,6CAAC,SAAI,WAAU,oEAAmE,gCAElF;AAAA,aACF;AAAA,WACF;AAAA,QAEC,QAAQ,aAAa,UACpB,8CAAC,SAAI,WAAU,QACb;AAAA,wDAAC,SAAI,WAAU,gEACb;AAAA,yDAAC,UAAK,sBAAQ;AAAA,YACd,8CAAC,UAAM;AAAA,mBAAK,MAAM,QAAQ,QAAQ;AAAA,cAAE;AAAA,eAAC;AAAA,aACvC;AAAA,UACA,6CAAC,SAAI,WAAU,gDACb;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,OAAO,EAAE,OAAO,GAAG,QAAQ,QAAQ,IAAI;AAAA;AAAA,UACzC,GACF;AAAA,WACF;AAAA,QAGD,QAAQ,SAAS,aAAa,QAAQ,WACrC;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,SAAS,QAAQ;AAAA,YACjB,SAAQ;AAAA,YACT;AAAA;AAAA,QAED;AAAA,SAEJ;AAAA,OACF;AAAA,EAEJ;AAGA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,0PACT,aAAa,oBAAoB,sCACnC;AAAA,MACA;AAAA,MAEA;AAAA,sDAAC,SAAI,WAAU,kDACb;AAAA,wDAAC,SAAI,WAAU,2BACb;AAAA,yDAAC,UAAK,WAAU,uEAAsE;AAAA,YACtF,6CAAC,UAAK,WAAU,iFACb,kBAAQ,SAAS,mBACpB;AAAA,aACF;AAAA,UACC,QAAQ,WACP;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,SAAS,QAAQ;AAAA,cACjB,SAAQ;AAAA,cAER;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,MAAK;AAAA,kBACL,QAAO;AAAA,kBACP,QAAO;AAAA,kBACP,eAAc;AAAA,kBACd,gBAAe;AAAA,kBACf,aAAY;AAAA,kBACZ,SAAQ;AAAA,kBACR,OAAM;AAAA,kBACN,OAAM;AAAA,kBAEN;AAAA,iEAAC,UAAK,GAAE,cAAa;AAAA,oBACrB,6CAAC,UAAK,GAAE,cAAa;AAAA;AAAA;AAAA,cACvB;AAAA;AAAA,UACF;AAAA,WAEJ;AAAA,QAEA,8CAAC,eAAY,WAAU,qBACrB;AAAA,wDAAC,SAAI,WAAU,yEACb;AAAA,yDAAC,SAAI,WAAU,eACb,wDAAC,SAAI,WAAU,2DACZ;AAAA,sBAAQ;AAAA,cACT,8CAAC,UAAK,WAAU,oDACb;AAAA;AAAA,gBAAI;AAAA,iBAEP;AAAA,eACF,GACF;AAAA,YACA,6CAAC,SAAI,WAAU,eACb,wDAAC,SAAI,WAAU,2DACZ;AAAA,sBAAQ,oBAAoB,QAAQ,CAAC;AAAA,cACtC,8CAAC,UAAK,WAAU,oDACb;AAAA;AAAA,gBAAI;AAAA,iBAEP;AAAA,eACF,GACF;AAAA,aACF;AAAA,UAEC,QAAQ,aAAa,UACpB,8CAAC,SACC;AAAA,0DAAC,SAAI,WAAU,8EACb;AAAA,2DAAC,UAAK,sBAAQ;AAAA,cACd,8CAAC,UAAM;AAAA,qBAAK,MAAM,QAAQ,QAAQ;AAAA,gBAAE;AAAA,iBAAC;AAAA,eACvC;AAAA,YACA,6CAAC,SAAI,WAAU,yDACb;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,OAAO,EAAE,OAAO,GAAG,QAAQ,QAAQ,IAAI;AAAA;AAAA,YACzC,GACF;AAAA,aACF;AAAA,UAGD,QAAQ,SAAS,aAAa,QAAQ,WACrC;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,SAAS,QAAQ;AAAA,cACjB,SAAQ;AAAA,cACT;AAAA;AAAA,UAED;AAAA,WAEJ;AAAA;AAAA;AAAA,EACF;AAEJ;;;AChIY,IAAAC,sBAAA;AA5EL,IAAM,mBAAoD,CAAC;AAAA,EAChE,iBAAiB,CAAC;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,EAAE;AAAA,EAChD,eAAe;AACjB,MAAM;AACJ,QAAM,gBAAgB,eAAe;AAAA,IACnC,CAAC,MAAM,EAAE,aAAa;AAAA,EACxB;AACA,QAAM,gBAAgB,eAAe;AAAA,IACnC,CAAC,MAAM,EAAE,aAAa;AAAA,EACxB;AAEA,QAAM,mBACJ,KAAK,IAAI,UAAU,KAAK,OAAO,KAAK,IAAI,QAAQ,KAAK;AAGvD,QAAM,qBAAqB;AAI3B,QAAM,kBAAkB,UACpB,eACA,gBAAgB,WACd,OAAO,SACP;AAEN,QAAM,YACJ,OAAO,qBAAqB,WACxB,GAAG,gBAAgB,OACnB,oBAAoB;AAK1B,QAAM,iBACJ,SAAS,WACL,gBAAgB,WACd,QAAQ,kBAAkB,aAAa,eAAe,QAAQ,YAAY,kCAC1E,QAAQ,SAAS,aAAa,UAAU,eAAe,CAAC,QAAQ,YAAY,kCAC9E,eAAe,OAAO,MAAM,QAAQ,YAAY;AAGtD,QAAM,oBAAoB,SAAS,YAAY,gBAAgB;AAE/D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,0FACT,aAAa,oBAAoB,sCACnC,IACE,oBACI,8CACA,wCACN;AAAA,MACA,OAAO;AAAA,QACL,QAAQ;AAAA,MACV;AAAA,MAGC;AAAA,sBAAc,SAAS,KACtB,6CAAC,SAAI,WAAU,2CACZ,wBAAc,IAAI,CAAC,YAClB,8CAAC,SAAI,WAAU,oCAEZ;AAAA,kBAAQ,WACP,6CAAC,SAAI,WAAU,iQACZ,kBAAQ,SACX;AAAA,UAIF;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,6NACT,QAAQ,cACJ,4DACA,EACN;AAAA,cACA,SAAS,QAAQ;AAAA,cACjB,SAAQ;AAAA,cAEP,kBAAQ;AAAA;AAAA,UACX;AAAA,aAnBqD,QAAQ,EAoB/D,CACD,GACH;AAAA,QAID,qBACE,sBACC,6CAAC,SAAI,WAAU,uBAAuB,+BAAoB,IAE1D,6CAAC,SAAI,WAAU,uBACb;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,2NACT,mBACI,oCACA,2EACN;AAAA,YACA,SAAS,MACP,eAAe,EAAE,OAAO,kBAAkB,SAAS,EAAE,CAAC;AAAA,YAExD,OAAO;AAAA,cACL,WAAW,mBACP,0BACA;AAAA,YACN;AAAA,YACA,OAAM;AAAA,YACN,SAAQ;AAAA,YAER;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,MAAK;AAAA,gBACL,OAAO;AAAA,kBACL,WAAW,UAAU,CAAC,UAAU;AAAA,gBAClC;AAAA,gBACA,SAAQ;AAAA,gBAGR;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,IAAG;AAAA,sBACH,IAAG;AAAA,sBACH,GAAE;AAAA,sBACF,QAAO;AAAA,sBACP,eAAc;AAAA,sBACd,aAAY;AAAA;AAAA,kBACd;AAAA,kBAEA,6CAAC,UAAK,GAAE,2BAA0B,MAAK,WAAU;AAAA,kBAEjD,6CAAC,UAAK,GAAE,6BAA4B,MAAK,WAAU;AAAA,kBAEnD,6CAAC,YAAO,IAAG,MAAK,IAAG,MAAK,MAAK,WAAU,GAAE,OAAM;AAAA;AAAA;AAAA,YACjD;AAAA;AAAA,QACF,GACF;AAAA,QAIH,uBACC,6CAAC,SAAI,WAAU,uBAAuB,gCAAqB,IAE3D,6CAAC,SAAI,WAAU,uBACb;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,6NACT,gBACI,4DACA,EACN;AAAA,YACA,SAAS,MAAM,WAAW;AAAA,YAC1B,OAAM;AAAA,YACN,SAAQ;AAAA,YAEP;AAAA;AAAA,cAEC;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,MAAK;AAAA,kBACL,QAAO;AAAA,kBACP,aAAY;AAAA,kBACZ,SAAQ;AAAA,kBAER;AAAA,iEAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,oBAC9B,6CAAC,YAAO,IAAG,MAAK,IAAG,MAAK,MAAK,gBAAe,GAAE,KAAI;AAAA,oBAClD,6CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAI,IAAG,KAAI;AAAA,oBACpC,6CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,oBACtC,6CAAC,UAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,oBACpC,6CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA;AAAA;AAAA,cACxC;AAAA;AAAA;AAAA,cAGA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,MAAK;AAAA,kBACL,QAAO;AAAA,kBACP,aAAY;AAAA,kBACZ,SAAQ;AAAA,kBAER;AAAA,iEAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,oBAC9B,6CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAI,IAAG,KAAI;AAAA,oBACpC,6CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,oBACtC,6CAAC,UAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,oBACpC,6CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA;AAAA;AAAA,cACxC;AAAA;AAAA;AAAA,QAEJ,GACF;AAAA,QAID,cAAc,SAAS,KACtB,6CAAC,SAAI,WAAU,2CACZ,wBAAc,IAAI,CAAC,YAClB,8CAAC,SAAI,WAAU,oCAEZ;AAAA,kBAAQ,WACP,6CAAC,SAAI,WAAU,iQACZ,kBAAQ,SACX;AAAA,UAIF;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,6NACT,QAAQ,cACJ,4DACA,EACN;AAAA,cACA,SAAS,QAAQ;AAAA,cACjB,SAAQ;AAAA,cAEP,kBAAQ;AAAA;AAAA,UACX;AAAA,aAnBqD,QAAQ,EAoB/D,CACD,GACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;;;AChRA,IAAAC,gBAA0C;AAE1C,IAAAA,gBAQO;AACP,+BAAqC;AAoS/B,IAAAC,sBAAA;AAlSN,IAAM,wBAAwB,CAC5B,QACA,oBACW;AACX,MAAI,OAAO,WAAW,UAAU;AAC9B,WAAO;AAAA,EACT;AACA,MAAI,OAAO,SAAS,GAAG,GAAG;AACxB,WAAQ,WAAW,MAAM,IAAI,MAAO;AAAA,EACtC;AACA,SAAO,WAAW,MAAM;AAC1B;AAEA,IAAM,mBAAmB;AAQzB,IAAM,qBAAqB;AAAA,EACzB,UAAU;AAAA,EACV,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC;AACzB;AAKA,IAAM,gCAAgC;AAuC/B,IAAM,yBAAqB;AAAA,EAIhC,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB;AAAA,IACA,wBAAwB;AAAA,IACxB,uBAAuB;AAAA,IACvB,iBAAiB,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,EAAE;AAAA,EAC1D,GACA,QACG;AACH,UAAM,gBAAY,sBAAuB,IAAI;AAC7C,2CAAoB,KAAK,MAAM,UAAU,OAAyB;AAElE,UAAM,gBAAY,sBAAuB,IAAI;AAC7C,UAAM,wBAAoB,sBAAuB,IAAI;AAErD,UAAM,CAAC,gBAAgB,iBAAiB,QAAI;AAAA,MAC1C,MACE,oBACC,OAAO,WAAW,cAAc,OAAO,cAAc;AAAA,IAC1D;AAEA,iCAAU,MAAM;AACd,UAAI,iBAAiB;AACnB,0BAAkB,eAAe;AACjC;AAAA,MACF;AACA,UAAI,OAAO,WAAW,YAAa;AACnC,YAAM,SAAS,MAAM,kBAAkB,OAAO,WAAW;AACzD,aAAO;AACP,aAAO,iBAAiB,UAAU,MAAM;AACxC,aAAO,MAAM,OAAO,oBAAoB,UAAU,MAAM;AAAA,IAC1D,GAAG,CAAC,eAAe,CAAC;AAMpB,UAAM,CAAC,eAAe,gBAAgB,QAAI,wBAAS,CAAC;AACpD,iCAAU,MAAM;AACd,YAAM,YAAY,kBAAkB;AACpC,UAAI,CAAC,UAAW;AAEhB,YAAM,UAAU,MAAM;AACpB,cAAM,eAAe,gBAChB,UAAU,SAAS,gBAAgB,IACpC;AACJ,cAAM,KAAK,eAAe,UAAU;AACpC,yBAAiB,EAAE;AACnB,oCAA4B,EAAE;AAAA,MAChC;AAEA,cAAQ;AACR,YAAM,KAAK,IAAI,eAAe,OAAO;AACrC,SAAG,QAAQ,SAAS;AACpB,aAAO,MAAM,GAAG,WAAW;AAAA,IAC7B,GAAG,CAAC,eAAe,yBAAyB,CAAC;AAE7C,UAAM,YACH,gBAAgB,mBAAmB,KAAK,eAAe;AAC1D,UAAM,SAAS;AAAA,MACb,oBAAoB;AAAA,MACpB;AAAA,IACF;AACA,UAAM,YAAY;AAAA,MAChB,uBAAuB;AAAA,MACvB;AAAA,IACF;AACA,UAAM,SAAS,KAAK,IAAI,WAAW,KAAK,IAAI,eAAe,WAAW,CAAC,CAAC;AAYxE,UAAM,EAAE,YAAY,YAAY,eAAe,QAAI,uBAAQ,MAAM;AAC/D,YAAM,YAAY,CAAC,QACjB,MAAM,KAAK,OAAO,IAAI,MAAM,iBAAiB;AAE/C,YAAM,WAAkD;AAAA,QACtD,EAAE,OAAO,UAAU,KAAK,EAAE;AAAA,QAC1B,EAAE,OAAO,UAAU,KAAK,SAAS;AAAA,QACjC,EAAE,OAAO,QAAQ,KAAK,OAAO;AAAA,QAC7B,EAAE,OAAO,QAAQ,KAAK,OAAO;AAAA,QAC7B,EAAE,OAAO,QAAQ,KAAK,EAAE;AAAA,MAC1B;AACA,YAAM,UAAU,SAAS;AAAA,QACvB,CAAC,GAAG,MAAM,UAAU,EAAE,GAAG,IAAI,UAAU,EAAE,GAAG;AAAA,MAC9C;AASA,YAAM,UAAiD,CAAC;AACxD,iBAAW,SAAS,SAAS;AAC3B,cAAM,OAAO,QAAQ,QAAQ,SAAS,CAAC;AACvC,YACE,QACA,KAAK,IAAI,UAAU,KAAK,GAAG,IAAI,UAAU,MAAM,GAAG,CAAC,IAAI,KACvD;AACA,kBAAQ,QAAQ,SAAS,CAAC,IAAI;AAC9B;AAAA,QACF;AACA,gBAAQ,KAAK,KAAK;AAAA,MACpB;AAEA,aAAO;AAAA,QACL,gBAAgB,QAAQ;AAAA,UAAI,CAAC,MAC3B,EAAE,UAAU,UAAU,EAAE,UAAU,SAAS,IAAI;AAAA,QACjD;AAAA,QACA,YAAY,QAAQ,IAAI,CAAC,MAAM,EAAE,KAAK;AAAA,QACtC,YAAY,QAAQ,IAAI,CAAC,MAAM,EAAE,GAAG;AAAA,MACtC;AAAA,IACF,GAAG,CAAC,UAAU,QAAQ,QAAQ,cAAc,CAAC;AAM7C,UAAM,eAAe,KAAK,IAAI,GAAG,WAAW,YAAY,KAAK,CAAC;AAkB9D,UAAM,eAAW,sBAAiB,IAAI;AACtC,iCAAU,MAAM;AACd,UAAI,YAAY;AAChB,UAAI,WAAW;AAEf,YAAM,UAAU,MAAM;AACpB,YAAI,UAAW;AACf,cAAMC,OAAM,SAAS;AACrB,YAAIA,QAAOA,KAAI,WAAW,SAAS,GAAG;AACpC,UAAAA,KAAI,OAAO,YAAY;AACvB;AAAA,QACF;AACA,oBAAY;AACZ,YAAI,WAAW,GAAI;AACnB,8BAAsB,OAAO;AAAA,MAC/B;AAEA,cAAQ;AACR,aAAO,MAAM;AACX,oBAAY;AAAA,MACd;AAAA,IACF,GAAG,CAAC,YAAY,CAAC;AAEjB,UAAM,iBAAa;AAAA,MACjB,CAAC,UAAkB;AACjB,cAAM,QAAQ,WAAW,KAAK,KAAK;AACnC,YAAI,UAAU,MAAO,eAAc,KAAK;AAAA,MAC1C;AAAA,MACA,CAAC,YAAY,OAAO,aAAa;AAAA,IACnC;AAEA,UAAM,oBAAoB,MAAM;AAC9B,UAAI,UAAU,UAAU;AACtB,sBAAc,MAAM;AAAA,MACtB,WAAW,UAAU,QAAQ;AAC3B,sBAAc,MAAM;AAAA,MACtB,WAAW,UAAU,QAAQ;AAC3B,sBAAc,QAAQ;AAAA,MACxB,OAAO;AACL,sBAAc,MAAM;AAAA,MACtB;AAAA,IACF;AAEA,UAAM,CAAC,eAAe,gBAAgB,QAAI,wBAAS,KAAK;AACxD,iCAAU,MAAM;AACd,YAAM,KAAK,UAAU;AACrB,UAAI,CAAC,GAAI;AACT,YAAM,WAAW,MAAM;AACrB;AAAA,UACE,UAAU,YAAY,GAAG,YAAY;AAAA,QACvC;AAAA,MACF;AACA,SAAG,iBAAiB,UAAU,QAAQ;AACtC,aAAO,MAAM,GAAG,oBAAoB,UAAU,QAAQ;AAAA,IACxD,GAAG,CAAC,OAAO,oBAAoB,CAAC;AAEhC,iCAAU,MAAM;AACd,UAAI,UAAU,SAAU,kBAAiB,KAAK;AAAA,IAChD,GAAG,CAAC,KAAK,CAAC;AAEV,UAAM,eAAe,CAAC;AAEtB,WACE,8EACE;AAAA,mDAAC,WAAO;AAAA;AAAA;AAAA,WAGN;AAAA,MAEF;AAAA,QAAC;AAAA;AAAA,UACC,gBAAc;AAAA,UACd,aAAa;AAAA,UACb,uBAAuB;AAAA,UACvB,aAAa;AAAA,UACb,QAAM;AAAA,UACN,SAAS,MAAM,cAAc,QAAQ;AAAA,UACrC,QAAQ;AAAA,UACR,KAAK;AAAA,UACL;AAAA,UACA,aAAa;AAAA,UAEb;AAAA;AAAA,cAAC,+BAAM;AAAA,cAAN;AAAA,gBACC,WAAU;AAAA,gBACV,OAAO,EAAE,eAAe,eAAe,OAAO;AAAA,gBAE7C;AAAA,mCACC;AAAA,oBAAC,+BAAM;AAAA,oBAAN;AAAA,sBACC,WAAU;AAAA,sBACV,SAAS;AAAA,sBACT,KAAK;AAAA;AAAA,kBACP;AAAA,kBAGF;AAAA,oBAAC,+BAAM;AAAA,oBAAN;AAAA,sBACC,WAAU;AAAA,sBACV,aAAa,CAAC,SACZ,gBAAgB,KAAK,mBAAmB;AAAA,sBAa1C,eAAe,CAAC,SACd,CAAC,gBAAgB,KAAK,gBAAgB,WAAW,SAAS;AAAA,sBAE5D,iBAAgB;AAAA,sBAChB;AAAA,sBAEA;AAAA,qEAAC,SAAI,WAAU,2BAA0B,KAAK,mBAC3C,wBACC,cAEA,6CAAC,SAAI,WAAU,uBACZ,oBAAU,IAAI,CAAC,SACd;AAAA,0BAAC;AAAA;AAAA,4BACC,WAAW,4LACT,KAAK,WACD,sDACA,EACN;AAAA,4BACA,UAAU,KAAK;AAAA,4BAEf,SAAS,MAAM;AACb,kCAAI,CAAC,KAAK,UAAU;AAClB,qCAAK,QAAQ;AACb,8CAAc,QAAQ;AAAA,8BACxB;AAAA,4BACF;AAAA,4BACA,SAAQ;AAAA,4BAER;AAAA,4EAAC,SAAI,WAAU,yFACZ;AAAA,qCAAK;AAAA,gCACL,KAAK,UAAU,UACd,6CAAC,UAAK,WAAU,iLACb,eAAK,OACR;AAAA,iCAEJ;AAAA,8BACA,6CAAC,UAAK,WAAU,qCACb,eAAK,OACR;AAAA;AAAA;AAAA,0BAnBK,KAAK;AAAA,wBAoBZ,CACD,GACH,GAEJ;AAAA,wBAEC,yBAAyB,iBACxB;AAAA,0BAAC;AAAA;AAAA,4BACC,WAAU;AAAA,4BACV,SAAS,MAAM;AACb,wCAAU,SAAS,SAAS,EAAE,UAAU,UAAU,KAAK,EAAE,CAAC;AAAA,4BAC5D;AAAA,4BACA,SAAQ;AAAA,4BAER;AAAA,8BAAC;AAAA;AAAA,gCACC,MAAK;AAAA,gCACL,QAAO;AAAA,gCACP,QAAO;AAAA,gCACP,eAAc;AAAA,gCACd,gBAAe;AAAA,gCACf,aAAY;AAAA,gCACZ,SAAQ;AAAA,gCACR,OAAM;AAAA,gCACN,OAAM;AAAA,gCAEN,uDAAC,cAAS,QAAO,mBAAkB;AAAA;AAAA,4BACrC;AAAA;AAAA,wBACF;AAAA;AAAA;AAAA,kBAEJ;AAAA;AAAA;AAAA,YACF;AAAA,YAEA;AAAA,cAAC;AAAA;AAAA,gBACC,QAAQ,UAAU,UAAU,UAAU;AAAA,gBACtC,OAAO,MAAM,cAAc,QAAQ;AAAA,gBACnC,QAAQ;AAAA;AAAA,YACV;AAAA;AAAA;AAAA,MACF;AAAA,OACF;AAAA,EAEJ;AACF;AAEA,mBAAmB,cAAc;AASjC,SAAS,eAAe;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,EAAE,GAAG,WAAW,IAAI,+BAAM,WAAW;AAE3C,QAAM,cAAU,4BAAa,GAAG,CAAC,UAAU;AACzC,QAAI,WAAW,WAAW,KAAK,OAAO,WAAW,WAAW,QAAQ;AAClE,aAAO;AAAA,IACT;AACA,UAAM,UAAM;AAAA,MACV,WAAW,IAAI,CAAC,UAAU,MAAM,UAAU;AAAA,MAC1C;AAAA,IACF;AACA,WAAO,IAAI,KAAK,IAAI;AAAA,EACtB,CAAC;AAWD,SACE;AAAA,IAAC,+BAAM;AAAA,IAAN;AAAA,MACC,WAAU;AAAA,MACV,OAAO,SAAS,QAAQ;AAAA,MACxB,OAAO,EAAE,QAAQ;AAAA;AAAA,EACnB;AAEJ;;;AC9dA,IAAAC,gBAOO;AAyQH,IAAAC,sBAAA;AA/KG,IAAM,yBAAqB;AAAA,EAChC;AACF;AAEO,IAAM,iBAA0D,CAAC;AAAA,EACtE;AACF,MAAM;AACJ,QAAM,CAAC,aAAa,cAAc,QAAI,wBAAS,IAAI;AACnD,QAAM,CAAC,SAAS,eAAe,QAAI,wBAAS,CAAC;AAC7C,QAAM,CAAC,OAAO,aAAa,QAAI,wBAAS,CAAC;AACzC,QAAM,CAAC,aAAa,sBAAsB,QAAI,wBAAsB,QAAQ;AAG5E,QAAM,uBAAmB,sBAAuB,IAAI;AAEpD,QAAM,qBAAiB,2BAAY,CAAC,QAAqB;AACvD,2BAAuB,GAAG;AAAA,EAC5B,GAAG,CAAC,CAAC;AAEL,QAAM,CAAC,qBAAqB,2BAA2B,QAAI,wBAAS,IAAI;AACxE,QAAM,6BAAyB,2BAAY,CAAC,QAAiB;AAC3D,gCAA4B,CAAC,SAAU,SAAS,MAAM,OAAO,GAAI;AAAA,EACnE,GAAG,CAAC,CAAC;AAGL,QAAM,CAAC,aAAa,mBAAmB,QAAI,wBAAS,KAAK;AACzD,QAAM,qBAAiB,2BAAY,CAAC,QAAiB;AACnD,wBAAoB,CAAC,SAAU,SAAS,MAAM,OAAO,GAAI;AAAA,EAC3D,GAAG,CAAC,CAAC;AAGL,QAAM,CAAC,SAAS,eAAe,QAAI,wBAA8B,MAAS;AAC1E,QAAM,iBAAa,2BAAY,CAAC,YAAsB;AACpD,oBAAgB,CAAC,SAAS;AACxB,UAAI,CAAC,QAAQ,CAAC,QAAS,QAAO;AAC9B,UAAI,CAAC,QAAQ,CAAC,QAAS,QAAO;AAC9B,UACE,KAAK,YAAY,QAAQ,WACzB,KAAK,wBAAwB,QAAQ,uBACrC,KAAK,UAAU,QAAQ,SACvB,KAAK,aAAa,QAAQ,YAC1B,KAAK,SAAS,QAAQ,QACtB,KAAK,kBAAkB,QAAQ,iBAC/B,KAAK,UAAU,QAAQ,OACvB;AACA,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,QAAM,CAAC,QAAQ,cAAc,QAAI,wBAAoB;AAAA,IACnD,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,OAAO;AAAA,IACP,KAAK;AAAA,EACP,CAAC;AAED,QAAM,gBAAY,2BAAY,CAAC,cAAkC;AAC/D,mBAAe,CAAC,UAAU,EAAE,GAAG,MAAM,GAAG,UAAU,EAAE;AAAA,EACtD,GAAG,CAAC,CAAC;AAEL,QAAM,wBAAoB,sBAExB,IAAI;AACN,QAAM,8BAA0B,sBAE9B,IAAI;AACN,QAAM,uBAAmB,sBAEvB,IAAI;AAEN,QAAM,mBAAe,2BAAY,CAAC,WAAkC;AAClE,QAAI,kBAAkB,SAAS;AAC7B,wBAAkB,QAAQ,MAAM;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,mBAAe,2BAAY,CAAC,WAAkC;AAClE,QAAI,wBAAwB,SAAS;AACnC,8BAAwB,QAAQ,MAAM;AAAA,IACxC;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,YAAQ;AAAA,IACZ,CAAC,QAA0B,WAAyB;AAClD,UAAI,iBAAiB,SAAS;AAC5B,yBAAiB,QAAQ,QAAQ,MAAM;AAAA,MACzC;AAAA,IACF;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,8BAA0B;AAAA,IAC9B,CAAC,OAAgD;AAC/C,wBAAkB,UAAU;AAAA,IAC9B;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,oCAAgC;AAAA,IACpC,CAAC,OAAgD;AAC/C,8BAAwB,UAAU;AAAA,IACpC;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,6BAAyB;AAAA,IAC7B,CAAC,OAAiE;AAChE,uBAAiB,UAAU;AAAA,IAC7B;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,iBAAa,2BAAY,CAAC,MAAc;AAC5C,oBAAgB,CAAC;AAAA,EACnB,GAAG,CAAC,CAAC;AAEL,QAAM,eAAW,2BAAY,CAAC,MAAc;AAC1C,kBAAc,CAAC;AAAA,EACjB,GAAG,CAAC,CAAC;AAGL,QAAM,mBAAe;AAAA,IACnB,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SACE,6CAAC,mBAAmB,UAAnB,EAA4B,OAAO,cACjC,UACH;AAEJ;AAEO,IAAM,iBAAiB,MAAwB;AACpD,QAAM,cAAU,0BAAW,kBAAkB;AAC7C,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,0DAA0D;AAAA,EAC5E;AACA,SAAO;AACT;;;AC9QA,IAAAC,gBAAqE;AA0SjE,IAAAC,sBAAA;AAxSJ,IAAMC,yBAAwB,CAC5B,QACA,oBACW;AACX,MAAI,OAAO,WAAW,UAAU;AAC9B,WAAO;AAAA,EACT;AACA,MAAI,OAAO,SAAS,GAAG,GAAG;AACxB,WAAQ,WAAW,MAAM,IAAI,MAAO;AAAA,EACtC;AACA,SAAO,WAAW,MAAM;AAC1B;AAyDO,IAAM,cAA0C,CAAC;AAAA,EACtD,YAAY,CAAC;AAAA,EACb;AAAA,EACA,iBAAiB,CAAC;AAAA,EAClB,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB,wBAAwB;AAAA,EACxB,uBAAuB;AAAA,EACvB,uBAAuB;AAAA,EACvB,aAAa;AACf,MAAM;AACJ,QAAM,iBAAa,0BAAW,kBAAkB;AAEhD,QAAM,aAAa,YAAY;AAG/B,QAAM,gBAAY;AAAA,IAChB,CAAC,SAAgC;AAE/B,UAAI,kBAAkB;AACpB,YAAI,OAAO,qBAAqB,YAAY;AAC1C,2BAAiB,IAAI;AAAA,QACvB,OAAO;AACL,UAAC,iBAAyB,UAAU;AAAA,QACtC;AAAA,MACF;AAEA,UAAI,YAAY;AACd,QAAC,WAAmB,UAAU;AAAA,MAChC;AAAA,IACF;AAAA,IACA,CAAC,kBAAkB,UAAU;AAAA,EAC/B;AAGA,QAAM,CAAC,kBAAkB,mBAAmB,QAAI;AAAA,IAC9C,gBAAgB;AAAA,EAClB;AAEA,QAAM,cAAc,aAAa,WAAW,cAAc;AAC1D,QAAM,qBAAiB;AAAA,IACrB,CAAC,UAAuB;AACtB,UAAI,YAAY;AACd,mBAAW,eAAe,KAAK;AAAA,MACjC,OAAO;AACL,4BAAoB,KAAK;AAAA,MAC3B;AAAA,IACF;AAAA,IACA,CAAC,UAAU;AAAA,EACb;AAIA,+BAAU,MAAM;AACd,QAAI,gBAAgB,YAAY;AAC9B,iBAAW,eAAe,YAAY;AAAA,IACxC;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,CAAC,MAAM,OAAO,QAAI,wBAA4B,MAAM;AAC1D,QAAM,mBAAe,sBAAuB,IAAI;AAChD,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,GAAG;AAG9C,+BAAU,MAAM;AACd,UAAM,SAAS,aAAa,SAAS;AACrC,QAAI,CAAC,OAAQ;AAEb,UAAM,eAAe,MAAM;AACzB,mBAAa,OAAO,sBAAsB,EAAE,MAAM;AAAA,IACpD;AAEA,iBAAa;AAEb,UAAM,WAAW,IAAI,eAAe,YAAY;AAChD,aAAS,QAAQ,MAAM;AAEvB,WAAO,MAAM;AACX,eAAS,WAAW;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,QAAM,iBAAiB,YAAY;AACnC,+BAAU,MAAM;AACd,QAAI,kBAAkB,CAAC,YAAY;AACjC,qBAAe,IAAI;AACnB,aAAO,MAAM,eAAe,KAAK;AAAA,IACnC;AAAA,EACF,GAAG,CAAC,gBAAgB,UAAU,CAAC;AAG/B,QAAM,gBACJ,oBAAoB,SAChB,kBACA,aACE,WAAW,cACX;AAER,QAAM,aACJ,mBAAmB,SACf,iBACA,aACE,WAAW,UACX;AAER,QAAM,aAAa,CAAC,WAAkC;AACpD,QAAI,cAAc;AAChB,mBAAa,MAAM;AAAA,IACrB,WAAW,YAAY;AACrB,iBAAW,aAAa,MAAM;AAAA,IAChC;AAAA,EACF;AAEA,QAAM,iBAAiB,CAAC,WAAkC;AACxD,QAAI,kBAAkB;AACpB,uBAAiB,MAAM;AAAA,IACzB,WAAW,YAAY;AACrB,iBAAW,aAAa,MAAM;AAAA,IAChC;AAAA,EACF;AAEA,QAAM,WAAW,aAAa,WAAW,QAAQ;AAGjD,QAAM,kBAAkB,YAAY,SAAY,UAAU,YAAY;AAKtE,QAAM,CAAC,eAAe,gBAAgB,QAAI,wBAAS,CAAC;AAGpD,+BAAU,MAAM;AACd,QAAI,OAAO,WAAW,YAAa;AAEnC,UAAM,cAAc,MAAM;AACxB,UAAI,YAAY;AACd,gBAAQ,UAAU;AAAA,MACpB,OAAO;AAEL,YAAI,OAAO,aAAa,KAAK;AAC3B,kBAAQ,QAAQ;AAAA,QAClB,OAAO;AACL,kBAAQ,MAAM;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAEA,gBAAY;AACZ,WAAO,iBAAiB,UAAU,WAAW;AAC7C,WAAO,MAAM,OAAO,oBAAoB,UAAU,WAAW;AAAA,EAC/D,GAAG,CAAC,UAAU,CAAC;AAMf,QAAM,aAAa;AACnB,QAAM,oBAAoB;AAG1B,QAAM,SAASA,uBAAsB,oBAAoB,OAAO,SAAS;AACzE,QAAM,SAASA,uBAAsB,oBAAoB,OAAO,SAAS;AACzE,QAAM,YAAYA;AAAA,IAChB,uBAAuB;AAAA,IACvB;AAAA,EACF;AACA,QAAM,SAAS,KAAK,IAAI,WAAW,aAAa;AAChD,QAAM,cAAc,YAAY,OAAO,UAAU;AACjD,QAAM,gBAAgB,aAAa,WAAW,sBAAsB;AAGpE,MAAI,aAAa,gBAAgB,KAAK;AACtC,MAAI,gBAAgB,QAAQ;AAC1B,iBAAa;AAAA,EACf,WAAW,gBAAgB,QAAQ;AACjC,iBAAa;AAAA,EACf,WAAW,gBAAgB,QAAQ;AACjC,iBAAa;AAAA,EACf;AAEA,QAAM,sBAAsB;AAG5B,QAAM,kBAAkB,SAAS;AACjC,QAAM,gBAAgB,UAAU,SAAS,UAAU;AAEnD,MAAI,aAAa;AACjB,MAAI,iBAAkC;AAEtC,MAAI,SAAS,UAAU;AACrB,QAAI,uBAAuB,iBAAiB;AAC1C,mBAAa;AAAA,IACf,WAAW,uBAAuB,eAAe;AAC/C,mBAAa;AAAA,IACf,OAAO;AACL,YAAM,YACH,sBAAsB,oBACtB,gBAAgB;AACnB,mBAAa,IAAI;AAAA,IACnB;AAGA,UAAM,iBAAiB,gBAAgB,WAAW,cAAc;AAChE,qBAAiB,QAAQ,aAAa,iBAAiB,EAAE;AAAA,EAC3D,OAAO;AAEL,iBAAa,gBAAgB,SAAS,IAAI;AAC1C,qBAAiB,eAAe,WAAW;AAAA,EAC7C;AAEA,SACE,8EACE;AAAA,iDAAC,SAAI,KAAK,cAAc,OAAO,EAAE,SAAS,OAAO,GAAG;AAAA,IAGnD,SAAS,WACR;AAAA,MAAC;AAAA;AAAA,QACC,iBAAiB;AAAA,QACjB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAa,YAAY;AAAA,QACzB;AAAA,QACA,2BAA2B;AAAA,QAC3B,eAAe;AAAA,QACf,KAAK;AAAA,QACL,gBAAgB,YAAY;AAAA,QAC5B;AAAA,QACA;AAAA,QACA,OAAO;AAAA;AAAA,IACT,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,aAAa,YAAY;AAAA,QACzB;AAAA,QACA,eAAe;AAAA,QACf,KAAK;AAAA,QACL;AAAA,QACA;AAAA,QACA,OAAO;AAAA;AAAA,IACT;AAAA,IAIF;AAAA,MAAC;AAAA;AAAA,QACC,cAAc;AAAA,QACd;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,cACE,gBAAgB,gBAAgB,WAAW,cAAc;AAAA,QAE3D,SAAS;AAAA,QACT;AAAA,QACA,QAAQ,YAAY;AAAA,QACpB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY,MAAM,WAAW;AAAA,QAC7B;AAAA,QACA;AAAA;AAAA,IACF;AAAA,IAGC,mBACC;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT;AAAA,QACA,YAAW;AAAA,QACX,OAAO;AAAA,UACL,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,eAAe,aAAa,MAAM,SAAS;AAAA,UAC3C,YAAY,aACR,SACA;AAAA,QACN;AAAA;AAAA,IACF;AAAA,KAEJ;AAEJ;;;ACpYA,IAAAC,gBAA2B;AAOlB,IAAAC,uBAAA;AADF,IAAM,UAAkC,CAAC,EAAE,SAAS,MAAM;AAC/D,SAAO,8CAAC,SAAI,WAAU,yBAAyB,UAAS;AAC1D;AAYO,IAAM,cAA0C,CAAC;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AACF,MAAM;AACJ,QAAM,cAAU,0BAAW,kBAAkB;AAE7C,QAAM,cAAc,CAAC,MAAwB;AAC3C,QAAI,SAAU;AACd,QAAI,QAAS,SAAQ;AACrB,QAAI,WAAW,QAAQ,gBAAgB;AACrC,cAAQ,eAAe,QAAQ;AAAA,IACjC;AAAA,EACF;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,8GACT,WACI,sDACA,gDACN;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,MAAK;AAAA,MAEJ;AAAA,gBACC,+CAAC,SAAI,WAAU,yFACZ;AAAA;AAAA,UACA,UAAU,UACT,8CAAC,UAAK,WAAU,iLACb,iBACH;AAAA,WAEJ;AAAA,QAEF,+CAAC,SAAI,WAAU,uCACb;AAAA,wDAAC,UAAK,WAAU,4CACb,iBACH;AAAA,UACC;AAAA,WACH;AAAA;AAAA;AAAA,EACF;AAEJ;AAEA,QAAQ,cAAc;AACtB,YAAY,cAAc;AAQnB,IAAM,eAA4C,CAAC;AAAA,EACxD;AAAA,EACA,cAAc;AAAA,EACd,YAAY;AACd,MAAM;AACJ,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,4DAA4D,SAAS,IAAI,cAAc,uCAAuC,EAAE;AAAA,MAE1I;AAAA;AAAA,EACH;AAEJ;AACA,aAAa,cAAc;AAMpB,IAAM,iBAAgD,CAAC;AAAA,EAC5D,YAAY;AACd,MAAM;AACJ,SAAO,8CAAC,SAAI,WAAW,mCAAmC,SAAS,IAAI;AACzE;AACA,eAAe,cAAc;AAOtB,IAAM,gBAA8C,CAAC;AAAA,EAC1D;AAAA,EACA,YAAY;AACd,MAAM;AACJ,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,kFAAkF,SAAS;AAAA,MAErG;AAAA;AAAA,EACH;AAEJ;AACA,cAAc,cAAc;;;ACgKrB,IAAK,UAAL,kBAAKC,aAAL;AAEL,EAAAA,SAAA,qBAAkB;AAElB,EAAAA,SAAA,wBAAqB;AAErB,EAAAA,SAAA,kBAAe;AANL,SAAAA;AAAA,GAAA;AAYL,IAAK,mBAAL,kBAAKC,sBAAL;AAEL,EAAAA,kBAAA,qBAAkB;AAElB,EAAAA,kBAAA,4BAAyB;AAJf,SAAAA;AAAA,GAAA;AAwDL,IAAK,cAAL,kBAAKC,iBAAL;AAEL,EAAAA,aAAA,oBAAiB;AAFP,SAAAA;AAAA,GAAA;;;AC9VZ,IAAAC,gBAAoC;AAapC,IAAM,cAAc;AAEpB,IAAM,cAAiC;AAAA,EACrC,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,SAAS;AACX;AAEA,SAAS,WAAW,SAAiC;AACnD,QAAM,SAAS,QAAQ,UAAU,UAAU,QAAQ;AACnD,QAAM,cAAc,QAAQ;AAE5B,QAAM,YAAqC,SACvC,CAAC,OAAO,WAAW,OAAO,QAAQ,IAClC;AAEJ,MAAI,UAAU;AACd,MAAI,aAAa,gBAAgB,UAAa,YAAY,eAAe,GAAG;AAC1E,cAAU,YAAY;AAAA,EACxB,WACE,aAAa,oBAAoB,UACjC,YAAY,mBAAmB,GAC/B;AACA,cAAU,YAAY;AAAA,EACxB,WAAW,aAAa,YAAY,QAAQ,aAAa,WAAW,GAAG;AACrE,cAAU,YAAY;AAAA,EACxB;AAEA,SAAO;AAAA,IACL,UAAU,QAAQ,YAAY;AAAA,IAC9B,QAAQ;AAAA,IACR;AAAA,EACF;AACF;AAwBA,IAAI,WAAW;AAOf,IAAI,aAAa;AACjB,IAAM,cAAc,oBAAI,IAAwC;AAChE,IAAI,cAAiC,EAAE,GAAG,YAAY;AACtD,IAAI,sBAGA,EAAE,QAAQ,MAAM,SAAS,KAAK;AAClC,IAAI,QAAuB;AAC3B,IAAI,oBAAyC;AAC7C,IAAI,oBAAyC;AAE7C,SAAS,cAAiC;AACxC,SAAO;AAAA,IACL,UAAU,YAAY;AAAA,IACtB,QAAQ,oBAAoB,SAAS,CAAC,GAAG,oBAAoB,MAAM,IAAI;AAAA,IACvE,SAAS,oBAAoB;AAAA,EAC/B;AACF;AAEA,SAAS,SAAS;AAChB,QAAM,WAAW,YAAY;AAC7B,aAAW,YAAY,YAAa,UAAS,QAAQ;AACvD;AAEA,SAAS,UAAU;AACjB,MAAI,UAAU;AAGd,MAAI,YAAY,QAAQ;AACtB,QAAI,CAAC,oBAAoB,QAAQ;AAC/B,0BAAoB,SAAS,CAAC,GAAG,YAAY,MAAM;AACnD,gBAAU;AAAA,IACZ,OAAO;AACL,YAAM,CAAC,MAAM,IAAI,IAAI,YAAY;AACjC,YAAM,CAAC,MAAM,IAAI,IAAI,oBAAoB;AAEzC,YAAM,OAAO,QAAQ,OAAO,QAAQ;AACpC,YAAM,OAAO,QAAQ,OAAO,QAAQ;AAGpC,UAAI,KAAK,IAAI,OAAO,IAAI,IAAI,QAAQ,KAAK,IAAI,OAAO,IAAI,IAAI,MAAM;AAChE,4BAAoB,SAAS,CAAC,MAAM,IAAI;AACxC,kBAAU;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAGA,MAAI,YAAY,YAAY,MAAM;AAChC,QAAI,oBAAoB,YAAY,MAAM;AACxC,0BAAoB,UAAU,YAAY;AAC1C,gBAAU;AAAA,IACZ,OAAO;AACL,YAAM,SAAS,YAAY;AAC3B,YAAM,UAAU,oBAAoB;AAGpC,UAAI,QAAQ,SAAS;AACrB,UAAI,QAAQ,IAAK,UAAS;AAC1B,UAAI,QAAQ,KAAM,UAAS;AAE3B,YAAM,WAAW,UAAU,QAAQ;AAEnC,YAAM,cAAe,WAAW,MAAO,OAAO;AAE9C,UAAI,KAAK,IAAI,KAAK,IAAI,KAAK;AACzB,4BAAoB,UAAU;AAC9B,kBAAU;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAEA,MAAI,QAAS,QAAO;AAEpB,UAAQ,sBAAsB,OAAO;AACvC;AAEA,SAAS,oBAAoB;AAC3B,UAAQ,sBAAsB,OAAO;AAErC;AACA,QAAM,iBAAiB;AAGvB,MAAI,SACD,mBAAmB,EACnB,KAAK,CAAC,SAAS;AACd,QAAI,mBAAmB,WAAY;AACnC,kBAAc,WAAW,IAAI;AAAA,EAC/B,CAAC,EACA,MAAM,CAAC,MAAM,QAAQ,KAAK,iCAAiC,CAAC,CAAC;AAEhE,sBAAoB,IAAI;AAAA;AAAA,IAEtB,CAAC,YAAiB;AAChB,oBAAc,WAAW,OAAO;AAAA,IAClC;AAAA,EACF;AAEA,sBAAoB,IAAI;AAAA;AAAA,IAEtB,CAAC,YAAiB;AAChB,oBAAc,WAAW,OAAO;AAAA,IAClC;AAAA,EACF;AAEA,MAAI,SACD,YAAY;AAAA,IACX,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,EACpB,CAAC,EACA,MAAM,CAAC,MAAM,QAAQ,KAAK,mCAAmC,CAAC,CAAC;AACpE;AAEA,SAAS,mBAAmB;AAC1B;AACA,MAAI,UAAU,KAAM,sBAAqB,KAAK;AAC9C,UAAQ;AACR,sBAAoB;AACpB,sBAAoB;AACpB,sBAAoB;AACpB,sBAAoB;AACpB,MAAI,SAAS,WAAW,EAAE,MAAM,MAAM;AAAA,EAAC,CAAC;AACxC,gBAAc,EAAE,GAAG,YAAY;AAC/B,wBAAsB,EAAE,QAAQ,MAAM,SAAS,KAAK;AACtD;AAEO,IAAM,kBAAkB,MAAM;AACnC,QAAM,CAAC,eAAe,gBAAgB,QACpC,wBAA4B,WAAW;AAEzC,+BAAU,MAAM;AACd;AACA,QAAI,aAAa,GAAG;AAClB,wBAAkB;AAAA,IACpB,OAAO;AAGL,uBAAiB,YAAY,CAAC;AAAA,IAChC;AAEA,gBAAY,IAAI,gBAAgB;AAEhC,WAAO,MAAM;AACX,kBAAY,OAAO,gBAAgB;AACnC;AACA,UAAI,aAAa,GAAG;AAClB,yBAAiB;AAAA,MACnB;AAAA,IACF;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SAAO;AACT;;;ACrOA,IAAAC,gBAAkE;AAoC3D,IAAM,iBAAiB,CAAC;AAAA,EAC7B,QAAQ;AAAA,EACR;AAAA,EACA,UAAU;AAAA,EACV,uBAAuB;AAAA,EACvB,UAAU;AAAA,EACV,cAAc;AAChB,MAA6C;AAC3C,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAuC,IAAI;AACrE,QAAM,CAAC,eAAe,gBAAgB,QAAI,wBAAwB,IAAI;AACtE,QAAM,CAAC,eAAe,gBAAgB,QAAI,wBAAS,KAAK;AACxD,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAwB,IAAI;AACtD,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAmC,WAAW;AAEtE,QAAM,oBAAoB,gBAAgB;AAG1C,QAAM,oBAAoB,gBAAgB,kBAAkB;AAC5D,QAAM,mBAAmB,kBAAkB,UAAU;AAErD,QAAM,qBAAiB,sBAAgC,IAAI;AAC3D,QAAM,mBAAe,sBAAgC,IAAI;AACzD,QAAM,0BAAsB,sBAAO,KAAK;AAMxC,QAAM,uBAAmB,sBAAsB,IAAI;AAGnD,QAAM,kBAAc;AAAA,IAClB,CAAC,IAAsB,OAAyB;AAC9C,YAAM,IAAI;AACV,YAAM,UAAM,GAAG,CAAC,IAAI,KAAK,KAAM;AAC/B,YAAM,UAAM,GAAG,CAAC,IAAI,KAAK,KAAM;AAC/B,YAAM,gBAAO,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,KAAM;AACzC,YAAM,gBAAO,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,KAAM;AAEzC,YAAM,IACJ,KAAK,IAAI,eAAK,CAAC,IAAI,KAAK,IAAI,eAAK,CAAC,IAClC,KAAK,IAAI,OAAE,IAAI,KAAK,IAAI,OAAE,IAAI,KAAK,IAAI,eAAK,CAAC,IAAI,KAAK,IAAI,eAAK,CAAC;AAClE,YAAM,IAAI,IAAI,KAAK,MAAM,KAAK,KAAK,CAAC,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC;AAEvD,aAAO,IAAI;AAAA,IACb;AAAA,IACA,CAAC;AAAA,EACH;AAKA,QAAM,4BAAwB,uBAAQ,MAAM;AAC1C,QAAI,CAAC,oBAAoB,CAAC,SAAS,MAAM,SAAS,YAAY,SAAS,GAAG;AACxE,UAAI,oBAAoB,aAAa;AACnC,eAAO,YAAY,kBAAkB,WAAW;AAAA,MAClD;AACA,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,MAAM,SAAS;AAG9B,QAAI,YAAY;AAChB,QAAI,eAAe;AAEnB,UAAM,YAAY,CAAC,IAAsB,QACtC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM;AAE5C,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,YAAM,IAAI,UAAU,kBAAkB,OAAO,CAAC,CAAqB;AACnE,UAAI,IAAI,WAAW;AACjB,oBAAY;AACZ,uBAAe;AAAA,MACjB;AAAA,IACF;AAGA,UAAM,kBAAkB,OAAO,MAAM,eAAe,CAAC;AACrD,QAAI,OAAO;AACX,QAAI,OAAyB;AAC7B,eAAW,SAAS,iBAAiB;AACnC,cAAQ,YAAY,MAAM,KAAyB;AACnD,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,GAAG,CAAC,kBAAkB,OAAO,aAAa,WAAW,CAAC;AAEtD,QAAM,gBAAY;AAAA,IAChB,OACE,QACA,MACA,cACG;AACH,UAAI,oBAAoB,QAAS;AAEjC,0BAAoB,UAAU;AAC9B,uBAAiB,IAAI;AAErB,UAAI;AACF,cAAM,OAAO,MAAM,IAAI,QAAQ,SAAS;AAAA,UACtC,aAAa;AAAA,UACb;AAAA,UACA;AAAA,QACF,CAAC;AAED,iBAAS,IAAI;AACb,iBAAS,IAAI;AAEb,YAAI,WAAW;AACb,gBAAM,SAAS,KAAK,SAAS;AAC7B,cAAI,MAAM;AACV,mBAAS,IAAI,GAAG,IAAI,OAAO,SAAS,GAAG,KAAK;AAC1C,mBAAO;AAAA,cACL,OAAO,CAAC;AAAA,cACR,OAAO,IAAI,CAAC;AAAA,YACd;AAAA,UACF;AACA,2BAAiB,GAAG;AAAA,QACtB;AAEA,uBAAe,UAAU;AACzB,qBAAa,UAAU;AAAA,MACzB,SAAS,KAAU;AACjB,iBAAS,IAAI,WAAW,uBAAuB;AAAA,MACjD,UAAE;AACA,yBAAiB,KAAK;AACtB,4BAAoB,UAAU;AAAA,MAChC;AAAA,IACF;AAAA,IACA,CAAC,SAAS,WAAW;AAAA,EACvB;AAEA,+BAAU,MAAM;AACd,QAAI,gBAAgB,cAAc;AAChC,cAAQ,YAAY;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAEhB,+BAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,eAAe,CAAC,mBAAmB;AAClD,UAAI,CAAC,WAAW,CAAC,aAAa;AAC5B,iBAAS,IAAI;AACb,yBAAiB,IAAI;AACrB,uBAAe,UAAU;AACzB,qBAAa,UAAU;AACvB,yBAAiB,UAAU;AAG3B,gBAAQ,WAAW;AAAA,MACrB;AACA;AAAA,IACF;AAEA,UAAM,cACJ,CAAC,aAAa,WACd,aAAa,QAAQ,CAAC,MAAM,YAAY,CAAC,KACzC,aAAa,QAAQ,CAAC,MAAM,YAAY,CAAC;AAM3C,UAAM,UAAU,GAAG,YAAY,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC;AACnD,QAAI,iBAAiB,YAAY,SAAS;AACxC,uBAAiB,UAAU;AAC3B,cAAQ,WAAW;AAAA,IACrB;AAEA,QAAI,aAAa;AACf,gBAAU,mBAAmB,aAAa,IAAI;AAAA,IAChD,WAAW,eAAe,SAAS;AAEjC,YAAM,UAAU,oBAAoB;AACpC,YAAM,OAAO,YAAY,SAAS,eAAe,OAAO;AACxD,UAAI,OAAO,sBAAsB;AAC/B,kBAAU,SAAS,aAAa,KAAK;AAAA,MACvC;AAAA,IACF,OAAO;AACL,gBAAU,mBAAmB,aAAa,IAAI;AAAA,IAChD;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,MACX,qBACA,eACA,UAAU,mBAAmB,aAAa,KAAK;AAAA,IACjD;AAAA,IACA,OAAO,MAAM,QAAQ,YAAY;AAAA,IACjC;AAAA,EACF;AACF;AAMO,IAAM,WAAW,CACtB,QACA,aACA,UAA6C,cAC1C;AACH,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAuC,IAAI;AACrE,QAAM,CAAC,eAAe,gBAAgB,QAAI,wBAAS,KAAK;AACxD,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAwB,IAAI;AAEtD,+BAAU,MAAM;AACd,QAAI,CAAC,UAAU,CAAC,aAAa;AAC3B,eAAS,IAAI;AACb;AAAA,IACF;AAEA,UAAM,aAAa,YAAY;AAC7B,uBAAiB,IAAI;AACrB,UAAI;AACF,cAAM,OAAO,MAAM,IAAI,QAAQ,SAAS;AAAA,UACtC;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AACD,iBAAS,IAAI;AACb,iBAAS,IAAI;AAAA,MACf,SAAS,KAAU;AACjB,iBAAS,IAAI,WAAW,uBAAuB;AAAA,MACjD,UAAE;AACA,yBAAiB,KAAK;AAAA,MACxB;AAAA,IACF;AAEA,eAAW;AAAA,EACb,GAAG,CAAC,QAAQ,aAAa,OAAO,CAAC;AAEjC,SAAO,EAAE,OAAO,eAAe,MAAM;AACvC;;;ACxRA,IAAAC,iBAAyD;AAsElD,IAAM,aAAa,CACxB,UAA6B,CAAC,MACT;AACrB,QAAM,EAAE,YAAY,SAAS,aAAa,IAAI;AAE9C,QAAM,CAAC,SAAS,UAAU,QAAI,yBAMpB,IAAI;AACd,QAAM,CAAC,WAAW,YAAY,QAAI,yBAAS,KAAK;AAEhD,gCAAU,MAAM;AACd,UAAM,cAAc,IAAI,GAAG,yBAAyB,CAAC,YAAiB;AACpE,mBAAa,KAAK;AAClB,iBAAW,OAAO;AAAA,IACpB,CAAC;AACD,UAAM,aAAa,IAAI,GAAG,wBAAwB,MAAM;AACtD,mBAAa,KAAK;AAClB,iBAAW,CAAC,SAAU,OAAO,EAAE,GAAG,MAAM,MAAM,aAAa,IAAI,IAAK;AAAA,IACtE,CAAC;AACD,UAAM,aAAa,IAAI,GAAG,wBAAwB,MAAM;AACtD,mBAAa,IAAI;AACjB,iBAAW,IAAI;AAAA,IACjB,CAAC;AAED,WAAO,MAAM;AACX,kBAAY;AACZ,iBAAW;AACX,iBAAW;AAAA,IACb;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,mBAAmB,WAAW;AAEpC,QAAM,cAAc,eAAe;AAAA,IACjC,aAAa,kBAAkB,eAAe;AAAA,IAC9C,SAAS,CAAC,aAAa,CAAC,CAAC,kBAAkB;AAAA,IAC3C,aAAa,kBAAkB,QAAQ;AAAA,IACvC,QAAQ,kBAAkB;AAAA,IAC1B,SAAS,kBAAkB,WAAW;AAAA,IACtC,sBAAsB,kBAAkB,wBAAwB;AAAA,EAClE,CAAC;AAID,QAAM,eAAW,uBAA4C,IAAI;AACjE,QAAM,cAAc,kBAAkB;AACtC,gCAAU,MAAM;AACd,QACE,gBACC,CAAC,SAAS,WACT,SAAS,QAAQ,CAAC,MAAM,YAAY,CAAC,KACrC,SAAS,QAAQ,CAAC,MAAM,YAAY,CAAC,IACvC;AACA,mBAAa,KAAK;AAAA,IACpB;AACA,aAAS,UAAU;AAAA,EACrB,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,sBAAkB,uBAAO,YAAY;AAC3C,kBAAgB,UAAU;AAC1B,gCAAU,MAAM;AACd,oBAAgB,UAAU,YAAY,IAAI;AAAA,EAC5C,GAAG,CAAC,YAAY,IAAI,CAAC;AAErB,QAAM,WAAW,CAAC,aAAa,CAAC,CAAC,kBAAkB;AAEnD,QAAM,0BAA0B,WAC5B,YAAY,wBACZ;AACJ,QAAM,sBAAsB,WAAW,YAAY,gBAAgB;AACnE,QAAM,uBAAuB,YAAY,OAAO,mBAAmB;AAEnE,QAAM,kBAAkB,2BAA2B;AACnD,QAAM,sBAAsB,kBAAkB;AAE9C,QAAM,cAAc,MAAM;AACxB,QACE,CAAC,wBACD,CAAC,uBACD,CAAC;AAED,aAAO;AACT,UAAM,QAAQ,0BAA0B;AACxC,WAAO,KAAK,KAAM,uBAAuB,QAAS,EAAE;AAAA,EACtD,GAAG;AAEH,QAAM,WACJ,uBAAuB,sBAAsB,IACzC,KAAK;AAAA,IACH;AAAA,IACA,KAAK;AAAA,MACH;AAAA,OACE,sBAAsB,mBAAmB,sBACzC;AAAA,IACJ;AAAA,EACF,IACA;AAEN,QAAM,aAAS,4BAAY,MAAM;AAC/B,iBAAa,IAAI;AACjB,eAAW,IAAI;AACf,QAAI,WAAW,MAAM;AACrB,QAAI,QAAS,SAAQ;AAAA,EACvB,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,YAAQ,4BAAY,MAAM;AAC9B,QAAI,WAAW,MAAM;AACrB,gBAAY,MAAM;AAAA,EACpB,GAAG,CAAC,YAAY,KAAK,CAAC;AAEtB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO,WAAW,YAAY,QAAQ;AAAA,IACtC;AAAA,IACA;AAAA,IACA,eAAe,WAAW,YAAY,gBAAgB;AAAA,IACtD,MAAM,WAAW,YAAY,OAAO;AAAA,IACpC;AAAA,IACA,aAAa,YAAY;AAAA,IACzB,OAAO,WAAW,YAAY,QAAQ;AAAA,IACtC;AAAA,IACA;AAAA,EACF;AACF;;;AC7MA,IAAAC,iBAAwB;AAMjB,IAAM,kBAAkB,CAC7B,OACA,iBACmC;AACnC,aAAO,wBAAQ,MAAM;AACnB,QAAI,CAAC,SAAS,CAAC,gBAAgB,MAAM,YAAY,SAAS,EAAG,QAAO;AAEpE,UAAM,SAAS,MAAM;AAGrB,QAAI,cAAc;AAClB,QAAI,eAAe;AAEnB,UAAM,YAAY,CAAC,IAAsB,OAAyB;AAChE,cAAQ,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM;AAAA,IACnD;AAGA,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,YAAM,OAAO,UAAU,cAAc,OAAO,CAAC,CAAC;AAC9C,UAAI,OAAO,aAAa;AACtB,sBAAc;AACd,uBAAe;AAAA,MACjB;AAAA,IACF;AAIA,UAAM,kBAAkB,OAAO,MAAM,eAAe,CAAC;AAErD,WAAO;AAAA,MACL,aAAa,CAAC,cAAc,GAAG,eAAe;AAAA,MAC9C,MAAM;AAAA,IACR;AAAA,EACF,GAAG,CAAC,OAAO,YAAY,CAAC;AAC1B;;;ACzCA,4BAA8B;AA6B1B,IAAAC,uBAAA;AAfG,IAAM,aAAwC,CAAC;AAAA,EACpD;AAAA,EACA,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,UAAU;AACZ,MAAM;AACJ,MAAI,CAAC,SAAU,QAAO;AAEtB,QAAM,OAA4C;AAAA,IAChD;AAAA,IACA,YAAY,CAAC;AAAA,IACb,MAAM;AAAA,EACR;AAEA,SACE,+CAAC,gCAAO,MAAY,IAAG,oBAAmB,MAAK,WAC7C;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,IAAG;AAAA,QACH,OAAO;AAAA,UACL,aAAa;AAAA,UACb,cAAc;AAAA,UACd,gBAAgB;AAAA,UAChB,cAAc,QAAQ;AAAA,QACxB;AAAA,QACA,MAAK;AAAA;AAAA,IACP;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,IAAG;AAAA,QACH,QAAQ;AAAA,UACN,YAAY;AAAA,UACZ,aAAa;AAAA,QACf;AAAA,QACA,OAAO;AAAA,UACL,cAAc;AAAA,UACd,gBAAgB;AAAA,UAChB,cAAc;AAAA,QAChB;AAAA,QACA,MAAK;AAAA;AAAA,IACP;AAAA,KACF;AAEJ;;;ACvDA,IAAM,sBAAsB;AASrB,IAAM,iBAAiB,CAC5B,QACA,cACA,SAAS,OAC4B;AACrC,QAAM,CAAC,KAAK,GAAG,IAAI;AACnB,QAAM,SAAU,MAAM,KAAK,KAAM;AACjC,QAAM,cAAkC,CAAC;AAEzC,WAAS,IAAI,GAAG,KAAK,QAAQ,KAAK;AAChC,UAAM,QAAS,IAAI,SAAU,IAAI,KAAK;AACtC,UAAM,OACF,eAAe,KAAK,IAAI,KAAK,IAAK,uBACnC,MAAM,KAAK;AACd,UAAM,OACF,eAAe,KAAK,IAAI,KAAK,KAC5B,sBAAsB,KAAK,IAAI,MAAM,MACvC,MAAM,KAAK;AACd,gBAAY,KAAK,CAAC,MAAM,MAAM,MAAM,IAAI,CAAC;AAAA,EAC3C;AAEA,SAAO;AAAA,IACL,UAAU;AAAA,MACR,aAAa,CAAC,WAAW;AAAA,MACzB,MAAM;AAAA,IACR;AAAA,IACA,YAAY,CAAC;AAAA,IACb,MAAM;AAAA,EACR;AACF;;;ACrCA,IAAAC,yBAA8B;AAE9B,IAAAC,iBAAwB;AAiCpB,IAAAC,uBAAA;AAlBG,IAAM,kBAAkD,CAAC;AAAA,EAC9D;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,QAAQ;AACV,MAAM;AACJ,QAAM,WAAO;AAAA,IACX,MAAM,eAAe,QAAQ,YAAY;AAAA,IACzC,CAAC,QAAQ,YAAY;AAAA,EACvB;AAEA,SACE,+CAAC,iCAAO,MAAY,IAAG,0BAAyB,MAAK,WACnD;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,IAAG;AAAA,QACH,OAAO;AAAA,UACL,cAAc;AAAA,UACd,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAK;AAAA;AAAA,IACP;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,IAAG;AAAA,QACH,OAAO;AAAA,UACL,cAAc;AAAA,UACd,kBAAkB,CAAC,GAAG,CAAC;AAAA,UACvB,cAAc;AAAA,QAChB;AAAA,QACA,MAAK;AAAA;AAAA,IACP;AAAA,KACF;AAEJ;;;ACvDA,IAAAC,yBAAsC;AAEtC,IAAAC,iBAA6C;AA8GvC,IAAAC,uBAAA;AAzGN,SAAS,gBAAgB,OAAe,OAAO,IAAe;AAC5D,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,QAAQ;AACf,SAAO,SAAS;AAChB,QAAM,MAAM,OAAO,WAAW,IAAI;AAClC,MAAI,OAAO,GAAG,OAAO,IAAI;AACzB,MAAI,YAAY;AAChB,MAAI,eAAe;AACnB,MAAI,SAAS,OAAO,OAAO,GAAG,OAAO,CAAC;AACtC,SAAO,IAAI,aAAa,GAAG,GAAG,MAAM,IAAI;AAC1C;AAEO,IAAM,YAER,CAAC,EAAE,KAAK,MAAM;AACjB,QAAM,CAAC,cAAc,eAAe,QAAI,yBAAiB,CAAC;AAC1D,QAAM,EAAE,SAAS,IAAI,QAAI,+BAAO;AAGhC,QAAM,aAAS;AAAA,IACb,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,EAAE,eAAe,EAAE,gBAAgB,IAAI;AAAA,IACjE,CAAC,IAAI;AAAA,EACP;AAEA,gCAAU,MAAM;AACd,QAAI,CAAC,IAAK;AACV,UAAM,QAAQ,IAAI,OAAO;AAGzB,UAAM,WAAW;AAAA,MACf,EAAE,OAAO,aAAM,MAAM,kBAAkB;AAAA,MACvC,EAAE,OAAO,mBAAO,MAAM,yBAAyB;AAAA,MAC/C,EAAE,OAAO,aAAM,MAAM,kBAAkB;AAAA,IACzC;AAEA,aAAS,QAAQ,CAAC,QAAQ;AACxB,UAAI,CAAC,MAAM,SAAS,IAAI,IAAI,GAAG;AAC7B,cAAM,SAAS,IAAI,MAAM,gBAAgB,IAAI,KAAK,GAAG,EAAE,YAAY,EAAE,CAAC;AAAA,MACxE;AAAA,IACF,CAAC;AAGD,QAAI,UAAU;AACd,WAAO,QAAQ,CAAC,QAAQ;AAEtB,UAAI,IAAI,UAAU;AAChB,cAAM,OAAO,cAAc,IAAI,EAAE;AACjC,YAAI,CAAC,MAAM,SAAS,IAAI,GAAG;AACzB,UAAC,MAAM,UAAkB,IAAI,UAAU,CAAC,OAAY,UAAe;AACjE,gBAAI,CAAC,SAAS,OAAO;AACnB,kBAAI,CAAC,MAAM,SAAS,IAAI,GAAG;AACzB,sBAAM,SAAS,MAAM,KAAK;AAC1B,gCAAgB,CAAC,SAAS,OAAO,CAAC;AAAA,cACpC;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAGA,UAAI,IAAI,OAAO;AACb,cAAM,OAAO,gBAAgB,IAAI,KAAK;AACtC,YAAI,CAAC,MAAM,SAAS,IAAI,GAAG;AACzB,gBAAM,SAAS,MAAM,gBAAgB,IAAI,KAAK,GAAG,EAAE,YAAY,EAAE,CAAC;AAClE;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAED,QAAI,UAAU,GAAG;AACf,sBAAgB,CAAC,SAAS,OAAO,OAAO;AAAA,IAC1C;AAAA,EACF,GAAG,CAAC,KAAK,MAAM,CAAC;AAEhB,QAAM,cAAe;AAAA,IACnB,OAAO;AAAA,MACL,UAAU,OAAO,IAAI,CAAC,SAAS;AAAA,QAC7B,UAAU;AAAA,UACR,aAAa,CAAC,IAAI,WAAW,IAAI,QAAQ;AAAA,UACzC,MAAM;AAAA,QACR;AAAA,QACA,YAAY;AAAA,UACV,GAAG;AAAA;AAAA,UAEH,YAAY,IAAI,WACZ,cAAc,IAAI,EAAE,KACpB,IAAI,aACF,IAAI,aACJ,IAAI,QACF,gBAAgB,IAAI,KAAK,KACzB,IAAI,SAAS,QACX,oBACA,IAAI,SAAS,eACX,2BACA;AAAA,QACd;AAAA,QACA,MAAM;AAAA,MACR,EAAE;AAAA,MACF,MAAM;AAAA,IACR;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,SACE,8CAAC,iCAAO,MAAM,SAAS,IAAG,YAAW,MAAK,WACxC;AAAA,IAAC;AAAA;AAAA,MACC,IAAG;AAAA,MACH,QAAQ;AAAA,QACN,sBAAsB;AAAA,QACtB,cAAc,CAAC,OAAO,UAAU;AAAA,QAChC,aAAa;AAAA,QACb,eAAe;AAAA,QACf,cAAc;AAAA,UACZ;AAAA,UACA,CAAC,MAAM;AAAA,UACP;AAAA;AAAA,UACA;AAAA,UACA,CAAC,OAAO,MAAM;AAAA;AAAA,QAChB;AAAA,QACA,aAAa,CAAC,gBAAgB;AAAA,QAC9B,eAAe,CAAC,GAAG,GAAG;AAAA,QACtB,iBAAiB;AAAA,QACjB,aAAa;AAAA,MACf;AAAA,MACA,OAAO;AAAA,QACL,gBAAgB,CAAC,eAAe,CAAC,QAAQ,GAAG,CAAC,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;AAAA,QAClE,cAAc;AAAA,QACd,mBAAmB;AAAA,QACnB,mBAAmB;AAAA,QACnB,gBAAgB,CAAC,eAAe,CAAC,QAAQ,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;AAAA,MACtE;AAAA,MACA,MAAK;AAAA;AAAA,EACP,GACF;AAEJ;;;AC9IA,IAAAC,yBAAuB;AAanB,IAAAC,uBAAA;AAVG,IAAM,aAGR,CAAC,EAAE,MAAM,QAAQ,MAAM;AAE1B,QAAM,aAAa,KAAK,OAAO,CAAC,MAAM,EAAE,gBAAgB,QAAQ;AAEhE,MAAI,WAAW,WAAW,EAAG,QAAO;AAEpC,SACE,+EACG,qBAAW,IAAI,CAAC,QACf;AAAA,IAAC;AAAA;AAAA,MACC,QAAO;AAAA,MAEP,UAAU,IAAI;AAAA,MACd,WAAW,IAAI;AAAA,MACf,SAAS,CAAC,MAAM;AACd,UAAE,cAAc,gBAAgB;AAChC,YAAI,QAAS,SAAQ,GAAG;AAAA,MAC1B;AAAA,MAEC,cAAI,kBACH,IAAI,kBAEJ;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,YACL,QAAQ;AAAA,YACR,QAAQ;AAAA,YACR,WAAW;AAAA,UACb;AAAA,UAEA;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO;AAAA,kBACL,YAAY;AAAA,kBACZ,iBAAiB,IAAI,SAAS,QAAQ,YAAY;AAAA,kBAClD,QAAQ;AAAA,kBACR,cAAc;AAAA,kBACd,SAAS;AAAA,kBACT,QAAQ;AAAA,kBACR,gBAAgB;AAAA,kBAChB,OAAO;AAAA,gBACT;AAAA,gBAEC,cAAI,QACH,8CAAC,UAAK,OAAO,EAAE,UAAU,OAAO,GAAI,cAAI,OAAM,IAE9C;AAAA,kBAAC;AAAA;AAAA,oBACC,OAAO;AAAA,sBACL,iBAAiB;AAAA,sBACjB,cAAc;AAAA,sBACd,QAAQ;AAAA,sBACR,OAAO;AAAA,oBACT;AAAA;AAAA,gBACD;AAAA;AAAA,YAEL;AAAA,YAEA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO;AAAA,kBACL,YAAY;AAAA,kBACZ,aAAa;AAAA,kBACb,WAAW,aAAa,IAAI,SAAS,QAAQ,YAAY,SAAS;AAAA,kBAClE,QAAQ;AAAA,kBACR,QAAQ;AAAA,kBACR,OAAO;AAAA,gBACT;AAAA;AAAA,YACD;AAAA;AAAA;AAAA,MACH;AAAA;AAAA,IAtDG,IAAI;AAAA,EAwDX,CACD,GACH;AAEJ;;;AC9EA,IAAAC,yBAAuB;AAmCf,IAAAC,uBAAA;AArBD,IAAM,oBAAsD,CAAC;AAAA,EAClE;AAAA,EACA;AACF,MAAM;AACJ,MAAI,CAAC,eAAgB,QAAO;AAE5B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,QAAO;AAAA,MACP,UAAU,eAAe,CAAC;AAAA,MAC1B,WAAW,eAAe,CAAC;AAAA,MAE3B;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,YACL,YAAY;AAAA,YACZ,SAAS;AAAA,YACT,gBAAgB;AAAA,YAChB,UAAU;AAAA,UACZ;AAAA,UAGA;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO;AAAA,kBACL,WAAW;AAAA,kBACX,iBAAiB;AAAA,kBACjB,cAAc;AAAA,kBACd,QAAQ;AAAA,kBACR,UAAU;AAAA,kBACV,OAAO;AAAA,gBACT;AAAA;AAAA,YACD;AAAA,YAGA,YAAY,UAAa,YAAY,QACpC;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO;AAAA,kBACL,QAAQ;AAAA,kBACR,UAAU;AAAA,kBACV,WAAW,UAAU,OAAO;AAAA,kBAC5B,OAAO;AAAA,kBACP,QAAQ;AAAA,gBACV;AAAA,gBAEA;AAAA,kBAAC;AAAA;AAAA,oBACC,OAAO,EAAE,QAAQ,QAAQ,OAAO,OAAO;AAAA,oBACvC,SAAQ;AAAA,oBAER;AAAA,oEAAC,UACC;AAAA,wBAAC;AAAA;AAAA,0BACC,IAAG;AAAA,0BACH,IAAG;AAAA,0BACH,IAAG;AAAA,0BACH,IAAG;AAAA,0BACH,IAAG;AAAA,0BACH,GAAE;AAAA,0BAEF;AAAA;AAAA,8BAAC;AAAA;AAAA,gCACC,QAAO;AAAA,gCACP,OAAO;AAAA,kCACL,WAAW;AAAA,kCACX,aAAa;AAAA,gCACf;AAAA;AAAA,4BACF;AAAA,4BACA;AAAA,8BAAC;AAAA;AAAA,gCACC,QAAO;AAAA,gCACP,OAAO;AAAA,kCACL,WAAW;AAAA,kCACX,aAAa;AAAA,gCACf;AAAA;AAAA,4BACF;AAAA;AAAA;AAAA,sBACF,GACF;AAAA,sBAEA;AAAA,wBAAC;AAAA;AAAA,0BACC,GAAE;AAAA,0BACF,MAAK;AAAA;AAAA,sBACP;AAAA;AAAA;AAAA,gBACF;AAAA;AAAA,YACF;AAAA,YAIF;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO;AAAA,kBACL,YAAY;AAAA,kBACZ,iBAAiB;AAAA,kBACjB,cAAc;AAAA,kBACd,WACE;AAAA,kBACF,SAAS;AAAA,kBACT,QAAQ;AAAA,kBACR,gBAAgB;AAAA,kBAChB,OAAO;AAAA,kBACP,QAAQ;AAAA,gBACV;AAAA,gBAEA;AAAA,kBAAC;AAAA;AAAA,oBACC,OAAO;AAAA,sBACL,iBAAiB;AAAA,sBACjB,QAAQ;AAAA,sBACR,cAAc;AAAA,sBACd,QAAQ;AAAA,sBACR,OAAO;AAAA,oBACT;AAAA;AAAA,gBACD;AAAA;AAAA,YACH;AAAA,YACA,8CAAC,WAAO,uKAA4J;AAAA;AAAA;AAAA,MACtK;AAAA;AAAA,EACF;AAEJ;;;ACnGA,IAAAC,yBAA6C;AAC7C,IAAAC,iBAOO;AACP,yBAAO;AAwXC,IAAAC,uBAAA;AAtXR,IAAM,cAAkC,CAAC;AAAA,EACvC,mBAAmB;AAAA,IACjB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,EACR;AAAA,EACA,QAAQ,CAAC;AAAA,EACT,WAAW;AAAA,EACX,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,sBAAsB,CAAC;AAAA,EACvB;AAAA,EACA,mBAAmB;AAAA,EACnB,YAAY,oBAAoB;AAAA,EAChC,aAAa;AAAA,EACb,yBAAyB;AAAA,EACzB;AAAA,EACA,OAAO,CAAC;AAAA,EACR;AAAA,EACA,OAAO;AAAA,EACP,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA,eAAe,CAAC;AAAA,EAChB,kBAAkB;AACpB,MAAM;AACJ,QAAM,kBAAc,2BAAW,kBAAkB;AACjD,QAAM,mBAAe,2BAAW,mBAAmB;AAEnD,QAAM,aAAS,uBAAsB,IAAI;AAGzC,QAAM,oBAAoB,gBAAgB;AAK1C,QAAM,UAAU,WAAW;AAAA,IACzB;AAAA,IACA,cAAc,aAAa,yBAAyB;AAAA,EACtD,CAAC;AAED,QAAM,mBAAmB,QAAQ;AAGjC,QAAM,iBAAiB,mBACnB;AAAA,IACE,uBAAuB,QAAQ;AAAA,IAC/B,MAAM,QAAQ;AAAA,IACd,OAAO,QAAQ;AAAA,IACf,OAAO,QAAQ;AAAA,IACf,eAAe,QAAQ;AAAA,EACzB,IACA;AACJ,QAAM,QAAQ,mBAAmB,QAAQ,OAAO,WAAW;AAC3D,QAAM,mBAAmB,mBACrB,6BAA6B,SAAS,YAAY,WAAW,QAC7D;AAEJ,QAAM,OAAO,gBAAgB,QAAQ;AACrC,QAAM,wBAAwB,cAC1B,YAAY,cACZ;AAGJ,QAAM,qBAAiB,uBAAO,qBAAqB;AACnD,QAAM,kBAAc,uBAAO,KAAK;AAWhC,QAAM,0BAAsB,uBAAO,CAAC;AACpC,QAAM,iBAAa,4BAAY,MAAM;AACnC,gBAAY,UAAU;AACtB,WAAO,EAAE,oBAAoB;AAAA,EAC/B,GAAG,CAAC,CAAC;AACL,QAAM,6BAAyB,4BAAY,CAAC,aAAqB;AAC/D,QAAI,oBAAoB,YAAY,UAAU;AAC5C,kBAAY,UAAU;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,QAAM,CAAC,oBAAoB,qBAAqB,QAAI;AAAA,IAClD;AAAA,EACF;AACA,QAAM,gBAAgB,cAClB,YAAY,cACZ;AAEJ,QAAM,oBAAoB,aAAa;AAEvC,QAAM,oBAAgB;AAAA,IACpB,CAAC,WAAoB;AACnB,qBAAe,UAAU;AAGzB,4BAAsB,MAAM;AAG5B,UAAI,mBAAmB;AACrB,0BAAkB,MAAM;AAAA,MAC1B;AAAA,IACF;AAAA,IACA,CAAC,iBAAiB;AAAA,EACpB;AAGA,gCAAU,MAAM;AACd,QAAI,eAAe,YAAY,gBAAgB,eAAe,SAAS;AACrE,qBAAe,UAAU,YAAY;AAAA,IACvC;AAAA,EACF,GAAG,CAAC,aAAa,aAAa,WAAW,CAAC;AAE1C,QAAM,4BAA4B,CAAC,GAAG,mBAAmB;AACzD,MAAI,KAAK,SAAS,KAAK,CAAC,0BAA0B,SAAS,eAAe,GAAG;AAC3E,8BAA0B,KAAK,eAAe;AAAA,EAChD;AAEA,QAAM,wBAAoB,uBAAO,iBAAiB;AAElD,gCAAU,MAAM;AACd,QAAI,sBAAsB,kBAAkB,SAAS;AACnD,oBAAc,iBAAiB;AAC/B,wBAAkB,UAAU;AAE5B,UAAI,qBAAqB,kBAAkB,UAAU,OAAO,SAAS;AACnE,cAAM,WAAW,WAAW;AAC5B,eAAO,QAAQ,MAAM;AAAA,UACnB,QAAQ,kBAAkB;AAAA,UAC1B,UAAU;AAAA,UACV,WAAW;AAAA,UACX,MAAM,KAAK,IAAI,OAAO,QAAQ,QAAQ,GAAG,EAAE;AAAA,QAC7C,CAAC;AACD,mBAAW,MAAM;AACf,iCAAuB,QAAQ;AAAA,QACjC,GAAG,IAAI;AAAA,MACT;AAAA,IACF;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA,kBAAkB;AAAA,IAClB;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,6BAAyB,uBAAY,IAAI;AAC/C,QAAM,kBAAc,uBAAsB,IAAI;AAG9C,gCAAU,MAAM;AACd,QAAI,CAAC,SAAS,CAAC,OAAO,SAAS;AAC7B,UAAI,CAAC,MAAO,wBAAuB,UAAU;AAC7C;AAAA,IACF;AAEA,UAAM,aAAa,UAAU,uBAAuB;AACpD,UAAM,cAAc,YAAY,YAAY;AAE5C,QAAI,SAAS,cAAc;AACzB,UAAI,eAAe,YAAY;AAM7B,sBAAc,IAAI;AAAA,MACpB;AACA,WACG,eAAe,eAChB,kBAAkB,UAClB,OAAO,SACP;AACA,cAAM,WAAW,WAAW;AAC5B,eAAO,QAAQ,MAAM;AAAA,UACnB,QAAQ,kBAAkB;AAAA,UAC1B,UAAU;AAAA,UACV,WAAW;AAAA,UACX,MAAM;AAAA;AAAA,QACR,CAAC;AACD,mBAAW,MAAM;AACf,iCAAuB,QAAQ;AAAA,QACjC,GAAG,IAAI;AAAA,MACT;AAAA,IACF,WAAW,SAAS,aAAa,YAAY;AAC3C,oBAAc,KAAK;AAEnB,YAAM,SAAS,MAAM;AACrB,UAAI,OAAO,SAAS,GAAG;AACrB,cAAM,SAAS,OAAO;AAAA,UACpB,CAAC,KAAK,UAAU;AACd,mBAAO;AAAA,cACL,CAAC,KAAK,IAAI,IAAI,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,KAAK,IAAI,IAAI,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;AAAA,cAC7D,CAAC,KAAK,IAAI,IAAI,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,KAAK,IAAI,IAAI,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;AAAA,YAC/D;AAAA,UACF;AAAA,UACA;AAAA,YACE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;AAAA,YAC3B,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;AAAA,UAC7B;AAAA,QACF;AAEA,eAAO,QAAQ;AAAA,UACb,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;AAAA,UACvD,EAAE,SAAS,KAAK,OAAO,IAAI;AAAA,QAC7B;AAAA,MACF;AAAA,IACF;AAEA,2BAAuB,UAAU;AACjC,gBAAY,UAAU;AAAA,EACxB,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA,kBAAkB;AAAA,IAClB;AAAA,IACA;AAAA,EACF,CAAC;AAGD,gCAAU,MAAM;AAEd,QACE,eAAe,WACf,CAAC,YAAY,WACb,kBAAkB,UAClB,OAAO,SACP;AACA,aAAO,QAAQ,OAAO;AAAA,QACpB,QAAQ,kBAAkB;AAAA,QAC1B,UAAU;AAAA;AAAA,QACV,QAAQ,CAAC,MAAM;AAAA,QACf,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,kBAAkB,MAAM,CAAC;AAG7B,QAAM,eAAe;AAAA,IACnB;AAAA,IACA,mBAAmB,kBAAkB,SAAS;AAAA,EAChD;AAIA,QAAM,oBAAoB,gBAAgB,yBAAyB;AACnE,QAAM,YAAY,gBAAgB,iBAAiB;AACnD,QAAM,uBAAuB,gBAAgB,OAAO,mBAAmB;AAIvE,QAAM,kBAAkB,qBAAqB;AAG7C,QAAM,WAAW,MAAM;AACrB,QAAI,CAAC,wBAAwB,CAAC,aAAa,CAAC,kBAAmB,QAAO;AACtE,UAAM,QAAQ,oBAAoB;AAClC,WAAO,KAAK,KAAM,uBAAuB,QAAS,EAAE;AAAA,EACtD,GAAG;AAEH,QAAM,cAAc,kBAAkB;AAEtC,QAAM,gBACJ,aAAa,YAAY,IACrB,KAAK;AAAA,IACH;AAAA,IACA,KAAK,IAAI,IAAK,YAAY,mBAAmB,YAAa,GAAG;AAAA,EAC/D,IACA;AAIN,QAAM,cACJ,oBAAoB,kBAAkB,QAClC;AAAA,IACE,qBAAqB;AAAA,IACrB;AAAA,IACA,OACE,SAAS,eAAe,4BAA4B;AAAA,IACtD;AAAA,IACA,SAAS,MAAM;AACb,cAAQ,OAAO;AACf,UAAI,mBAAmB;AACrB,0BAAkB;AAAA,MACpB;AAAA,IACF;AAAA,IACA,SAAS,eAAe;AAAA,IACxB,UAAU;AAAA,EACZ,IACA;AAGN,QAAM,gBAAgB,aAAa;AACnC,gCAAU,MAAM;AACd,QAAI,eAAe;AACjB,oBAAc,WAAW;AAAA,IAC3B;AAAA,EACF,GAAG,CAAC,aAAa,aAAa,CAAC;AAG/B,QAAM,oBAAoB,aAAa;AACvC,gCAAU,MAAM;AACd,QAAI,qBAAqB,oBAAoB,QAAW;AACtD,wBAAkB,eAAe;AAAA,IACnC;AAAA,EACF,GAAG,CAAC,iBAAiB,iBAAiB,CAAC;AAKvC,QAAM,oBAAoB,aAAa,CAAC;AAExC,QAAM,EAAE,kBAAkB,wBAAwB,QAAI,wBAAQ,MAAM;AAClE,UAAMC,oBAAsC,CAAC;AAC7C,UAAM,qBAAwC,CAAC;AAE/C,mBAAAC,QAAM,SAAS,QAAQ,UAAU,CAAC,UAAU;AAC1C,UAAI,eAAAA,QAAM,eAAe,KAAK,GAAG;AAC/B,cAAM,OAAO,MAAM;AACnB,cAAM,cAAe,MAAc,eAAgB,MAAc;AACjE,cAAM,SAAS,SAAS,WAAW,gBAAgB;AACnD,cAAM,kBACJ,UACA,SAAS,eACT,SAAS,gBACT,SAAS,kBACT,SAAS,iBACT;AAAA,UACE;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,SAAS,WAAW;AAExB,YAAI,QAAQ;AACV,yBAAAA,QAAM,SAAS;AAAA,YACZ,MAAkC,MAAM;AAAA,YACzC,CAAC,gBAAgB;AACf,kBAAI,aAAa;AACf,mCAAmB,KAAK,WAAW;AAAA,cACrC;AAAA,YACF;AAAA,UACF;AAAA,QACF,WAAW,iBAAiB;AAC1B,6BAAmB,KAAK,KAAK;AAAA,QAC/B,OAAO;AACL,UAAAD,kBAAiB,KAAK,KAAK;AAAA,QAC7B;AAAA,MACF,OAAO;AACL,QAAAA,kBAAiB,KAAK,KAAK;AAAA,MAC7B;AAAA,IACF,CAAC;AAED,UAAME,2BACJ,mBAAmB,SAAS,IAC1B,8CAAC,WAAS,8BAAmB,IAC3B;AAEN,WAAO,EAAE,kBAAAF,mBAAkB,yBAAAE,yBAAwB;AAAA,EACrD,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,iBAAiB,CAAC,MAAW;AACjC,QAAI,cAAc,mBAAmB;AACnC,mBAAa,cAAc,CAAC,EAAE,OAAO,KAAK,EAAE,OAAO,GAAG,CAAC;AACvD;AAAA,IACF;AAEA,UAAM,kBAAkB,EAAE,YAAY,CAAC;AAEvC,QAAI,YAAY;AACd,YAAM,aAAa,gBAAgB;AAAA,QACjC,CAAC,MAAW,EAAE,MAAM,OAAO;AAAA,MAC7B;AACA,UAAI,YAAY;AACd,mBAAW,WAAW,UAAiB;AACvC;AAAA,MACF;AAAA,IACF;AAGA,UAAM,iBAAiB,gBAAgB;AAAA,MAAK,CAAC,MAC3C,0BAA0B,SAAS,EAAE,MAAM,EAAE;AAAA,IAC/C;AAEA,QAAI,CAAC,gBAAgB;AACnB,UAAI,gBAAgB;AAClB,uBAAe,CAAC;AAAA,MAClB;AAAA,IACF;AAEA,QAAI,QAAS,SAAQ,CAAC;AAAA,EACxB;AAEA,QAAM,yBAAqB;AAAA,IACzB,CAAC,YAAmC;AAClC,UAAI,kBAAkB,UAAU,OAAO,SAAS;AAC9C,sBAAc,IAAI;AAClB,cAAM,WAAW,WAAW;AAE5B,eAAO,QAAQ,MAAM;AAAA,UACnB,QAAQ,kBAAkB;AAAA,UAC1B,UAAU;AAAA,UACV,WAAW;AAAA,UACX,OAAO,SAAS,SAAS;AAAA,UACzB,MAAM,KAAK,IAAI,OAAO,QAAQ,QAAQ,GAAG,EAAE;AAAA,UAC3C,GAAI,SAAS,YAAY,SACrB,EAAE,SAAS,QAAQ,QAAQ,IAC3B,CAAC;AAAA,QACP,CAAC;AAGD,mBAAW,MAAM;AACf,iCAAuB,QAAQ;AAAA,QACjC,GAAG,IAAI;AAAA,MACT;AAAA,IACF;AAAA,IACA;AAAA,MACE,kBAAkB;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,kBAAc;AAAA,IAClB,CAAC,QAA0B,WAAyB;AAClD,YAAM,MAAM,OAAO;AACnB,UAAI,CAAC,IAAK;AAMV,oBAAc,KAAK;AACnB,YAAM,WAAW,WAAW;AAE5B,UAAI,MAAM;AAAA,QACR,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,OAAO,QAAQ,SAAS;AAAA,QACxB,MAAM,QAAQ,QAAQ,IAAI,QAAQ;AAAA;AAAA;AAAA,QAGlC,GAAI,QAAQ,aAAa,SACrB,EAAE,UAAU,OAAO,SAAS,IAC5B,CAAC;AAAA,QACL,GAAI,QAAQ,YAAY,SAAY,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,MACrE,CAAC;AAMD,UAAI,KAAK,WAAW,MAAM,uBAAuB,QAAQ,CAAC;AAAA,IAC5D;AAAA,IACA,CAAC,eAAe,YAAY,sBAAsB;AAAA,EACpD;AAEA,QAAM,yBAAqB,4BAAY,CAAC,WAAkC;AACxE,QAAI,OAAO,SAAS;AAClB,aAAO,QAAQ,OAAO;AAAA,QACpB,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,QACX,OAAO,QAAQ,SAAS;AAAA,MAC1B,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,gCAAU,MAAM;AACd,QAAI,aAAa;AACf,kBAAY,wBAAwB,kBAAkB;AACtD,kBAAY,8BAA8B,kBAAkB;AAC5D,kBAAY,uBAAuB,WAAW;AAAA,IAChD;AAAA,EACF,GAAG,CAAC,aAAa,oBAAoB,oBAAoB,WAAW,CAAC;AAErE,QAAM,iBAAa,4BAAY,MAAM;AACnC,QAAI,OAAO,WAAW,aAAa;AACjC,kBAAY,WAAW,OAAO,QAAQ,WAAW,CAAC;AAClD,kBAAY,SAAS,OAAO,QAAQ,SAAS,CAAC;AAAA,IAChD;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAQhB,QAAM,wBAAwB,MAAM;AAClC,QAAI,WAAY;AAEhB,QAAI,eAAe,SAAS;AAC1B,oBAAc,KAAK;AACnB,UAAI,OAAO,SAAS;AAClB,eAAO,QAAQ,KAAK;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,0CAA0C,cAAc,oBAAoB,qBAAqB,EAAE,IAAI,SAAS;AAAA,MAC3H;AAAA,MAEA;AAAA;AAAA,UAAC,uBAAAC;AAAA,UAAA;AAAA,YACC,oBAAoB;AAAA,YACpB;AAAA,YACA,qBAAqB;AAAA,YACrB;AAAA,YACA;AAAA,YACA,SAAS;AAAA,YACT;AAAA,YACA,aAAa;AAAA,YACb,QAAQ,CAAC,MAAM;AACb,kBAAI,OAAQ,QAAO,CAAC;AACpB,kBAAI,qBAAqB,kBAAkB,UAAU,OAAO,SAAS;AACnE,uBAAO,QAAQ,OAAO;AAAA,kBACpB,QAAQ,kBAAkB;AAAA,kBAC1B,MAAM;AAAA,gBACR,CAAC;AAAA,cACH;AAAA,YACF;AAAA,YACA,aAAa;AAAA,YACb,QAAQ;AAAA,YACR,eAAe;AAAA,YACf,cAAc;AAAA,YACd,SAAS;AAAA,YACT,KAAK;AAAA,YAEJ;AAAA,kCACC,kBAAkB,WACjB,qBACC,mBAAmB;AAAA,gBACjB,QAAQ,kBAAkB;AAAA,gBAC1B,SAAS,kBAAkB;AAAA,cAC7B,CAAC,IAED;AAAA,gBAAC;AAAA;AAAA,kBACC,gBAAgB,kBAAkB;AAAA,kBAClC,SAAS,kBAAkB;AAAA;AAAA,cAC7B;AAAA,cAGH,gBACC,aAAa,eAAe,KAC5B,kBAAkB,UAChB;AAAA,gBAAC;AAAA;AAAA,kBACC,QAAQ,kBAAkB;AAAA,kBAC1B,cAAc,aAAa;AAAA;AAAA,cAC7B;AAAA,cAGH,gBAAgB,8CAAC,cAAW,UAAU,cAAc;AAAA,cAEpD,KAAK,SAAS,KACb,gFACE;AAAA,8DAAC,aAAU,MAAY;AAAA,gBACvB,8CAAC,cAAW,SAAS,YAAY,MAAY;AAAA,iBAC/C;AAAA,cAED;AAAA;AAAA;AAAA,QACH;AAAA,QACC,gBAAgB,eAAe,CAAC,YAAY,eAC3C;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA,SAAS;AAAA,YACT;AAAA,YACA,YAAY;AAAA,YACZ,aAAa,eAAe;AAAA,YAC5B,WAAW;AAAA,YACV,GAAG;AAAA;AAAA,QACN;AAAA;AAAA;AAAA,EAEJ;AAEJ;AAEA,IAAM,wBAAiE,CAAC;AAAA,EACtE;AACF,MAAM;AACJ,QAAM,cAAU,2BAAW,kBAAkB;AAC7C,MAAI,SAAS;AACX,WAAO,+EAAG,UAAS;AAAA,EACrB;AACA,SAAO,8CAAC,kBAAgB,UAAS;AACnC;AAEO,IAAMC,OAA0B,CAAC,UAAU;AAChD,SACE,8CAAC,yBACC,wDAAC,sCACC,wDAAC,eAAa,GAAG,OAAO,GAC1B,GACF;AAEJ;;;AC7oBA,IAAAC,iBAAkB;AAClB,oBAA2B;AAUpB,SAAS,UAAU,aAAqB,QAAkB,CAAC,GAAG;AACnE,QAAM,YAAY,SAAS,eAAe,WAAW;AACrD,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,sBAAsB,WAAW,cAAc;AAAA,EACjE;AAEA,QAAM,WAAO,0BAAW,SAAS;AACjC,OAAK,OAAO,eAAAC,QAAM,cAAcC,MAAK,KAAK,CAAC;AAC3C,SAAO;AACT;;;ACpBA,6BAA0B;AAE1B,IAAM,eAAe;AACrB,IAAM,gBAAgB;AACtB,IAAM,qBAAqB;AAC3B,IAAM,gCAAgC;AACtC,IAAM,qBACJ;AACF,IAAM,aAAa;AACnB,IAAM,mBAAmB;AACzB,IAAM,sBAAsB;AAa5B,eAAsB,eACpB,MACA,UAAkC,CAAC,GAClB;AACjB,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,kBAAkB,QAAQ,mBAAmB;AACnD,QAAM,QACJ,QAAQ,UAAU,QAAQ,UAAU,GAAG,QAAQ,OAAO,WAAW;AAYnE,QAAM,KAAK,IAAI,uBAAAC,QAAc;AAAA,IAC3B,mBAAmB;AAAA,MACjB,OAAO;AAAA,MACP,GAAI,QAAQ,qBACR,EAAE,UAAU,QAAQ,mBAAmB,IACvC,CAAC;AAAA,IACP;AAAA,IACA,mBAAmB;AAAA,MACjB,OAAO,QAAQ,mBAAmB;AAAA,MAClC,MAAM,QAAQ,kBAAkB;AAAA,MAChC,GAAI,QAAQ,qBACR,EAAE,UAAU,QAAQ,mBAAmB,IACvC,CAAC;AAAA,IACP;AAAA,IACA,sBAAsB;AAAA,MACpB,OAAO,QAAQ,sBAAsB;AAAA,MACrC,MAAM,QAAQ,qBAAqB;AAAA,MACnC,GAAI,QAAQ,wBACR,EAAE,UAAU,QAAQ,sBAAsB,IAC1C,CAAC;AAAA,IACP;AAAA,IACA;AAAA,IACA,aAAa;AAAA,MACX;AAAA,MACA,MAAM,QAAQ,YAAY;AAAA,MAC1B,GAAI,QAAQ,eAAe,EAAE,UAAU,QAAQ,aAAa,IAAI,CAAC;AAAA,IACnE;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ,QAAQ,UAAU;AAAA,IAC1B,WAAW;AAAA,MACT,sBAAsB,QAAQ,wBAAwB;AAAA,MACtD,MAAM;AAAA,MACN,YAAY;AAAA,IACd;AAAA,IACA,OAAO,QAAQ,SAAS;AAAA,IACxB,MAAM;AAAA,IACN,OAAO;AAAA,IACP,GAAI,QAAQ,SAAS,OACjB;AAAA,MACE,OAAO,QAAQ,QAAQ;AAAA,MACvB,cAAc;AAAA,QACZ,oBAAoB,QAAQ,sBAAsB;AAAA,QAClD,WAAW,QAAQ,YAAY;AAAA,QAC/B,QAAQ,QAAQ,cAAc;AAAA,MAChC;AAAA,IACF,IACA,CAAC;AAAA,EACP,CAAC;AAED,QAAM,SAAS,MAAM,GAAG,WAAW,KAAK;AACxC,MAAI,CAAC,UAAU,EAAE,kBAAkB,OAAO;AACxC,UAAM,IAAI,MAAM,kCAAkC;AAAA,EACpD;AACA,QAAM,YAAY,MAAM,cAAc,MAAM;AAC5C,QAAM,eAAe,QAAQ,gBAAgB;AAC7C,QAAM,sBACJ,QAAQ,gBAAgB;AAE1B,QAAM,WAAW,QACb,MAAM,iBAAiB,WAAW,OAAO,MAAM,iBAAiB,KAAK,IACrE;AAEJ,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,IAAM,gBAAgB,CAAC,SACrB,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC/B,QAAM,SAAS,IAAI,WAAW;AAC9B,SAAO,YAAY,MAAM,QAAQ,OAAO,MAAgB;AACxD,SAAO,UAAU;AACjB,SAAO,cAAc,IAAI;AAC3B,CAAC;AAEH,IAAM,YAAY,CAAC,QACjB,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC/B,QAAM,MAAM,IAAI,MAAM;AACtB,MAAI,SAAS,MAAM,QAAQ,GAAG;AAC9B,MAAI,UAAU;AACd,MAAI,MAAM;AACZ,CAAC;AAMH,eAAe,iBACb,WACA,OACA,MACA,iBACA,WACiB;AACjB,QAAM,UAAU,MAAM,UAAU,SAAS;AACzC,QAAM,kBAAkB,KAAK,MAAM,OAAO,gBAAgB;AAC1D,QAAM,UAAU,KAAK,MAAM,OAAO,mBAAmB;AAErD,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,QAAQ;AACf,SAAO,SAAS,OAAO;AACvB,QAAM,MAAM,OAAO,WAAW,IAAI;AAClC,MAAI,CAAC,KAAK;AAGR,WAAO;AAAA,EACT;AAEA,MAAI,YAAY;AAChB,MAAI,SAAS,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AAE9C,QAAM,WAAW,KAAK,MAAM,kBAAkB,IAAI;AAClD,MAAI,YAAY;AAChB,MAAI,OAAO,WAAW,QAAQ,OAAO,OAAO,QAAQ,CAAC;AACrD,MAAI,YAAY;AAChB,MAAI,eAAe;AACnB,MAAI;AAAA,IACF;AAAA,IACA,OAAO,QAAQ;AAAA,IACf,kBAAkB,IAAI,UAAU;AAAA,IAChC,OAAO,QAAQ,UAAU;AAAA,EAC3B;AAEA,MAAI,UAAU,SAAS,GAAG,iBAAiB,MAAM,IAAI;AAErD,SAAO,OAAO,UAAU,WAAW;AACrC;AAMA,SAAS,qBACP,KACA,GACA,GACA,OACA,QACA,QACM;AACN,MAAI,UAAU;AACd,MAAI,OAAO,IAAI,QAAQ,CAAC;AACxB,MAAI,MAAM,IAAI,OAAO,GAAG,IAAI,OAAO,IAAI,QAAQ,MAAM;AACrD,MAAI,MAAM,IAAI,OAAO,IAAI,QAAQ,GAAG,IAAI,QAAQ,MAAM;AACtD,MAAI,MAAM,GAAG,IAAI,QAAQ,GAAG,GAAG,MAAM;AACrC,MAAI,MAAM,GAAG,GAAG,IAAI,OAAO,GAAG,MAAM;AACpC,MAAI,UAAU;AAChB;AAiBA,eAAe,cACb,cACA,cACA,qBACA,iBACiB;AACjB,QAAM,QAAQ,MAAM,UAAU,YAAY;AAC1C,QAAM,cAAc,MAAM,QAAQ,eAAe;AACjD,QAAM,eAAe,MAAM,SAAS,eAAe;AACnD,QAAM,aAAa,KAAK,IAAI,aAAa,YAAY;AACrD,QAAM,SACH,KAAK,IAAI,KAAK,IAAI,qBAAqB,CAAC,GAAG,EAAE,IAAI,MAAO;AAE3D,QAAM,cACJ,SAAS,KAAK,gBAAgB,cAAc,iBAAiB;AAC/D,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,QAAQ;AACf,SAAO,SAAS;AAChB,QAAM,MAAM,OAAO,WAAW,IAAI;AAClC,MAAI,CAAC,KAAK;AAGR,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,GAAG;AACd,yBAAqB,KAAK,GAAG,GAAG,YAAY,YAAY,MAAM;AAC9D,QAAI,KAAK;AAAA,EACX;AAEA,MAAI,YAAY;AAChB,MAAI,SAAS,GAAG,GAAG,YAAY,UAAU;AAEzC,QAAM,UAAU,KAAK,OAAO,aAAa,MAAM,SAAS,CAAC;AACzD,QAAM,UAAU,KAAK,OAAO,aAAa,MAAM,UAAU,CAAC;AAC1D,MAAI,UAAU,OAAO,SAAS,OAAO;AAErC,SAAO,OAAO,UAAU,WAAW;AACrC;;;AC7PA,kBAAiB;AAqBjB,eAAsB,aACpB,cACwB;AACxB,QAAM,QAAQ,MAAMC,WAAU,YAAY;AAE1C,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,QAAQ,MAAM,gBAAgB,MAAM;AAC3C,SAAO,SAAS,MAAM,iBAAiB,MAAM;AAC7C,QAAM,MAAM,OAAO,WAAW,IAAI;AAClC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AAEA,MAAI,UAAU,OAAO,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AACtD,QAAM,YAAY,IAAI,aAAa,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AACpE,QAAM,WAAO,YAAAC,SAAK,UAAU,MAAM,UAAU,OAAO,UAAU,QAAQ;AAAA,IACnE,mBAAmB;AAAA,EACrB,CAAC;AAED,SAAO,MAAM,QAAQ;AACvB;AAEA,IAAMD,aAAY,CAAC,QACjB,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC/B,QAAM,MAAM,IAAI,MAAM;AACtB,MAAI,SAAS,MAAM,QAAQ,GAAG;AAC9B,MAAI,UAAU;AACd,MAAI,MAAM;AACZ,CAAC;;;ACtCI,IAAM,iBAAiB;AAAA,EAC5B,oBACE,KACA,MACA,SACe;AACf,WAAO;AAAA,MACL,OAAO,EAAE,MAAM,QAAQ;AAAA,MACvB,WAAW,IAAI;AAAA,MACf,YAAY,IAAI;AAAA,MAChB,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,eAAe,KAAa,WAAuC;AACjE,QAAI,QAAQ,GACV,MAAM,GACN,MAAM;AACR,UAAM,cAAkC,CAAC;AACzC,UAAM,QAAQ,MAAM;AAEpB,WAAO,QAAQ,IAAI,QAAQ;AACzB,UAAI,GACF,WAAW,GACX,SAAS;AACX,SAAG;AACD,YAAI,IAAI,WAAW,OAAO,IAAI;AAC9B,mBAAW,IAAI,OAAS;AACxB,oBAAY;AAAA,MACd,SAAS,KAAK;AACd,YAAM,OAAO,SAAS,IAAI,EAAE,UAAU,KAAK,UAAU;AACrD,aAAO;AAEP,iBAAW;AACX,eAAS;AACT,SAAG;AACD,YAAI,IAAI,WAAW,OAAO,IAAI;AAC9B,mBAAW,IAAI,OAAS;AACxB,oBAAY;AAAA,MACd,SAAS,KAAK;AACd,YAAM,OAAO,SAAS,IAAI,EAAE,UAAU,KAAK,UAAU;AACrD,aAAO;AAEP,kBAAY,KAAK,CAAC,MAAM,OAAO,MAAM,KAAK,CAAC;AAAA,IAC7C;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,eACJ,KACA,QACA,SACA,SACwB;AACxB,UAAM,eAAe,OAAO,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,GAAG;AAClE,UAAM,cACJ,YAAY,YAAY,SAAS,YAAY,YAAY,QAAQ;AACnE,UAAM,MAAM,GAAG,OAAO,aAAa,WAAW,IAAI,YAAY;AAE9D,UAAM,WAAW,MAAM,MAAM,GAAG;AAChC,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,eAAe,SAAS,UAAU,EAAE;AAAA,IACtD;AACA,UAAM,OAAO,MAAM,SAAS,KAAK;AAEjC,QAAI,KAAK,SAAS,QAAQ,CAAC,KAAK,UAAU,KAAK,OAAO,WAAW,GAAG;AAClE,YAAM,IAAI,MAAM,UAAU;AAAA,IAC5B;AAEA,UAAM,QAAQ,KAAK,OAAO,CAAC;AAC3B,UAAM,QACJ,MAAM,MAAM;AAAA,MAAQ,CAAC,QACnB,IAAI,OAAO,IAAI,CAAC,UAAe;AAAA,QAC7B,UAAU,KAAK;AAAA,QACf,UAAU,KAAK;AAAA,QACf,aAAa,KAAK,UAAU,eAAe;AAAA,MAC7C,EAAE;AAAA,IACJ,KAAK,CAAC;AAER,WAAO;AAAA,MACL,MAAM;AAAA,QACJ,gBAAgB,MAAM;AAAA,QACtB,iBAAiB,MAAM;AAAA,QACvB,UAAU,MAAM;AAAA,QAChB;AAAA,MACF;AAAA,MACA,WAAW,IAAI;AAAA,MACf,YAAY,IAAI;AAAA,MAChB,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,EACF;AAAA,EACA,MAAM,WACJ,KACA,QACwB;AACxB,UAAM,EAAE,QAAQ,aAAa,WAAW,SAAS,SAAS,IAAI,IAAI;AAElE,QACE,CAAC,KAAK,kBAAkB,MAAM,KAC9B,CAAC,KAAK,kBAAkB,WAAW,GACnC;AACA,aAAO,KAAK;AAAA,QACV;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,QAAI,aAAa,CAAC,UAAU,MAAM,KAAK,iBAAiB,GAAG;AACzD,aAAO,KAAK;AAAA,QACV;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,YAAY,CAAC,QAAQ,GAAI,aAAa,CAAC,GAAI,WAAW;AAE5D,QAAI;AACF,UAAI,OAAO,YAAY,QAAQ;AAC7B,eAAO,MAAM,KAAK;AAAA,UAChB;AAAA,UACA;AAAA,UACA;AAAA,UACA,OAAO;AAAA,QACT;AAAA,MACF,OAAO;AACL,eAAO,MAAM,KAAK;AAAA,UAChB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,UAAI,iBAAiB,SAAS,MAAM,QAAQ,SAAS,UAAU,GAAG;AAChE,eAAO,KAAK;AAAA,UACV;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,UAAI,iBAAiB,WAAW;AAC9B,eAAO,KAAK;AAAA,UACV;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,aAAO,KAAK;AAAA,QACV;AAAA,QACA;AAAA,QACA,0BAA0B,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MACpF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,mBACJ,KACA,QACA,SACA,UACA,SACwB;AACxB,UAAM,kBACJ,YAAY,YACR,SACA,YAAY,YACV,eACA;AACR,UAAM,OAAO;AAAA,MACX,SAAS;AAAA,MACT,oBAAoB;AAAA,QAClB,UAAU,YAAY;AAAA,MACxB;AAAA,MACA,WAAW,OAAO,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE;AAAA,IACzD;AAEA,UAAM,WAAW,MAAM,MAAM,GAAG,OAAO,UAAU;AAAA,MAC/C,MAAM,KAAK,UAAU,IAAI;AAAA,MACzB,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,QAAQ;AAAA,IACV,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,mBAAmB,SAAS,UAAU,EAAE;AAAA,IAC1D;AACA,UAAM,OAAO,MAAM,SAAS,KAAK;AAEjC,QAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,KAAK,QAAQ,KAAK,KAAK,KAAK,WAAW,GAAG;AAChE,YAAM,IAAI,MAAM,UAAU;AAAA,IAC5B;AAEA,UAAM,OAAO,KAAK;AAClB,UAAM,qBAAqB,KAAK,eAAe,KAAK,KAAK,CAAC,EAAE,OAAO,CAAC;AAEpE,UAAM,QACJ,KAAK,KAAK;AAAA,MAAQ,CAAC,QACjB,IAAI,WAAW,IAAI,CAAC,cAAmB;AAAA,QACrC,UAAU,SAAS,SAAS;AAAA;AAAA,QAC5B,UAAU,SAAS;AAAA,QACnB,aAAa,SAAS,eAAe;AAAA,MACvC,EAAE;AAAA,IACJ,KAAK,CAAC;AAER,WAAO;AAAA,MACL,MAAM;AAAA,QACJ,gBAAgB,KAAK,QAAQ,SAAS;AAAA;AAAA,QACtC,iBAAiB,KAAK,QAAQ;AAAA,QAC9B,UAAU;AAAA,UACR,aAAa;AAAA,UACb,MAAM;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,MACA,WAAW,IAAI;AAAA,MACf,YAAY,IAAI;AAAA,MAChB,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,kBAAkB,OAAkC;AAClD,UAAM,CAAC,KAAK,GAAG,IAAI;AACnB,WAAO,OAAO,QAAQ,OAAO,OAAO,OAAO,OAAO,OAAO;AAAA,EAC3D;AACF;;;AC7OE,cAAW;;;AC6Bb,SAAS,WAA6B,KAAW;AAE/C,QAAM,YAAY,OAAO,oBAAoB,GAAG;AAGhD,aAAW,QAAQ,WAAW;AAC5B,UAAM,QAAS,IAAgC,IAAI;AAEnD,QACE,SACA,OAAO,UAAU,YACjB,CAAC,OAAO,SAAS,KAAK;AAAA,IAEtB,EAAE,iBAAiB,SACnB;AACA,iBAAW,KAAe;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO,OAAO,OAAO,GAAG;AAC1B;AAMA,IAAI,sBAAmD;AAWvD,IAAI,eAA+C;AAE5C,IAAM,aAAN,MAAiB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKN,OAAO,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,IAKnC,QAAQ;AAAA,EACV,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOe,SAAS,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQrC,QAAQ,CAAC,iBACP,aAAa,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAM3B,UAAU,CACR,MACA,YACoB,eAAe,MAAM,OAAO;AAAA,EACpD,CAAC;AAAA,EACO;AAAA;AAAA;AAAA;AAAA;AAAA,EAKQ,UAAU,OAAO,OAAO;AAAA;AAAA,IAEtC,KAAK,CAAC,QACJ,KAAK,OAAO,KAAK,eAAe,EAAE,IAAI,CAAC;AAAA;AAAA,IAEzC,QAAQ,MACN,KAAK,OAAO,KAAK,iBAAiB;AAAA;AAAA,IAEpC,KAAK,CAAC,KAAa,UACjB,KAAK,OAAO,KAAK,eAAe,EAAE,KAAK,MAAM,CAAC;AAAA,EAClD,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAKe,cAAc,OAAO,OAAO;AAAA;AAAA,IAE1C,KAAK,CAAC,QACJ,KAAK,OAAO,KAAK,cAAc,EAAE,IAAI,CAAC;AAAA;AAAA,IAExC,KAAK,CAAC,KAAa,UACjB,KAAK,OAAO,KAAK,cAAc,EAAE,KAAK,MAAM,CAAC;AAAA,EACjD,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAKe,WAAW,OAAO,OAAO;AAAA;AAAA,IAEvC,aAAa,MACX,KAAK,OAAO,KAAQ,wBAAwB;AAAA;AAAA,IAE9C,aAAa,CAAc,SACzB,KAAK,OAAO,KAAW,0BAA0B,EAAE,KAAK,CAAC;AAAA,EAC7D,CAAC;AAAA;AAAA;AAAA;AAAA,EAIe,WAAW,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA,IAIvC,oBAAoB,MAClB,KAAK,OAAO,KAAK,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA,IAKzC,aAAa,CACX,WACkB,KAAK,OAAO,KAAK,yBAAyB,MAAM;AAAA;AAAA;AAAA;AAAA,IAIpE,YAAY,MAAqB,KAAK,OAAO,KAAK,sBAAsB;AAAA,EAC1E,CAAC;AAAA;AAAA;AAAA;AAAA,EAIe,OAAO,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,IAKnC,YAAY,CACV,WAEA,KAAK,OAAO,KAAK,oBAAoB,EAAE,OAAO,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,IAKjD,oBAAoB,CAAC,UAAqB;AACxC,aAAO,KAAK,OAAO,KAAK,uBAAuB,EAAE,OAAO,SAAS,CAAC,EAAE,CAAC;AAAA,IACvE;AAAA,EAIF,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAKe,aAAa,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMzC,UAAU,CAAC,MAAyC,WAAsB;AACxE,aAAO,KAAK,OAAO,KAAK,sBAAsB,EAAE,QAAQ,KAAK,CAAC;AAAA,IAChE;AAAA,EAKF,CAAC;AAAA;AAAA;AAAA;AAAA,EAIe,QAAQ,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOpC,WAAW,MACT,KAAK,OAAO,KAAK,cAAc,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASnC,WAAW,CAAC,QAAgB,aAC1B,KAAK,OAAO,KAAK,cAAc,EAAE,QAAQ,SAAS,CAAC;AAAA,EACvD,CAAC;AAAA;AAAA;AAAA;AAAA,EAIe,UAAU,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,IAKtC,SAAS,CACP,YAEA,KAAK,OAAO,KAAK,mBAAmB,OAAO;AAAA,EAC/C,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAKe,WAAW,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOvC,OAAO,CAAC,IAAY,OAAe,WACjC,KAAK,OAAO,KAAK,kBAAkB,EAAE,IAAI,QAAQ,MAAM,CAAC;AAAA,EAC5D,CAAC;AAAA;AAAA;AAAA;AAAA,EAIe,SAAS,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,IAKrC,SAAS,CAAC,UACR,KAAK,OAAO,KAAK,kBAAkB,EAAE,MAAM,CAAC;AAAA,EAChD,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAKe,UAAU,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,IAKtC,SAAS,OACP,YACiC;AACjC,aAAO,KAAK,OAAO,KAAK,mBAAmB,OAAO;AAAA,IACpD;AAAA,EACF,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAKe,aAAa,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA,IAIzC,OAAO,MAAY;AACjB,WAAK,OAAO,oBAAoB;AAAA,QAC9B,WAAW;AAAA,QACX,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA,eAAe,CAAC,YAIJ;AACV,WAAK,OAAO,oBAAoB;AAAA,QAC9B,WAAW;AAAA,QACX,SAAS,EAAE,GAAG,SAAS,MAAM,UAAU;AAAA,QACvC,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAIA,OAAO,MAAY;AACjB,WAAK,OAAO,oBAAoB;AAAA,QAC9B,WAAW;AAAA,QACX,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAAA;AAAA;AAAA;AAAA,EAIe,WAAW,OAAO,OAAO;AAAA;AAAA,IAEvC,oBAAoB,MAClB,KAAK,OAAO,KAAK,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA,IAKzC,oBAAoB,CAClB,WAEA,KAAK,OAAO,KAAK,wBAAwB,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOjD,aAAa,CAAC,YACZ,KAAK,OAAO,KAAK,yBAAyB,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,IAKnD,cAAc,CACZ,eAEA,KAAK,OAAO,KAAK,iBAAiB,EAAE,WAAW,CAAC;AAAA,EACpD,CAAC;AAAA;AAAA;AAAA;AAAA,EAIe,KAAK,OAAO,OAAO;AAAA;AAAA,IAEjC,MAAM,MAAqB,KAAK,OAAO,KAAK,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,IAKlD,iBAAiB,CAAC,WAChB,KAAK,OAAO,KAAK,qBAAqB,MAAM;AAAA,EAChD,CAAC;AAAA;AAAA;AAAA;AAAA,EAIe,QAAQ,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,IAKpC,KAAK,IAAI,YAAuB,KAAK,OAAO,KAAK,aAAa,EAAE,QAAQ,CAAC;AAAA,EAC3E,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAKe,UAAU,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA,IAItC,YAAY,MAAqB;AAC/B,YAAM,YAAY,OAAO,aACrB,OAAO,WAAW,IAClB,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,CAAC;AAC1C,aAAO,KAAK,OAAO,KAAK,0BAA0B;AAAA,QAChD;AAAA,QACA,YAAY;AAAA,MACd,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA,WAAW,CACT,cACkB;AAClB,YAAM,YAAY,OAAO,aACrB,OAAO,WAAW,IAClB,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,CAAC;AAC1C,aAAO,KAAK,OAAO,KAAK,yBAAyB;AAAA,QAC/C,SAAS,EAAE,UAAU;AAAA,QACrB;AAAA,QACA,YAAY;AAAA,MACd,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA,UAAU,OACR,YACgD;AAEhD,YAAM,YAAY,OAAO,aACrB,OAAO,WAAW,IAClB,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,CAAC;AAE1C,YAAM,UAAwB;AAAA,QAC5B;AAAA,QACA;AAAA,QACA,YAAY;AAAA,QACZ,MAAM;AAAA,MACR;AAGA,UAAI,qBAAqB;AACvB,cAAM,WAAW,MAAM,eAAe;AAAA,UACpC;AAAA,UACA;AAAA,QACF;AACA,YAAI,SAAS,WAAW,SAAS,MAAM;AACrC,iBAAO,SAAS;AAAA,QAClB;AACA,cAAM,IAAI,MAAM,SAAS,OAAO,WAAW,gBAAgB;AAAA,MAC7D;AAGA,aAAO,KAAK,OAAO,KAAK,wBAAwB;AAAA,QAC9C;AAAA,QACA;AAAA,QACA,YAAY;AAAA,MACd,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAAA,EAED,cAAc;AACZ,SAAK,SAAS,IAAI,OAAO;AAIzB,SAAK,OAAO;AAAA;AAAA,MAEV,CAAC,SAAS;AACR,YAAI,MAAM,IAAK,gBAAe,KAAK;AAAA,MACrC;AAAA,IACF;AAGA,SAAK,aAAa,KAAK,WAAW,KAAK,IAAI;AAC3C,SAAK,SAAS,KAAK,OAAO,KAAK,IAAI;AACnC,SAAK,cAAc,KAAK,YAAY,KAAK,IAAI;AAC7C,SAAK,eAAe,KAAK,aAAa,KAAK,IAAI;AAC/C,SAAK,KAAK,KAAK,GAAG,KAAK,IAAI;AAC3B,SAAK,MAAM,KAAK,IAAI,KAAK,IAAI;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKO,OAAO,SAA0D;AACtE,QAAI,QAAQ,gBAAgB;AAC1B,4BAAsB,QAAQ;AAAA,IAChC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,cAAc,SAAiD;AACpE,WAAO,KAAK,OAAO,KAAK,kBAAkB,OAAO;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAa,WACX,SACkC;AAClC,UAAM,MAAM,MAAM,KAAK,OAAO;AAAA,MAC5B;AAAA,MACA;AAAA,IACF;AACA,QAAI,KAAK,IAAK,gBAAe,IAAI;AACjC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,SAEO;AACZ,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,YAAY,MAAqC;AACtD,WAAO,KAAK,OAAO,KAAK,mBAAmB,EAAE,KAAK,CAAC;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,eAAwC;AAC7C,WAAO,KAAK,OAAO,KAAK,kBAAkB;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,GACL,OACA,UACY;AACZ,WAAO,KAAK,OAAO,GAAM,OAAiB,QAAQ;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,IAAiB,OAAiB,UAAmC;AAC1E,SAAK,OAAO,IAAO,OAAiB,QAAQ;AAAA,EAC9C;AACF;AAMO,IAAM,MAAM,WAAW,IAAI,WAAW,CAAC;;;ACjjB9C,IAAAE,iBAAkE;AA4lB1D,IAAAC,uBAAA;AA5kBR,IAAMC,qBAAoC;AAAA,EACxC;AAAA,IACE,WAAW;AAAA,IACX,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,UAAU;AAAA,IACV,MAAM;AAAA,IACN,OAAO;AAAA,IACP,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,WAAW;AAAA,IACX,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,UAAU;AAAA,IACV,MAAM;AAAA,IACN,OAAO;AAAA,IACP,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,WAAW;AAAA,IACX,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,UAAU;AAAA,IACV,MAAM;AAAA,IACN,OAAO;AAAA,IACP,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AACF;AAkBA,IAAM,wBAAwB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,GAAG;AAEV,IAAM,uBAAuB,CAAC,aAAa,aAAa,WAAW,EAAE,KAAK,GAAG;AAQ7E,SAAS,gBAAgB,OAAuB;AAC9C,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,WAAQ,OAAO,KAAM,MAAM,WAAW,CAAC;AAAA,EACzC;AACA,UAAQ,SAAS,GAAG,SAAS,EAAE;AACjC;AAOA,SAAS,iBAAiB,MAAsB;AAC9C,QAAM,YAAY,gBAAgB,IAAI;AACtC,SAAO,6DAA6D,SAAS,UAAU,qBAAqB,SAAS,oBAAoB;AAC3I;AAQA,SAAS,qBAAqB,OAA+C;AAC3E,MAAI;AACF,UAAM,MAAM,MAAM,WAAW,SAAS,IAAI,MAAM,MAAM,CAAC,IAAI;AAC3D,UAAM,YAAY,IAAI,MAAM,GAAG,EAAE,CAAC;AAClC,UAAM,SAAS,UAAU,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG;AAC7D,UAAM,cAAc;AAAA,MAClB,KAAK,MAAM,EACR,MAAM,EAAE,EACR,IAAI,CAAC,MAAM,IAAI,KAAK,EAAE,WAAW,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAC9D,KAAK,EAAE;AAAA,IACZ;AAEA,WAAO,KAAK,MAAM,WAAW;AAAA,EAC/B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAkBA,SAAS,iBAAiB,cAAkC;AAC1D,QAAM,SAAS,eAAe,qBAAqB,YAAY,IAAI;AACnE,QAAM,OAAQ,QAAQ,OAA8B;AACpD,QAAM,WACH,QAAQ,QACR,QAAQ,YACT;AACF,QAAM,WAAY,QAAQ,YAAmC;AAC7D,QAAM,CAAC,WAAW,GAAG,aAAa,IAAI,SAAS,MAAM,GAAG;AACxD,SAAO;AAAA,IACL,OAAO;AAAA,IACP,aAAa;AAAA,IACb,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,OAAO;AAAA,IACP,WAAW,aAAa;AAAA,IACxB;AAAA,IACA,UAAU,cAAc,KAAK,GAAG,KAAK;AAAA,IACrC,aAAa;AAAA,IACb,KAAK;AAAA,IACL;AAAA,IACA;AAAA,IACA,IAAI;AAAA,EACN;AACF;AAKA,IAAM,aAAa,CAAC,IAAsB,OAAyB;AACjE,QAAM,OAAQ,GAAG,CAAC,IAAI,KAAK,KAAM;AACjC,QAAM,OAAQ,GAAG,CAAC,IAAI,KAAK,KAAM;AACjC,QAAM,QAAS,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,KAAM;AAC3C,QAAM,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI;AACxC,QAAM,IACJ,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAC9B,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI;AACjD,UAAS,KAAK,MAAM,GAAG,CAAC,IAAI,MAAO,KAAK,KAAK,OAAO;AACtD;AAQO,IAAM,eAA4C,CAAC;AAAA,EACxD;AAAA,EACA,kBAAkB,CAAC,QAAQ,OAAO;AAAA;AAAA,EAClC,WAAW;AAAA,EACX;AAAA,EACA,kBAAkB;AAAA,EAClB;AAAA,EACA;AACF,MAAM;AACJ,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAS,QAAQ;AACjD,QAAM,CAAC,UAAU,WAAW,QAAI,yBAA2B,eAAe;AAC1E,QAAM,CAAC,SAAS,UAAU,QAAI,yBAAiB,CAAC;AAChD,QAAM,CAAC,iBAAiB,kBAAkB,QAAI,yBAAS,eAAe;AACtE,QAAM,CAAC,SAAS,UAAU,QAAI,yBAAS,KAAK;AAC5C,QAAM,CAAC,aAAa,cAAc,QAAI,yBAAS,IAAI;AACnD,QAAM,CAAC,cAAc,eAAe,QAAI,yBAAS,CAAC;AAClD,QAAM,CAAC,YAAY,aAAa,QAAI,yBAAqB,GAAG;AAC5D,QAAM,CAAC,mBAAmB,oBAAoB,QAAI,yBAAS,KAAK;AAEhE,QAAM,wBAAoB,uBAAmB,IAAI;AACjD,QAAM,mBAAe,uBAAe,CAAC;AACrC,QAAM,sBAAkB,uBAAY,IAAI;AAGxC,QAAM,eAAW,uBAAO;AAAA,IACtB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,oBAAoB,MAAM;AAAA,IAAC;AAAA,IAC3B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,4BAAwB;AAAA,IAC5B,CAAC,QAA0B,eAAuB;AAChD,YAAM,eAAe,SAAS;AAC9B,YAAM,UAAU;AAAA,QACd,eAAe;AAAA,QACf,SAAS;AAAA,UACP,UAAU;AAAA,UACV,iBAAiB;AAAA,UACjB,aAAa;AAAA,QACf;AAAA,QACA,UAAU;AAAA,UACR,QAAQ;AAAA,YACN,UAAU;AAAA,YACV,UAAU;AAAA,YACV,kBAAkB;AAAA,YAClB,SAAS;AAAA,YACT,UAAU,OAAO,CAAC;AAAA,YAClB,WAAW,OAAO,CAAC;AAAA,YACnB,OAAO,aAAa,WAChB,MAAM,aAAa,kBACnB;AAAA,UACN;AAAA,UACA,WAAW,KAAK,IAAI;AAAA,QACtB;AAAA,QACA,WAAW,KAAK,IAAI;AAAA,MACtB;AAEA,MAAC,OAAe,iBAAiB,gBAAgB;AAAA,QAC/C;AAAA,QACA;AAAA,QACA,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,yBAAqB,4BAAY,MAAM;AAC3C,UAAM,eAAe,SAAS;AAC9B,0BAAsB,aAAa,UAAU,aAAa,OAAO;AAAA,EACnE,GAAG,CAAC,qBAAqB,CAAC;AAM1B,QAAM,oBAAgB;AAAA,IACpB,CAAC,WAA6B;AAC5B,kBAAY,MAAM;AAClB,2BAAqB,KAAK;AAC1B,4BAAsB,QAAQ,SAAS,QAAQ,OAAO;AAAA,IACxD;AAAA,IACA,CAAC,qBAAqB;AAAA,EACxB;AAEA,gCAAU,MAAM;AACd,aAAS,UAAU;AAAA,MACjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAGD,gCAAU,MAAM;AACd,gBAAY,QAAQ;AAAA,EACtB,GAAG,CAAC,QAAQ,CAAC;AAEb,gCAAU,MAAM;AACd,uBAAmB,eAAe;AAAA,EACpC,GAAG,CAAC,eAAe,CAAC;AAGpB,gCAAU,MAAM;AACd,QAAI,kBAAkB,eAAe,SAAS,GAAG;AAC/C,mBAAa,UAAU;AACvB,kBAAY,eAAe,CAAC,CAAC;AAAA,IAC/B;AAAA,EACF,GAAG,CAAC,cAAc,CAAC;AAInB,gCAAU,MAAM;AACd,QAAI,kBAAkB,WAAW,gBAAgB,SAAS;AAExD,MAAC,IAAY,OAAO;AAAA,QAClB;AAAA,QACA,gBAAgB;AAAA,MAClB;AAAA,IACF;AAAA,EACF,GAAG,CAAC,eAAe,CAAC;AAGpB,gCAAU,MAAM;AACd,UAAM,SAAU,IAAY;AAC5B,UAAM,eAAe,OAAO,KAAK,KAAK,MAAM;AAE5C,UAAM,aAAa,MAAM;AACvB,UAAI,kBAAkB,SAAS;AAC7B,sBAAc,kBAAkB,OAAO;AACvC,0BAAkB,UAAU;AAAA,MAC9B;AACA,sBAAgB,UAAU;AAAA,IAC5B;AAEA,UAAM,cAAc,CAAC,WAAiB;AACpC,iBAAW;AACX,sBAAgB,UAAU,UAAU,CAAC;AAErC,YAAM,eAAe,QAAQ,YAAY;AACzC,YAAM,WAAW,KAAK;AAAA,QACpB;AAAA,QACA,eAAe,SAAS,QAAQ;AAAA,MAClC;AAEA,wBAAkB,UAAU,YAAY,MAAM;AAC5C,cAAM,QAAQ,SAAS;AAEvB,YAAI,MAAM,UAAU;AAClB,cAAI,MAAM,kBAAkB,MAAM,eAAe,SAAS,GAAG;AAE3D,gBAAI,aAAa,UAAU,MAAM,eAAe,SAAS,GAAG;AAC1D,oBAAM,eAAe,MAAM,eAAe,aAAa,OAAO;AAC9D,oBAAM,YAAY,MAAM,eAAe,aAAa,UAAU,CAAC;AAE/D,2BAAa,WAAW;AACxB,oBAAM,aAAa,WAAW,cAAc,SAAS;AAErD,oBAAM,WAAW,UAAU;AAC3B,oBAAM,YAAY,SAAS;AAAA,YAC7B,OAAO;AAEL,oBAAM;AAAA,gBACJ,MAAM,eAAe,MAAM,eAAe,SAAS,CAAC;AAAA,cACtD;AAAA,YACF;AAAA,UACF,OAAO;AAEL,kBAAM,YAAY,CAAC,SAAS;AAAA,cAC1B,KAAK,CAAC,KAAK,KAAK,OAAO,IAAI,OAAO;AAAA,cAClC,KAAK,CAAC,KAAK,KAAK,OAAO,IAAI,OAAO;AAAA,YACpC,CAAC;AAAA,UACH;AAAA,QACF;AAEA,cAAM,mBAAmB;AAAA,MAC3B,GAAG,QAAQ;AAAA,IACb;AAEA,UAAM,yBAAyB,OAAO,YAAiB;AACrD,YAAM;AAAA,QACJ;AAAA,QACA,SAAS;AAAA,QACT,SAAS,kBAAkB,CAAC;AAAA,QAC5B;AAAA,MACF,IAAI;AACJ,YAAM,QAAQ,SAAS;AAEvB,YAAM,UAAU,IAAI,QAAQ,eAAe;AAE3C,UAAI,MAAM,cAAc;AACtB,gBAAQ;AAAA,UACN;AAAA,UACA,UAAU,MAAM,aAAa,QAAQ,WAAW,EAAE,CAAC;AAAA,QACrD;AAAA,MACF;AAEA,UAAI,QAAQ,OAAO,SAAS,YAAY,CAAC,QAAQ,IAAI,cAAc,GAAG;AACpE,gBAAQ,IAAI,gBAAgB,kBAAkB;AAAA,MAChD;AAEA,UAAI;AACF,cAAM,WAAW,MAAM,MAAM,KAAK;AAAA,UAChC,MAAM,OACF,OAAO,SAAS,WACd,OACA,KAAK,UAAU,IAAI,IACrB;AAAA,UACJ;AAAA,UACA;AAAA,QACF,CAAC;AAED,cAAM,cAAc,SAAS,QAAQ,IAAI,cAAc;AACvD,YAAI;AAEJ,YAAI,aAAa,SAAS,kBAAkB,GAAG;AAC7C,yBAAe,MAAM,SAAS,KAAK;AAAA,QACrC,OAAO;AACL,yBAAe,MAAM,SAAS,KAAK;AAAA,QACrC;AAEA,cAAM,aAAqC,CAAC;AAC5C,iBAAS,QAAQ,QAAQ,CAAC,OAAO,QAAQ;AACvC,qBAAW,GAAG,IAAI;AAAA,QACpB,CAAC;AAED,eAAO;AAAA,UACL,MAAM;AAAA,UACN,SAAS;AAAA,UACT,QAAQ,SAAS;AAAA,UACjB,YAAY,SAAS;AAAA,QACvB;AAAA,MACF,SAAS,OAAY;AACnB,cAAM;AAAA,UACJ,OAAO,MAAM,WAAW;AAAA,UACxB,QAAQ;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAGA,WAAO,OAAO,OAAO,MAAc,YAAiB;AAElD,UAAI,SAAS,cAAc;AACzB,eAAO,QAAQ,QAAQ;AAAA,UACrB;AAAA;AAAA,UACA,SAAS,EAAE,OAAO,OAAO;AAAA;AAAA,UACzB,aAAa;AAAA,UACb,KAAK,CAAC;AAAA,UACN,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,EAAE;AAAA,UAC/C,MAAM;AAAA,UACN,QAAQ,CAAC;AAAA,UACT,SAAS,iBAAiB,SAAS,QAAQ,YAAY;AAAA,UACvD,SAAS;AAAA,UACT,UAAU,CAAC;AAAA,UACX,MAAM,SAAS;AAAA,UACf,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAGA,UAAI,SAAS,wBAAwB;AACnC,cAAM,QAAQ,SAAS;AACvB,eAAO,QAAQ,QAAQ;AAAA,UACrB,QAAQ;AAAA,YACN,UAAU;AAAA,YACV,UAAU;AAAA,YACV,kBAAkB;AAAA,YAClB,SAAS,MAAM;AAAA,YACf,UAAU,MAAM,SAAS,CAAC;AAAA,YAC1B,WAAW,MAAM,SAAS,CAAC;AAAA,YAC3B,OAAO,MAAM,WAAW,MAAM,MAAM,kBAAkB;AAAA,UACxD;AAAA,UACA,WAAW,KAAK,IAAI;AAAA,QACtB,CAAC;AAAA,MACH;AACA,UAAI,SAAS,yBAAyB;AACpC,oBAAY,OAAO;AACnB,eAAO,QAAQ,QAAQ;AAAA,MACzB;AACA,UAAI,SAAS,wBAAwB;AACnC,mBAAW;AACX,eAAO,QAAQ,QAAQ;AAAA,MACzB;AAGA,UAAI,SAAS,mBAAmB;AAC9B,eAAO,uBAAuB,OAAO;AAAA,MACvC;AAGA,UAAI,SAAS,iBAAiB,SAAS,cAAc;AACnD,eAAO,QAAQ,QAAQ,aAAa,QAAQ,YAAY,QAAQ,GAAG,EAAE,CAAC;AAAA,MACxE;AACA,UAAI,SAAS,iBAAiB,SAAS,cAAc;AACnD,qBAAa,QAAQ,YAAY,QAAQ,GAAG,IAAI,QAAQ,KAAK;AAC7D,eAAO,QAAQ,QAAQ;AAAA,MACzB;AACA,UAAI,SAAS,oBAAoB;AAC/B,eAAO,QAAQ,QAAQ,iBAAiB,SAAS,QAAQ,YAAY,CAAC;AAAA,MACxE;AACA,UAAI,SAAS,uBAAuB;AAClC,cAAM,QAAQ,SAAS,SAAS,CAAC;AACjC,YAAI,MAAM,WAAW,GAAG;AACtB,iBAAO,QAAQ,QAAQ,iBAAiB,OAAO,CAAC;AAAA,QAClD;AACA,cAAM,MAA8B,CAAC;AACrC,mBAAW,QAAQ,OAAO;AACxB,cAAI,IAAI,IAAI,iBAAiB,IAAI;AAAA,QACnC;AACA,eAAO,QAAQ,QAAQ,GAAG;AAAA,MAC5B;AAGA,UAAI,SAAS,wBAAwB;AACnC,eAAO,QAAQ,QAAQ,EAAE,SAAS,MAAM,UAAU,UAAU,CAAC;AAAA,MAC/D;AAGA,UAAI,SAAS,oBAAoB;AAC/B,eAAO,QAAQ,QAAQA,kBAAiB;AAAA,MAC1C;AACA,UAAI,SAAS,mBAAmB;AAC9B,cAAM,OAAO,SAAS;AACtB,eAAO,QAAQ;AAAA,UACbA,mBAAkB,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI,KAAK;AAAA,YAChD,WAAW;AAAA,YACX,aAAa;AAAA,YACb,mBAAmB;AAAA,YACnB,UAAU;AAAA,YACV,MAAM,QAAQ;AAAA,YACd,OAAO,QAAQ;AAAA,YACf,kBAAkB;AAAA,YAClB,UAAU;AAAA,YACV,UAAU;AAAA,UACZ;AAAA,QACF;AAAA,MACF;AACA,UAAI,SAAS,mBAAmB;AAC9B,eAAO,QAAQ,QAAQ;AAAA,UACrB,SAAS;AAAA,UACT,eAAe,MAAM,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;AAAA,QAC1D,CAAC;AAAA,MACH;AAGA,UACE,SAAS,oBACT,SAAS,UACT,SAAS,kBACT;AACA,eAAO,QAAQ,QAAQ,EAAE,SAAS,KAAK,CAAC;AAAA,MAC1C;AAEA,aAAO,aAAa,MAAM,OAAO;AAAA,IACnC;AAEA,eAAW,IAAI;AAEf,WAAO,MAAM;AACX,iBAAW;AACX,aAAO,OAAO;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,iBACJ,eAAe,OAAO,eAAe,MAAO;AAE9C,QAAM,+BAA2B;AAAA,IAC/B,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,cAAc;AAAA,IAChB;AAAA,IACA,CAAC,mBAAmB,eAAe,cAAc;AAAA,EACnD;AAEA,MAAI,CAAC,QAAS,QAAO;AAErB,SACE,+CAAC,SAAI,WAAU,0BAEb;AAAA,kDAAC,SAAI,WAAU,iBACb,wDAAC,oBAAoB,UAApB,EAA6B,OAAO,0BAClC,UACH,GACF;AAAA,IAEC,cACC;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,SAAS,MAAM,eAAe,KAAK;AAAA,QACnC,OAAM;AAAA,QACN,MAAK;AAAA,QACL,SAAQ;AAAA,QAER;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,MAAK;AAAA,YACL,QAAO;AAAA,YACP,QAAO;AAAA,YACP,eAAc;AAAA,YACd,gBAAe;AAAA,YACf,aAAY;AAAA,YACZ,SAAQ;AAAA,YACR,OAAM;AAAA,YACN,OAAM;AAAA,YAEN;AAAA,4DAAC,UAAK,GAAE,WAAU;AAAA,cAClB,8CAAC,UAAK,GAAE,WAAU;AAAA,cAClB,8CAAC,UAAK,GAAE,YAAW;AAAA,cACnB,8CAAC,UAAK,GAAE,YAAW;AAAA,cACnB,8CAAC,UAAK,GAAE,YAAW;AAAA,cACnB,8CAAC,YAAO,IAAG,MAAK,IAAG,KAAI,GAAE,KAAI;AAAA,cAC7B,8CAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA;AAAA;AAAA,QAChC;AAAA;AAAA,IACF,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO,EAAE,QAAQ,KAAK;AAAA,QAGtB;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,SAAS,MAAM,eAAe,IAAI;AAAA,cAElC;AAAA,+DAAC,UAAK,WAAU,oDACd;AAAA,gEAAC,UAAK,WAAU,WAAU,6BAAG;AAAA,kBAAO;AAAA,mBACtC;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAU;AAAA,oBACV,MAAK;AAAA,oBACL,SAAQ;AAAA,oBACT;AAAA;AAAA,gBAED;AAAA;AAAA;AAAA,UACF;AAAA,UAEA,+CAAC,SAAI,WAAU,2BACb;AAAA,2DAAC,SAAI,WAAU,qCACb;AAAA,6DAAC,WAAM,WAAU,0CACf;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,SAAS;AAAA,oBACT,WAAU;AAAA,oBACV,UAAU,CAAC,MAAM,YAAY,EAAE,OAAO,OAAO;AAAA,oBAC7C,MAAK;AAAA;AAAA,gBACP;AAAA,gBACA,+CAAC,UAAK,WAAU,4BAA2B;AAAA;AAAA,kBAC9B,iBAAiB,WAAW;AAAA,mBACzC;AAAA,iBACF;AAAA,cAEA,+CAAC,SAAI,WAAU,2BACb;AAAA,8DAAC,UAAK,WAAU,8BAA6B,oBAAM;AAAA,gBACnD;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAU;AAAA,oBACV,UAAU,CAAC,MAAM,mBAAmB,OAAO,EAAE,OAAO,KAAK,CAAC;AAAA,oBAC1D,OAAO;AAAA,oBAEN,WAAC,GAAG,GAAG,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,IAAI,CAAC,MAChC,+CAAC,YAAe,OAAO,GACpB;AAAA;AAAA,sBAAE;AAAA,yBADQ,CAEb,CACD;AAAA;AAAA,gBACH;AAAA,iBACF;AAAA,eACF;AAAA,YAEA,+CAAC,SAAI,WAAU,0BACb;AAAA,6DAAC,SAAI,WAAU,uBACb;AAAA,8DAAC,UAAK,WAAU,wCAAuC,iBAEvD;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAU;AAAA,oBACV,UAAU,CAAC,MAAM;AACf,4BAAM,MAAM,WAAW,EAAE,OAAO,KAAK,KAAK;AAC1C,kCAAY,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC;AAC9B,yCAAmB;AAAA,oBACrB;AAAA,oBACA,MAAK;AAAA,oBACL,MAAK;AAAA,oBACL,OAAO,SAAS,CAAC;AAAA;AAAA,gBACnB;AAAA,iBACF;AAAA,cACA,+CAAC,SAAI,WAAU,uBACb;AAAA,8DAAC,UAAK,WAAU,wCAAuC,iBAEvD;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAU;AAAA,oBACV,UAAU,CAAC,MAAM;AACf,4BAAM,MAAM,WAAW,EAAE,OAAO,KAAK,KAAK;AAC1C,kCAAY,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC;AAC9B,yCAAmB;AAAA,oBACrB;AAAA,oBACA,MAAK;AAAA,oBACL,MAAK;AAAA,oBACL,OAAO,SAAS,CAAC;AAAA;AAAA,gBACnB;AAAA,iBACF;AAAA,cACA,+CAAC,SAAI,WAAU,kCACb;AAAA,8DAAC,UAAK,WAAU,8BAA6B,+BAE7C;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAU;AAAA,oBACV,KAAI;AAAA,oBACJ,KAAI;AAAA,oBACJ,UAAU,CAAC,MAAM;AACf,iCAAW,SAAS,EAAE,OAAO,OAAO,EAAE,CAAC;AACvC,yCAAmB;AAAA,oBACrB;AAAA,oBACA,MAAK;AAAA,oBACL,OAAO;AAAA;AAAA,gBACT;AAAA,gBACA,+CAAC,SAAI,WAAU,6BAA6B;AAAA;AAAA,kBAAQ;AAAA,mBAAC;AAAA,iBACvD;AAAA,eACF;AAAA,YAEA;AAAA,cAAC;AAAA;AAAA,gBACC,WAAW,0EACT,oBACI,iDACA,iEACN;AAAA,gBACA,SAAS,MAAM,qBAAqB,CAAC,SAAS,CAAC,IAAI;AAAA,gBACnD,MAAK;AAAA,gBACL,SAAQ;AAAA,gBAEP,8BACG,mDACA;AAAA;AAAA,YACN;AAAA,YAEA,+CAAC,SAAI,WAAU,sDACb;AAAA,6DAAC,SAAI,WAAU,qCACb;AAAA,8DAAC,UAAK,WAAU,8BAA6B,yBAAW;AAAA,gBACxD,+CAAC,SAAI,WAAU,2BACb;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,WAAU;AAAA,sBACV,KAAI;AAAA,sBACJ,UAAU,CAAC,MACT,gBAAgB,KAAK,IAAI,GAAG,OAAO,EAAE,OAAO,KAAK,KAAK,CAAC,CAAC;AAAA,sBAE1D,MAAK;AAAA,sBACL,OAAO;AAAA;AAAA,kBACT;AAAA,kBACA;AAAA,oBAAC;AAAA;AAAA,sBACC,WAAU;AAAA,sBACV,UAAU,CAAC,MACT,cAAc,EAAE,OAAO,KAAmB;AAAA,sBAE5C,OAAO;AAAA,sBAEP;AAAA,sEAAC,YAAO,OAAM,KAAI,eAAC;AAAA,wBACnB,8CAAC,YAAO,OAAM,MAAK,gBAAE;AAAA;AAAA;AAAA,kBACvB;AAAA,mBACF;AAAA,iBACF;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,KAAK,eAAe,OAAO,KAAK;AAAA,kBAChC,KAAI;AAAA,kBACJ,UAAU,CAAC,MAAM,gBAAgB,OAAO,EAAE,OAAO,KAAK,CAAC;AAAA,kBACvD,MAAM,eAAe,OAAO,MAAM;AAAA,kBAClC,MAAK;AAAA,kBACL,OAAO;AAAA;AAAA,cACT;AAAA,cACA,8CAAC,SAAI,WAAU,6BACZ,2BAAiB,IACd,WACA,GAAG,YAAY,GAAG,UAAU,uBAClC;AAAA,eACF;AAAA,aACF;AAAA;AAAA;AAAA,IACF;AAAA,KAEJ;AAEJ;;;ACnyBA,IAAAC,iBAAyD;AA4FjD,IAAAC,uBAAA;AAnED,IAAM,eAA4C,CAAC;AAAA,EACxD,QAAQ,cAAc;AAAA,EACtB;AACF,MAAM;AACJ,QAAM,CAAC,aAAa,cAAc,QAAI,yBAAS,WAAW;AAC1D,QAAM,CAAC,MAAM,OAAO,QAAI,yBAAqB,CAAC,CAAC;AAC/C,QAAM,gBAAY,uBAAuB,IAAI;AAG7C,gCAAU,MAAM;AACd,mBAAe,WAAW;AAAA,EAC5B,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,YAAY,MAAM,QAAQ,CAAC,CAAC;AAElC,QAAM,aAAS,4BAAY,CAAC,OAAe,SAAc;AAEvD,QAAI,MAAM,8DAAgD,EAAG;AAE7D,UAAM,QAAkB;AAAA,MACtB,SAAS,OAAO,SAAS,WAAW,OAAO,KAAK,UAAU,MAAM,MAAM,CAAC;AAAA,MACvE,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC;AAAA,MACtC;AAAA,MACA,OAAM,oBAAI,KAAK,GAAE,mBAAmB;AAAA,IACtC;AAEA,YAAQ,CAAC,SAAS,CAAC,OAAO,GAAG,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC;AAAA,EAClD,GAAG,CAAC,CAAC;AAEL,gCAAU,MAAM;AACd,QAAI,OAAO,WAAW,YAAa;AAGnC,UAAM,SAAU,IAAY;AAC5B,UAAM,eAAe,OAAO,KAAK,KAAK,MAAM;AAE5C,WAAO,OAAO,OAAO,MAAc,YAAiB;AAClD,aAAO,QAAQ,IAAI,IAAI,OAAO;AAC9B,aAAO,aAAa,MAAM,OAAO;AAAA,IACnC;AAGA,UAAM,iBAAiB,OAAO,oBAAoB,KAAK,MAAM;AAC7D,WAAO,sBAAsB,CAAC,aAAkB;AAC9C,YAAM,OACJ,SAAS,aAAa,SAAS,SAAS,SAAS,QAAQ;AAC3D,UAAI,OAAO,SAAS,UAAU;AAC5B,eAAO,OAAO,IAAI,IAAI,SAAS,WAAW,SAAS,SAAS,QAAQ;AACpE,uBAAe,QAAQ;AAAA,MACzB;AAAA,IACF;AAEA,WAAO,MAAM;AACX,aAAO,OAAO;AACd,aAAO,sBAAsB;AAAA,IAC/B;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEX,MAAI,CAAC,aAAa;AAChB,WACE;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,SAAS,MAAM,eAAe,IAAI;AAAA,QAClC,OAAM;AAAA,QACN,MAAK;AAAA,QACL,SAAQ;AAAA,QAER;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,MAAK;AAAA,YACL,QAAO;AAAA,YACP,QAAO;AAAA,YACP,eAAc;AAAA,YACd,gBAAe;AAAA,YACf,aAAY;AAAA,YACZ,SAAQ;AAAA,YACR,OAAM;AAAA,YACN,OAAM;AAAA,YAEN;AAAA,4DAAC,UAAK,GAAE,kBAAiB;AAAA,cACzB,8CAAC,UAAK,GAAE,oBAAmB;AAAA,cAC3B,8CAAC,UAAK,GAAE,sCAAqC;AAAA,cAC7C,8CAAC,UAAK,GAAE,8EAA6E;AAAA,cACrF,8CAAC,UAAK,GAAE,aAAY;AAAA,cACpB,8CAAC,UAAK,GAAE,6BAA4B;AAAA,cACpC,8CAAC,UAAK,GAAE,WAAU;AAAA,cAClB,8CAAC,UAAK,GAAE,6BAA4B;AAAA,cACpC,8CAAC,UAAK,GAAE,gCAA+B;AAAA,cACvC,8CAAC,UAAK,GAAE,aAAY;AAAA,cACpB,8CAAC,UAAK,GAAE,gCAA+B;AAAA;AAAA;AAAA,QACzC;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,SACE,+CAAC,SAAI,WAAU,6JACb;AAAA,mDAAC,SAAI,WAAU,0CACb;AAAA,qDAAC,UAAK,WAAU,0FACd;AAAA,sDAAC,UAAK,WAAU,qDAAoD;AAAA,QAAE;AAAA,SAExE;AAAA,MACA,+CAAC,SAAI,WAAU,cACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,SAAS;AAAA,YACT,MAAK;AAAA,YACL,SAAQ;AAAA,YACT;AAAA;AAAA,QAED;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,SAAS,MAAM;AACb,6BAAe,KAAK;AACpB,kBAAI,QAAS,SAAQ;AAAA,YACvB;AAAA,YACA,MAAK;AAAA,YACL,SAAQ;AAAA,YACT;AAAA;AAAA,QAED;AAAA,SACF;AAAA,OACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,KAAK;AAAA,QAEJ,eAAK,WAAW,IACf,8CAAC,SAAI,WAAU,0CAAyC,0EAExD,IAEA,KAAK,IAAI,CAAC,QACR;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YAGV;AAAA,6DAAC,SAAI,WAAU,+CACb;AAAA,8DAAC,UAAK,WAAU,cAAc,cAAI,MAAK;AAAA,gBACvC,8CAAC,UAAK,WAAU,6FACb,cAAI,OACP;AAAA,iBACF;AAAA,cACA,8CAAC,SAAI,WAAU,4CACZ,cAAI,SACP;AAAA;AAAA;AAAA,UAVK,IAAI;AAAA,QAWX,CACD;AAAA;AAAA,IAEL;AAAA,KACF;AAEJ;;;ACrLA,IAAAC,iBAA4C;AA0FtC,IAAAC,uBAAA;AAhCN,IAAM,yBAAyB;AAC/B,IAAM,mBAAmB;AACzB,IAAM,aAAa;AACnB,IAAM,gBAAgB;AACtB,IAAM,iBAAiB;AACvB,IAAM,qBAAqB;AAE3B,SAAS,iBAAiB;AAAA,EACxB;AAAA,EACA;AACF,GAAgC;AAQ9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,WAAW;AAAA,QACX,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,gBAAgB;AAAA,QAChB,OAAO;AAAA,MACT;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,QAAQ;AAAA,YACR,OAAO;AAAA,cACL,WAAW,eACP,yCACA;AAAA,cACJ,OAAO,eAAe,YAAY;AAAA,cAClC,WAAW,eAAe,SAAY,UAAU,WAAW,GAAG;AAAA,YAChE;AAAA,YACA,SAAQ;AAAA,YACR,OAAO;AAAA,YAEP;AAAA,4DAAC,WAAM,wBAAU;AAAA,cACjB;AAAA,gBAAC;AAAA;AAAA,kBACC,GAAE;AAAA,kBACF,MAAK;AAAA,kBACL,QAAO;AAAA,kBACP,eAAc;AAAA,kBACd,aAAa;AAAA;AAAA,cACf;AAAA;AAAA;AAAA,QACF;AAAA,QACA,8CAAC,WACE,8EACH;AAAA;AAAA;AAAA,EACF;AAEJ;AAEO,IAAM,gBAAgB,CAAC;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV;AACF,MAA0B;AACxB,QAAM,mBAAe,uBAAuB,IAAI;AAChD,QAAM,gBAAY,uBAAsB,IAAI;AAC5C,QAAM,eAAW,uBAAO,CAAC;AACzB,QAAM,sBAAkB,uBAAO,CAAC;AAChC,QAAM,kBAAc,uBAAO,CAAC;AAC5B,QAAM,mBAAe,uBAAsB,IAAI;AAC/C,QAAM,mBAAe,uBAAO,KAAK;AACjC,QAAM,sBAAkB,uBAAO,CAAC;AAChC,QAAM,kBAAc,uBAAsB,IAAI;AAC9C,QAAM,CAAC,cAAc,eAAe,QAAI,yBAAS,CAAC;AAClD,QAAM,CAAC,cAAc,eAAe,QAAI,yBAAS,KAAK;AAMtD,QAAM,CAAC,YAAY,aAAa,QAAI,yBAAS,KAAK;AAGlD,QAAM,kBAAc,uBAAO,QAAQ;AACnC,cAAY,UAAU;AACtB,QAAM,mBAAe,uBAAO,SAAS;AACrC,eAAa,UAAU;AACvB,QAAM,uBAAmB,uBAAO,aAAa;AAC7C,mBAAiB,UAAU;AAC3B,QAAM,iBAAa,uBAAO,OAAO;AACjC,aAAW,UAAU;AAerB,gCAAU,MAAM;AACd,UAAM,KAAK,aAAa;AACxB,QAAI,CAAC,MAAM,OAAO,WAAW,YAAa;AAE1C,UAAM,mBAAmB,MAAM;AAC7B,YAAM,qBAAqB,GAAG,gBAAgB,GAAG;AACjD,YAAM,qBAAqB,GAAG,eAAe,OAAO;AACpD,UAAI,sBAAsB,oBAAoB;AAC5C,gBAAQ;AAAA,UACN;AAAA,QAQF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,MAAM,sBAAsB,gBAAgB;AAClD,WAAO,iBAAiB,UAAU,gBAAgB;AAClD,WAAO,MAAM;AACX,2BAAqB,GAAG;AACxB,aAAO,oBAAoB,UAAU,gBAAgB;AAAA,IACvD;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,gCAAU,MAAM;AACd,UAAM,KAAK,aAAa;AACxB,QAAI,CAAC,GAAI;AAET,UAAM,qBAAqB,CAAC,UAAkB;AAC5C,sBAAgB,UAAU;AAC1B,sBAAgB,KAAK;AAAA,IACvB;AAEA,UAAM,YAAY,MAAM;AACtB,UAAI,YAAY,YAAY,MAAM;AAChC,6BAAqB,YAAY,OAAO;AACxC,oBAAY,UAAU;AAAA,MACxB;AAAA,IACF;AAEA,UAAM,gBAAgB,MAAM;AAC1B,mBAAa,UAAU;AACvB,gBAAU,UAAU;AACpB,mBAAa,UAAU;AACvB,oBAAc,KAAK;AACnB,yBAAmB,CAAC;AAAA,IACtB;AAEA,UAAM,WAAW,MAAM;AACrB,kBAAY,WAAW;AACvB,UAAI,KAAK,IAAI,YAAY,OAAO,IAAI,oBAAoB;AACtD,oBAAY,UAAU;AACtB;AAAA,MACF;AAIA,SAAG,aAAa,YAAY,UAAU;AACtC,UACE,GAAG,aAAa,KAChB,GAAG,aAAa,GAAG,eAAe,GAAG,cACrC;AACA,oBAAY,UAAU;AACtB;AAAA,MACF;AACA,kBAAY,UAAU,sBAAsB,QAAQ;AAAA,IACtD;AAEA,UAAM,oBAAoB,CAAC,MAAoB;AAC7C,UAAI,YAAY,QAAS;AACzB,UAAI,aAAa,YAAY,KAAM;AACnC,gBAAU;AACV,mBAAa,UAAU,EAAE;AACzB,gBAAU,UAAU,EAAE;AACtB,eAAS,UAAU,EAAE;AACrB,sBAAgB,UAAU,YAAY,IAAI;AAC1C,kBAAY,UAAU;AACtB,mBAAa,UAAU;AACvB,oBAAc,IAAI;AAClB,UAAI;AACF,WAAG,kBAAkB,EAAE,SAAS;AAAA,MAClC,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,oBAAoB,CAAC,MAAoB;AAC7C,UAAI,UAAU,YAAY,QAAQ,EAAE,cAAc,aAAa,SAAS;AACtE;AAAA,MACF;AACA,YAAM,aAAa,EAAE,UAAU,UAAU;AACzC,UAAI,CAAC,aAAa,WAAW,KAAK,IAAI,UAAU,IAAI,eAAe;AAGjE;AAAA,MACF;AAEA,YAAM,MAAM,YAAY,IAAI;AAC5B,YAAM,YAAY,EAAE,UAAU,SAAS;AACvC,YAAM,KAAK,KAAK,IAAI,MAAM,gBAAgB,SAAS,CAAC;AACpD,kBAAY,UAAU,YAAY;AAClC,eAAS,UAAU,EAAE;AACrB,sBAAgB,UAAU;AAM1B,UAAI,EAAE,WAAY,GAAE,eAAe;AAEnC,YAAM,QAAQ,GAAG,aAAa;AAC9B,UAAI,SAAS,aAAa,GAAG;AAE3B,qBAAa,UAAU;AACvB;AAAA,UACE,KAAK;AAAA,YACH,KAAK,IAAI,aAAa,eAAe,CAAC,IAAI;AAAA,YAC1C,WAAW;AAAA,UACb;AAAA,QACF;AACA;AAAA,MACF;AAKA,UAAI,aAAa,SAAS;AAGxB,qBAAa,UAAU;AACvB,2BAAmB,CAAC;AAAA,MACtB;AACA,SAAG,aAAa;AAAA,IAClB;AAEA,UAAM,mBAAmB,CAAC,MAAoB;AAC5C,UAAI,UAAU,YAAY,QAAQ,EAAE,cAAc,aAAa,SAAS;AACtE;AAAA,MACF;AACA,YAAM,aAAa,aAAa;AAChC,mBAAa,UAAU;AACvB,gBAAU,UAAU;AACpB,mBAAa,UAAU;AACvB,oBAAc,KAAK;AAEnB,UAAI,CAAC,YAAY;AAGf,YAAI,KAAK,IAAI,YAAY,OAAO,IAAI,oBAAoB;AACtD,oBAAU;AACV,sBAAY,UAAU,sBAAsB,QAAQ;AAAA,QACtD;AACA;AAAA,MACF;AAEA,YAAM,gBAAgB,gBAAgB,WAAW,iBAAiB;AAClE,UAAI,CAAC,eAAe;AAClB,2BAAmB,CAAC;AACpB;AAAA,MACF;AACA,sBAAgB,IAAI;AACpB,yBAAmB,iBAAiB,OAAO;AAC3C,cAAQ,QAAQ,aAAa,QAAQ,CAAC,EACnC,MAAM,CAAC,QAAQ;AAKd,gBAAQ,MAAM,2BAA2B,GAAG;AAAA,MAC9C,CAAC,EACA,QAAQ,MAAM;AACb,wBAAgB,KAAK;AACrB,2BAAmB,CAAC;AAAA,MACtB,CAAC;AAAA,IACL;AAEA,UAAM,sBAAsB,CAAC,MAAoB;AAK/C,UAAI,EAAE,cAAc,aAAa,QAAS;AAC1C,gBAAU;AACV,oBAAc;AAAA,IAChB;AAEA,OAAG,iBAAiB,eAAe,iBAAiB;AACpD,OAAG,iBAAiB,eAAe,mBAAmB,EAAE,SAAS,MAAM,CAAC;AACxE,OAAG,iBAAiB,aAAa,gBAAgB;AACjD,OAAG,iBAAiB,iBAAiB,mBAAmB;AACxD,WAAO,MAAM;AACX,gBAAU;AACV,SAAG,oBAAoB,eAAe,iBAAiB;AACvD,SAAG,oBAAoB,eAAe,iBAAiB;AACvD,SAAG,oBAAoB,aAAa,gBAAgB;AACpD,SAAG,oBAAoB,iBAAiB,mBAAmB;AAAA,IAC7D;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,kBAAkB,eAAe,gBAAgB;AACvD,QAAM,WAAW,KAAK,IAAI,kBAAkB,eAAe,CAAC;AAO5D,QAAM,aAAa,iBAAiB,KAAK,CAAC,gBAAgB,CAAC;AAE3D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,0BAA0B,SAAS;AAAA,MAC9C,KAAK;AAAA,MACL,OAAO;AAAA,QACL,WAAW;AAAA,QACX,oBAAoB;AAAA,QACpB,aAAa;AAAA,MACf;AAAA,MAKA;AAAA,sDAAC,WAEG,wJAEJ;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,YAAY;AAAA,cACZ,SAAS;AAAA,cACT,QAAQ;AAAA,cACR,gBAAgB;AAAA,cAChB,UAAU;AAAA,cACV,YAAY,aAAa,yBAAyB;AAAA,cAClD,YAAY;AAAA,cACZ,OAAO;AAAA,YACT;AAAA,YAEC,4BACC,gBAAgB,EAAE,cAAc,SAAS,CAAC,IAE1C,8CAAC,oBAAiB,cAA4B,UAAoB;AAAA;AAAA,QAEtE;AAAA,QACC;AAAA;AAAA;AAAA,EACH;AAEJ;;;ACraA,IAAAC,eAAiB;AACjB,IAAAC,iBAA4C;AA0HxC,IAAAC,uBAAA;AAnGG,SAAS,UAAU,EAAE,QAAQ,SAAS,YAAY,GAAG,GAAmB;AAC7E,QAAM,eAAW,uBAAgC,IAAI;AACrD,QAAM,gBAAY,uBAAiC,IAAI;AACvD,QAAM,gBAAY,uBAA2B,IAAI;AACjD,QAAM,qBAAiB,uBAAsB,IAAI;AACjD,QAAM,oBAAgB,uBAAO,KAAK;AAClC,QAAM,CAAC,SAAS,UAAU,QAAI,yBAAS,KAAK;AAG5C,gCAAU,MAAM;AACd,QAAI,YAAY;AAChB,kBAAc,UAAU;AAExB,UAAM,UAAU,MAAM;AACpB,UAAI,eAAe,SAAS;AAC1B,6BAAqB,eAAe,OAAO;AAC3C,uBAAe,UAAU;AAAA,MAC3B;AACA,UAAI,UAAU,SAAS;AACrB,mBAAW,SAAS,UAAU,QAAQ,UAAU,GAAG;AACjD,gBAAM,KAAK;AAAA,QACb;AACA,kBAAU,UAAU;AAAA,MACtB;AAAA,IACF;AAEA,UAAM,OAAO,MAAM;AACjB,UAAI,aAAa,cAAc,QAAS;AACxC,YAAM,QAAQ,SAAS;AACvB,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC,SAAS,MAAM,eAAe,MAAM,oBAAoB,CAAC,QAAQ;AACpE,uBAAe,UAAU,sBAAsB,IAAI;AACnD;AAAA,MACF;AACA,YAAM,MAAM,OAAO,WAAW,IAAI;AAClC,UAAI,CAAC,KAAK;AACR,uBAAe,UAAU,sBAAsB,IAAI;AACnD;AAAA,MACF;AACA,aAAO,SAAS,MAAM;AACtB,aAAO,QAAQ,MAAM;AACrB,UAAI,UAAU,OAAO,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AACtD,YAAM,YAAY,IAAI,aAAa,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AACpE,YAAM,WAAO,aAAAC,SAAK,UAAU,MAAM,UAAU,OAAO,UAAU,QAAQ;AAAA,QACnE,mBAAmB;AAAA,MACrB,CAAC;AACD,UAAI,MAAM,MAAM;AACd,sBAAc,UAAU;AACxB,gBAAQ;AACR,eAAO,KAAK,IAAI;AAChB;AAAA,MACF;AACA,qBAAe,UAAU,sBAAsB,IAAI;AAAA,IACrD;AAEA,UAAM,QAAQ,YAAY;AACxB,UAAI;AACF,cAAM,UAAU,MAAM,IAAI,WAAW,QAAQ,QAAQ;AACrD,YAAI,CAAC,SAAS;AACZ,oBAAU,oDAA8C;AACxD;AAAA,QACF;AACA,YAAI,CAAC,UAAU,gBAAgB,CAAC,UAAU,aAAa,cAAc;AACnE;AAAA,YACE;AAAA,UACF;AACA;AAAA,QACF;AACA,cAAM,SAAS,MAAM,UAAU,aAAa,aAAa;AAAA,UACvD,OAAO,EAAE,YAAY,cAAc;AAAA,QACrC,CAAC;AACD,YAAI,WAAW;AACb,qBAAW,SAAS,OAAO,UAAU,EAAG,OAAM,KAAK;AACnD;AAAA,QACF;AACA,kBAAU,UAAU;AACpB,cAAM,QAAQ,SAAS;AACvB,YAAI,CAAC,MAAO;AACZ,cAAM,YAAY;AAClB,cAAM,aAAa,eAAe,MAAM;AACxC,cAAM,MAAM,KAAK;AACjB,YAAI,UAAW;AACf,mBAAW,IAAI;AACf,uBAAe,UAAU,sBAAsB,IAAI;AAAA,MACrD,SAAS,KAAK;AACZ,gBAAQ,MAAM,oCAAoC,GAAG;AACrD,kBAAU,kEAAyD;AAAA,MACrE;AAAA,IACF;AAEA,UAAM;AAEN,WAAO,MAAM;AACX,kBAAY;AACZ,cAAQ;AAAA,IACV;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,OAAO;AAAA,QACL,YAAY;AAAA,QACZ,SAAS;AAAA,QACT,gBAAgB;AAAA,QAChB,UAAU;AAAA,QACV,UAAU;AAAA,MACZ;AAAA,MAGA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,aAAW;AAAA,YACX,KAAK;AAAA,YACL,OAAO,EAAE,QAAQ,QAAQ,WAAW,SAAS,OAAO,OAAO;AAAA;AAAA,QAC7D;AAAA,QACA,8CAAC,YAAO,KAAK,WAAW,OAAO,EAAE,SAAS,OAAO,GAAG;AAAA,QACnD,WACC;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,QAAQ;AAAA,cACR,cAAc;AAAA,cACd,QAAQ;AAAA,cACR,MAAM;AAAA,cACN,eAAe;AAAA,cACf,UAAU;AAAA,cACV,OAAO;AAAA,cACP,KAAK;AAAA,YACP;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EAEJ;AAEJ;;;AC5JA,IAAAC,iBAAmD;AA4C/C,IAAAC,uBAAA;AApCJ,IAAM,iBAAa,8BAA+B,EAAE,UAAU,MAAM,CAAC;AAM9D,IAAM,cAAc,UAAM,2BAAW,UAAU,EAAE;AAejD,IAAM,cAA0C,CAAC;AAAA,EACtD;AAAA,EACA,QAAQ;AAAA,EACR,GAAG;AACL,MAAM;AACJ,QAAM,WACJ,OAAO,WAAW,eAClB,EACG,OAAe,4BAA4B,QAC5C,CAAC,CAAE,OAAe;AAGtB,QAAM,YAAQ,wBAAQ,OAAO,EAAE,SAAS,IAAI,CAAC,QAAQ,CAAC;AAEtD,QAAM,UACJ,gFACG;AAAA;AAAA,KACC,SAAS,aAAa,8CAAC,gBAAa;AAAA,KACxC;AAGF,MAAI,UAAU;AACZ,WACE,8CAAC,WAAW,UAAX,EAAoB,OACnB,wDAAC,gBAAc,GAAG,aAAc,mBAAQ,GAC1C;AAAA,EAEJ;AAEA,SAAO,8CAAC,WAAW,UAAX,EAAoB,OAAe,mBAAQ;AACrD;;;AC5DA,IAAAC,iBAOO;AA4WK,IAAAC,uBAAA;AA1SZ,IAAM,8BAA8B;AACpC,IAAM,8BAA8B;AACpC,IAAM,2BAA2B;AACjC,IAAM,kBAAkB;AACxB,IAAM,cAAc;AACpB,IAAM,mBAAmB;AACzB,IAAM,wBAAwB;AAC9B,IAAM,wCAAwC;AAC9C,IAAM,oCAAoC;AAC1C,IAAM,mBAAmB;AACzB,IAAM,2BAA2B;AACjC,IAAM,+BAA+B;AACrC,IAAM,kBAAkB,aAAa,gBAAgB,MAAM,WAAW;AAiB/D,IAAM,gBAAgB,CAAC;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA,WAAW;AAAA,EACX,kBAAkB;AACpB,MAA0B;AACxB,QAAM,mBAAe,uBAAuB,IAAI;AAChD,QAAM,CAAC,gBAAgB,iBAAiB,QAAI,yBAAS,CAAC;AACtD,QAAM,CAAC,OAAO,QAAQ,QAAI,yBAAS,CAAC;AACpC,QAAM,CAAC,OAAO,QAAQ,QAAI,yBAAS,CAAC;AACpC,QAAM,CAAC,aAAa,cAAc,QAAI,yBAAS,KAAK;AACpD,QAAM,CAAC,aAAa,cAAc,QAAI,yBAAS,KAAK;AACpD,QAAM,oBAAgB,uBAA0B,IAAI;AAOpD,QAAM,CAAC,eAAe,gBAAgB,QAAI;AAAA,IAAS,MACjD,KAAK;AAAA,MACH;AAAA,MACA,MAAM,UAAU,CAAC,SAAS,KAAK,OAAO,QAAQ;AAAA,IAChD;AAAA,EACF;AAOA,QAAM,sBAAkB,uBAAO,QAAQ;AAEvC,QAAM,CAAC,eAAe,gBAAgB,QAAI,yBAAS,IAAI;AAEvD,gCAAU,MAAM;AACd,UAAM,QAAQ,WAAW,MAAM;AAC7B,uBAAiB,KAAK;AAAA,IACxB,GAAG,GAAI;AACP,WAAO,MAAM,aAAa,KAAK;AAAA,EACjC,GAAG,CAAC,CAAC;AAEL,gCAAU,MAAM;AACd,QAAI,aAAa,gBAAgB,SAAS;AACxC,YAAM,MAAM,MAAM,UAAU,CAAC,SAAS,KAAK,OAAO,QAAQ;AAC1D,UAAI,QAAQ,GAAI,kBAAiB,GAAG;AACpC,sBAAgB,UAAU;AAAA,IAC5B;AAAA,EACF,GAAG,CAAC,UAAU,KAAK,CAAC;AAEpB,QAAM,cAAc,KAAK;AAAA,IACvB,KAAK,IAAI,eAAe,CAAC;AAAA,IACzB,KAAK,IAAI,MAAM,SAAS,GAAG,CAAC;AAAA,EAC9B;AAEA,sCAAgB,MAAM;AACpB,UAAM,KAAK,aAAa;AACxB,QAAI,CAAC,GAAI;AACT,UAAM,SAAS,MAAM,kBAAkB,GAAG,WAAW;AACrD,WAAO;AACP,UAAM,WAAW,IAAI,eAAe,MAAM;AAC1C,aAAS,QAAQ,EAAE;AACnB,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,CAAC;AAEL,QAAM,aAAa,iBAAiB;AACpC,QAAM,OAAO,aAAa;AAC1B,QAAM,cAAc,iBAAiB,cAAc;AACnD,QAAM,aAAa,aAAa,cAAc,OAAO;AAErD,QAAM,cAAc,CAAC,cAAsB;AACzC,qBAAiB,SAAS;AAC1B,UAAM,WAAW,MAAM,SAAS;AAChC,QAAI,YAAY,SAAS,OAAO,SAAU,gBAAe,SAAS,EAAE;AAAA,EACtE;AAEA,QAAM,mBAAmB,CAAC,MAAuC;AAC/D,UAAM,QAAQ,EAAE,cAAc,CAAC;AAC/B,QAAI,CAAC,MAAO;AAEZ,QAAI,kBAAkB;AACtB,QAAI,cAAc;AAChB,YAAM,WACJ,aAAa,sBAAsB;AACrC,YAAM,aAAc,EAAE,OAAuB;AAAA,QAC3C;AAAA,MACF;AACA,wBAAkB,CAAC,cAAc,WAAW,aAAa;AAAA,IAC3D;AAEA,kBAAc,UAAU;AAAA,MACtB,OAAO,EAAE;AAAA,MACT,OAAO,MAAM;AAAA,MACb,OAAO,MAAM;AAAA,MACb,YAAY;AAAA,MACZ,QAAQ,MAAM;AAAA,MACd,QAAQ,MAAM;AAAA,MACd,WAAW;AAAA,MACX,WAAW;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAEA,QAAM,kBAAkB,CAAC,MAAuC;AAC9D,UAAM,QAAQ,EAAE,cAAc,CAAC;AAC/B,UAAM,QAAQ,cAAc;AAC5B,QAAI,CAAC,SAAS,CAAC,MAAO;AAEtB,UAAM,QAAQ,MAAM,UAAU,MAAM;AACpC,UAAM,QAAQ,MAAM,UAAU,MAAM;AAEpC,QAAI,CAAC,MAAM,YAAY;AACrB,UACE,KAAK,IAAI,KAAK,IAAI,+BAClB,KAAK,IAAI,KAAK,IAAI,6BAClB;AACA;AAAA,MACF;AAMA,YAAM,iBACJ,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,KAC/B,KAAK,IAAI,KAAK,MAAM,KAAK,IAAI,KAAK,KAAK,iBAAiB;AAC3D,UAAI,gBAAgB;AAClB,cAAM,aAAa;AAAA,MACrB,WAAW,gBAAgB,MAAM,iBAAiB;AAChD,cAAM,aAAa;AAAA,MACrB,OAAO;AACL,cAAM,aAAa;AAAA,MACrB;AAAA,IACF;AAEA,QAAI,MAAM,eAAe,cAAe;AAExC,UAAM,KAAK,EAAE,YAAY,MAAM;AAC/B,QAAI,KAAK,GAAG;AACV,YAAM,aAAa,MAAM,UAAU,MAAM,SAAS;AAClD,YAAM,aAAa,MAAM,UAAU,MAAM,SAAS;AAAA,IACpD;AACA,UAAM,QAAQ,MAAM;AACpB,UAAM,QAAQ,MAAM;AACpB,UAAM,QAAQ,EAAE;AAEhB,QAAI,MAAM,eAAe,KAAK;AAC5B,UAAI,CAAC,YAAa,gBAAe,IAAI;AACrC,YAAM,UAAU,gBAAgB,KAAK,QAAQ;AAC7C,YAAM,QAAQ,gBAAgB,MAAM,SAAS,KAAK,QAAQ;AAC1D,eAAS,WAAW,QAAQ,QAAQ,kBAAkB,KAAK;AAAA,IAC7D,WAAW,cAAc;AACvB,YAAM,YAAY,aAAa,aAAa;AAC5C,UAAI,UAAU;AACd,UAAI,cAAc,OAAQ,WAAU,KAAK,IAAI,GAAG,KAAK;AACrD,UAAI,cAAc,KAAM,WAAU,KAAK,IAAI,GAAG,KAAK;AACnD,YAAM,iBACJ,KAAK,KAAK,OAAO,IACjB,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,IAAI,qBAAqB;AAEvD,UAAI,CAAC,YAAa,gBAAe,IAAI;AACrC,eAAS,cAAc;AACvB,mBAAa,eAAe,gBAAgB,IAAI;AAAA,IAClD;AAEA,QAAI,EAAE,YAAY;AAIhB,QAAE,eAAe;AAAA,IACnB;AAAA,EACF;AAEA,QAAM,UAAU,MAAM;AACpB,UAAM,QAAQ,cAAc;AAC5B,kBAAc,UAAU;AACxB,mBAAe,KAAK;AACpB,mBAAe,KAAK;AAEpB,QAAI,CAAC,OAAO;AACV,eAAS,CAAC;AACV,eAAS,CAAC;AACV;AAAA,IACF;AAEA,QAAI,MAAM,eAAe,KAAK;AAC5B,YAAM,sBACJ,KAAK,IAAI,KAAK,IAAI,+BAClB,KAAK,IAAI,MAAM,SAAS,IAAI;AAC9B,UAAI,qBAAqB;AACvB,cAAM,YACJ,QAAQ,IACJ,KAAK,IAAI,MAAM,SAAS,GAAG,cAAc,CAAC,IAC1C,KAAK,IAAI,GAAG,cAAc,CAAC;AACjC,oBAAY,SAAS;AAAA,MACvB;AAAA,IACF,WAAW,MAAM,eAAe,KAAK;AACnC,YAAM,oBACJ,cAAc,oBAAoB;AACpC,YAAM,4BACJ,cAAc,mBAAmB;AAMnC,YAAM,YAAY,cAAc,aAAa;AAC7C,YAAM,uBACJ,cAAc,SACV,KAAK,IAAI,GAAG,MAAM,SAAS,IAC3B,cAAc,OACZ,KAAK,IAAI,GAAG,CAAC,MAAM,SAAS,IAC5B,KAAK,IAAI,MAAM,SAAS;AAChC,YAAM,oBACJ,KAAK,IAAI,KAAK,IAAI,qBAClB,uBAAuB;AACzB,UAAI,kBAAmB,eAAc,YAAY;AAAA,IACnD;AAEA,aAAS,CAAC;AACV,aAAS,CAAC;AACV,kBAAc,eAAe,GAAG,KAAK;AAAA,EACvC;AASA,QAAM,cAAc,KAAK,IAAI,GAAG,cAAc,QAAQ;AACtD,QAAM,YAAY,KAAK,IAAI,MAAM,SAAS,GAAG,cAAc,QAAQ;AAEnE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,wCAAwC,aAAa,EAAE;AAAA,MAClE,eAAe;AAAA,MACf,YAAY;AAAA,MACZ,aAAa;AAAA,MACb,cAAc;AAAA,MACd,KAAK;AAAA,MAEL;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO;AAAA,YACL,WAAW,cAAc,UAAU;AAAA,YACnC,YAAY,eAAe,gBAAgB,SAAS;AAAA,YACpD,YAAY;AAAA,UACd;AAAA,UAEC,gBAAM,IAAI,CAAC,MAAM,UAAU;AAC1B,gBAAI,QAAQ,eAAe,QAAQ,UAAW,QAAO;AACrD,kBAAM,WAAW,UAAU;AAC3B,kBAAM,iBAAiB,WAAW,QAAQ;AAC1C,kBAAM,WAAW,KAAK,IAAI,QAAQ,WAAW;AAK7C,kBAAM,YAAY,YAAY;AAC9B,mBACE;AAAA,cAAC;AAAA;AAAA,gBACC,WAAW,yCAAyC,iBAAiB,EAAE,IAAI,KAAK,aAAa,EAAE;AAAA,gBAE/F,OAAO;AAAA,kBACL,SAAS,YAAY,IAAI;AAAA,kBACzB,eAAe,YAAY,SAAY;AAAA,kBACvC,WAAW,cAAc,QAAQ,IAAI,kBAAkB,cAAc;AAAA,kBACrE,YACG,YAAY,eAAgB,gBACzB,SACA;AAAA,kBACN,OAAO,GAAG,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAMpB,QAAQ,WAAW,IAAI;AAAA,gBACzB;AAAA,gBAEC,eAAK;AAAA;AAAA,cAlBD,KAAK;AAAA,YAmBZ;AAAA,UAEJ,CAAC;AAAA;AAAA,MACH;AAAA;AAAA,EACF;AAEJ;;;AC7YA,IAAAC,iBAAuB;AAIvB,IAAM,wBAAwB;AAM9B,IAAM,2BAA2B;AAY1B,IAAM,eAAe,CAAC,WAAuB;AAClD,QAAM,eAAW,uBAAwC,IAAI;AAC7D,QAAM,wBAAoB,uBAAO,KAAK;AAEtC,QAAM,eAAe,CAAC,MAA+B;AACnD,UAAM,QAAQ,EAAE,cAAc,CAAC;AAC/B,aAAS,UAAU,QAAQ,EAAE,GAAG,MAAM,SAAS,GAAG,MAAM,QAAQ,IAAI;AAAA,EACtE;AAEA,QAAM,aAAa,CAAC,MAA+B;AACjD,UAAM,QAAQ,SAAS;AACvB,UAAM,QAAQ,EAAE,eAAe,CAAC;AAChC,aAAS,UAAU;AACnB,QAAI,CAAC,SAAS,CAAC,MAAO;AAEtB,UAAM,QAAQ,KAAK,MAAM,MAAM,UAAU,MAAM,GAAG,MAAM,UAAU,MAAM,CAAC;AACzE,QAAI,QAAQ,sBAAuB;AAEnC,sBAAkB,UAAU;AAC5B,eAAW,MAAM;AACf,wBAAkB,UAAU;AAAA,IAC9B,GAAG,wBAAwB;AAC3B,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,MAAM;AACpB,QAAI,kBAAkB,SAAS;AAC7B,wBAAkB,UAAU;AAC5B;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,SAAO,EAAE,SAAS,YAAY,aAAa;AAC7C;;;AC7CA,eAAsB,mBACpB,KACA,QACwB;AACxB,SAAO,eAAe,WAAW,KAAK,MAAM;AAC9C;AAKO,SAAS,gBACd,KACA,WACA,KACA;AACA,QAAM,WAAW,aAAa,SAAS;AACvC,QAAM,gBAAgB,oBAAoB,SAAS;AACnD,QAAM,cAAc,kBAAkB,SAAS;AAE/C,QAAM,UAAU;AAAA,IACd,UAAU;AAAA,MACR;AAAA,QACE,UAAU,IAAI,QAAQ,UAAU;AAAA,QAChC,YAAY,CAAC;AAAA,QACb,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,MAAM;AAAA,EACR;AAEA,QAAM,SAAS,IAAI,UAAU,QAAQ;AACrC,MAAI,QAAQ;AAEV,IAAC,OAAoC,QAAQ,OAAO;AAAA,EACtD,OAAO;AACL,QAAI,UAAU,UAAU;AAAA,MACtB,MAAM;AAAA,MACN,MAAM;AAAA,IACR,CAAC;AAED,QAAI,SAAS;AAAA,MACX,IAAI;AAAA,MACJ,QAAQ;AAAA,QACN,YAAY;AAAA,QACZ,aAAa;AAAA,MACf;AAAA,MACA,OAAO;AAAA,QACL,cAAc;AAAA,QACd,gBAAgB;AAAA,QAChB,cAAc;AAAA,MAChB;AAAA,MACA,QAAQ;AAAA,MACR,MAAM;AAAA,IACR,CAAC;AAED,QAAI,SAAS;AAAA,MACX,IAAI;AAAA,MACJ,QAAQ;AAAA,QACN,YAAY;AAAA,QACZ,aAAa;AAAA,MACf;AAAA,MACA,OAAO;AAAA,QACL,cAAc;AAAA;AAAA,QACd,cAAc;AAAA,MAChB;AAAA,MACA,QAAQ;AAAA,MACR,MAAM;AAAA,IACR,CAAC;AAAA,EACH;AACF;AAEO,SAAS,iBAAiB,KAAU,WAAmB;AAC5D,QAAM,WAAW,aAAa,SAAS;AACvC,QAAM,gBAAgB,oBAAoB,SAAS;AACnD,QAAM,cAAc,kBAAkB,SAAS;AAE/C,MAAI,IAAI,SAAS,WAAW,EAAG,KAAI,YAAY,WAAW;AAC1D,MAAI,IAAI,SAAS,aAAa,EAAG,KAAI,YAAY,aAAa;AAC9D,MAAI,IAAI,UAAU,QAAQ,EAAG,KAAI,aAAa,QAAQ;AACxD;;;ACnDA,SAAS,SAAS,SAAiB,MAAsB;AACvD,MAAI,KAAK,WAAW,SAAS,KAAK,KAAK,WAAW,UAAU,GAAG;AAC7D,WAAO;AAAA,EACT;AAEA,MAAI,YAAY,QAAQ,KAAK;AAC7B,SAAO,UAAU,SAAS,GAAG,GAAG;AAC9B,gBAAY,UAAU,MAAM,GAAG,EAAE;AAAA,EACnC;AAEA,MAAI,YAAY,KAAK,KAAK;AAC1B,MAAI,CAAC,UAAU,WAAW,GAAG,GAAG;AAC9B,gBAAY,IAAI,SAAS;AAAA,EAC3B;AAGA,QAAM,iBAAiB,UAAU,SAAS,SAAS;AACnD,QAAM,mBACJ,UAAU,WAAW,UAAU,KAAK,cAAc;AAEpD,MAAI,kBAAkB,kBAAkB;AACtC,UAAM,eAAe,UAAU,MAAM,CAAC;AACtC,WAAO,GAAG,SAAS,GAAG,YAAY;AAAA,EACpC;AAEA,SAAO,GAAG,SAAS,GAAG,SAAS;AACjC;AAUA,SAAS,mBAAmB,MAAyC;AACnE,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,QAAM,QACJ,OAGA;AACF,SAAO,QAAQ,IAAI,KAAK;AAC1B;AAwBO,SAAS,iBACd,SACkB;AAClB,QAAM,aAAa,MACjB,mBAAmB,MAAM,KACxB,IAAI,OAAO,GAAG,cACf,QAAQ;AAEV,QAAM,WAAW,MACf,mBAAmB,IAAI,KACtB,IAAI,OAAO,GAAG,gBACf,QAAQ;AAEV,SAAO;AAAA,IACL,IAAI,UAAkB;AACpB,aAAO,WAAW;AAAA,IACpB;AAAA,IAEA,QAAQ,CAAC,SACP,IAAI,QAAQ,QAAQ;AAAA,MAClB,QAAQ;AAAA,MACR,KAAK,SAAS,WAAW,GAAG,IAAI;AAAA,IAClC,CAAC;AAAA,IAEH,KAAK,CAAC,SACJ,IAAI,QAAQ,QAAQ;AAAA,MAClB,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,QAAQ;AAAA,MACR,KAAK,SAAS,WAAW,GAAG,IAAI;AAAA,IAClC,CAAC;AAAA,IAEH,cAAc,CAAC,OAAO,YAAY,CAAC,MACjC,IAAI,QAAQ,QAAQ;AAAA,MAClB,MAAM,EAAE,OAAO,UAAU;AAAA,MACzB,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,QAAQ;AAAA,MACR,KAAK,SAAS,WAAW,GAAG,UAAU;AAAA,IACxC,CAAC;AAAA,IAEH,OAAO,CAAC,MAAM,SACZ,IAAI,QAAQ,QAAQ;AAAA,MAClB;AAAA,MACA,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,QAAQ;AAAA,MACR,KAAK,SAAS,WAAW,GAAG,IAAI;AAAA,IAClC,CAAC;AAAA,IAEH,MAAM,CAAC,MAAM,SACX,IAAI,QAAQ,QAAQ;AAAA,MAClB;AAAA,MACA,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,QAAQ;AAAA,MACR,KAAK,SAAS,WAAW,GAAG,IAAI;AAAA,IAClC,CAAC;AAAA,IAEH,IAAI,QAA4B;AAC9B,aAAO,SAAS;AAAA,IAClB;AAAA,EACF;AACF;;;ACuDO,SAAS,gBACd,SACgE;AAChE,QAAM,eAAe,QAAQ;AAE7B,MAAI,KAAuB;AAE3B,QAAM,gBAAgB,oBAAI,IAA8C;AAKxE,QAAM,kBAAkB,oBAAI,IAAiC;AAC7D,MAAI,mBAAyD;AAC7D,MAAI,iBAAiB;AACrB,MAAI,eAAe;AACnB,MAAI,SAA6B;AACjC,QAAM,kBAAkB,oBAAI,IAA0C;AAEtE,QAAM,YAAY,CAAC,SAA6B;AAC9C,QAAI,WAAW,KAAM;AACrB,aAAS;AACT,eAAW,MAAM,gBAAiB,IAAG,MAAM;AAAA,EAC7C;AAEA,QAAM,WAAW,MAAc,QAAQ,WAAW,QAAQ,IAAI,SAAS;AAEvE,QAAM,aAAa,CACjB,QACA,cACG;AACH,QAAI,IAAI,eAAe,UAAU,MAAM;AAGrC,SAAG,KAAK,KAAK,UAAU,EAAE,QAAQ,CAAC,YAAsB,GAAG,UAAU,CAAC,CAAC;AAAA,IACzE;AAAA,EACF;AAEA,QAAM,oBAAoB,MAAM;AAC9B,QAAI,iBAAkB,cAAa,gBAAgB;AACnD,uBAAmB,WAAW,MAAM;AAClC,uBAAiB,KAAK,IAAI,iBAAiB,GAAG,GAAK;AACnD,cAAQ;AAAA,IACV,GAAG,cAAc;AAAA,EACnB;AAEA,QAAM,UAAU,YAA2B;AACzC,QACE,IAAI,eAAe,UAAU,QAC7B,IAAI,eAAe,UAAU,cAC7B,cACA;AACA;AAAA,IACF;AACA,mBAAe;AACf,cAAU,YAAY;AAEtB,QAAI;AACF,YAAM,QAAQ,SAAS;AACvB,UAAI,CAAC,OAAO;AACV,gBAAQ;AAAA,UACN;AAAA,QACF;AACA,uBAAe;AACf,kBAAU,QAAQ;AAClB;AAAA,MACF;AAEA,UAAI,aAAqC,CAAC;AAC1C,UAAI,2BAA2B,KAAK,QAAQ,eAAe,MAAM;AAC/D,cAAM,iBAAiB,MAAM,QAAQ,IAAI;AAAA,UACvC,QAAQ,cAAc;AAAA,QACxB;AACA,qBAAa,EAAE,QAAQ,eAAe,KAAK,OAAO;AAAA,MACpD,WAAW,QAAQ,UAAU;AAC3B,cAAM,SAAS,QAAQ,SAAS,WAAW,SAAS,IAChD,QAAQ,SAAS,MAAM,CAAC,IACxB,QAAQ;AACZ,qBAAa,EAAE,OAAO,OAAO;AAAA,MAC/B,WAAW,QAAQ,gBAAgB,OAAO;AAAA,MAG1C,OAAO;AACL,gBAAQ,KAAK,6CAA6C;AAC1D,uBAAe;AACf,kBAAU,QAAQ;AAClB;AAAA,MACF;AAEA,YAAM,SAAS,IAAI,gBAAgB,EAAE,GAAG,QAAQ,OAAO,GAAG,WAAW,CAAC;AACtE,YAAM,QAAQ,OAAO,SAAS;AAC9B,WAAK,IAAI,UAAU,QAAQ,GAAG,KAAK,IAAI,KAAK,KAAK,KAAK;AAEtD,SAAG,SAAS,MAAM;AAChB,uBAAe;AACf,kBAAU,MAAM;AAChB,yBAAiB;AACjB,YAAI,cAAc;AAChB,qBAAW,aAAa,cAAc,KAAK,GAAG;AAC5C,uBAAW,aAAa,SAAS;AAAA,UACnC;AAAA,QACF;AAAA,MACF;AAEA,SAAG,YAAY,CAAC,UAAU;AACxB,YAAI;AACF,gBAAM,UAAU,KAAK,MAAM,MAAM,IAAI;AACrC,cAAI,cAAc;AAChB,kBAAM,YAAY,QAAQ,YAAY;AACtC,gBAAI,OAAO,cAAc,UAAU;AACjC,oBAAM,YAAY,cAAc,IAAI,SAAS;AAC7C,kBAAI,WAAW;AACb,2BAAW,MAAM,UAAW,IAAG,OAAO;AAAA,cACxC;AAAA,YACF;AAAA,UACF;AAIA,qBAAW,MAAM,gBAAiB,IAAG,OAAO;AAAA,QAC9C,SAAS,KAAK;AACZ,kBAAQ,MAAM,iCAAiC,GAAG;AAAA,QACpD;AAAA,MACF;AAEA,SAAG,UAAU,MAAM;AACjB,uBAAe;AACf,kBAAU,QAAQ;AAClB,0BAAkB;AAAA,MACpB;AAEA,SAAG,UAAU,CAAC,QAAQ;AACpB,gBAAQ,MAAM,eAAe,GAAG;AAChC,uBAAe;AACf,YAAI,MAAM;AAAA,MACZ;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,MAAM,wCAAwC,GAAG;AACzD,qBAAe;AACf,gBAAU,QAAQ;AAClB,wBAAkB;AAAA,IACpB;AAAA,EACF;AAEA,QAAM,aAAa,MAAM;AACvB,QAAI,kBAAkB;AACpB,mBAAa,gBAAgB;AAC7B,yBAAmB;AAAA,IACrB;AACA,QAAI,IAAI;AACN,SAAG,UAAU;AACb,SAAG,MAAM;AACT,WAAK;AAAA,IACP;AACA,cAAU,QAAQ;AAAA,EACpB;AAEA,QAAM,YAAY,MAA0B;AAE5C,QAAM,iBAAiB,CACrB,aACiB;AACjB,oBAAgB,IAAI,QAAQ;AAC5B,aAAS,MAAM;AACf,WAAO,MAAM;AACX,sBAAgB,OAAO,QAAQ;AAAA,IACjC;AAAA,EACF;AAEA,QAAM,YAAY,CAChB,WACA,aACiB;AACjB,UAAM,eAAe,CAAC,cAAc,IAAI,SAAS;AACjD,QAAI,aAAc,eAAc,IAAI,WAAW,oBAAI,IAAI,CAAC;AACxD,kBAAc,IAAI,SAAS,GAAG,IAAI,QAAQ;AAC1C,QAAI,aAAc,YAAW,aAAa,SAAS;AACnD,YAAQ;AAER,WAAO,MAAM;AACX,YAAM,MAAM,cAAc,IAAI,SAAS;AACvC,UAAI,CAAC,IAAK;AACV,UAAI,OAAO,QAAQ;AACnB,UAAI,IAAI,SAAS,GAAG;AAClB,sBAAc,OAAO,SAAS;AAC9B,mBAAW,eAAe,SAAS;AAAA,MACrC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YAAY,CAAC,aAAwD;AACzE,oBAAgB,IAAI,QAAQ;AAC5B,YAAQ;AACR,WAAO,MAAM;AACX,sBAAgB,OAAO,QAAQ;AAAA,IACjC;AAAA,EACF;AAEA,MAAI,cAAc;AAChB,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,SAAS,YAAY,WAAW,WAAW,eAAe;AACrE;;;A1CraA,IAAO,cAAQ;","names":["Map","import_class_variance_authority","React","import_jsx_runtime","Content","import_react","import_jsx_runtime","React","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","ref","import_react","import_jsx_runtime","import_react","import_jsx_runtime","resolveHeightToPixels","import_react","import_jsx_runtime","UIEvent","GeolocationEvent","GlobalEvent","import_react","import_react","import_react","import_react","import_jsx_runtime","import_react_maplibre","import_react","import_jsx_runtime","import_react_maplibre","import_react","import_jsx_runtime","import_react_maplibre","import_jsx_runtime","import_react_maplibre","import_jsx_runtime","import_react_maplibre","import_react","import_jsx_runtime","mapLibreChildren","React","menuContentFromChildren","MapLibre","Map","import_react","React","Map","QRCodeStyling","loadImage","jsQR","import_react","import_jsx_runtime","MOCK_ACHIEVEMENTS","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_jsqr","import_react","import_jsx_runtime","jsQR","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react"]}