@minmaps-dev/mm-web-sdk 1.0.0-rc.46 → 1.0.0-rc.47

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
@@ -233,6 +233,11 @@ interface Zone {
233
233
  /** Authored hex color (e.g. "#d32f2f"); may be empty when the author
234
234
  * hasn't picked one — such zones are skipped for color-coding. */
235
235
  color: string;
236
+ /** The color this zone's rooms are drawn in under the active theme — `color`
237
+ * in the default theme, its high-contrast palette entry under high contrast.
238
+ * Use this, not `color`, for a legend swatch, and re-read it on
239
+ * `themeChanged`. Set on `getZones()` results only. */
240
+ displayColor?: string;
236
241
  description?: string;
237
242
  }
238
243
 
@@ -348,7 +353,7 @@ interface MapEvent {
348
353
  venue?: any;
349
354
  camera?: CameraState;
350
355
  /** Emitted by `themeChanged`; `'custom'` when consumer passed a raw style. */
351
- theme?: 'default' | 'high-contrast' | 'custom';
356
+ theme?: 'default' | 'high-contrast' | 'color-blind' | 'custom';
352
357
  /** Emitted by `localeChanged` after `setLocale()` finishes patching the
353
358
  * venue model. BCP-47 code (`'en'`, `'es'`, `'es-MX'`). */
354
359
  locale?: string;
@@ -383,7 +388,7 @@ type BoundsPadding = number | {
383
388
  * `options.theme` init option. Pass a `StyleSpecification` directly for
384
389
  * custom themes.
385
390
  */
386
- type ThemeName = 'default' | 'high-contrast';
391
+ type ThemeName = 'default' | 'high-contrast' | 'color-blind';
387
392
  /**
388
393
  * Style of the disc + ring rendered behind each amenity icon. The SDK
389
394
  * composites this into the icon bitmap at registration time, so badge +
@@ -414,7 +419,10 @@ interface SDKOptions {
414
419
  debugGlobal?: string | false;
415
420
  /**
416
421
  * Initial theme. `'default'` uses the bundled hybrid 3D theme.
417
- * `'high-contrast'` uses the WCAG-AA tuned theme. Pass a
422
+ * `'high-contrast'` uses the WCAG-AA tuned theme. `'color-blind'` keeps the
423
+ * default look but swaps the colors that red-green and blue-yellow color
424
+ * blindness merge (the route, room categories and department zones,
425
+ * restrooms, parks). Pass a
418
426
  * `StyleSpecification` for fully custom styling.
419
427
  */
420
428
  theme?: ThemeName | any;
@@ -1073,6 +1081,24 @@ interface OpenStatusOptions {
1073
1081
  * wrong answer at a kiosk is worse than a missing one.
1074
1082
  */
1075
1083
  declare function parseOpenHours(raw: unknown): OpenHours | null;
1084
+ /**
1085
+ * The weekday `now` falls on in `timeZone` (host clock when omitted or
1086
+ * unrecognised) — the same day `getOpenStatus` evaluates against. Exported so
1087
+ * a week table can highlight "today" without disagreeing with the status line
1088
+ * around the venue's midnight.
1089
+ */
1090
+ declare function dayKeyAt(now: Date, timeZone?: string): DayKey;
1091
+ /**
1092
+ * A short label for `timeZone` (host zone when omitted or unrecognised) — the
1093
+ * zone `getOpenStatus` reads hours against — so a UI can say "Opens 9:00 AM ET".
1094
+ *
1095
+ * US zones get the generic form (`ET`, `CT`, `MT`, `PT`, `AKT`), which doesn't
1096
+ * flip with daylight saving. Elsewhere the engine has no generic abbreviation
1097
+ * (it would spell out "Germany Time"), so this falls back to the specific short
1098
+ * name, which may be an offset (`GMT+2`). `now` only matters for that fallback
1099
+ * and for zones like Phoenix that print `MST` year-round.
1100
+ */
1101
+ declare function timeZoneAbbreviation(now?: Date, timeZone?: string): string;
1076
1102
  /**
1077
1103
  * The live open/closed state for a parsed week.
1078
1104
  *
@@ -1083,10 +1109,32 @@ declare function parseOpenHours(raw: unknown): OpenHours | null;
1083
1109
  *
1084
1110
  * Hours carry no timezone of their own, so they are read against the host clock
1085
1111
  * unless `options.timeZone` names the venue's zone. The kiosk case needs no
1086
- * option: the machine stands in the building it is describing.
1112
+ * option: the machine stands in the building it is describing. A web consumer
1113
+ * whose visitors may be elsewhere should resolve the venue's zone (e.g. from
1114
+ * `MinuteMaps.getVenueCenter()`) and pass it.
1087
1115
  */
1088
1116
  declare function getOpenStatus(hours: OpenHours, now?: Date, options?: OpenStatusOptions): OpenStatus;
1089
1117
 
1118
+ /** One floor of the active route, drawn on its own for a printout. */
1119
+ type RouteFloorImage = {
1120
+ floor: Floor;
1121
+ /** The bare map canvas (no DOM chrome), as a `data:` URL. */
1122
+ dataUrl: string;
1123
+ };
1124
+ type RouteImageOptions = {
1125
+ /** CSS-pixel size the map is laid out at while capturing. Default 1200×800. */
1126
+ width?: number;
1127
+ height?: number;
1128
+ /** Canvas pixels per CSS pixel. Default 2, crisp enough for paper. */
1129
+ pixelRatio?: number;
1130
+ /** Padding around each floor's route segment, in CSS px. Default 40. */
1131
+ padding?: number;
1132
+ /** Image MIME type passed to `toDataURL`. Default `'image/png'`. */
1133
+ type?: string;
1134
+ /** Encoder quality for lossy types (`'image/jpeg'`, `'image/webp'`). */
1135
+ quality?: number;
1136
+ };
1137
+
1090
1138
  type JacsProviderConfig = {
1091
1139
  mode: 'proxy';
1092
1140
  proxyBaseUrl?: string;
@@ -1404,6 +1452,8 @@ declare class SnapshotProvider implements JacsReader {
1404
1452
  private fetchJson;
1405
1453
  }
1406
1454
 
1455
+ /** A built-in theme name, or `'custom'` when a raw style was passed. */
1456
+ type ActiveThemeName = ThemeName | 'custom';
1407
1457
  declare class MinuteMaps {
1408
1458
  private config;
1409
1459
  private map;
@@ -1461,8 +1511,9 @@ declare class MinuteMaps {
1461
1511
  /** Multiplier applied to every theme label's `text-size`, mutable via
1462
1512
  * `setTextScale`. Re-applied after every `setTheme()` swap. */
1463
1513
  private textScale;
1464
- /** Each label layer's unscaled `text-size`, captured by `setTextScale`.
1465
- * Cleared on `setTheme()` — the recreated layers carry new base values. */
1514
+ /** Each label layer's unscaled `text-size` and em offsets, captured by
1515
+ * `setTextScale` and keyed `"<layer id>|<property>"`. Cleared on
1516
+ * `setTheme()` — the recreated layers carry new base values. */
1466
1517
  private baseTextSizes;
1467
1518
  /** Tracks the active theme name so `setTheme()` is a no-op when re-requested. */
1468
1519
  private activeThemeName;
@@ -1478,6 +1529,9 @@ declare class MinuteMaps {
1478
1529
  * step rides — empty unless `setActiveStep` is on a transition. Drives
1479
1530
  * `applyRouteConnectorHighlight`. */
1480
1531
  private activeTransitionWaypointIds;
1532
+ /** Set while `captureRouteFloorImages` runs; holds the bounds padding to
1533
+ * put back afterwards (updated by any `setBoundsPadding` in between). */
1534
+ private routeCapture;
1481
1535
  private amenityManager;
1482
1536
  private wayfinding;
1483
1537
  private highlightManager;
@@ -1511,6 +1565,12 @@ declare class MinuteMaps {
1511
1565
  * fresh insets, the same way it already re-fits an active route. Cleared by
1512
1566
  * `clearHighlight`. */
1513
1567
  private selectedCoordinates;
1568
+ /** Zoom floor for the current selection's camera move, or `null` to keep
1569
+ * the current zoom. Set by `selectPOI` (a list pick can arrive from the
1570
+ * Campus view, where the roof still covers the room); kept beside
1571
+ * `selectedCoordinates` so a `setBoundsPadding` re-nudge carries the same
1572
+ * zoom instead of cancelling the zoom-in halfway. Cleared with it. */
1573
+ private selectedMinZoom;
1514
1574
  private youAreHerePulse;
1515
1575
  /** Theme layers whose features represent a tappable destination/amenity.
1516
1576
  * A click hit-tests these (see `SelectionManager`) → `poiSelected`. The
@@ -1651,16 +1711,62 @@ declare class MinuteMaps {
1651
1711
  */
1652
1712
  private registerRuntimeIcons;
1653
1713
  /**
1654
- * Set the active map theme by name (`'default'` / `'high-contrast'`) or by
1714
+ * Set the active map theme by name (`'default'` / `'high-contrast'` /
1715
+ * `'color-blind'`) or by
1655
1716
  * passing a custom `StyleSpecification`. The current floor, route, POIs
1656
1717
  * and camera are preserved across the swap — only layer styling changes.
1657
1718
  *
1658
1719
  * Used by kiosk consumers to wire the OS-level / popover high-contrast
1659
1720
  * toggle to the map. See `KIOSK.md` for the pattern.
1721
+ *
1722
+ * Switching between the two built-in themes happens in place (paint
1723
+ * properties plus the sprite — see `swapBuiltinThemeInPlace`); a custom style,
1724
+ * or leaving one, rebuilds the style with `setStyle`. Calls run one at a time
1725
+ * in the order made, so a quick double toggle can't interleave two swaps.
1660
1726
  */
1661
1727
  setTheme(theme: ThemeName | StyleSpecification): Promise<void>;
1728
+ /** Tail of the `setTheme` queue. */
1729
+ private themeQueue;
1730
+ private applyTheme;
1731
+ /**
1732
+ * Switch between built-in themes without `setStyle`. They share every layer
1733
+ * and differ only in paint and sprite (high contrast and color-blind are
1734
+ * derived from hybrid — see `themes/`), so this rewrites the paint
1735
+ * properties that differ and points the map at the other sprite sheet.
1736
+ * Sources, filters, zoom ranges, layout overrides (text scale, dyslexic font)
1737
+ * and the selection's destination focus are untouched, so unlike the
1738
+ * `setStyle` path there is nothing to capture and restore.
1739
+ *
1740
+ * Returns `false`, having changed nothing, when the two themes differ in
1741
+ * anything paint can't express; the caller then falls back to `setStyle`.
1742
+ */
1743
+ private swapBuiltinThemeInPlace;
1744
+ /** Room layers whose color a zone palette replaces. The
1745
+ * highlight pair is here so a selected room's raised block keeps its
1746
+ * palette color instead of reverting to the authored one. */
1747
+ private static readonly ZONE_PAINT_TARGETS;
1748
+ /** Zone id → palette fill for `themeName`, over the zones in use (see
1749
+ * `assignZonePaletteColors` for why only those), or `null` for a theme that
1750
+ * draws the authored colors. */
1751
+ private paletteZoneColors;
1752
+ /**
1753
+ * Under a theme with a zone palette (high contrast, color-blind), color each
1754
+ * zoned room from it, keeping the theme's own value for everything else.
1755
+ * Under the default theme, write the theme's own value back: its expression
1756
+ * already tints by the authored `zoneColor`, and an in-place swap away from
1757
+ * color-blind wouldn't reset these layers otherwise, since the two static
1758
+ * themes' unit fills are identical and `diffThemePaint` skips them.
1759
+ *
1760
+ * Writes the room layers' paint, so it must run before `setUnitFocusDim(true)`
1761
+ * captures them — otherwise clearing the selection would hand back the
1762
+ * palette-less value.
1763
+ */
1764
+ private applyZonePaint;
1765
+ /** The color a zone's rooms are drawn in under the active theme: its palette
1766
+ * entry under high contrast or color-blind, its authored color otherwise. */
1767
+ private zoneDisplayColor;
1662
1768
  /** Currently active theme name (or `'custom'` when a raw style was passed). */
1663
- getActiveTheme(): 'default' | 'high-contrast' | 'custom';
1769
+ getActiveTheme(): ActiveThemeName;
1664
1770
  /**
1665
1771
  * Update the SDK's reduced-motion preference at runtime. When true, every
1666
1772
  * imperative camera move (`setView`, `resetView`, `refit`, recenter, route
@@ -1704,6 +1810,10 @@ declare class MinuteMaps {
1704
1810
  * wrapped), so zoom interpolation and data-driven sizing keep working. Re-applied after
1705
1811
  * `setTheme()`, since `setStyle({ diff: false })` recreates every layer from
1706
1812
  * the pristine theme JSON. Non-finite or non-positive values reset to 1.
1813
+ *
1814
+ * The em-based `text-offset` / `text-variable-anchor-offset` are divided by
1815
+ * the same factor, so each label keeps its pixel distance from an icon that
1816
+ * doesn't scale (see `scaleTextEmOffset`).
1707
1817
  */
1708
1818
  setTextScale(scale: number): void;
1709
1819
  getTextScale(): number;
@@ -1761,6 +1871,28 @@ declare class MinuteMaps {
1761
1871
  setFlatMode(enabled: boolean): void;
1762
1872
  toggleFlatMode(): void;
1763
1873
  getIsFlatMode(): boolean;
1874
+ /**
1875
+ * Street address of the venue, from its first JACS building's `address`.
1876
+ * The CMS's Edit Venue form saves its Address field there, since it binds a
1877
+ * venue to a single building. `null` before the venue loads or when the
1878
+ * address is blank. In the venue's default language: `/all` ignores
1879
+ * `?locale=` and the locale refetch doesn't cover buildings.
1880
+ */
1881
+ getVenueAddress(): string | null;
1882
+ /**
1883
+ * Description of the venue, from its first JACS building's `description` —
1884
+ * stored there by the CMS's Edit Venue form, like `getVenueAddress()`.
1885
+ * `null` before the venue loads or when the description is blank. Same
1886
+ * locale caveat: always the venue's default language.
1887
+ */
1888
+ getVenueDescription(): string | null;
1889
+ /**
1890
+ * Center of the venue's bounds as `[lng, lat]`. `null` before the venue
1891
+ * loads or when it has no coordinates. JACS records no time zone, so a
1892
+ * consumer whose visitors may be outside the venue's zone resolves one from
1893
+ * this point and passes it to `getOpenStatus` / `dayKeyAt`.
1894
+ */
1895
+ getVenueCenter(): [number, number] | null;
1764
1896
  getFloors(): Floor[];
1765
1897
  getCurrentFloor(): Floor | null;
1766
1898
  getDefaultFloor(): Floor | null;
@@ -1784,12 +1916,14 @@ declare class MinuteMaps {
1784
1916
  floorShortName?: string;
1785
1917
  zoneName?: string;
1786
1918
  zoneDescription?: string;
1787
- /** The department's authored hex colour (`Zone.color`) — the same value
1788
- * that tints this room's polygon on the map, so a consumer can print a
1789
- * swatch beside the department name and connect the two. Absent when the
1790
- * author never picked one, which is also when the map leaves the room
1791
- * untinted; treat "no colour" as "this department isn't colour-coded",
1792
- * not as "fall back to a default swatch". */
1919
+ /** The colour that tints this room's polygon on the map under the active
1920
+ * theme — the department's authored `Zone.color`, or its high-contrast
1921
+ * palette entry under high contrast (`Zone.displayColor`) — so a consumer
1922
+ * can print a swatch beside the department name and connect the two.
1923
+ * Re-read it on `themeChanged`. Absent when the author never picked one,
1924
+ * which is also when the map leaves the room untinted; treat "no colour"
1925
+ * as "this department isn't colour-coded", not as "fall back to a default
1926
+ * swatch". */
1793
1927
  zoneColor?: string;
1794
1928
  keywords?: string[];
1795
1929
  description?: string;
@@ -2074,10 +2208,26 @@ declare class MinuteMaps {
2074
2208
  * instead swap the connector(s) the step rides to their highlighted
2075
2209
  * sprite badge (`CONNECTOR_HIGHLIGHTED_ICON_SUFFIX`).
2076
2210
  *
2211
+ * `opts.fit` moves the camera too:
2212
+ * - `'step'` frames just this step (zoomed no closer than
2213
+ * `ROUTE_STEP_FIT_MAX_ZOOM`) instead of the floor's whole segment, and
2214
+ * keeps framing it through later re-fits — `setBoundsPadding` as the
2215
+ * consumer's directions card resizes, a floor switch back to the step's
2216
+ * floor — until another fit or a new route.
2217
+ * - `'route'` goes back to the route's own framing (its floor segment),
2218
+ * as when it was first drawn — e.g. a "Restart" on the first step.
2219
+ *
2220
+ * Omitted, the camera is left alone, so a route's first framing stays
2221
+ * the whole route.
2222
+ *
2077
2223
  * Pass `null` to clear the highlight without changing the floor or
2078
2224
  * tearing down the route.
2079
2225
  */
2080
- setActiveStep(step: WayfindStep | null): Promise<void>;
2226
+ setActiveStep(step: WayfindStep | null, opts?: {
2227
+ fit?: 'step' | 'route';
2228
+ }): Promise<void>;
2229
+ /** The coordinates of `step`'s point range, for the camera to frame. */
2230
+ private stepFocusFor;
2081
2231
  private writeActiveStepHighlight;
2082
2232
  private clearActiveStepHighlight;
2083
2233
  /**
@@ -2091,6 +2241,24 @@ declare class MinuteMaps {
2091
2241
  * that predates the variant) rather than drawing nothing.
2092
2242
  */
2093
2243
  private applyRouteConnectorHighlight;
2244
+ /**
2245
+ * Draw each floor the active route crosses, in route order, and return
2246
+ * one image per floor — for printing directions.
2247
+ *
2248
+ * Images are the map canvas alone, so the consumer's DOM chrome (panels,
2249
+ * buttons, the floor picker) never appears in them. For the duration the
2250
+ * map container is laid out at a fixed `width` × `height`, the camera
2251
+ * fits each floor's segment of the route with uniform `padding`, and the
2252
+ * line is drawn solid (no draw-on sweep, no step highlight). Afterwards
2253
+ * the container size, floor, camera and padding are put back. Hide the
2254
+ * map behind a loading screen while this runs; the visitor would
2255
+ * otherwise see it jump between floors.
2256
+ *
2257
+ * The step highlight is cleared, not restored: call `setActiveStep`
2258
+ * again with the step your UI is showing. Resolves to `[]` when no route
2259
+ * is displayed.
2260
+ */
2261
+ captureRouteFloorImages(opts?: RouteImageOptions): Promise<RouteFloorImage[]>;
2094
2262
  clearRoute(): void;
2095
2263
  /**
2096
2264
  * Put the end-of-route marker on `poi`, or take it down (`null`). With
@@ -2124,8 +2292,10 @@ declare class MinuteMaps {
2124
2292
  *
2125
2293
  * This is deliberately *not* `highlightPOI`, which is the search-locate
2126
2294
  * gesture — it zooms and recenters and draws a pulsing ring, and emits
2127
- * nothing. Selection is the quieter one: current zoom kept, no ring, the
2128
- * raised room is the indicator.
2295
+ * nothing. Selection is the quieter one: no ring, the raised room is the
2296
+ * indicator, and the current zoom is kept — unless it is further out than
2297
+ * the Kiosk view (`KIOSK_VIEW_MIN_ZOOM`), where the building's roof still
2298
+ * hides the room, in which case the camera zooms in to that view.
2129
2299
  *
2130
2300
  * Accepts a `POI` (preferred — its `type` and `waypointId` pin down the exact
2131
2301
  * instance, which matters for an amenity that shares one id across every
@@ -2206,7 +2376,8 @@ declare class MinuteMaps {
2206
2376
  /** Gentle pan so the selection sits in the centre of the map area MapLibre
2207
2377
  * frames within `boundsPadding` (which the consumer sets to reserve for its
2208
2378
  * bottom-docked chrome / info card). A straight `easeTo`, current zoom kept,
2209
- * so it reads as a nudge, not a recenter. */
2379
+ * so it reads as a nudge, not a recenter — unless `selectedMinZoom` is set
2380
+ * and the camera is further out, in which case it zooms in to that floor. */
2210
2381
  private easeToSelection;
2211
2382
  /** Dim every unit's paint (or restore it) so a selected room reads as the
2212
2383
  * focus. Idempotent: capturing only happens on the first activate, and the
@@ -2652,5 +2823,5 @@ type ResolvedIconSource = {
2652
2823
  */
2653
2824
  declare function resolveAmenityIconSource(amenity: AmenityLike, preferredLocale?: string): ResolvedIconSource | null;
2654
2825
 
2655
- export { BUILDING_NAME_EXTENSOR_KEY, DAY_KEYS, IMAGE_ALT_EXTENSOR_KEY, MinuteMaps, OPEN_HOURS_EXTENSOR_KEY, OPEN_HOURS_VERSION, PHONE_EXTENSOR_KEY, POINT_OF_INTEREST_EXTENSOR_KEY, RESERVED_EXTENSOR_PREFIX, SNAPSHOT_SCHEMA_VERSION, SnapshotProvider, SnapshotUnavailableError, VenueDirectory, activeSectionIndex, createMinuteMapsSDK, customerDisplayName, getOpenStatus, groupStepsIntoFloorSections, isConnectorAmenity, parseBuildingName, parseImageAlt, parseOpenHours, parsePhone, parsePointOfInterest, resolveAmenityIconSource, resolveSnapshotLocale };
2656
- export type { Amenity, AmenityBadgeStyle, AmenityWithFloor, Bounds, BoundsPadding, CameraState, Customer, CustomerVenues, DayKey, Destination, DestinationPhone, EventCallback, Floor, FloorMetadata, HoursRange, JMapAuth, JMapConfig, JacsAuth, JacsConfig, JacsProviderConfig, JacsReader, ListCustomerVenuesOptions, MapEvent, OpenHours, OpenHoursTransition, OpenStatus, OpenStatusOptions, POI, POISearchResult, ResolvedIconSource, RouteFloorSection, RoutePoint, RoutingOptions, SDKConfig, SDKOptions, SnapshotProviderConfig, SnapshotUpdateCheck, SnapshotVersions, ThemeName, TransitionStep, VenueDirectoryConfig, VenueSummary, ViewOptions, WayfindCenterMode, WayfindStep, Waypoint, Zone };
2826
+ export { BUILDING_NAME_EXTENSOR_KEY, DAY_KEYS, IMAGE_ALT_EXTENSOR_KEY, MinuteMaps, OPEN_HOURS_EXTENSOR_KEY, OPEN_HOURS_VERSION, PHONE_EXTENSOR_KEY, POINT_OF_INTEREST_EXTENSOR_KEY, RESERVED_EXTENSOR_PREFIX, SNAPSHOT_SCHEMA_VERSION, SnapshotProvider, SnapshotUnavailableError, VenueDirectory, activeSectionIndex, createMinuteMapsSDK, customerDisplayName, dayKeyAt, getOpenStatus, groupStepsIntoFloorSections, isConnectorAmenity, parseBuildingName, parseImageAlt, parseOpenHours, parsePhone, parsePointOfInterest, resolveAmenityIconSource, resolveSnapshotLocale, timeZoneAbbreviation };
2827
+ export type { Amenity, AmenityBadgeStyle, AmenityWithFloor, Bounds, BoundsPadding, CameraState, Customer, CustomerVenues, DayKey, Destination, DestinationPhone, EventCallback, Floor, FloorMetadata, HoursRange, JMapAuth, JMapConfig, JacsAuth, JacsConfig, JacsProviderConfig, JacsReader, ListCustomerVenuesOptions, MapEvent, OpenHours, OpenHoursTransition, OpenStatus, OpenStatusOptions, POI, POISearchResult, ResolvedIconSource, RouteFloorImage, RouteFloorSection, RouteImageOptions, RoutePoint, RoutingOptions, SDKConfig, SDKOptions, SnapshotProviderConfig, SnapshotUpdateCheck, SnapshotVersions, ThemeName, TransitionStep, VenueDirectoryConfig, VenueSummary, ViewOptions, WayfindCenterMode, WayfindStep, Waypoint, Zone };