@cloudparse/up-miniapps-sdk 0.6.4 → 0.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1143,6 +1143,25 @@ declare const useMockLocation: () => MockLocationContextType | null;
1143
1143
  */
1144
1144
  declare function renderMap(containerId: string, props?: MapProps): react_dom_client.Root;
1145
1145
 
1146
+ interface PullToRefreshIndicatorState {
1147
+ /** 0 (no pull) to 1 (at/past the trigger threshold). */
1148
+ progress: number;
1149
+ isRefreshing: boolean;
1150
+ }
1151
+ interface PullToRefreshProps {
1152
+ onRefresh: () => Promise<void> | void;
1153
+ children: React__default.ReactNode;
1154
+ className?: string;
1155
+ disabled?: boolean;
1156
+ /** Visual (post-resistance) px of pull required to trigger a refresh. Default 64. */
1157
+ pullThreshold?: number;
1158
+ /** Visual cap so the indicator never drags further than this. Default 96. */
1159
+ maxPull?: number;
1160
+ /** Fully replaces the default indicator — e.g. a brand-specific spinner/logo. */
1161
+ renderIndicator?: (state: PullToRefreshIndicatorState) => React__default.ReactNode;
1162
+ }
1163
+ declare const PullToRefresh: ({ onRefresh, children, className, disabled, pullThreshold, maxPull, renderIndicator, }: PullToRefreshProps) => React__default.JSX.Element;
1164
+
1146
1165
  interface QRScannerProps {
1147
1166
  /** Called once with the decoded string the moment a QR code is detected. Scanning stops immediately after. */
1148
1167
  onScan: (data: string) => void;
@@ -1806,4 +1825,4 @@ interface BroadcastWsServiceClient<TMessage extends WsMessage = WsMessage> {
1806
1825
  declare function createWsService<TMessage extends WsMessage = WsMessage>(options: CreateChannelWsServiceOptions<TMessage>): WsServiceClient<TMessage>;
1807
1826
  declare function createWsService<TMessage extends WsMessage = WsMessage>(options: CreateBroadcastWsServiceOptions<TMessage>): BroadcastWsServiceClient<TMessage>;
1808
1827
 
1809
- export { type ApiServiceClient, type BridgeMessageType, BridgeMocker, type BridgeMockerProps, type BroadcastWsServiceClient, type CenterCallbackParams, type CreateApiServiceOptions, type CreateBroadcastWsServiceOptions, type CreateChannelWsServiceOptions, type CreateWsServiceOptions, type CustomControl, DebugConsole, type DebugConsoleProps, type DeclarativeJourneyOptions, type DrawerState, type EtaData, type FidelityTransactionTypeType, type FlyToParams, GeolocationEvent, GlobalEvent, type HapticStyleType, type IBridgeEnvelope, type IContextState, type IEdgeInsets, type IFidelityBalance, type IFidelityHistoryParams, type IFidelityTransaction, type IGenerateQrCodeOptions, type IInitializationOptions, type IInitializationResponse, type ILocationData, type INetworkOptions, type INetworkResponse, type IPaymentRequest, type IPickImageResult, type ISaveImageResult, type IUserProfile, type LiveRoutingOptions, type LiveRoutingResult, type LocationStreamConfig, Map, MapControls, MapControlsContext, type MapControlsProps, type MapControlsState, type MapInsets, MapMenu, MapMenuDivider, type MapMenuDividerProps, MapMenuFooter, type MapMenuFooterProps, MapMenuItem, type MapMenuItemProps, type MapMenuProps, MapMenuTitle, type MapMenuTitleProps, type MapProps, type MenuItem, MiniAppSDK, MockLocationContext, type MockLocationContextType, type NetworkMethodType, type POI, QRScanner, type QRScannerProps, RouteLayer, type RouteLayerProps, RouteRequest, RouteResponse, RouteStep, type SDKEvent, SDKMapProvider, SDKProvider, type SDKProviderProps, type ScrollConfig, type StreamAccelerometerData, type StreamHeadingData, type StreamLocationData, type StreamUpdatePayload, type SwipeAxisPriority, SwipeCarousel, type SwipeCarouselItem, type SwipeCarouselProps, type SwipeCarouselVerticalDragConfig, UIEvent, type UseJourneyOptions, type UseJourneyResult, type UserLocationState, type WsConnectionStatus, type WsMessage, type WsServiceClient, createApiService, createWsService, sdk as default, renderMap, sdk, useIsMocked, useJourney, useLiveRouting, useMapControls, useMockLocation, useRoute, useTrimmedRoute, useUserLocation };
1828
+ export { type ApiServiceClient, type BridgeMessageType, BridgeMocker, type BridgeMockerProps, type BroadcastWsServiceClient, type CenterCallbackParams, type CreateApiServiceOptions, type CreateBroadcastWsServiceOptions, type CreateChannelWsServiceOptions, type CreateWsServiceOptions, type CustomControl, DebugConsole, type DebugConsoleProps, type DeclarativeJourneyOptions, type DrawerState, type EtaData, type FidelityTransactionTypeType, type FlyToParams, GeolocationEvent, GlobalEvent, type HapticStyleType, type IBridgeEnvelope, type IContextState, type IEdgeInsets, type IFidelityBalance, type IFidelityHistoryParams, type IFidelityTransaction, type IGenerateQrCodeOptions, type IInitializationOptions, type IInitializationResponse, type ILocationData, type INetworkOptions, type INetworkResponse, type IPaymentRequest, type IPickImageResult, type ISaveImageResult, type IUserProfile, type LiveRoutingOptions, type LiveRoutingResult, type LocationStreamConfig, Map, MapControls, MapControlsContext, type MapControlsProps, type MapControlsState, type MapInsets, MapMenu, MapMenuDivider, type MapMenuDividerProps, MapMenuFooter, type MapMenuFooterProps, MapMenuItem, type MapMenuItemProps, type MapMenuProps, MapMenuTitle, type MapMenuTitleProps, type MapProps, type MenuItem, MiniAppSDK, MockLocationContext, type MockLocationContextType, type NetworkMethodType, type POI, PullToRefresh, type PullToRefreshIndicatorState, type PullToRefreshProps, QRScanner, type QRScannerProps, RouteLayer, type RouteLayerProps, RouteRequest, RouteResponse, RouteStep, type SDKEvent, SDKMapProvider, SDKProvider, type SDKProviderProps, type ScrollConfig, type StreamAccelerometerData, type StreamHeadingData, type StreamLocationData, type StreamUpdatePayload, type SwipeAxisPriority, SwipeCarousel, type SwipeCarouselItem, type SwipeCarouselProps, type SwipeCarouselVerticalDragConfig, UIEvent, type UseJourneyOptions, type UseJourneyResult, type UserLocationState, type WsConnectionStatus, type WsMessage, type WsServiceClient, createApiService, createWsService, sdk as default, renderMap, sdk, useIsMocked, useJourney, useLiveRouting, useMapControls, useMockLocation, useRoute, useTrimmedRoute, useUserLocation };
package/dist/index.d.ts CHANGED
@@ -1143,6 +1143,25 @@ declare const useMockLocation: () => MockLocationContextType | null;
1143
1143
  */
1144
1144
  declare function renderMap(containerId: string, props?: MapProps): react_dom_client.Root;
1145
1145
 
1146
+ interface PullToRefreshIndicatorState {
1147
+ /** 0 (no pull) to 1 (at/past the trigger threshold). */
1148
+ progress: number;
1149
+ isRefreshing: boolean;
1150
+ }
1151
+ interface PullToRefreshProps {
1152
+ onRefresh: () => Promise<void> | void;
1153
+ children: React__default.ReactNode;
1154
+ className?: string;
1155
+ disabled?: boolean;
1156
+ /** Visual (post-resistance) px of pull required to trigger a refresh. Default 64. */
1157
+ pullThreshold?: number;
1158
+ /** Visual cap so the indicator never drags further than this. Default 96. */
1159
+ maxPull?: number;
1160
+ /** Fully replaces the default indicator — e.g. a brand-specific spinner/logo. */
1161
+ renderIndicator?: (state: PullToRefreshIndicatorState) => React__default.ReactNode;
1162
+ }
1163
+ declare const PullToRefresh: ({ onRefresh, children, className, disabled, pullThreshold, maxPull, renderIndicator, }: PullToRefreshProps) => React__default.JSX.Element;
1164
+
1146
1165
  interface QRScannerProps {
1147
1166
  /** Called once with the decoded string the moment a QR code is detected. Scanning stops immediately after. */
1148
1167
  onScan: (data: string) => void;
@@ -1806,4 +1825,4 @@ interface BroadcastWsServiceClient<TMessage extends WsMessage = WsMessage> {
1806
1825
  declare function createWsService<TMessage extends WsMessage = WsMessage>(options: CreateChannelWsServiceOptions<TMessage>): WsServiceClient<TMessage>;
1807
1826
  declare function createWsService<TMessage extends WsMessage = WsMessage>(options: CreateBroadcastWsServiceOptions<TMessage>): BroadcastWsServiceClient<TMessage>;
1808
1827
 
1809
- export { type ApiServiceClient, type BridgeMessageType, BridgeMocker, type BridgeMockerProps, type BroadcastWsServiceClient, type CenterCallbackParams, type CreateApiServiceOptions, type CreateBroadcastWsServiceOptions, type CreateChannelWsServiceOptions, type CreateWsServiceOptions, type CustomControl, DebugConsole, type DebugConsoleProps, type DeclarativeJourneyOptions, type DrawerState, type EtaData, type FidelityTransactionTypeType, type FlyToParams, GeolocationEvent, GlobalEvent, type HapticStyleType, type IBridgeEnvelope, type IContextState, type IEdgeInsets, type IFidelityBalance, type IFidelityHistoryParams, type IFidelityTransaction, type IGenerateQrCodeOptions, type IInitializationOptions, type IInitializationResponse, type ILocationData, type INetworkOptions, type INetworkResponse, type IPaymentRequest, type IPickImageResult, type ISaveImageResult, type IUserProfile, type LiveRoutingOptions, type LiveRoutingResult, type LocationStreamConfig, Map, MapControls, MapControlsContext, type MapControlsProps, type MapControlsState, type MapInsets, MapMenu, MapMenuDivider, type MapMenuDividerProps, MapMenuFooter, type MapMenuFooterProps, MapMenuItem, type MapMenuItemProps, type MapMenuProps, MapMenuTitle, type MapMenuTitleProps, type MapProps, type MenuItem, MiniAppSDK, MockLocationContext, type MockLocationContextType, type NetworkMethodType, type POI, QRScanner, type QRScannerProps, RouteLayer, type RouteLayerProps, RouteRequest, RouteResponse, RouteStep, type SDKEvent, SDKMapProvider, SDKProvider, type SDKProviderProps, type ScrollConfig, type StreamAccelerometerData, type StreamHeadingData, type StreamLocationData, type StreamUpdatePayload, type SwipeAxisPriority, SwipeCarousel, type SwipeCarouselItem, type SwipeCarouselProps, type SwipeCarouselVerticalDragConfig, UIEvent, type UseJourneyOptions, type UseJourneyResult, type UserLocationState, type WsConnectionStatus, type WsMessage, type WsServiceClient, createApiService, createWsService, sdk as default, renderMap, sdk, useIsMocked, useJourney, useLiveRouting, useMapControls, useMockLocation, useRoute, useTrimmedRoute, useUserLocation };
1828
+ export { type ApiServiceClient, type BridgeMessageType, BridgeMocker, type BridgeMockerProps, type BroadcastWsServiceClient, type CenterCallbackParams, type CreateApiServiceOptions, type CreateBroadcastWsServiceOptions, type CreateChannelWsServiceOptions, type CreateWsServiceOptions, type CustomControl, DebugConsole, type DebugConsoleProps, type DeclarativeJourneyOptions, type DrawerState, type EtaData, type FidelityTransactionTypeType, type FlyToParams, GeolocationEvent, GlobalEvent, type HapticStyleType, type IBridgeEnvelope, type IContextState, type IEdgeInsets, type IFidelityBalance, type IFidelityHistoryParams, type IFidelityTransaction, type IGenerateQrCodeOptions, type IInitializationOptions, type IInitializationResponse, type ILocationData, type INetworkOptions, type INetworkResponse, type IPaymentRequest, type IPickImageResult, type ISaveImageResult, type IUserProfile, type LiveRoutingOptions, type LiveRoutingResult, type LocationStreamConfig, Map, MapControls, MapControlsContext, type MapControlsProps, type MapControlsState, type MapInsets, MapMenu, MapMenuDivider, type MapMenuDividerProps, MapMenuFooter, type MapMenuFooterProps, MapMenuItem, type MapMenuItemProps, type MapMenuProps, MapMenuTitle, type MapMenuTitleProps, type MapProps, type MenuItem, MiniAppSDK, MockLocationContext, type MockLocationContextType, type NetworkMethodType, type POI, PullToRefresh, type PullToRefreshIndicatorState, type PullToRefreshProps, QRScanner, type QRScannerProps, RouteLayer, type RouteLayerProps, RouteRequest, RouteResponse, RouteStep, type SDKEvent, SDKMapProvider, SDKProvider, type SDKProviderProps, type ScrollConfig, type StreamAccelerometerData, type StreamHeadingData, type StreamLocationData, type StreamUpdatePayload, type SwipeAxisPriority, SwipeCarousel, type SwipeCarouselItem, type SwipeCarouselProps, type SwipeCarouselVerticalDragConfig, UIEvent, type UseJourneyOptions, type UseJourneyResult, type UserLocationState, type WsConnectionStatus, type WsMessage, type WsServiceClient, createApiService, createWsService, sdk as default, renderMap, sdk, useIsMocked, useJourney, useLiveRouting, useMapControls, useMockLocation, useRoute, useTrimmedRoute, useUserLocation };
package/dist/index.js CHANGED
@@ -202,11 +202,61 @@ var Bridge = class {
202
202
  }
203
203
  }
204
204
  /**
205
- * Internal handler for mock message processing, overrideable in test environments
205
+ * Internal handler for mock message processing, overrideable in test environments.
206
+ *
207
+ * Every mini-app that calls a bridge method also has to run standalone in a plain
208
+ * browser (dev, and this vault's own Chrome-based verification) with no native shell
209
+ * attached — `isNative()` is false, so `send()` never round-trips through the real
210
+ * host at all. Before this switch existed, EVERY unhandled type here resolved with
211
+ * plain `undefined` (see the `default` branch below), which silently broke any caller
212
+ * checking a result shape like `{success: boolean}` — `undefined?.success` reads as
213
+ * `false`, not "no answer", so e.g. `sdk.media.saveImage()` looked like a real
214
+ * permission-denied rejection in the browser instead of "there's no native shell
215
+ * here to ask." Add a `case` here — instead of leaving every mini-app to
216
+ * individually special-case "what happens when I call this with no shell attached" —
217
+ * whenever a bridge method's mock behavior should be more than a no-op.
206
218
  */
207
219
  handleMockMessage(type, payload) {
208
- console.warn(`[Bridge] Mock mode active: Unhandled message type ${type}`);
209
- return Promise.resolve();
220
+ switch (type) {
221
+ case "SAVE_IMAGE":
222
+ return this.mockSaveImage(
223
+ payload
224
+ );
225
+ default:
226
+ console.warn(
227
+ `[Bridge] Mock mode active: Unhandled message type ${type}`
228
+ );
229
+ return Promise.resolve();
230
+ }
231
+ }
232
+ /**
233
+ * Standalone-browser stand-in for the native `SAVE_IMAGE` handler: triggers a real
234
+ * browser download (an `<a download>` click) instead of writing to a device photo
235
+ * library, which doesn't exist here. Resolves `{success: true}` on a real trigger so
236
+ * every mini-app's own `result?.success` check gets the same shape/semantics as the
237
+ * real native response — no per-app "am I in mock mode" branching needed. Consumers
238
+ * can still keep their own `catch` fallback for the genuinely different case of a
239
+ * native shell that's missing its WebView bridge (see `sendOnce`'s own rejection
240
+ * path) — that's a real native edge case, not mocking, and this method never runs
241
+ * for it (`send()` only reaches `handleMockMessage` when `!isNative()`).
242
+ */
243
+ mockSaveImage(payload) {
244
+ if (typeof document === "undefined") {
245
+ return Promise.resolve({ success: false });
246
+ }
247
+ try {
248
+ const href = payload.base64.startsWith("data:") ? payload.base64 : `data:image/png;base64,${payload.base64}`;
249
+ const link = document.createElement("a");
250
+ link.href = href;
251
+ link.download = payload.filename ? `${payload.filename}.png` : "image.png";
252
+ document.body.appendChild(link);
253
+ link.click();
254
+ link.remove();
255
+ return Promise.resolve({ success: true });
256
+ } catch (err) {
257
+ console.warn("[Bridge] Mock SAVE_IMAGE download failed:", err);
258
+ return Promise.resolve({ success: false });
259
+ }
210
260
  }
211
261
  sendOnce(type, payload, timeoutMs) {
212
262
  return new Promise((resolve, reject) => {
@@ -3331,7 +3381,7 @@ async function generateQrCode(data, options = {}) {
3331
3381
  const size = options.size ?? DEFAULT_SIZE;
3332
3382
  const color = options.color ?? DEFAULT_COLOR;
3333
3383
  const backgroundColor = options.backgroundColor ?? DEFAULT_BACKGROUND;
3334
- const label = options.label || (options.appName ? `UP - ${options.appName}` : "");
3384
+ const label = options.label || (options.appName ? `${options.appName} by UP` : "");
3335
3385
  const qr = new QRCodeStyling({
3336
3386
  backgroundOptions: {
3337
3387
  color: backgroundColor,
@@ -3490,7 +3540,7 @@ var loadImage2 = (src) => new Promise((resolve, reject) => {
3490
3540
  });
3491
3541
 
3492
3542
  // package.json
3493
- var version = "0.6.4";
3543
+ var version = "0.6.7";
3494
3544
 
3495
3545
  // src/sdk.ts
3496
3546
  function deepFreeze(obj) {
@@ -4636,18 +4686,271 @@ var DebugConsole = ({
4636
4686
  ] });
4637
4687
  };
4638
4688
 
4639
- // src/components/QRScanner.tsx
4640
- import jsQR2 from "jsqr";
4689
+ // src/components/PullToRefresh.tsx
4641
4690
  import { useEffect as useEffect10, useRef as useRef10, useState as useState11 } from "react";
4642
4691
  import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
4643
- function QRScanner({ onScan, onError, className = "" }) {
4644
- const videoRef = useRef10(null);
4645
- const canvasRef = useRef10(null);
4646
- const streamRef = useRef10(null);
4647
- const tickRequestRef = useRef10(null);
4648
- const hasScannedRef = useRef10(false);
4649
- const [isReady, setIsReady] = useState11(false);
4692
+ var DEFAULT_PULL_THRESHOLD = 64;
4693
+ var DEFAULT_MAX_PULL = 96;
4694
+ var RESISTANCE = 0.5;
4695
+ var DRAG_DEADZONE = 8;
4696
+ var FLING_FRICTION = 0.95;
4697
+ var FLING_MIN_VELOCITY = 0.02;
4698
+ function DefaultIndicator({
4699
+ progress,
4700
+ isRefreshing
4701
+ }) {
4702
+ return /* @__PURE__ */ jsxs14(
4703
+ "div",
4704
+ {
4705
+ style: {
4706
+ alignItems: "center",
4707
+ background: "rgba(24, 24, 27, 0.9)",
4708
+ border: "1px solid rgba(255, 255, 255, 0.1)",
4709
+ borderRadius: 9999,
4710
+ boxShadow: "0 4px 16px -4px rgba(0, 0, 0, 0.5)",
4711
+ display: "flex",
4712
+ height: 28,
4713
+ justifyContent: "center",
4714
+ width: 28
4715
+ },
4716
+ children: [
4717
+ /* @__PURE__ */ jsxs14(
4718
+ "svg",
4719
+ {
4720
+ height: 14,
4721
+ style: {
4722
+ animation: isRefreshing ? "up-sdk-ptr-spin 0.8s linear infinite" : void 0,
4723
+ color: isRefreshing ? "#a78bfa" : "#a1a1aa",
4724
+ transform: isRefreshing ? void 0 : `rotate(${progress * 360}deg)`
4725
+ },
4726
+ viewBox: "0 0 24 24",
4727
+ width: 14,
4728
+ children: [
4729
+ /* @__PURE__ */ jsx18("title", { children: "Refreshing" }),
4730
+ /* @__PURE__ */ jsx18(
4731
+ "path",
4732
+ {
4733
+ d: "M21 12a9 9 0 1 1-2.64-6.36",
4734
+ fill: "none",
4735
+ stroke: "currentColor",
4736
+ strokeLinecap: "round",
4737
+ strokeWidth: 2.5
4738
+ }
4739
+ )
4740
+ ]
4741
+ }
4742
+ ),
4743
+ /* @__PURE__ */ jsx18("style", { children: "@keyframes up-sdk-ptr-spin { to { transform: rotate(360deg); } }" })
4744
+ ]
4745
+ }
4746
+ );
4747
+ }
4748
+ var PullToRefresh = ({
4749
+ onRefresh,
4750
+ children,
4751
+ className = "",
4752
+ disabled = false,
4753
+ pullThreshold = DEFAULT_PULL_THRESHOLD,
4754
+ maxPull = DEFAULT_MAX_PULL,
4755
+ renderIndicator
4756
+ }) => {
4757
+ const containerRef = useRef10(null);
4758
+ const startYRef = useRef10(null);
4759
+ const lastYRef = useRef10(0);
4760
+ const lastMoveTimeRef = useRef10(0);
4761
+ const velocityRef = useRef10(0);
4762
+ const pointerIdRef = useRef10(null);
4763
+ const isPullingRef = useRef10(false);
4764
+ const pullDistanceRef = useRef10(0);
4765
+ const flingRafRef = useRef10(null);
4766
+ const [pullDistance, setPullDistance] = useState11(0);
4767
+ const [isRefreshing, setIsRefreshing] = useState11(false);
4768
+ const [isTracking, setIsTracking] = useState11(false);
4769
+ const disabledRef = useRef10(disabled);
4770
+ disabledRef.current = disabled;
4771
+ const onRefreshRef = useRef10(onRefresh);
4772
+ onRefreshRef.current = onRefresh;
4773
+ const pullThresholdRef = useRef10(pullThreshold);
4774
+ pullThresholdRef.current = pullThreshold;
4775
+ const maxPullRef = useRef10(maxPull);
4776
+ maxPullRef.current = maxPull;
4650
4777
  useEffect10(() => {
4778
+ const el = containerRef.current;
4779
+ if (!el) return;
4780
+ const updatePullDistance = (value) => {
4781
+ pullDistanceRef.current = value;
4782
+ setPullDistance(value);
4783
+ };
4784
+ const stopFling = () => {
4785
+ if (flingRafRef.current !== null) {
4786
+ cancelAnimationFrame(flingRafRef.current);
4787
+ flingRafRef.current = null;
4788
+ }
4789
+ };
4790
+ const resetTracking = () => {
4791
+ pointerIdRef.current = null;
4792
+ startYRef.current = null;
4793
+ isPullingRef.current = false;
4794
+ setIsTracking(false);
4795
+ updatePullDistance(0);
4796
+ };
4797
+ const runFling = () => {
4798
+ velocityRef.current *= FLING_FRICTION;
4799
+ if (Math.abs(velocityRef.current) < FLING_MIN_VELOCITY) {
4800
+ flingRafRef.current = null;
4801
+ return;
4802
+ }
4803
+ el.scrollTop -= velocityRef.current * 16;
4804
+ if (el.scrollTop <= 0 || el.scrollTop >= el.scrollHeight - el.clientHeight) {
4805
+ flingRafRef.current = null;
4806
+ return;
4807
+ }
4808
+ flingRafRef.current = requestAnimationFrame(runFling);
4809
+ };
4810
+ const handlePointerDown = (e) => {
4811
+ if (disabledRef.current) return;
4812
+ if (pointerIdRef.current !== null) return;
4813
+ stopFling();
4814
+ pointerIdRef.current = e.pointerId;
4815
+ startYRef.current = e.clientY;
4816
+ lastYRef.current = e.clientY;
4817
+ lastMoveTimeRef.current = performance.now();
4818
+ velocityRef.current = 0;
4819
+ isPullingRef.current = false;
4820
+ setIsTracking(true);
4821
+ try {
4822
+ el.setPointerCapture(e.pointerId);
4823
+ } catch {
4824
+ }
4825
+ };
4826
+ const handlePointerMove = (e) => {
4827
+ if (startYRef.current === null || e.pointerId !== pointerIdRef.current) {
4828
+ return;
4829
+ }
4830
+ const totalDelta = e.clientY - startYRef.current;
4831
+ if (!isPullingRef.current && Math.abs(totalDelta) < DRAG_DEADZONE) {
4832
+ return;
4833
+ }
4834
+ const now = performance.now();
4835
+ const stepDelta = e.clientY - lastYRef.current;
4836
+ const dt = Math.max(now - lastMoveTimeRef.current, 1);
4837
+ velocityRef.current = stepDelta / dt;
4838
+ lastYRef.current = e.clientY;
4839
+ lastMoveTimeRef.current = now;
4840
+ if (e.cancelable) e.preventDefault();
4841
+ const atTop = el.scrollTop <= 0;
4842
+ if (atTop && totalDelta > 0) {
4843
+ isPullingRef.current = true;
4844
+ updatePullDistance(
4845
+ Math.min(
4846
+ Math.max(totalDelta - DRAG_DEADZONE, 0) * RESISTANCE,
4847
+ maxPullRef.current
4848
+ )
4849
+ );
4850
+ return;
4851
+ }
4852
+ if (isPullingRef.current) {
4853
+ isPullingRef.current = false;
4854
+ updatePullDistance(0);
4855
+ }
4856
+ el.scrollTop -= stepDelta;
4857
+ };
4858
+ const handlePointerEnd = (e) => {
4859
+ if (startYRef.current === null || e.pointerId !== pointerIdRef.current) {
4860
+ return;
4861
+ }
4862
+ const wasPulling = isPullingRef.current;
4863
+ pointerIdRef.current = null;
4864
+ startYRef.current = null;
4865
+ isPullingRef.current = false;
4866
+ setIsTracking(false);
4867
+ if (!wasPulling) {
4868
+ if (Math.abs(velocityRef.current) > FLING_MIN_VELOCITY) {
4869
+ stopFling();
4870
+ flingRafRef.current = requestAnimationFrame(runFling);
4871
+ }
4872
+ return;
4873
+ }
4874
+ const shouldRefresh = pullDistanceRef.current >= pullThresholdRef.current;
4875
+ if (!shouldRefresh) {
4876
+ updatePullDistance(0);
4877
+ return;
4878
+ }
4879
+ setIsRefreshing(true);
4880
+ updatePullDistance(pullThresholdRef.current);
4881
+ Promise.resolve(onRefreshRef.current()).catch((err) => {
4882
+ console.error("Pull-to-refresh failed:", err);
4883
+ }).finally(() => {
4884
+ setIsRefreshing(false);
4885
+ updatePullDistance(0);
4886
+ });
4887
+ };
4888
+ const handlePointerCancel = (e) => {
4889
+ if (e.pointerId !== pointerIdRef.current) return;
4890
+ stopFling();
4891
+ resetTracking();
4892
+ };
4893
+ el.addEventListener("pointerdown", handlePointerDown);
4894
+ el.addEventListener("pointermove", handlePointerMove, { passive: false });
4895
+ el.addEventListener("pointerup", handlePointerEnd);
4896
+ el.addEventListener("pointercancel", handlePointerCancel);
4897
+ return () => {
4898
+ stopFling();
4899
+ el.removeEventListener("pointerdown", handlePointerDown);
4900
+ el.removeEventListener("pointermove", handlePointerMove);
4901
+ el.removeEventListener("pointerup", handlePointerEnd);
4902
+ el.removeEventListener("pointercancel", handlePointerCancel);
4903
+ };
4904
+ }, []);
4905
+ const indicatorHeight = isRefreshing ? pullThreshold : pullDistance;
4906
+ const progress = Math.min(indicatorHeight / pullThreshold, 1);
4907
+ const isSettling = pullDistance === 0 && !isRefreshing && !isTracking;
4908
+ return /* @__PURE__ */ jsxs14(
4909
+ "div",
4910
+ {
4911
+ className: `up-sdk-pull-to-refresh ${className}`,
4912
+ ref: containerRef,
4913
+ style: {
4914
+ overflowY: "auto",
4915
+ overscrollBehavior: "none",
4916
+ touchAction: "none"
4917
+ },
4918
+ children: [
4919
+ /* @__PURE__ */ jsx18("style", { children: ".up-sdk-pull-to-refresh::-webkit-scrollbar { display: none; } .up-sdk-pull-to-refresh { scrollbar-width: none; -ms-overflow-style: none; }" }),
4920
+ /* @__PURE__ */ jsx18(
4921
+ "div",
4922
+ {
4923
+ style: {
4924
+ alignItems: "center",
4925
+ display: "flex",
4926
+ height: indicatorHeight,
4927
+ justifyContent: "center",
4928
+ overflow: "hidden",
4929
+ transition: isSettling ? "height 0.2s ease-out" : "none",
4930
+ userSelect: "none",
4931
+ width: "100%"
4932
+ },
4933
+ children: renderIndicator ? renderIndicator({ isRefreshing, progress }) : /* @__PURE__ */ jsx18(DefaultIndicator, { isRefreshing, progress })
4934
+ }
4935
+ ),
4936
+ children
4937
+ ]
4938
+ }
4939
+ );
4940
+ };
4941
+
4942
+ // src/components/QRScanner.tsx
4943
+ import jsQR2 from "jsqr";
4944
+ import { useEffect as useEffect11, useRef as useRef11, useState as useState12 } from "react";
4945
+ import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
4946
+ function QRScanner({ onScan, onError, className = "" }) {
4947
+ const videoRef = useRef11(null);
4948
+ const canvasRef = useRef11(null);
4949
+ const streamRef = useRef11(null);
4950
+ const tickRequestRef = useRef11(null);
4951
+ const hasScannedRef = useRef11(false);
4952
+ const [isReady, setIsReady] = useState12(false);
4953
+ useEffect11(() => {
4651
4954
  let cancelled = false;
4652
4955
  hasScannedRef.current = false;
4653
4956
  const cleanup = () => {
@@ -4730,7 +5033,7 @@ function QRScanner({ onScan, onError, className = "" }) {
4730
5033
  cleanup();
4731
5034
  };
4732
5035
  }, []);
4733
- return /* @__PURE__ */ jsxs14(
5036
+ return /* @__PURE__ */ jsxs15(
4734
5037
  "div",
4735
5038
  {
4736
5039
  className,
@@ -4742,7 +5045,7 @@ function QRScanner({ onScan, onError, className = "" }) {
4742
5045
  position: "relative"
4743
5046
  },
4744
5047
  children: [
4745
- /* @__PURE__ */ jsx18(
5048
+ /* @__PURE__ */ jsx19(
4746
5049
  "video",
4747
5050
  {
4748
5051
  playsInline: true,
@@ -4750,8 +5053,8 @@ function QRScanner({ onScan, onError, className = "" }) {
4750
5053
  style: { height: "100%", objectFit: "cover", width: "100%" }
4751
5054
  }
4752
5055
  ),
4753
- /* @__PURE__ */ jsx18("canvas", { ref: canvasRef, style: { display: "none" } }),
4754
- isReady && /* @__PURE__ */ jsx18(
5056
+ /* @__PURE__ */ jsx19("canvas", { ref: canvasRef, style: { display: "none" } }),
5057
+ isReady && /* @__PURE__ */ jsx19(
4755
5058
  "div",
4756
5059
  {
4757
5060
  style: {
@@ -4773,7 +5076,7 @@ function QRScanner({ onScan, onError, className = "" }) {
4773
5076
 
4774
5077
  // src/components/SDKProvider.tsx
4775
5078
  import { createContext as createContext3, useContext as useContext6, useMemo as useMemo8 } from "react";
4776
- import { Fragment as Fragment5, jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
5079
+ import { Fragment as Fragment5, jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
4777
5080
  var SDKContext = createContext3({ isMocked: false });
4778
5081
  var useIsMocked = () => useContext6(SDKContext).isMocked;
4779
5082
  var SDKProvider = ({
@@ -4783,24 +5086,24 @@ var SDKProvider = ({
4783
5086
  }) => {
4784
5087
  const isMocked = typeof window !== "undefined" && !(window.__UP_REACT_NATIVE_APP__ === true || !!window.ReactNativeWebView);
4785
5088
  const value = useMemo8(() => ({ isMocked }), [isMocked]);
4786
- const content = /* @__PURE__ */ jsxs15(Fragment5, { children: [
5089
+ const content = /* @__PURE__ */ jsxs16(Fragment5, { children: [
4787
5090
  children,
4788
- (debug || isMocked) && /* @__PURE__ */ jsx19(DebugConsole, {})
5091
+ (debug || isMocked) && /* @__PURE__ */ jsx20(DebugConsole, {})
4789
5092
  ] });
4790
5093
  if (isMocked) {
4791
- return /* @__PURE__ */ jsx19(SDKContext.Provider, { value, children: /* @__PURE__ */ jsx19(BridgeMocker, { ...mockerProps, children: content }) });
5094
+ return /* @__PURE__ */ jsx20(SDKContext.Provider, { value, children: /* @__PURE__ */ jsx20(BridgeMocker, { ...mockerProps, children: content }) });
4792
5095
  }
4793
- return /* @__PURE__ */ jsx19(SDKContext.Provider, { value, children: content });
5096
+ return /* @__PURE__ */ jsx20(SDKContext.Provider, { value, children: content });
4794
5097
  };
4795
5098
 
4796
5099
  // src/components/SwipeCarousel.tsx
4797
5100
  import {
4798
- useEffect as useEffect11,
5101
+ useEffect as useEffect12,
4799
5102
  useLayoutEffect,
4800
- useRef as useRef11,
4801
- useState as useState12
5103
+ useRef as useRef12,
5104
+ useState as useState13
4802
5105
  } from "react";
4803
- import { jsx as jsx20 } from "react/jsx-runtime";
5106
+ import { jsx as jsx21 } from "react/jsx-runtime";
4804
5107
  var DIRECTION_LOCK_THRESHOLD_PX = 8;
4805
5108
  var SWIPE_DISTANCE_THRESHOLD_PX = 40;
4806
5109
  var SWIPE_VELOCITY_THRESHOLD = 0.4;
@@ -4827,28 +5130,28 @@ var SwipeCarousel = ({
4827
5130
  overscan = DEFAULT_OVERSCAN,
4828
5131
  visibleOverscan = DEFAULT_VISIBLE_OVERSCAN
4829
5132
  }) => {
4830
- const containerRef = useRef11(null);
4831
- const [containerWidth, setContainerWidth] = useState12(0);
4832
- const [dragX, setDragX] = useState12(0);
4833
- const [dragY, setDragY] = useState12(0);
4834
- const [isDraggingX, setIsDraggingX] = useState12(false);
4835
- const [isDraggingY, setIsDraggingY] = useState12(false);
4836
- const touchStateRef = useRef11(null);
4837
- const [internalIndex, setInternalIndex] = useState12(
5133
+ const containerRef = useRef12(null);
5134
+ const [containerWidth, setContainerWidth] = useState13(0);
5135
+ const [dragX, setDragX] = useState13(0);
5136
+ const [dragY, setDragY] = useState13(0);
5137
+ const [isDraggingX, setIsDraggingX] = useState13(false);
5138
+ const [isDraggingY, setIsDraggingY] = useState13(false);
5139
+ const touchStateRef = useRef12(null);
5140
+ const [internalIndex, setInternalIndex] = useState13(
4838
5141
  () => Math.max(
4839
5142
  0,
4840
5143
  items.findIndex((item) => item.id === activeId)
4841
5144
  )
4842
5145
  );
4843
- const prevActiveIdRef = useRef11(activeId);
4844
- const [timingWaiting, setTimingWaiting] = useState12(true);
4845
- useEffect11(() => {
5146
+ const prevActiveIdRef = useRef12(activeId);
5147
+ const [timingWaiting, setTimingWaiting] = useState13(true);
5148
+ useEffect12(() => {
4846
5149
  const timer = setTimeout(() => {
4847
5150
  setTimingWaiting(false);
4848
5151
  }, 1e3);
4849
5152
  return () => clearTimeout(timer);
4850
5153
  }, []);
4851
- useEffect11(() => {
5154
+ useEffect12(() => {
4852
5155
  if (activeId !== prevActiveIdRef.current) {
4853
5156
  const idx = items.findIndex((item) => item.id === activeId);
4854
5157
  if (idx !== -1) setInternalIndex(idx);
@@ -4977,7 +5280,7 @@ var SwipeCarousel = ({
4977
5280
  };
4978
5281
  const windowStart = Math.max(0, activeIndex - overscan);
4979
5282
  const windowEnd = Math.min(items.length - 1, activeIndex + overscan);
4980
- return /* @__PURE__ */ jsx20(
5283
+ return /* @__PURE__ */ jsx21(
4981
5284
  "div",
4982
5285
  {
4983
5286
  className: `relative overflow-hidden touch-pan-y ${className ?? ""}`,
@@ -4986,7 +5289,7 @@ var SwipeCarousel = ({
4986
5289
  onTouchMove: handleTouchMove,
4987
5290
  onTouchStart: handleTouchStart,
4988
5291
  ref: containerRef,
4989
- children: /* @__PURE__ */ jsx20(
5292
+ children: /* @__PURE__ */ jsx21(
4990
5293
  "div",
4991
5294
  {
4992
5295
  className: "relative h-full",
@@ -5001,7 +5304,7 @@ var SwipeCarousel = ({
5001
5304
  const verticalOffset = isActive ? dragY : 0;
5002
5305
  const distance = Math.abs(index - activeIndex);
5003
5306
  const isVisible = distance <= visibleOverscan;
5004
- return /* @__PURE__ */ jsx20(
5307
+ return /* @__PURE__ */ jsx21(
5005
5308
  "div",
5006
5309
  {
5007
5310
  className: `absolute top-0 left-0 h-full shrink-0 ${itemClassName ?? ""} ${item.className ?? ""}`,
@@ -5276,6 +5579,7 @@ export {
5276
5579
  MapMenuTitle,
5277
5580
  MiniAppSDK,
5278
5581
  MockLocationContext,
5582
+ PullToRefresh,
5279
5583
  QRScanner,
5280
5584
  RouteLayer,
5281
5585
  SDKMapProvider,