@cloudparse/up-miniapps-sdk 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -788,6 +788,19 @@ interface MapProps {
788
788
  onPoiClick?: (poi: POI) => void;
789
789
  /** Route geometry to display on the map. */
790
790
  route?: GeoJSON.LineString;
791
+ /**
792
+ * Visual style for the route line the Map draws internally (both for
793
+ * `route` and for an active `navigation`/`navigationData` journey) —
794
+ * see `RouteLayerProps`. Defaults to `RouteLayer`'s own defaults
795
+ * (`#3b82f6` blue, solid) when omitted, so existing consumers are
796
+ * unaffected.
797
+ */
798
+ routeStyle?: {
799
+ color?: string;
800
+ width?: number;
801
+ opacity?: number;
802
+ dashArray?: number[];
803
+ };
791
804
  /** Whether to show the out-of-the-box navigation UI. */
792
805
  showNavigationUI?: boolean;
793
806
  /** Callback triggered when the user aborts/closes the navigation UI. */
@@ -814,6 +827,12 @@ interface MapProps {
814
827
  * Defaults to 'preview'.
815
828
  */
816
829
  mode?: "preview" | "navigation";
830
+ /**
831
+ * Distance in meters from the destination at which the journey
832
+ * counts as arrived. GPS accuracy means the live remaining distance
833
+ * rarely reaches exactly 0. Defaults to 15m.
834
+ */
835
+ arrivalThresholdMeters?: number;
817
836
  };
818
837
  /** Callback triggered when the navigation mode changes (e.g. from preview to navigation). */
819
838
  onNavigationModeChange?: (mode: "preview" | "navigation") => void;
@@ -832,6 +851,8 @@ interface MapProps {
832
851
  mode?: "preview" | "navigation";
833
852
  /** Function to transition to active navigation mode */
834
853
  start?: () => void;
854
+ /** True once the live remaining distance drops to/below `navigation.arrivalThresholdMeters`. */
855
+ hasArrived?: boolean;
835
856
  };
836
857
  /** Whether to show the vertical drawer and floating right controls. Defaults to true. */
837
858
  showControls?: boolean;
@@ -874,6 +895,8 @@ interface EtaData {
874
895
  onStart?: () => void;
875
896
  isCalculating?: boolean;
876
897
  error?: string | null;
898
+ /** True once the live remaining distance drops to/below `navigation.arrivalThresholdMeters`. */
899
+ hasArrived?: boolean;
877
900
  }
878
901
 
879
902
  interface MapInsets {
@@ -1030,6 +1053,12 @@ interface LiveRoutingOptions {
1030
1053
  enabled?: boolean;
1031
1054
  /** Initial mode: 'preview' or 'navigation'. Defaults to 'preview'. */
1032
1055
  initialMode?: "preview" | "navigation";
1056
+ /**
1057
+ * Distance in meters from the destination at which the journey counts
1058
+ * as arrived (`hasArrived` becomes true). GPS accuracy means the live
1059
+ * `currentDistanceMeters` rarely reaches exactly 0. Defaults to 15m.
1060
+ */
1061
+ arrivalThresholdMeters?: number;
1033
1062
  }
1034
1063
  interface LiveRoutingResult {
1035
1064
  /** The calculated route data from the last API call */
@@ -1048,8 +1077,15 @@ interface LiveRoutingResult {
1048
1077
  mode: "preview" | "navigation";
1049
1078
  /** Start active navigation (switch mode to 'navigation') */
1050
1079
  start: () => void;
1080
+ /**
1081
+ * True once `currentDistanceMeters` drops to/below
1082
+ * `arrivalThresholdMeters`. Use this instead of checking
1083
+ * `currentDistanceMeters <= 0` — the point never reaches exactly 0 with
1084
+ * live GPS.
1085
+ */
1086
+ hasArrived: boolean;
1051
1087
  }
1052
- declare const useLiveRouting: ({ origin: manualOrigin, destination, profile, recalculateThreshold, enabled, initialMode, }: LiveRoutingOptions) => LiveRoutingResult;
1088
+ declare const useLiveRouting: ({ origin: manualOrigin, destination, profile, recalculateThreshold, enabled, initialMode, arrivalThresholdMeters, }: LiveRoutingOptions) => LiveRoutingResult;
1053
1089
  /**
1054
1090
  * A simple hook to fetch a route once between two points.
1055
1091
  * Does not automatically recalculate or track user location.
@@ -1077,6 +1113,12 @@ interface DeclarativeJourneyOptions {
1077
1113
  origin?: [number, number] | null;
1078
1114
  /** Initial mode. 'preview' shows the route overview, 'navigation' starts active guidance. Defaults to 'preview'. */
1079
1115
  mode?: NavMode;
1116
+ /**
1117
+ * Distance in meters from the destination at which the journey counts
1118
+ * as arrived (`hasArrived` becomes true). GPS accuracy means the live
1119
+ * `distanceRemainingMeters` rarely reaches exactly 0. Defaults to 15m.
1120
+ */
1121
+ arrivalThresholdMeters?: number;
1080
1122
  }
1081
1123
  interface UseJourneyOptions {
1082
1124
  /**
@@ -1112,6 +1154,13 @@ interface UseJourneyResult {
1112
1154
  etaMinutes: number;
1113
1155
  /** Journey completion progress, 0-100. */
1114
1156
  progress: number;
1157
+ /**
1158
+ * True once the live remaining distance drops to/below
1159
+ * `arrivalThresholdMeters`. Check this instead of
1160
+ * `distanceRemainingMeters <= 0` — it usually never reaches exactly 0
1161
+ * with live GPS, so a UI that waits for that may never show "arrived".
1162
+ */
1163
+ hasArrived: boolean;
1115
1164
  /** Switch from 'preview' to active 'navigation' guidance. */
1116
1165
  start: () => void;
1117
1166
  /** Cancel the journey entirely. Always returns to 'preview' the next time a journey starts. */
@@ -1153,6 +1202,14 @@ interface RouteLayerProps {
1153
1202
  width?: number;
1154
1203
  /** Opacity of the route line. Defaults to 0.8. */
1155
1204
  opacity?: number;
1205
+ /**
1206
+ * MapLibre `line-dasharray` for the colored line (the white casing
1207
+ * underneath always stays solid, for legibility against any basemap).
1208
+ * Units are multiples of `width`. E.g. `[0, 2]` with the layer's own
1209
+ * `line-cap: round` (always on) renders as a dotted trail instead of a
1210
+ * continuous line. Omit for a solid line (default).
1211
+ */
1212
+ dashArray?: number[];
1156
1213
  }
1157
1214
  declare const RouteLayer: React__default.FC<RouteLayerProps>;
1158
1215
 
@@ -1513,6 +1570,14 @@ declare class MiniAppSDK {
1513
1570
  destination: [number, number];
1514
1571
  origin?: [number, number];
1515
1572
  profile?: "driving" | "cycling" | "walking";
1573
+ /**
1574
+ * Distance in meters from the destination at which the journey
1575
+ * counts as arrived (`useJourney().hasArrived` becomes true). GPS
1576
+ * accuracy means the live remaining distance rarely reaches
1577
+ * exactly 0 — this is the threshold a consumer's own UI should
1578
+ * treat as "done" instead of waiting for that. Defaults to 15m.
1579
+ */
1580
+ arrivalThresholdMeters?: number;
1516
1581
  }) => void;
1517
1582
  /**
1518
1583
  * Starts the active navigation (active guidance).
package/dist/index.js CHANGED
@@ -2010,13 +2010,15 @@ var useUserLocation = () => {
2010
2010
 
2011
2011
  // src/components/Map/hooks/useLiveRouting.ts
2012
2012
  import { useCallback as useCallback4, useEffect as useEffect4, useMemo as useMemo3, useRef as useRef5, useState as useState6 } from "react";
2013
+ var DEFAULT_ARRIVAL_THRESHOLD_METERS = 15;
2013
2014
  var useLiveRouting = ({
2014
2015
  origin: manualOrigin,
2015
2016
  destination,
2016
2017
  profile = "driving",
2017
2018
  recalculateThreshold = 50,
2018
2019
  enabled = true,
2019
- initialMode = "preview"
2020
+ initialMode = "preview",
2021
+ arrivalThresholdMeters = DEFAULT_ARRIVAL_THRESHOLD_METERS
2020
2022
  }) => {
2021
2023
  const [route, setRoute] = useState6(null);
2022
2024
  const [totalDistance, setTotalDistance] = useState6(null);
@@ -2070,6 +2072,7 @@ var useLiveRouting = ({
2070
2072
  }
2071
2073
  return dist;
2072
2074
  }, [trackingLocation, route, destination, getDistance]);
2075
+ const hasArrived = currentDistanceMeters !== null && currentDistanceMeters <= arrivalThresholdMeters;
2073
2076
  const calculate = useCallback4(
2074
2077
  async (origin, dest, isNewDest) => {
2075
2078
  if (isRequestInProgress.current) return;
@@ -2127,6 +2130,8 @@ var useLiveRouting = ({
2127
2130
  if (lastResetDestKey.current !== destKey) {
2128
2131
  lastResetDestKey.current = destKey;
2129
2132
  setMode(initialMode);
2133
+ setRoute(null);
2134
+ setTotalDistance(null);
2130
2135
  }
2131
2136
  if (destChanged) {
2132
2137
  calculate(calculationOrigin, destination, true);
@@ -2152,6 +2157,7 @@ var useLiveRouting = ({
2152
2157
  return {
2153
2158
  currentDistanceMeters,
2154
2159
  error,
2160
+ hasArrived,
2155
2161
  isCalculating,
2156
2162
  mode,
2157
2163
  recalculate: () => calculationOrigin && destination && calculate(calculationOrigin, destination, false),
@@ -2217,6 +2223,7 @@ var useJourney = (options = {}) => {
2217
2223
  }, []);
2218
2224
  const effectiveOptions = progNav || navigation;
2219
2225
  const internalNav = useLiveRouting({
2226
+ arrivalThresholdMeters: effectiveOptions?.arrivalThresholdMeters,
2220
2227
  destination: effectiveOptions?.destination || null,
2221
2228
  enabled: !isAborted && !!effectiveOptions?.destination,
2222
2229
  initialMode: effectiveOptions?.mode || "preview",
@@ -2272,6 +2279,7 @@ var useJourney = (options = {}) => {
2272
2279
  distanceRemainingMeters,
2273
2280
  error: isActive ? internalNav.error : null,
2274
2281
  etaMinutes,
2282
+ hasArrived: isActive ? internalNav.hasArrived : false,
2275
2283
  isActive,
2276
2284
  isCalculating: isActive ? internalNav.isCalculating : false,
2277
2285
  mode: isActive ? internalNav.mode : "preview",
@@ -2316,7 +2324,8 @@ var RouteLayer = ({
2316
2324
  geometry,
2317
2325
  color = "#3b82f6",
2318
2326
  width = 5,
2319
- opacity = 0.8
2327
+ opacity = 0.8,
2328
+ dashArray
2320
2329
  }) => {
2321
2330
  if (!geometry) return null;
2322
2331
  const data = {
@@ -2349,7 +2358,8 @@ var RouteLayer = ({
2349
2358
  paint: {
2350
2359
  "line-color": color,
2351
2360
  "line-opacity": opacity,
2352
- "line-width": width
2361
+ "line-width": width,
2362
+ ...dashArray ? { "line-dasharray": dashArray } : {}
2353
2363
  },
2354
2364
  type: "line"
2355
2365
  }
@@ -2783,6 +2793,7 @@ var MapInternal = ({
2783
2793
  pois = [],
2784
2794
  onPoiClick,
2785
2795
  route: externalRoute,
2796
+ routeStyle,
2786
2797
  showNavigationUI: externalShowNavigationUI,
2787
2798
  navigationData: externalNavigationData,
2788
2799
  onNavigationAbort,
@@ -2807,6 +2818,7 @@ var MapInternal = ({
2807
2818
  const hasIntegratedNav = journey.isActive;
2808
2819
  const navigationData = hasIntegratedNav ? {
2809
2820
  currentDistanceMeters: journey.distanceRemainingMeters,
2821
+ hasArrived: journey.hasArrived,
2810
2822
  mode: journey.mode,
2811
2823
  route: journey.route,
2812
2824
  start: journey.start,
@@ -2967,6 +2979,7 @@ var MapInternal = ({
2967
2979
  const showEtaData = showNavigationUI && navigationData && route ? {
2968
2980
  distanceRemainingKm: kmRemaining,
2969
2981
  etaMins,
2982
+ hasArrived: navigationData.hasArrived ?? false,
2970
2983
  label: mode === "navigation" ? "Walking Guidance Active" : "Route Preview",
2971
2984
  mode,
2972
2985
  onAbort: () => {
@@ -3141,7 +3154,23 @@ var MapInternal = ({
3141
3154
  initialViewState,
3142
3155
  interactiveLayerIds: mergedInteractiveLayerIds,
3143
3156
  mapStyle,
3144
- maxBounds,
3157
+ maxBounds: (
3158
+ // @vis.gl/react-maplibre's own <Map> component (aliased MapLibre
3159
+ // here) types maxBounds as a flat [west, south, east, north]
3160
+ // tuple — raw maplibre-gl's LngLatBoundsLike still accepts a
3161
+ // pair-of-corners shape, this narrowing is the wrapper's own.
3162
+ // This SDK's public MapProps.maxBounds keeps the
3163
+ // [[lng, lat], [lng, lat]] pair-of-corners shape (matches every
3164
+ // other coordinate prop in this SDK, e.g. flyTo), so it's
3165
+ // flattened here at the point of use rather than changing the
3166
+ // public API.
3167
+ maxBounds ? [
3168
+ maxBounds[0][0],
3169
+ maxBounds[0][1],
3170
+ maxBounds[1][0],
3171
+ maxBounds[1][1]
3172
+ ] : void 0
3173
+ ),
3145
3174
  onClick: handleMapClick,
3146
3175
  onContextMenu,
3147
3176
  onDragStart: handleUserInteraction,
@@ -3178,7 +3207,16 @@ var MapInternal = ({
3178
3207
  radiusMeters: mockLocation.radiusMeters
3179
3208
  }
3180
3209
  ),
3181
- displayRoute && /* @__PURE__ */ jsx16(RouteLayer, { geometry: displayRoute }),
3210
+ displayRoute && /* @__PURE__ */ jsx16(
3211
+ RouteLayer,
3212
+ {
3213
+ color: routeStyle?.color,
3214
+ dashArray: routeStyle?.dashArray,
3215
+ geometry: displayRoute,
3216
+ opacity: routeStyle?.opacity,
3217
+ width: routeStyle?.width
3218
+ }
3219
+ ),
3182
3220
  pois.length > 0 && /* @__PURE__ */ jsxs12(Fragment5, { children: [
3183
3221
  /* @__PURE__ */ jsx16(POILayers, { pois }),
3184
3222
  /* @__PURE__ */ jsx16(POIMarkers, { onClick: onPoiClick, pois })
@@ -3403,7 +3441,7 @@ var loadImage2 = (src) => new Promise((resolve, reject) => {
3403
3441
  });
3404
3442
 
3405
3443
  // package.json
3406
- var version = "0.8.0";
3444
+ var version = "0.9.0";
3407
3445
 
3408
3446
  // src/sdk.ts
3409
3447
  function deepFreeze(obj) {