@minmaps-dev/mm-web-sdk 1.0.0-rc.31 → 1.0.0-rc.33

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
@@ -142,6 +142,10 @@ interface Waypoint {
142
142
  floorId?: string | number;
143
143
  /** Whether this is the primary/default waypoint */
144
144
  isPrimary?: boolean;
145
+ /** CMS zone (department) this waypoint belongs to, if any. The only backend
146
+ * link between a location and its department — read at runtime across the
147
+ * data provider (see the package CLAUDE.md zone landmine). */
148
+ zoneId?: string | number;
145
149
  }
146
150
  /**
147
151
  * Amenity enriched with the floor it belongs to
@@ -277,6 +281,10 @@ type ArriveStep = StepBase & {
277
281
  interface MapEvent {
278
282
  floor?: Floor;
279
283
  poi?: POI;
284
+ /** All POIs co-located at a clicked point (overlapping pins / a shared
285
+ * suite). Emitted by `poiSelected`; length ≥ 1, and `poi` mirrors
286
+ * `pois[0]` for single-POI consumers. */
287
+ pois?: POI[];
280
288
  coordinates?: [number, number];
281
289
  error?: any;
282
290
  venue?: any;
@@ -528,6 +536,23 @@ declare class AmenityManager {
528
536
  declare class MinuteMaps {
529
537
  private config;
530
538
  private map;
539
+ /**
540
+ * Generation token for `init()`. Bumped by every `init()` and by `destroy()`,
541
+ * so an init suspended on a network await can tell it has been superseded and
542
+ * bail instead of creating a map nobody holds a reference to.
543
+ *
544
+ * This is what makes `destroy()` safe *during* init: `destroy()` only removes
545
+ * `this.map`, which is still null until step 3, so a teardown that lands
546
+ * mid-fetch has nothing to clean up — and without this token the init would
547
+ * resume and build a fully live orphan (WebGL context, render loop, map-level
548
+ * listeners, YAH pulse) that can never be reached to shut down. React
549
+ * StrictMode's mount → unmount → mount does exactly this on every dev load.
550
+ *
551
+ * A counter, not a sticky `destroyed` flag: `destroy()` → `init()` re-init is
552
+ * a supported lifecycle (see the manager-class note in CLAUDE.md), so the
553
+ * instance has to stay usable after teardown.
554
+ */
555
+ private initGeneration;
531
556
  private data;
532
557
  private wayfindingProvider;
533
558
  private events;
@@ -549,7 +574,47 @@ declare class MinuteMaps {
549
574
  private amenityManager;
550
575
  private wayfinding;
551
576
  private highlightManager;
577
+ private selectionManager;
578
+ /** Captured unit paint values to restore when the selection clears, or
579
+ * `null` when no room is currently focused. See `UNIT_DIM_TARGETS`. */
580
+ private unitDimRestore;
581
+ /** Captured destination-layer filters to restore when the selection clears,
582
+ * or `null` when no destination focus is active. See `setDestinationFocus`. */
583
+ private destFocusRestore;
584
+ /** The allow-list currently narrowing the destination layers, or `null` when
585
+ * no focus is active. Kept alongside `destFocusRestore` (which holds the
586
+ * *previous* filters, not the ids) so `setTheme` can re-apply the same focus
587
+ * to the new style's layers after a swap discards the old ones. */
588
+ private destFocusIds;
552
589
  private youAreHerePulse;
590
+ /** Theme layers whose features represent a tappable destination/amenity.
591
+ * A click hit-tests these (see `SelectionManager`) → `poiSelected`. The
592
+ * "You are here" anchor and the transient highlight layers are excluded;
593
+ * a POI drawn across the circle/label/icon layers is de-duped downstream
594
+ * in `resolveClickedPOIs`. */
595
+ private static readonly CLICKABLE_POI_LAYERS;
596
+ /** Room-body layers that are also tappable: a click on a `Units` polygon
597
+ * resolves to the destination pin inside it (see `resolvePOIsFromFeatures`).
598
+ * Queried alongside the pin layers so tapping the room or its dot behaves
599
+ * identically. Kept separate from the pin list because these carry no POI
600
+ * identity of their own — they resolve spatially. */
601
+ private static readonly CLICKABLE_UNIT_LAYERS;
602
+ /** While a room is selected, the other units are recolored to a flat, muted
603
+ * gray so the raised, full-strength highlight block reads as the focus. We
604
+ * recolor rather than lower opacity on purpose: translucent extrusions blend
605
+ * through their neighbours and look murky. The blocks stay fully opaque (and
606
+ * keep their vertical-gradient shading, so they still read as rooms) — just
607
+ * colorless. The selected room's own base grays too, but its highlight cap
608
+ * sits opaque and taller on top, so it still stands out. The original paint
609
+ * value (the data-driven color expression) is captured at mute time and put
610
+ * back on `clearHighlight`, so department tinting returns intact. */
611
+ private static readonly UNIT_DIM_TARGETS;
612
+ /** Destination marker layers hidden down to just the selected destination
613
+ * while a room is focused, so the map declutters to the one place in view.
614
+ * Amenity/connector layers (`poiType: 'amenity'`), the "you are here" anchor,
615
+ * and room name labels (`map-labels`) are deliberately absent — they stay
616
+ * visible as wayfinding reference. Restored on `clearHighlight`. */
617
+ private static readonly DESTINATION_FOCUS_LAYERS;
553
618
  /** Categorical POI layers in the bundled theme that `setPOIFilter`
554
619
  * toggles. Layers absent from this list — `poi-you-are-here-*`, the
555
620
  * `poi-accessibility-icons` badge, and the `poi-highlight-*` layers —
@@ -559,6 +624,25 @@ declare class MinuteMaps {
559
624
  private poiVisibleTypes;
560
625
  constructor(config: SDKConfig);
561
626
  init(): Promise<void>;
627
+ /**
628
+ * Supply an image the current style has requested but doesn't have.
629
+ *
630
+ * Every imperatively-registered image is served from here, because a theme
631
+ * swap (`setStyle` with `diff: false`) drops all of them and the code that
632
+ * registered them doesn't run again:
633
+ *
634
+ * - the **route arrow** isn't in the sprite sheet at all — it's canvas-drawn
635
+ * on demand (this was already the case);
636
+ * - **amenity / destination icons** come back from `iconCache`. Their
637
+ * registrars run only during `init`, so before this they went missing on
638
+ * the first theme swap and never returned — the map kept the dots and
639
+ * labels but lost every badge and logo.
640
+ *
641
+ * Serving lazily (rather than re-registering everything on `style.load`)
642
+ * means only the ids the new style actually asks for are restored, with no
643
+ * refetch and no re-compositing.
644
+ */
645
+ private serveMissingStyleImage;
562
646
  on(event: string, cb: (e: MapEvent) => void): void;
563
647
  off(event: string, cb?: (e: MapEvent) => void): void;
564
648
  addControl(control: IControl, position?: ControlPosition): void;
@@ -642,6 +726,30 @@ declare class MinuteMaps {
642
726
  getDefaultFloor(): Floor | null;
643
727
  getDestinations(floor?: Floor): Destination[];
644
728
  getZones(): Zone[];
729
+ /** The department (zone) a POI belongs to, resolved via its waypoint's
730
+ * `zoneId` — the only backend link between a location and a department
731
+ * (see the zone landmine in the package CLAUDE.md). `null` when the POI
732
+ * has no waypoint, no zone, or the zone id is unknown. */
733
+ getZoneForPOI(poi: POI): Zone | null;
734
+ /** Human-readable detail fields for a POI info popover. Only surfaces
735
+ * fields that exist on the current data — `category`, `floorName`,
736
+ * `zoneName`, `keywords`, and `description` are each omitted when absent.
737
+ * Keeps the display-field derivation (incl. the zone lookup) in the SDK
738
+ * so consumers stay thin. */
739
+ getPOIDetails(poi: POI): {
740
+ name: string;
741
+ type: 'amenity' | 'destination' | 'kiosk';
742
+ category?: string;
743
+ floorName?: string;
744
+ zoneName?: string;
745
+ zoneDescription?: string;
746
+ keywords?: string[];
747
+ description?: string;
748
+ };
749
+ /** Resolve the source Destination/Amenity record backing a rendered POI,
750
+ * for detail fields (category, localized description) that don't live on
751
+ * the built POI object. */
752
+ private getSourceEntity;
645
753
  getPolygonLayers(): any[];
646
754
  getFloorMapTemplate3d(floorId: string | number): any[];
647
755
  getAllPOIs(floor?: Floor): POI[];
@@ -777,8 +885,52 @@ declare class MinuteMaps {
777
885
  * it lives on another one. Pass a POI / amenity / destination id.
778
886
  */
779
887
  highlightPOI(id: string | number): Promise<void>;
780
- /** Remove the POI highlight set by `highlightPOI`. */
888
+ /** Remove the POI highlight set by `highlightPOI`, un-dim the other units,
889
+ * and bring back the destination markers hidden by a room selection. */
781
890
  clearHighlight(): void;
891
+ /** Map a click's raw feature hits to the full, de-duplicated POIs at that
892
+ * point (see `resolvePOIsFromFeatures`). Injected into `SelectionManager`.
893
+ * `getAllPOIs()` is the current floor's rendered POIs — the only clickable
894
+ * ones — and carries each POI's `waypoint`, needed for directions. */
895
+ private resolveClickedPOIs;
896
+ /** Emit `poiSelected` for the co-located POIs at a clicked point. Focuses the
897
+ * selection in place (no recenter — the user already sees where they
898
+ * tapped): rings the tapped dot and, when the tap landed in a room, raises
899
+ * that room as a highlighted block so the eye goes to the selected unit.
900
+ * `clearHighlight` removes both. `poi` mirrors `pois[0]` for single-POI
901
+ * consumers. */
902
+ private emitPoiSelected;
903
+ /**
904
+ * Build the room-highlight payload for a selection. The colour comes from the
905
+ * *clicked* feature (the rendered truth), but the geometry comes from the
906
+ * floor's full source polygon — the clicked feature is from
907
+ * `queryRenderedFeatures`, whose geometry is clipped to on-screen tiles, so
908
+ * highlighting it directly would leave any off-screen part of the room grey
909
+ * (its base extrusion is muted). Falls back to the clipped geometry if the
910
+ * full polygon can't be found. Returns `null` for a pin with no room.
911
+ */
912
+ private unitHighlightFor;
913
+ /** The full, unclipped `Units` polygon on the current floor that contains
914
+ * `coord`, straight from the floor source (not the tile-clipped render). */
915
+ private fullUnitPolygonAt;
916
+ /**
917
+ * Hide every destination marker except the given ids (pass `null` to
918
+ * restore all). Narrows each destination layer's own filter with an id
919
+ * allow-list; amenity/connector/"you are here" layers are untouched, so they
920
+ * stay on the map as reference. Captures the original filters once and puts
921
+ * them back verbatim, so the layers' base rules (poiType, showLabel, iconId)
922
+ * survive.
923
+ */
924
+ private setDestinationFocus;
925
+ /** Gentle pan so the selection sits in the centre of the map area MapLibre
926
+ * frames within `boundsPadding` (which the consumer sets to reserve for its
927
+ * bottom-docked chrome / info card). A straight `easeTo`, current zoom kept,
928
+ * so it reads as a nudge, not a recenter. */
929
+ private easeToSelection;
930
+ /** Dim every unit's paint (or restore it) so a selected room reads as the
931
+ * focus. Idempotent: capturing only happens on the first activate, and the
932
+ * captured originals are put back verbatim on deactivate. */
933
+ private setUnitFocusDim;
782
934
  /**
783
935
  * Show only the named POI categories on the map. Pass `['amenity']` to
784
936
  * emphasize amenities (e.g. while an Amenities drawer is open) — destination