Appearance
MapInstance — module-level vs instance-level API
init() returns a MapInstance handle representing the embedded map. Most lifecycle and command methods are also accessible at the module level (mapsted.maps.*) because the API is designed around a single map per page. Both surfaces exist intentionally — this page explains why and when to prefer each.
What MapInstance is
ts
import * as maps from '@mapsted/maps-js-api';
const map = await maps.init({
element: '#map-container',
propertyId: 603,
mapsDomain: 'https://maps.mapsted.com',
});map is the MapInstance returned by init(). It exposes:
| Method | Purpose |
|---|---|
destroy() | Tear the iframe down and reset all state. |
getState() | Snapshot of current MapState (active building, floor, language, lifecycle state). |
isReady() | Async — resolves to true once the lifecycle is in READY state (await it). |
subscribe() | React-style state subscription. Distinct from event-system on(). |
The dual API surface
Almost every method is callable both ways:
ts
// Instance-level
await map.destroy();
const state = await map.getState();
// Module-level — equivalent
await maps.destroy();
const state = await maps.getState();Both forms target the same singleton internally. Module-level calls are the older surface (V2/V3 ergonomic muscle memory); instance-level calls are the canonical contract returned by init().
Single-map-per-page constraint
The API is designed around a single mounted map per page. Calling init() a second time without a prior destroy() throws MAPSTED-1001. Both the module-level and instance-level handles refer to the same underlying iframe.
ts
const a = await maps.init({ element: '#map-1', propertyId: 603 /* ... */ });
await maps.init({ element: '#map-2', propertyId: 603 /* ... */ }); // throws MAPSTED-1001To swap maps:
ts
await a.destroy();
const b = await maps.init({ element: '#map-2', propertyId: 603 /* ... */ });When to prefer instance-level
- TypeScript ergonomics — the typed
MapInstancehandle gives IDE autocomplete and lets you pass the map around as a value (e.g. into a React Context or a Redux store). - Multi-component composition — a top-level component owns the
MapInstancefrominit()and child components receive it via props rather than reaching for the global. - Test mocking — easier to stub a typed object than a global namespace.
When to prefer module-level
- CDN / single-script embedding — the IIFE bundle exposes
window.mapsted.maps.*for legacy V2/V3 muscle memory; existing CDN snippets keep working. - Quick console debugging —
mapsted.maps.getState()is one autocomplete hop in the browser devtools console without needing the instance reference. - Lifecycle calls before
init()—await mapsted.maps.isReady()is callable beforeinit()resolves (it resolves tofalse); the instance does not exist yet.
Subscriptions: instance-level vs event system
MapInstance also exposes subscribe(), which is distinct from the event system on()/off()/once():
| API | Fires on | Use for |
|---|---|---|
instance.subscribe(handler) | Any MapState field change | React/Vue/Svelte state syncing |
maps.on(eventName, handler) | A specific named event firing | Discrete event reactions (selection, navigation, idle, theme) |
See Event system for the event-driven API and Lifecycle for the state-machine view.