@projektemacher/storymapjs 0.10.8 → 0.11.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.
Files changed (195) hide show
  1. package/CHANGELOG +81 -0
  2. package/README.md +129 -12
  3. package/dist/assets/{demo-DBpeF31K.js → demo-bWnOyfUw.js} +1 -1
  4. package/dist/assets/harness-C3JUv5Ii.js +1 -0
  5. package/dist/assets/{harness-multi-CYHgI0a9.js → harness-multi-XZNex3tb.js} +1 -1
  6. package/dist/assets/{harness-support-Do7sIp2j.js → harness-support-CjfZIVeb.js} +1 -1
  7. package/dist/assets/main-DQ32hWBM.js +17 -0
  8. package/dist/context.json +13 -2
  9. package/dist/css/storymap.css +1 -1
  10. package/dist/demo.html +3 -2
  11. package/dist/docs/api/assets/navigation.js +1 -1
  12. package/dist/docs/api/assets/search.js +1 -1
  13. package/dist/docs/api/classes/StoryMap.html +777 -269
  14. package/dist/docs/api/functions/MediaType.html +1 -1
  15. package/dist/docs/api/functions/isPresentation3Collection.html +1 -1
  16. package/dist/docs/api/functions/isPresentation3Manifest.html +1 -1
  17. package/dist/docs/api/functions/isSlideshowCollection.html +51 -0
  18. package/dist/docs/api/functions/loadCSS.html +1 -1
  19. package/dist/docs/api/functions/manifestToStorymapData.html +1 -1
  20. package/dist/docs/api/functions/setLanguage.html +1 -1
  21. package/dist/docs/api/functions/slideshowToStorymapData.html +51 -0
  22. package/dist/docs/api/functions/slideshowVersion.html +48 -0
  23. package/dist/docs/api/functions/storymapToManifest.html +1 -1
  24. package/dist/docs/api/functions/validateStorymap.html +1 -1
  25. package/dist/docs/api/functions/validateStorymapAndReport.html +1 -1
  26. package/dist/docs/api/index.html +115 -12
  27. package/dist/docs/api/interfaces/AnimationHandle.html +2 -2
  28. package/dist/docs/api/interfaces/ImagereadyPayload.html +4 -4
  29. package/dist/docs/api/interfaces/LanguageEntry.html +6 -6
  30. package/dist/docs/api/interfaces/LatLngLiteral.html +4 -4
  31. package/dist/docs/api/interfaces/LoadOptions.html +2 -2
  32. package/dist/docs/api/interfaces/MapEvents.html +116 -0
  33. package/dist/docs/api/interfaces/MapMarkerEvents.html +66 -0
  34. package/dist/docs/api/interfaces/MarkerEventPayload.html +57 -0
  35. package/dist/docs/api/interfaces/MediaEvents.html +78 -0
  36. package/dist/docs/api/interfaces/MenuBarEvents.html +114 -0
  37. package/dist/docs/api/interfaces/MessageEvents.html +72 -0
  38. package/dist/docs/api/interfaces/OlLayer.html +1 -1
  39. package/dist/docs/api/interfaces/OlMap.html +1 -1
  40. package/dist/docs/api/interfaces/OlSource.html +1 -1
  41. package/dist/docs/api/interfaces/OlTileLayer.html +1 -1
  42. package/dist/docs/api/interfaces/OlVectorLayer.html +1 -1
  43. package/dist/docs/api/interfaces/OlView.html +1 -1
  44. package/dist/docs/api/interfaces/SlideBackgroundState.html +66 -0
  45. package/dist/docs/api/interfaces/SlideEvents.html +78 -0
  46. package/dist/docs/api/interfaces/SlideNavEvents.html +72 -0
  47. package/dist/docs/api/interfaces/SlideshowPlayerSettings.html +182 -0
  48. package/dist/docs/api/interfaces/SlideshowToStorymapResult.html +60 -0
  49. package/dist/docs/api/interfaces/SlideshowTranslatorOptions.html +65 -0
  50. package/dist/docs/api/interfaces/SlideshowWarning.html +72 -0
  51. package/dist/docs/api/interfaces/StoryMapEvents.html +146 -0
  52. package/dist/docs/api/interfaces/StoryMapMarker.html +763 -0
  53. package/dist/docs/api/interfaces/StorySliderEvents.html +102 -0
  54. package/dist/docs/api/interfaces/StorymapBasemap.html +69 -0
  55. package/dist/docs/api/interfaces/StorymapData.html +12 -6
  56. package/dist/docs/api/interfaces/StorymapDataWrapper.html +2 -2
  57. package/dist/docs/api/interfaces/StorymapDocument.html +2 -2
  58. package/dist/docs/api/interfaces/StorymapError.html +3 -3
  59. package/dist/docs/api/interfaces/StorymapGeoreference.html +5 -5
  60. package/dist/docs/api/interfaces/StorymapGeoreferenceBody.html +4 -4
  61. package/dist/docs/api/interfaces/StorymapGroundControlPoint.html +4 -4
  62. package/dist/docs/api/interfaces/StorymapLanguageMap.html +2 -2
  63. package/dist/docs/api/interfaces/StorymapManifest.html +12 -12
  64. package/dist/docs/api/interfaces/StorymapManifestAnnotation.html +43 -11
  65. package/dist/docs/api/interfaces/StorymapManifestBackground.html +6 -6
  66. package/dist/docs/api/interfaces/StorymapManifestCanvas.html +65 -17
  67. package/dist/docs/api/interfaces/StorymapManifestContentResource.html +8 -8
  68. package/dist/docs/api/interfaces/StorymapManifestFeatureCollection.html +4 -4
  69. package/dist/docs/api/interfaces/StorymapManifestGeoreferencing.html +7 -7
  70. package/dist/docs/api/interfaces/StorymapManifestImageService.html +4 -4
  71. package/dist/docs/api/interfaces/StorymapManifestRange.html +5 -5
  72. package/dist/docs/api/interfaces/StorymapManifestService.html +4 -4
  73. package/dist/docs/api/interfaces/StorymapManifestSpecificResource.html +4 -4
  74. package/dist/docs/api/interfaces/StorymapManifestStatement.html +3 -3
  75. package/dist/docs/api/interfaces/StorymapMapOptions.html +5 -5
  76. package/dist/docs/api/interfaces/StorymapOptions.html +277 -75
  77. package/dist/docs/api/interfaces/StorymapOverlayLayer.html +42 -11
  78. package/dist/docs/api/interfaces/StorymapSlide.html +70 -16
  79. package/dist/docs/api/interfaces/StorymapSlideBackground.html +4 -4
  80. package/dist/docs/api/interfaces/StorymapSlideLocation.html +58 -14
  81. package/dist/docs/api/interfaces/StorymapSlideMarker.html +8 -9
  82. package/dist/docs/api/interfaces/StorymapSlideMedia.html +49 -10
  83. package/dist/docs/api/interfaces/StorymapSlideNarration.html +61 -9
  84. package/dist/docs/api/interfaces/StorymapSlideText.html +4 -4
  85. package/dist/docs/api/interfaces/StorymapTilejson.html +8 -8
  86. package/dist/docs/api/interfaces/SwipableEvents.html +102 -0
  87. package/dist/docs/api/interfaces/TextEvents.html +66 -0
  88. package/dist/docs/api/media/events.md +66 -0
  89. package/dist/docs/api/media/migration-from-knightlab.md +89 -49
  90. package/dist/docs/api/media/slideshow.md +109 -0
  91. package/dist/docs/api/media/storymap-as-iiif-manifest.md +1007 -0
  92. package/dist/docs/api/modules.html +6 -6
  93. package/dist/docs/api/types/ContentState.html +3 -3
  94. package/dist/docs/api/types/FiredEvent.html +43 -0
  95. package/dist/docs/api/types/ImagereadyKind.html +1 -1
  96. package/dist/docs/api/types/MediaTypeMatch.html +5 -5
  97. package/dist/docs/api/types/SwipeDirection.html +36 -0
  98. package/dist/docs/api/types/TileSourceFactory.html +1 -1
  99. package/dist/docs/authoring.html +20 -7
  100. package/dist/docs/events.html +263 -0
  101. package/dist/docs/iiif.html +136 -22
  102. package/dist/docs/migration.html +66 -19
  103. package/dist/docs/readme.html +113 -12
  104. package/dist/embed/index.html +7 -0
  105. package/dist/examples/font-css-false.json +33 -0
  106. package/dist/examples/issue-image-region.json +1 -1
  107. package/dist/examples/layers-control.json +60 -0
  108. package/dist/examples/map-template-provider.json +36 -0
  109. package/dist/examples/multi-media.json +71 -0
  110. package/dist/examples-iiif/annotated-image.json +16 -0
  111. package/dist/examples-iiif/font-css-false.json +114 -0
  112. package/dist/examples-iiif/issue-image-region.json +1 -1
  113. package/dist/examples-iiif/layers-control.json +226 -0
  114. package/dist/examples-iiif/map-template-provider.json +133 -0
  115. package/dist/examples-iiif/multi-media.json +237 -0
  116. package/dist/examples-slideshow/single.json +79 -0
  117. package/dist/examples-slideshow/static/pixel.png +0 -0
  118. package/dist/examples-slideshow/static.json +44 -0
  119. package/dist/harness-multi.html +3 -3
  120. package/dist/harness.html +4 -3
  121. package/dist/index.html +3 -2
  122. package/dist/js/storymap.d.ts +1326 -289
  123. package/dist/js/storymap.js +6690 -4784
  124. package/dist/js/storymap.js.map +1 -1
  125. package/dist/navplace-properties.json +14 -0
  126. package/dist/site.css +54 -36
  127. package/docs/migration-from-knightlab.md +89 -49
  128. package/docs/storymap-as-iiif-manifest.md +199 -126
  129. package/package.json +4 -2
  130. package/schema/storymap.schema.json +334 -34
  131. package/src/core/Util.ts +3 -1
  132. package/src/core/mixins.ts +42 -28
  133. package/src/language/Language.ts +7 -0
  134. package/src/language/locale/.expected-gaps.json +287 -27
  135. package/src/language/locale/de.json +11 -1
  136. package/src/language/locale/en.json +11 -1
  137. package/src/main.ts +51 -0
  138. package/src/map/Map.ts +44 -6
  139. package/src/map/MapMarker.ts +16 -3
  140. package/src/map/openlayers/Map.OpenLayers.ts +787 -62
  141. package/src/map/openlayers/MapMarker.OpenLayers.ts +113 -13
  142. package/src/map/slideView.ts +149 -0
  143. package/src/map/types.ts +2 -0
  144. package/src/media/EmbedUtil.ts +27 -2
  145. package/src/media/Media.ts +27 -4
  146. package/src/media/embedId.ts +6 -0
  147. package/src/media/types/Flickr.ts +14 -3
  148. package/src/media/types/HtmlMedia.ts +66 -0
  149. package/src/media/types/Image.ts +15 -3
  150. package/src/media/types/SoundCloud.ts +1 -1
  151. package/src/media/types/Text.ts +27 -8
  152. package/src/media/types/Twitter.ts +9 -7
  153. package/src/media/types/Vimeo.ts +1 -1
  154. package/src/media/types/YouTube.ts +2 -2
  155. package/src/scss/Typography.scss +15 -15
  156. package/src/scss/VCO.StoryMap.scss +173 -8
  157. package/src/scss/core/Reset.scss +5 -18
  158. package/src/scss/map/VCO.Map.scss +1 -1
  159. package/src/scss/map/VCO.MapMarker.scss +20 -9
  160. package/src/scss/map/openlayers/VCO.Map.OpenLayers.scss +7 -4
  161. package/src/scss/media/VCO.Media.scss +7 -7
  162. package/src/scss/media/types/VCO.Media.Blockquote.scss +1 -1
  163. package/src/scss/media/types/VCO.Media.Text.scss +5 -5
  164. package/src/scss/media/types/VCO.Media.Twitter.scss +4 -4
  165. package/src/scss/media/types/VCO.Media.Wikipedia.scss +2 -19
  166. package/src/scss/site/site.scss +55 -36
  167. package/src/scss/slider/VCO.Slide.scss +49 -11
  168. package/src/scss/slider/VCO.SlideNav.scss +23 -7
  169. package/src/scss/slider/VCO.StorySlider.scss +50 -0
  170. package/src/scss/snapmap/VCO.SnapMap.scss +3 -3
  171. package/src/scss/ui/VCO.Consent.scss +20 -14
  172. package/src/scss/ui/VCO.Layers.scss +119 -0
  173. package/src/scss/ui/VCO.MenuBar.Button.scss +140 -19
  174. package/src/scss/ui/VCO.MenuBar.scss +9 -2
  175. package/src/scss/ui/VCO.Message.scss +14 -0
  176. package/src/slider/Slide.ts +232 -74
  177. package/src/slider/SlideNav.ts +15 -4
  178. package/src/slider/StorySlider.ts +203 -22
  179. package/src/storymap/Consent.ts +22 -0
  180. package/src/storymap/StoryMap.ts +944 -131
  181. package/src/storymap/content-state.ts +3 -8
  182. package/src/storymap/font-css.ts +72 -0
  183. package/src/storymap/from-slideshow.ts +785 -0
  184. package/src/storymap/iiif-shared.ts +228 -0
  185. package/src/storymap/iiif.ts +289 -100
  186. package/src/storymap/to-iiif.ts +131 -44
  187. package/src/types.ts +382 -17
  188. package/src/ui/LayersControl.ts +302 -0
  189. package/src/ui/MenuBar.ts +232 -21
  190. package/src/ui/Message.ts +36 -3
  191. package/src/ui/Swipable.ts +25 -7
  192. package/dist/assets/harness-Cr0rYpvt.js +0 -1
  193. package/dist/assets/main-DXalctuR.js +0 -17
  194. package/src/scss/VCO.StoryMap.Dark.scss +0 -150
  195. package/src/scss/Variables.Dark.scss +0 -57
@@ -1,7 +1,9 @@
1
1
  import { default as default_2 } from 'ol/control/OverviewMap';
2
2
  import { default as default_3 } from 'ol/Overlay';
3
3
  import { default as default_4 } from 'ol/tilegrid/TileGrid';
4
+ import { default as default_5 } from 'ol/source/ImageStatic';
4
5
  import { Extent } from 'ol/extent';
6
+ import { Image as Image_2 } from 'ol/layer';
5
7
  import { Map as Map_3 } from 'ol';
6
8
  import { default as OlLayer } from 'ol/layer/Layer';
7
9
  import { default as OlMap } from 'ol/Map';
@@ -12,6 +14,7 @@ import { default as OlVectorLayer } from 'ol/layer/Vector';
12
14
  import { default as OlView } from 'ol/View';
13
15
  import { Style } from 'ol/style';
14
16
  import { Tile } from 'ol/layer';
17
+ import { unByKey } from 'ol/Observable';
15
18
  import { Vector } from 'ol/layer';
16
19
  import { XYZ } from 'ol/source';
17
20
 
@@ -137,6 +140,9 @@ declare interface ConsentService {
137
140
  label: string;
138
141
  }
139
142
 
143
+ /** Constructor shape accepted by the mixin functions. */
144
+ declare type Constructor<T = object> = new (...args: any[]) => T;
145
+
140
146
  export declare type ContentState = {
141
147
  /** The canvas (or other resource) the state points at. */
142
148
  id: string;
@@ -150,7 +156,7 @@ export declare type ContentState = {
150
156
 
151
157
  declare interface DragData {
152
158
  sliding: boolean;
153
- direction: string | null;
159
+ direction: SwipeDirection | null;
154
160
  pagex: {
155
161
  start: number;
156
162
  end: number;
@@ -193,13 +199,25 @@ declare interface DragEventNames {
193
199
  }
194
200
 
195
201
  /** Eventing members provided by the Evented mixin. */
196
- declare interface EventedInstance {
197
- on: (type: string, fn: unknown, context?: unknown) => unknown;
198
- off: (type: string, fn: unknown, context?: unknown) => unknown;
199
- fire: (type: string, data?: unknown, target?: unknown) => unknown;
200
- hasEventListeners: (type: string) => boolean;
202
+ declare interface EventedInstance<M = Record<string, unknown>> {
203
+ on<K extends keyof M & string>(type: K, fn: (e: FiredEvent<M, K>) => void, context?: unknown): this;
204
+ off<K extends keyof M & string>(type: K, fn: (e: FiredEvent<M, K>) => void, context?: unknown): this;
205
+ fire<K extends keyof M & string>(type: K, data?: M[K]): this;
206
+ hasEventListeners<K extends keyof M & string>(type: K): boolean;
201
207
  }
202
208
 
209
+ /** What a listener receives: the payload, plus the framework's own fields.
210
+ *
211
+ * Kept as an intersection because `fire` merges them into one object — that
212
+ * is what a handler gets. As a side effect it also fixes the `type`
213
+ * clobbering at the type level: intersecting `type: "loaded"` with
214
+ * `type?: string` yields `"loaded"`.
215
+ */
216
+ export declare type FiredEvent<M, K extends keyof M & string> = M[K] & {
217
+ type: K;
218
+ target: unknown;
219
+ };
220
+
203
221
  declare type IconSpec = {
204
222
  url: string;
205
223
  size: number[];
@@ -237,6 +255,14 @@ export declare function isPresentation3Collection(data: unknown): boolean;
237
255
  */
238
256
  export declare function isPresentation3Manifest(data: unknown): boolean;
239
257
 
258
+ /**
259
+ * True for a slideshow tour document: a v2 `AnnotationCollection` or a v1
260
+ * `AnnotationPageSequence` carrying the matching extension context (never a
261
+ * P3 `Manifest`/`Collection`), with items shaped like tour annotations.
262
+ * Narrow by conjunction so P3 `seeAlso` collections never match.
263
+ */
264
+ export declare function isSlideshowCollection(doc: unknown): boolean;
265
+
240
266
  /**
241
267
  * UI strings for the active locale.
242
268
  *
@@ -278,6 +304,84 @@ export declare interface LatLngLiteral {
278
304
  lng?: number;
279
305
  }
280
306
 
307
+ declare interface LayersBasemapRow {
308
+ kind: "basemap";
309
+ map_type: string;
310
+ label: string;
311
+ checked: boolean;
312
+ }
313
+
314
+ declare class LayersControl extends LayersControl_base {
315
+ constructor(...args: ConstructorParameters<typeof LayersControlBase>);
316
+ }
317
+
318
+ declare const LayersControl_base: Constructor<EventedInstance<LayersControlEvents>> & typeof LayersControlBase;
319
+
320
+ declare class LayersControlBase {
321
+ "_el": {
322
+ container: HTMLElement;
323
+ button: HTMLButtonElement;
324
+ panel: HTMLElement;
325
+ };
326
+ "_menubar": HTMLElement;
327
+ "_delegate": LayersControlDelegate | null;
328
+ "_rows": LayersRow[];
329
+ "_open": boolean;
330
+ "_panel_id": string;
331
+ "_onKeyDownBound": ((e: KeyboardEvent) => void) | null;
332
+ "_onPointerDownBound": ((e: Event) => void) | null;
333
+ "fire": EventedInstance<LayersControlEvents>["fire"];
334
+ constructor(menubar: HTMLElement);
335
+ /** Hand the control its state source (StoryMap wires this via MenuBar). */
336
+ setDelegate(delegate: LayersControlDelegate): void;
337
+ /** Re-pull rows from the delegate and sync the panel in place. */
338
+ refresh(): void;
339
+ /** Re-resolve row labels (function labels repaint on language change). */
340
+ refreshLabels(): void;
341
+ open(): void;
342
+ close(): void;
343
+ /**
344
+ * Release the document listeners and drop the nodes. Called by
345
+ * `MenuBar.dispose()`; the control must not be used afterwards.
346
+ */
347
+ dispose(): void;
348
+ _onButtonClick(): void;
349
+ _onRowChange(e: Event, row: LayersRow): void;
350
+ _onPanelKeyDown(e: KeyboardEvent): void;
351
+ _onDocumentPointerDown(e: Event): void;
352
+ _sameRows(rows: LayersRow[]): boolean;
353
+ _updateRows(rows: LayersRow[]): void;
354
+ _buildRows(rows: LayersRow[]): void;
355
+ _buildGroup(kind: "basemap" | "overlay", rows: LayersRow[]): HTMLElement;
356
+ _buildRow(row: LayersRow): HTMLElement;
357
+ }
358
+
359
+ declare interface LayersControlDelegate {
360
+ /** Current rows, basemaps first. Empty while there is nothing to switch. */
361
+ rows(): LayersRow[];
362
+ }
363
+
364
+ declare interface LayersControlEvents {
365
+ basemapchange: {
366
+ map_type: string;
367
+ };
368
+ overlaychange: {
369
+ index: number;
370
+ visible: boolean;
371
+ };
372
+ }
373
+
374
+ declare interface LayersOverlayRow {
375
+ kind: "overlay";
376
+ /** Built-layer index: malformed entries are skipped, like setOverlayVisible. */
377
+ index: number;
378
+ label: string;
379
+ checked: boolean;
380
+ locked: boolean;
381
+ }
382
+
383
+ declare type LayersRow = LayersOverlayRow | LayersBasemapRow;
384
+
281
385
  /** Legacy drag handlers historically mixed mouse and touch event surfaces. */
282
386
  declare type LegacyEvent = Event & {
283
387
  originalEvent?: TouchEvent;
@@ -333,23 +437,12 @@ declare const Map_base: {
333
437
  onRemove(): void;
334
438
  _el: Record<string, unknown>;
335
439
  data?: unknown;
336
- on: (type: string, fn: unknown, context?: unknown) => unknown;
337
- off: (type: string, fn: unknown, context?: unknown) => unknown;
338
- fire: (type: string, data?: unknown, target?: unknown) => unknown;
339
- hasEventListeners: (type: string) => boolean;
340
- };
341
- } & {
342
- new (...args: any[]): {
343
- _vco_events?: Record<string, {
344
- action: unknown;
345
- context: unknown;
346
- }[]> | undefined;
347
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
348
- hasEventListeners(type: string): boolean;
349
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
350
- fire(type: string, data?: unknown, target?: unknown): /*elided*/ any;
440
+ on<K extends "loaded" | "change" | "added" | "removed" | "markerclick" | "popupopen" | "popupclose" | "markerRemoved" | "markerAdded" | "imageready" | "tilesallowed">(type: K, fn: (e: FiredEvent<MapEvents, K>) => void, context?: unknown): /*elided*/ any;
441
+ off<K extends "loaded" | "change" | "added" | "removed" | "markerclick" | "popupopen" | "popupclose" | "markerRemoved" | "markerAdded" | "imageready" | "tilesallowed">(type: K, fn: (e: FiredEvent<MapEvents, K>) => void, context?: unknown): /*elided*/ any;
442
+ fire<K extends "loaded" | "change" | "added" | "removed" | "markerclick" | "popupopen" | "popupclose" | "markerRemoved" | "markerAdded" | "imageready" | "tilesallowed">(type: K, data?: MapEvents[K] | undefined): /*elided*/ any;
443
+ hasEventListeners<K extends "loaded" | "change" | "added" | "removed" | "markerclick" | "popupopen" | "popupclose" | "markerRemoved" | "markerAdded" | "imageready" | "tilesallowed">(type: K): boolean;
351
444
  };
352
- } & typeof MapBase;
445
+ } & Constructor<EventedInstance<MapEvents>> & typeof MapBase;
353
446
 
354
447
  declare class MapBase {
355
448
  "_el": {
@@ -377,6 +470,8 @@ declare class MapBase {
377
470
  "_line": Vector | null;
378
471
  "_line_active": Vector | null;
379
472
  "current_marker": number;
473
+ /** The wheel handler on the map element, stored for dispose(). */
474
+ "_onWheelBound": ((e: WheelEvent) => void) | null;
380
475
  "bounds_array": number[][] | null;
381
476
  "_tile_layer": OlLayer | null;
382
477
  "_tile_layer_mini": OlLayer | null;
@@ -388,7 +483,7 @@ declare class MapBase {
388
483
  "timer": ReturnType<typeof setTimeout> | null;
389
484
  "touch_scale": number;
390
485
  "scroll": ScrollState;
391
- "fire": EventedInstance["fire"];
486
+ "fire": EventedInstance<MapEvents>["fire"];
392
487
  constructor(elem: string | HTMLElement, data?: Partial<StorymapData>, options?: Partial<StorymapOptions>);
393
488
  updateDisplay(w: number, h: number, animate?: boolean, d?: number, offset?: unknown): void;
394
489
  goTo(n: number, change?: boolean): void;
@@ -523,6 +618,12 @@ declare class MapBase {
523
618
  _onMarkerClick(e: {
524
619
  marker_number: number;
525
620
  }): void;
621
+ _onMarkerPopupOpen(e: {
622
+ marker_number: number;
623
+ }): void;
624
+ _onMarkerPopupClose(e: {
625
+ marker_number: number;
626
+ }): void;
526
627
  _onMapLoaded(e?: unknown): void;
527
628
  _onWheel(e: WheelEvent): void;
528
629
  _scollZoom(e?: unknown): void;
@@ -538,22 +639,28 @@ declare class MapBase {
538
639
  _initEvents(): void;
539
640
  }
540
641
 
642
+ export declare interface MapEvents {
643
+ change: {
644
+ current_marker: number;
645
+ };
646
+ loaded: StorymapData;
647
+ added: StorymapData;
648
+ removed: StorymapData;
649
+ markerAdded: MapMarker;
650
+ markerRemoved: MapMarker;
651
+ markerclick: MarkerEventPayload;
652
+ popupopen: MarkerEventPayload;
653
+ popupclose: MarkerEventPayload;
654
+ imageready: ImagereadyPayload;
655
+ /** Deferred tile layers attached after a tile consent grant. */
656
+ tilesallowed: undefined;
657
+ }
658
+
541
659
  declare class MapMarker extends MapMarker_base {
542
660
  constructor(...args: ConstructorParameters<typeof MapMarkerBase>);
543
661
  }
544
662
 
545
- declare const MapMarker_base: {
546
- new (...args: any[]): {
547
- _vco_events?: Record<string, {
548
- action: unknown;
549
- context: unknown;
550
- }[]> | undefined;
551
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
552
- hasEventListeners(type: string): boolean;
553
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
554
- fire(type: string, data?: unknown, target?: unknown): /*elided*/ any;
555
- };
556
- } & typeof MapMarkerBase;
663
+ declare const MapMarker_base: Constructor<EventedInstance<MapMarkerEvents>> & typeof MapMarkerBase;
557
664
 
558
665
  declare class MapMarkerBase {
559
666
  "_el": Record<string, HTMLElement>;
@@ -568,7 +675,7 @@ declare class MapMarkerBase {
568
675
  "data": MapMarkerData;
569
676
  "options": StorymapOptions;
570
677
  "animator": AnimationHandle | null;
571
- "fire": EventedInstance["fire"];
678
+ "fire": EventedInstance<MapMarkerEvents>["fire"];
572
679
  constructor(data?: MapMarkerData, options?: Partial<StorymapOptions>);
573
680
  /**
574
681
  * @deprecated No-op since 0.9.x upstream (the original marker defined an
@@ -620,6 +727,17 @@ declare type MapMarkerData = StorymapSlide & {
620
727
  real_marker?: boolean;
621
728
  };
622
729
 
730
+ export declare interface MapMarkerEvents {
731
+ markerclick: MarkerEventPayload;
732
+ popupopen: MarkerEventPayload;
733
+ popupclose: MarkerEventPayload;
734
+ }
735
+
736
+ /** A marker event payload: the marker by slide index. */
737
+ export declare interface MarkerEventPayload {
738
+ marker_number: number;
739
+ }
740
+
623
741
  /** The resolved marker presentation: `marker.*` over `location.*`. */
624
742
  declare interface MarkerPresentation {
625
743
  icon?: string;
@@ -631,18 +749,38 @@ declare interface MarkerPresentation {
631
749
  useCustomMarker?: boolean;
632
750
  }
633
751
 
752
+ declare interface MediaData extends StorymapSlideMedia {
753
+ uniqueid?: string | null;
754
+ link?: string | null;
755
+ link_target?: string | null;
756
+ [key: string]: unknown;
757
+ }
758
+
759
+ export declare interface MediaEvents {
760
+ loaded: MediaData;
761
+ media_loaded: MediaData;
762
+ media_ended: MediaData;
763
+ added: MediaData;
764
+ removed: MediaData;
765
+ }
766
+
634
767
  declare interface MediaInstance {
635
768
  addTo: (container: HTMLElement) => void;
636
769
  loadMedia: () => void;
637
770
  stopMedia: () => void;
638
771
  updateDisplay: (w?: number, h?: number, l?: string) => void;
639
772
  dispose?: () => void;
640
- on?: EventedInstance["on"];
641
- off?: EventedInstance["off"];
773
+ on?: EventedInstance<MediaEvents>["on"];
774
+ off?: EventedInstance<MediaEvents>["off"];
642
775
  _state?: {
643
776
  loaded?: boolean;
644
777
  eager?: boolean;
645
778
  };
779
+ /** Per-item consent identity: each item is built with its own
780
+ `media_name`/`media_type`, which `hasPlayableMedia` reads back (#358). */
781
+ options?: {
782
+ media_type?: string;
783
+ };
646
784
  }
647
785
 
648
786
  /**
@@ -679,31 +817,23 @@ declare const MenuBar_base: {
679
817
  onRemove(): void;
680
818
  _el: Record<string, unknown>;
681
819
  data?: unknown;
682
- on: (type: string, fn: unknown, context?: unknown) => unknown;
683
- off: (type: string, fn: unknown, context?: unknown) => unknown;
684
- fire: (type: string, data?: unknown, target?: unknown) => unknown;
685
- hasEventListeners: (type: string) => boolean;
686
- };
687
- } & {
688
- new (...args: any[]): {
689
- _vco_events?: Record<string, {
690
- action: unknown;
691
- context: unknown;
692
- }[]> | undefined;
693
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
694
- hasEventListeners(type: string): boolean;
695
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
696
- fire(type: string, data?: unknown, target?: unknown): /*elided*/ any;
820
+ on<K extends "fullscreen" | "loaded" | "added" | "removed" | "overview" | "overlaychange" | "basemapchange" | "back_to_start" | "autoplay_toggle" | "progress_go" | "collapse">(type: K, fn: (e: FiredEvent<MenuBarEvents, K>) => void, context?: unknown): /*elided*/ any;
821
+ off<K extends "fullscreen" | "loaded" | "added" | "removed" | "overview" | "overlaychange" | "basemapchange" | "back_to_start" | "autoplay_toggle" | "progress_go" | "collapse">(type: K, fn: (e: FiredEvent<MenuBarEvents, K>) => void, context?: unknown): /*elided*/ any;
822
+ fire<K extends "fullscreen" | "loaded" | "added" | "removed" | "overview" | "overlaychange" | "basemapchange" | "back_to_start" | "autoplay_toggle" | "progress_go" | "collapse">(type: K, data?: MenuBarEvents[K] | undefined): /*elided*/ any;
823
+ hasEventListeners<K extends "fullscreen" | "loaded" | "added" | "removed" | "overview" | "overlaychange" | "basemapchange" | "back_to_start" | "autoplay_toggle" | "progress_go" | "collapse">(type: K): boolean;
697
824
  };
698
- } & typeof MenuBarBase;
825
+ } & Constructor<EventedInstance<MenuBarEvents>> & typeof MenuBarBase;
699
826
 
700
827
  declare class MenuBarBase {
701
828
  "_el": Record<string, HTMLElement>;
702
829
  "collapsed": boolean;
703
830
  "options": MenuBarOptions;
704
831
  "animator": Record<string, unknown>;
705
- "fire": EventedInstance["fire"];
832
+ "fire": EventedInstance<MenuBarEvents>["fire"];
706
833
  _fullscreenActive: boolean;
834
+ _autoplayStopped: boolean;
835
+ /** The layer switcher, if `show_layers_control` is on. */
836
+ "_layersControl": LayersControl | null;
707
837
  constructor(elem: HTMLElement | string, parent_elem?: HTMLElement, options?: object);
708
838
  show(d?: number): void;
709
839
  hide(top: number): void;
@@ -715,7 +845,7 @@ declare class MenuBarBase {
715
845
  setFullscreenState(active: boolean): void;
716
846
  /**
717
847
  * Repaint the overview button label. An image map has no interactive
718
- * overview, so it gets the shorter wording.
848
+ * overview, so it gets the shorter wording. Icon-only on mobile.
719
849
  */
720
850
  _renderOverviewLabel(): void;
721
851
  /**
@@ -726,15 +856,35 @@ declare class MenuBarBase {
726
856
  * Repaint the collapse/expand toggle. Icon-only on mobile.
727
857
  */
728
858
  _renderCollapseLabel(collapsed: boolean): void;
859
+ /**
860
+ * Reflect the autoplay state in the toggle label.
861
+ */
862
+ setAutoplayState(stopped: boolean): void;
729
863
  /**
730
864
  * Repaint every text label from the active language (see `setLanguage`).
731
- * Icon-only mobile buttons carry no text and are left untouched.
865
+ * Icon-only mobile buttons carry text via aria-label instead.
732
866
  */
733
867
  refreshLabels(): void;
734
868
  /**
735
- * Update the progress indicator (issue #247); no-op when disabled.
869
+ * Icon-only mobile buttons expose their labels to assistive tech since
870
+ * the visible text is icon glyphs.
871
+ */
872
+ _renderMobileLabels(): void;
873
+ /** Hand the layer switcher its state source (StoryMap wires this). */
874
+ setLayersDelegate(delegate: LayersControlDelegate): void;
875
+ /** Re-pull the switcher rows (overlays, basemaps, consent state). */
876
+ refreshLayers(): void;
877
+ /**
878
+ * Update the progress indicator; no-op when disabled. The `progressbar`
879
+ * option selects the style (slideshow `progressbar`): the classic fill
880
+ * `bar` (default), height variants `block`/`thinblock`, or per-slide
881
+ * `dots`/`squares` buttons that jump to their slide.
736
882
  */
737
883
  setProgress(current: number, total: number): void;
884
+ /** The resolved progress style: `progressbar` wins, `show_progress` decides the default. */
885
+ _progressStyle(): "off" | "bar" | "dots" | "squares" | "block" | "thinblock";
886
+ /** Per-slide progress buttons for the `dots`/`squares` styles. */
887
+ _renderProgressSteps(style: "dots" | "squares", current: number, total: number): void;
738
888
  /**
739
889
  * Update the route distance display (issue #341); no-op when disabled or
740
890
  * before the first reading.
@@ -744,6 +894,14 @@ declare class MenuBarBase {
744
894
  _onButtonOverview(e: Event): void;
745
895
  _onButtonBackToStart(e: Event): void;
746
896
  _onButtonFullscreen(e: Event): void;
897
+ _onButtonAutoplay(): void;
898
+ _onLayersBasemap(e: {
899
+ map_type: string;
900
+ }): void;
901
+ _onLayersOverlay(e: {
902
+ index: number;
903
+ visible: boolean;
904
+ }): void;
747
905
  _onButtonCollapseMap(e: Event): void;
748
906
  _initLayout(): void;
749
907
  _updateDisplay(width?: number, height?: number, animate?: boolean): void;
@@ -754,6 +912,30 @@ declare class MenuBarBase {
754
912
  dispose(): void;
755
913
  }
756
914
 
915
+ export declare interface MenuBarEvents {
916
+ overview: Event;
917
+ back_to_start: Event;
918
+ fullscreen: Event;
919
+ autoplay_toggle: undefined;
920
+ progress_go: {
921
+ slide: number;
922
+ };
923
+ collapse: {
924
+ y: number;
925
+ collapsed: boolean;
926
+ };
927
+ basemapchange: {
928
+ map_type: string;
929
+ };
930
+ overlaychange: {
931
+ index: number;
932
+ visible: boolean;
933
+ };
934
+ loaded: undefined;
935
+ added: undefined;
936
+ removed: undefined;
937
+ }
938
+
757
939
  declare interface MenuBarOptions {
758
940
  width: number;
759
941
  height: number;
@@ -780,43 +962,40 @@ declare const Message_base: {
780
962
  onRemove(): void;
781
963
  _el: Record<string, unknown>;
782
964
  data?: unknown;
783
- on: (type: string, fn: unknown, context?: unknown) => unknown;
784
- off: (type: string, fn: unknown, context?: unknown) => unknown;
785
- fire: (type: string, data?: unknown, target?: unknown) => unknown;
786
- hasEventListeners: (type: string) => boolean;
965
+ on<K extends "loaded" | "added" | "removed" | "clicked">(type: K, fn: (e: FiredEvent<MessageEvents, K>) => void, context?: unknown): /*elided*/ any;
966
+ off<K extends "loaded" | "added" | "removed" | "clicked">(type: K, fn: (e: FiredEvent<MessageEvents, K>) => void, context?: unknown): /*elided*/ any;
967
+ fire<K extends "loaded" | "added" | "removed" | "clicked">(type: K, data?: MessageEvents[K] | undefined): /*elided*/ any;
968
+ hasEventListeners<K extends "loaded" | "added" | "removed" | "clicked">(type: K): boolean;
787
969
  };
788
- } & {
789
- new (...args: any[]): {
790
- _vco_events?: Record<string, {
791
- action: unknown;
792
- context: unknown;
793
- }[]> | undefined;
794
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
795
- hasEventListeners(type: string): boolean;
796
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
797
- fire(type: string, data?: unknown, target?: unknown): /*elided*/ any;
798
- };
799
- } & typeof MessageBase;
970
+ } & Constructor<EventedInstance<MessageEvents>> & typeof MessageBase;
800
971
 
801
972
  declare class MessageBase {
802
973
  "_el": Record<string, HTMLElement>;
803
974
  "options": MessageOptions;
804
975
  "data": Record<string, unknown>;
805
976
  "animator": Record<string, unknown>;
806
- "fire": EventedInstance["fire"];
977
+ "fire": EventedInstance<MessageEvents>["fire"];
807
978
  constructor(data?: Record<string, unknown>, options?: Record<string, unknown>, add_to_container?: HTMLElement);
808
979
  updateMessage(t: string): void;
809
980
  _updateMessage(t?: string): void;
810
981
  _onMouseClick(): void;
982
+ _onKeyDown(e: Event): void;
811
983
  _initLayout(): void;
812
984
  _initEvents(): void;
813
985
  /**
814
- * Release the click listener and drop the element. Called by
986
+ * Release the listeners and drop the element. Called by
815
987
  * `StorySlider.dispose()`; the message must not be used afterwards.
816
988
  */
817
989
  dispose(): void;
818
990
  }
819
991
 
992
+ export declare interface MessageEvents {
993
+ clicked: MessageOptions;
994
+ loaded: Record<string, unknown>;
995
+ added: Record<string, unknown>;
996
+ removed: Record<string, unknown>;
997
+ }
998
+
820
999
  declare interface MessageOptions {
821
1000
  width: number;
822
1001
  height: number;
@@ -846,7 +1025,7 @@ declare class OpenLayers extends Map_2 {
846
1025
  "_line_active": Vector;
847
1026
  "_tile_layer_mini": OlLayer | null;
848
1027
  "_mini_map": default_2;
849
- "_markers": OpenLayersMapMarker[];
1028
+ "_markers": StoryMapMarker[];
850
1029
  /** App-level stacked overlays (see the `overlays` option) */
851
1030
  "_overlay_layers": OlLayer[];
852
1031
  /**
@@ -859,6 +1038,36 @@ declare class OpenLayers extends Map_2 {
859
1038
  "_line_animation": number | null;
860
1039
  /** Sources `imageready` has already been fired for. */
861
1040
  "_imageready_fired": WeakSet<object>;
1041
+ /** The `loadend` subscription key, stored so dispose() can detach it. */
1042
+ "_loadend_key": Parameters<typeof unByKey>[0] | null;
1043
+ /**
1044
+ * Per-slide basemap layers by key (multi-manifest tours): built on first
1045
+ * use through the tile layer factory, then reused. Empty until a slide
1046
+ * names a `location.basemap`.
1047
+ */
1048
+ "_basemap_cache": globalThis.Map<string, OlLayer>;
1049
+ /**
1050
+ * The active per-slide basemap key, or null when the story basemap is
1051
+ * showing. Restored to the story basemap on slides without one.
1052
+ */
1053
+ "_slide_basemap": string | null;
1054
+ /** Spotlight mask element (slideshow passepartout), or null when off. */
1055
+ "_mask_el": HTMLDivElement | null;
1056
+ /** Per-slide image overlay layer (slideshow imgoverlay), or null. */
1057
+ "_imgoverlay_layer": OlLayer | null;
1058
+ /** Guards stale static-fallback probes (see `_probeStaticFallback`). */
1059
+ "_static_probe_token": number;
1060
+ /**
1061
+ * Set by `dispose()` so in-flight fetches and probes resolve into
1062
+ * no-ops instead of touching a torn-down map.
1063
+ */
1064
+ "_disposed": boolean;
1065
+ /**
1066
+ * Per-URL probe tokens for static slide basemaps: concurrent probes for
1067
+ * different slides must not cancel each other (see
1068
+ * `_createStaticImageBasemap`).
1069
+ */
1070
+ "_slide_probe_tokens": globalThis.Map<string, number>;
862
1071
  _createMap(): void;
863
1072
  /** Extra attribution fragments (e.g. overlay credits), always listed last. */
864
1073
  "_extra_attributions": string[];
@@ -880,15 +1089,37 @@ declare class OpenLayers extends Map_2 {
880
1089
  /** The highlighted route line layer drawn up to the current slide. */
881
1090
  getLineActive(): OlLayer | null;
882
1091
  /** The markers, in slide order (the index matches the slide index). */
883
- getMarkers(): OpenLayersMapMarker[];
1092
+ getMarkers(): StoryMapMarker[];
884
1093
  /** One marker by slide index, or `null`. */
885
- getMarker(index: number): OpenLayersMapMarker | null;
1094
+ getMarker(index: number): StoryMapMarker | null;
886
1095
  /**
887
1096
  * (Re)render the attribution line for the current map type. Called at
888
1097
  * creation and on every `map_type` switch, which previously left the
889
1098
  * initial text stale.
890
1099
  */
891
1100
  _updateAttribution(): void;
1101
+ /**
1102
+ * Provider credit for a `map_type`, in both renderings: the linked HTML
1103
+ * for our own `.vco-map-attribution` line and the plain text for the
1104
+ * OpenLayers source `attributions`. One table — the two previous
1105
+ * functions repeated the same `osm/stadia/mapbox/esri` switch and could
1106
+ * drift apart, leaving a provider credited in one place but not the other
1107
+ * (which their terms of service require).
1108
+ */
1109
+ _providerCredit(map_type: string): {
1110
+ html: string;
1111
+ text: string;
1112
+ };
1113
+ /**
1114
+ * The table row for an absolute tile template's host, or null when the
1115
+ * template is relative (a host serving its own tiles credits itself via
1116
+ * `attribution`) or unknown. Subdomains match their parent, so
1117
+ * `a.tile.openstreetmap.org` credits OSM.
1118
+ */
1119
+ _hostCredit(map_type: string): {
1120
+ html: string;
1121
+ text: string;
1122
+ } | null;
892
1123
  _getAttribution(map_type: string): string[];
893
1124
  /**
894
1125
  * The provider credit for `map_type` as plain text (no HTML), for the
@@ -950,6 +1181,12 @@ declare class OpenLayers extends Map_2 {
950
1181
  * `getOverlayLayers().length`.
951
1182
  */
952
1183
  getOverlayCount(): number;
1184
+ /**
1185
+ * The built overlay entries, parallel to `getOverlayLayers()`: malformed
1186
+ * entries are skipped, so this is what a control must iterate to stay on
1187
+ * the same index space as `setOverlayVisible()`.
1188
+ */
1189
+ getOverlayEntries(): StorymapOverlayLayer[];
953
1190
  /**
954
1191
  * Show or hide a stacked overlay by index (re-syncs attribution). The
955
1192
  * index counts built layers, i.e. it skips malformed entries.
@@ -989,6 +1226,51 @@ declare class OpenLayers extends Map_2 {
989
1226
  zoom: number;
990
1227
  center: number[];
991
1228
  } | null;
1229
+ /**
1230
+ * Paint the story's static image when its IIIF `info.json` cannot be
1231
+ * used (unreachable, or missing dimensions): a single-resolution
1232
+ * `ImageStatic` layer replaces the empty tile layer, so the tour still
1233
+ * shows its picture instead of a blank basemap. Needs
1234
+ * `iiif.fallbackUrl` (the full-size image) plus `iiif.width`/`height`
1235
+ * (canvas size); without dimensions the natural size is probed, but
1236
+ * only for slideshow tours — internal documents keep the existing
1237
+ * error path. Returns false when nothing was (or will be) painted.
1238
+ */
1239
+ _useStaticFallback(empty_layer: Tile): boolean;
1240
+ /**
1241
+ * Resolve a fallback image's natural size, then paint it. Stale probes
1242
+ * (a newer probe started, e.g. after a basemap switch) and unusable
1243
+ * dimensions fall back to the logged IIIF error.
1244
+ */
1245
+ _probeStaticFallback(empty_layer: Tile, url: string): Promise<void>;
1246
+ /**
1247
+ * The natural size of an image URL. Separated for testability: unit
1248
+ * tests stub the `Image` constructor rather than the network.
1249
+ */
1250
+ _probeStaticImage(url: string): Promise<{
1251
+ width: number;
1252
+ height: number;
1253
+ }>;
1254
+ /**
1255
+ * One static image source: shared by the story fallback (known extent),
1256
+ * per-slide static basemaps (probed extent) and per-slide overlays
1257
+ * (view extent). Layer assembly stays per call site — base (z 0),
1258
+ * pending-fill and overlay (z 5, opacity) have different lifecycles.
1259
+ */
1260
+ _newStaticSource(url: string, extent: Extent, projection: string | OlProjection, attributions?: string | string[]): default_5;
1261
+ /**
1262
+ * One static image layer: the constructor shared by the story fallback,
1263
+ * per-slide static basemaps and per-slide overlays. Extent and
1264
+ * projection are the caller's policy (canvas size, probed size, or view
1265
+ * extent); presentation rides the options.
1266
+ */
1267
+ _newStaticLayer(url: string, extent: Extent, projection: string | OlProjection, presentation?: {
1268
+ opacity?: number;
1269
+ attributions?: string | string[];
1270
+ zIndex?: number;
1271
+ }): Image_2<default_5>;
1272
+ /** Swap the empty tile layer for a static image of the given extent. */
1273
+ _buildStaticLayer(empty_layer: Tile, url: string, width: number, height: number): void;
992
1274
  _createTileLayer(map_type: string): OlLayer;
993
1275
  /**
994
1276
  * A layer's source, or null when it has none. Custom `Layer` subclasses
@@ -1069,15 +1351,15 @@ declare class OpenLayers extends Map_2 {
1069
1351
  _createMiniMap(): void;
1070
1352
  _fitMiniMapToImage(): void;
1071
1353
  _createMarker(d: StorymapSlide): void;
1072
- _addMarker(marker: OpenLayersMapMarker): void;
1354
+ _addMarker(marker: StoryMapMarker): void;
1073
1355
  /**
1074
1356
  * Position marker overlays on the unwrapped longitude path so they sit on
1075
1357
  * the same world copy as the fitted view and the line (issue #381).
1076
1358
  * Image-space coordinates are not degrees and stay untouched.
1077
1359
  */
1078
1360
  _afterCreateMarkers(): void;
1079
- _removeMarker(marker: OpenLayersMapMarker): void;
1080
- _getAllMarkersBounds(markers_array: OpenLayersMapMarker[]): number[][];
1361
+ _removeMarker(marker: StoryMapMarker): void;
1362
+ _getAllMarkersBounds(markers_array: StoryMapMarker[]): number[][];
1081
1363
  /**
1082
1364
  * Normalize a longitude sequence so consecutive values differ by at most
1083
1365
  * 180 degrees: markers keep their raw coordinates (OpenLayers wraps the
@@ -1143,10 +1425,84 @@ declare class OpenLayers extends Map_2 {
1143
1425
  /**
1144
1426
  * Image region stop: fit the xywh bbox ([x, y, w, h] image pixels —
1145
1427
  * the EPSG:4326 image space) with the shared animation options, then
1146
- * keep the minimap collapse state in sync like `_viewTo`.
1428
+ * keep the minimap collapse state in sync like `_viewTo`. A slide
1429
+ * rotation follows the fit (fit() takes no rotation), plus the
1430
+ * filter/mask tail when the location is passed.
1147
1431
  */
1148
- _fitRegion(region: [number, number, number, number], opts?: ViewToOptions): void;
1432
+ _fitRegion(region: [number, number, number, number], opts?: ViewToOptions, loc?: StorymapSlideLocation): void;
1149
1433
  _toViewCoords(loc: LatLngLiteral): number[];
1434
+ /**
1435
+ * Swap the base layer for a slide `location.basemap` (multi-manifest
1436
+ * tours): built on first use through the tile layer factory (custom
1437
+ * factories apply), then cached. A slide without one restores the story
1438
+ * basemap. No-op when the requested key is already showing, so resize
1439
+ * and re-fit paths pass through untouched. Consent-denied tiles skip
1440
+ * the switch entirely.
1441
+ */
1442
+ _switchSlideBasemap(loc: StorymapSlideLocation | null | undefined): void;
1443
+ /**
1444
+ * Build a per-slide basemap layer: IIIF `info.json` URLs (or bare
1445
+ * service bases) become tile layers; plain image URLs become static
1446
+ * image layers (dimensions probed); anything else goes through the
1447
+ * regular tile layer factory, so keywords and templates keep working.
1448
+ */
1449
+ _createSlideBasemap(key: string): OlLayer;
1450
+ /**
1451
+ * A basemap from a plain image URL (no IIIF service): an `ImageLayer`
1452
+ * filled in once the natural size probes. Used for per-slide basemaps
1453
+ * pointing at static files, and as the fallback when an `info.json`
1454
+ * turns out unreachable (some `.jpx`/`.jp2` bases serve one, some are
1455
+ * plain files — only the fetch tells). Unusable dimensions keep the
1456
+ * error logged and the layer empty, like the failed-service path.
1457
+ */
1458
+ _createStaticImageBasemap(url: string): OlLayer;
1459
+ /**
1460
+ * Replace a failed IIIF slide basemap with a probed static image under
1461
+ * the same cache key, swapping it into the map when still current (the
1462
+ * visitor may have moved on while the fetch was in flight, in which
1463
+ * case the cache holds it for a return visit).
1464
+ */
1465
+ _replaceWithStaticBasemap(key: string, pending: Tile): void;
1466
+ /**
1467
+ * The story's own base layer (as opposed to a per-slide one): stashed
1468
+ * on creation so a slide basemap can hand back to it without refetching.
1469
+ */
1470
+ "_story_basemap_layer": OlLayer | null;
1471
+ /**
1472
+ * Apply a slide's CSS filter grading to the map viewport
1473
+ * (slideshow `filters`). Always assigned — "" clears — so grading never
1474
+ * leaks onto the next slide.
1475
+ */
1476
+ _applySlideFilter(loc: StorymapSlideLocation | null | undefined): void;
1477
+ /**
1478
+ * Apply a slide's spotlight mask (slideshow `passepartout`): normalized
1479
+ * viewport fractions stay visible while the rest is dimmed. Rendered as
1480
+ * up to four percentage-positioned divs (or one for `invert`), so it
1481
+ * needs no updates on pan/zoom/resize. `pointer-events: none` keeps
1482
+ * markers clickable through the shade; the marker overlay container
1483
+ * (z-index 1) paints above it. Absent/invalid clears the mask.
1484
+ */
1485
+ _applySlideMask(loc: StorymapSlideLocation | null | undefined): void;
1486
+ /** Filter + mask together: the synchronous tail of every navigation. */
1487
+ _applySlideFilterAndMask(loc: StorymapSlideLocation | null | undefined): void;
1488
+ /**
1489
+ * Rotate the view to a slide `rotation` (degrees clockwise). Merges into
1490
+ * the caller's animation when one is running; on its own (region fits,
1491
+ * location-less slides, overview reset) it animates alone, or sets
1492
+ * synchronously when the navigation is instant. A no-op when neither
1493
+ * the slide nor the view is rotated, so unrotated stories animate
1494
+ * exactly as before.
1495
+ */
1496
+ _applySlideRotation(loc: StorymapSlideLocation | null | undefined, duration?: number, instant?: boolean): void;
1497
+ /**
1498
+ * Show a per-slide image overlay (slideshow `imgoverlay`) while its
1499
+ * slide is active. `extent` pins it (`[west, south, east, north]` lon/lat,
1500
+ * raw image pixels on image-space maps); otherwise it covers the current
1501
+ * view, optionally scaled to `size` (fraction of the viewport). Painted
1502
+ * above the base (z 5) below the route lines. Null/empty clears.
1503
+ * Consent-denied tiles skip it like every other layer.
1504
+ */
1505
+ setSlideImageOverlay(overlay: StorymapImageOverlay | null | undefined): void;
1150
1506
  _getMapZoom(): number;
1151
1507
  _getMapCenter(): LatLngLiteral;
1152
1508
  _getMapCenterOffset(location: LatLngLiteral, zoom: number): LatLngLiteral;
@@ -1199,81 +1555,6 @@ declare class OpenLayers extends Map_2 {
1199
1555
  _setViewInstant(loc: StorymapSlideLocation, zoom: number): void;
1200
1556
  }
1201
1557
 
1202
- declare class OpenLayersMapMarker extends MapMarker {
1203
- "_overlay": default_3;
1204
- "_onMarkerClickBound": ((e: Event) => void) | null;
1205
- /** marker.popup: the active marker opens its card when clicked. */
1206
- "_popup_enabled": boolean;
1207
- /** marker.audioBadge: flag a slide that has narration or audio media. */
1208
- "_audio_badge": boolean;
1209
- /**
1210
- * The popup card while it is open. `declare` fields are undefined until
1211
- * assigned, so every read below is a truthiness check, never `=== null`,
1212
- * and there is no constructor to initialise them: `MapMarker`'s own
1213
- * constructor already runs `_initLayout()` → `_createMarker()`, which
1214
- * assigns the flags, and initialising afterwards would wipe them.
1215
- */
1216
- "_popup_el": HTMLElement | null;
1217
- /** Escape-to-close, detached in dispose(). */
1218
- "_onPopupKeyBound": ((e: KeyboardEvent) => void) | null;
1219
- /** Mirrors `active()`, as a flag rather than a method reference. */
1220
- "_is_active": boolean;
1221
- /**
1222
- * The merged marker presentation: `marker.*` wins, `location.*` is the
1223
- * legacy spelling and still works (docs/plans/iiif-media-tours.md §2).
1224
- * `location` also stays the carrier of geography, so lat/lon are read
1225
- * from it alone — presentation never moves a marker.
1226
- */
1227
- _presentation(d?: MapMarkerData): MarkerPresentation;
1228
- _createMarker(d?: MapMarkerData, o?: StorymapOptions): void;
1229
- _createMarkerElement(d: MapMarkerData, o?: StorymapOptions): HTMLDivElement;
1230
- /**
1231
- * The marker's {lat, lon}, or null when it is a non-georeferenced marker
1232
- * (an overview slide, or a slide with only an image region). `_createMarker`
1233
- * already established this for a real marker, but returning it from one
1234
- * place means the type checker can see it too.
1235
- */
1236
- latLon(): LatLngLiteral | null;
1237
- _addTo(m: Map_3): void;
1238
- _removeFrom(m: Map_3): void;
1239
- /**
1240
- * Terminal teardown: detach the click listener and drop the overlay and
1241
- * element. Called by the map's dispose(); the marker must not be used
1242
- * afterwards.
1243
- */
1244
- /**
1245
- * Toggle the popup card for the *active* marker. Inactive markers keep
1246
- * their original behaviour — a click navigates — so a popup never
1247
- * swallows navigation on a map full of pins.
1248
- *
1249
- * The card is a DOM element parented to the marker element and positioned
1250
- * with CSS, which is how it survives a move to the vector renderer
1251
- * (docs/plans/issue-159-vector-markers.md): only the anchor is the
1252
- * marker's, and that is `latLon()`.
1253
- */
1254
- _togglePopup(): void;
1255
- _closePopup(): void;
1256
- get popupOpen(): boolean;
1257
- /**
1258
- * Headline, a sanitized excerpt, the media thumb and an audio control.
1259
- * Every piece of text goes through `sanitizeSlideText` — a slide's text
1260
- * is untrusted input and a marker card is no different (the stored-XSS
1261
- * audit made that lesson once; a label is attacker-controlled text like
1262
- * any other).
1263
- */
1264
- _createPopupElement(): HTMLElement | null;
1265
- /**
1266
- * A small indicator on markers whose slide has narration or audio media
1267
- * (the Micrio affordance). Recomputed on activation, because a slide's
1268
- * media may only be known once it is resolved.
1269
- */
1270
- _updateAudioBadge(): void;
1271
- dispose(): void;
1272
- _active(a: boolean): void;
1273
- _customIconAnchor(size?: number[]): number[];
1274
- _location(): LatLngLiteral | null;
1275
- }
1276
-
1277
1558
  /** Wheel/scroll zoom bookkeeping (handles cleared via clearTimeout). */
1278
1559
  declare interface ScrollState {
1279
1560
  start_time: number | null;
@@ -1307,34 +1588,31 @@ declare const Slide_base: {
1307
1588
  onRemove(): void;
1308
1589
  _el: Record<string, unknown>;
1309
1590
  data?: unknown;
1310
- on: (type: string, fn: unknown, context?: unknown) => unknown;
1311
- off: (type: string, fn: unknown, context?: unknown) => unknown;
1312
- fire: (type: string, data?: unknown, target?: unknown) => unknown;
1313
- hasEventListeners: (type: string) => boolean;
1314
- };
1315
- } & {
1316
- new (...args: any[]): {
1317
- _vco_events?: Record<string, {
1318
- action: unknown;
1319
- context: unknown;
1320
- }[]> | undefined;
1321
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
1322
- hasEventListeners(type: string): boolean;
1323
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
1324
- fire(type: string, data?: unknown, target?: unknown): /*elided*/ any;
1591
+ on<K extends "call_to_action" | "loaded" | "added" | "removed" | "background_change">(type: K, fn: (e: FiredEvent<SlideEvents, K>) => void, context?: unknown): /*elided*/ any;
1592
+ off<K extends "call_to_action" | "loaded" | "added" | "removed" | "background_change">(type: K, fn: (e: FiredEvent<SlideEvents, K>) => void, context?: unknown): /*elided*/ any;
1593
+ fire<K extends "call_to_action" | "loaded" | "added" | "removed" | "background_change">(type: K, data?: SlideEvents[K] | undefined): /*elided*/ any;
1594
+ hasEventListeners<K extends "call_to_action" | "loaded" | "added" | "removed" | "background_change">(type: K): boolean;
1325
1595
  };
1326
- } & typeof SlideBase;
1596
+ } & Constructor<EventedInstance<SlideEvents>> & typeof SlideBase;
1327
1597
 
1328
1598
  declare interface SlideBackgroundChange {
1329
1599
  color_value?: string;
1330
1600
  image?: boolean;
1331
1601
  }
1332
1602
 
1603
+ export declare interface SlideBackgroundState {
1604
+ image: boolean;
1605
+ color: boolean;
1606
+ color_value: string;
1607
+ }
1608
+
1333
1609
  declare class SlideBase {
1334
1610
  /** `call_to_action` is only created when the slide shows one. */
1335
1611
  "_el": SlideElements;
1612
+ /** The primary media item; always `_medias[0]` when present (#358). */
1336
1613
  "_media": MediaInstance | null;
1337
- "_mediaclass": unknown;
1614
+ /** Every media item: `[media, ...media_extra]` with a non-empty url. */
1615
+ "_medias": MediaInstance[];
1338
1616
  "_text": Text_2;
1339
1617
  "_state": {
1340
1618
  loaded: boolean;
@@ -1342,15 +1620,24 @@ declare class SlideBase {
1342
1620
  "_scroll_hint": HTMLElement | null;
1343
1621
  "_scroll_hint_dismissed": boolean;
1344
1622
  "_onSlideScrollBound": EventListener;
1345
- /** Every `media_ended` handler registered via `onMediaEnded`, kept so `dispose()` can remove them. */
1346
- "_media_ended_fns": (() => void)[];
1623
+ /** Every `media_ended` handler registered via `onMediaEnded`, with the
1624
+ media it was attached to so `dispose()` can remove them. */
1625
+ "_media_ended_fns": {
1626
+ media: MediaInstance;
1627
+ fn: () => void;
1628
+ }[];
1629
+ /** The `media_loaded` handlers below, kept for the same reason. */
1630
+ "_media_loaded_fns": {
1631
+ media: MediaInstance;
1632
+ fn: () => void;
1633
+ }[];
1347
1634
  "has": SlideHas;
1348
1635
  "title": string;
1349
1636
  "data": StorymapSlide;
1350
1637
  "options": SlideOptions;
1351
1638
  "active": boolean;
1352
1639
  "animator": unknown;
1353
- "fire": EventedInstance["fire"];
1640
+ "fire": EventedInstance<SlideEvents>["fire"];
1354
1641
  "onLoaded": () => void;
1355
1642
  constructor(data: StorymapSlide, options: Record<string, unknown>, title_slide?: boolean);
1356
1643
  show(): void;
@@ -1365,11 +1652,13 @@ declare class SlideBase {
1365
1652
  loadMedia(): void;
1366
1653
  _eagerLoadImages(): void;
1367
1654
  stopMedia(): void;
1368
- getBackground(): {
1369
- image: boolean;
1370
- color: boolean;
1371
- color_value: string;
1372
- };
1655
+ /**
1656
+ * Stop this slide's ambient audio beds (`media.stopOnExit: false`) —
1657
+ * called by the viewer when another slide claims the audio, not on every
1658
+ * deactivation (see `stopMedia`, which skips them).
1659
+ */
1660
+ stopAmbientMedia(): void;
1661
+ getBackground(): SlideBackgroundState;
1373
1662
  /**
1374
1663
  * True when this slide's media is a timed, playable one (audio or video).
1375
1664
  * `autoplay_media` waits for such a slide's media to end instead of using
@@ -1380,9 +1669,18 @@ declare class SlideBase {
1380
1669
  * Call `fn` when this slide's media finishes playing. A slide with no
1381
1670
  * media — or media that cannot end — never calls it, which is why
1382
1671
  * `autoplay_media` keeps its timer as a fallback rather than waiting on
1383
- * an event that may not arrive.
1672
+ * an event that may not arrive. Multi-media slides never call it either:
1673
+ * waiting for the last of several items to end would stall autoplay, so
1674
+ * the timer stays the advance for those (#358).
1384
1675
  */
1385
1676
  onMediaEnded(fn: () => void): void;
1677
+ /**
1678
+ * Drop `media_ended` handlers armed by `onMediaEnded()` without waiting
1679
+ * for dispose: re-arming (autoplay revisit) or navigating away must not
1680
+ * accumulate stale advance closures — an ambient bed outliving its slide
1681
+ * would otherwise fire a previous slide's advance on ending.
1682
+ */
1683
+ clearMediaEnded(): void;
1386
1684
  scrollToTop(): void;
1387
1685
  /**
1388
1686
  * Show a bouncing downward arrow when the slide content overflows
@@ -1413,16 +1711,20 @@ declare type SlideElements = {
1413
1711
  call_to_action: HTMLElement | null;
1414
1712
  };
1415
1713
 
1714
+ export declare interface SlideEvents {
1715
+ background_change: SlideBackgroundState;
1716
+ call_to_action: Event;
1717
+ loaded: StorymapSlide;
1718
+ added: StorymapSlide;
1719
+ removed: StorymapSlide;
1720
+ }
1721
+
1416
1722
  declare interface SlideHas {
1417
1723
  headline: boolean;
1418
1724
  text: boolean;
1419
1725
  media: boolean;
1420
1726
  title: boolean;
1421
- background: {
1422
- image: boolean;
1423
- color: boolean;
1424
- color_value: string;
1425
- };
1727
+ background: SlideBackgroundState;
1426
1728
  }
1427
1729
 
1428
1730
  declare class SlideNav extends SlideNav_base {
@@ -1442,23 +1744,12 @@ declare const SlideNav_base: {
1442
1744
  onRemove(): void;
1443
1745
  _el: Record<string, unknown>;
1444
1746
  data?: unknown;
1445
- on: (type: string, fn: unknown, context?: unknown) => unknown;
1446
- off: (type: string, fn: unknown, context?: unknown) => unknown;
1447
- fire: (type: string, data?: unknown, target?: unknown) => unknown;
1448
- hasEventListeners: (type: string) => boolean;
1449
- };
1450
- } & {
1451
- new (...args: any[]): {
1452
- _vco_events?: Record<string, {
1453
- action: unknown;
1454
- context: unknown;
1455
- }[]> | undefined;
1456
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
1457
- hasEventListeners(type: string): boolean;
1458
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
1459
- fire(type: string, data?: unknown, target?: unknown): /*elided*/ any;
1747
+ on<K extends "loaded" | "added" | "removed" | "clicked">(type: K, fn: (e: FiredEvent<SlideNavEvents, K>) => void, context?: unknown): /*elided*/ any;
1748
+ off<K extends "loaded" | "added" | "removed" | "clicked">(type: K, fn: (e: FiredEvent<SlideNavEvents, K>) => void, context?: unknown): /*elided*/ any;
1749
+ fire<K extends "loaded" | "added" | "removed" | "clicked">(type: K, data?: SlideNavEvents[K] | undefined): /*elided*/ any;
1750
+ hasEventListeners<K extends "loaded" | "added" | "removed" | "clicked">(type: K): boolean;
1460
1751
  };
1461
- } & typeof SlideNavBase;
1752
+ } & Constructor<EventedInstance<SlideNavEvents>> & typeof SlideNavBase;
1462
1753
 
1463
1754
  declare class SlideNavBase {
1464
1755
  "_el": Record<string, HTMLElement>;
@@ -1467,7 +1758,7 @@ declare class SlideNavBase {
1467
1758
  "options": SlideNavOptions;
1468
1759
  "animator": AnimationHandle | null;
1469
1760
  "animator_position": AnimationHandle | null;
1470
- "fire": EventedInstance["fire"];
1761
+ "fire": EventedInstance<SlideNavEvents>["fire"];
1471
1762
  constructor(data?: Partial<SlideNavData>, options?: Partial<SlideNavOptions>, add_to_container?: HTMLElement);
1472
1763
  update(d?: Partial<SlideNavData>): void;
1473
1764
  setColor(inverted: boolean): void;
@@ -1492,6 +1783,13 @@ declare interface SlideNavData {
1492
1783
  [key: string]: unknown;
1493
1784
  }
1494
1785
 
1786
+ export declare interface SlideNavEvents {
1787
+ clicked: SlideNavOptions;
1788
+ loaded: SlideNavData;
1789
+ added: SlideNavData;
1790
+ removed: SlideNavData;
1791
+ }
1792
+
1495
1793
  declare interface SlideNavOptions {
1496
1794
  direction: string;
1497
1795
  [key: string]: unknown;
@@ -1509,6 +1807,64 @@ declare interface SlideOptions {
1509
1807
  [key: string]: unknown;
1510
1808
  }
1511
1809
 
1810
+ /** The embed `settings` JSON (string → web component), all fields optional. */
1811
+ export declare interface SlideshowPlayerSettings {
1812
+ uri?: unknown;
1813
+ mode?: unknown;
1814
+ viewerheight?: unknown;
1815
+ autoplay?: unknown;
1816
+ slidetimeout?: unknown;
1817
+ fxmode?: unknown;
1818
+ shownav?: unknown;
1819
+ showfullscreen?: unknown;
1820
+ showinfo?: unknown;
1821
+ showscrollbars?: unknown;
1822
+ progressbar?: unknown;
1823
+ textmode?: unknown;
1824
+ textsize?: unknown;
1825
+ imgoverlay?: unknown;
1826
+ imgoverlayurl?: unknown;
1827
+ imgoverlaysize?: unknown;
1828
+ showheadings?: unknown;
1829
+ bgcolor?: unknown;
1830
+ hudbgcolor?: unknown;
1831
+ hudcolor?: unknown;
1832
+ hudopacity?: unknown;
1833
+ [key: string]: unknown;
1834
+ }
1835
+
1836
+ /**
1837
+ * Translate one slideshow tour document (plus any following pages) into
1838
+ * storymap data. Slideshow-only fields land verbatim; internal validation
1839
+ * (`validateStorymap`) must still pass on the result.
1840
+ */
1841
+ export declare function slideshowToStorymapData(doc: unknown, opts?: SlideshowTranslatorOptions): SlideshowToStorymapResult;
1842
+
1843
+ export declare interface SlideshowToStorymapResult {
1844
+ data: StorymapData;
1845
+ warnings: SlideshowWarning[];
1846
+ }
1847
+
1848
+ export declare interface SlideshowTranslatorOptions {
1849
+ /** Parsed embed settings; option keys land on the storymap object. */
1850
+ settings?: SlideshowPlayerSettings | null;
1851
+ /**
1852
+ * Following `AnnotationPage`s for `first.next` chains (fetched by the
1853
+ * caller: CLI and viewer). Items append in order.
1854
+ */
1855
+ extraPages?: unknown[];
1856
+ }
1857
+
1858
+ /** 2 for the `strollview` extension, 1 for the legacy context, else 0. */
1859
+ export declare function slideshowVersion(doc: unknown): 0 | 1 | 2;
1860
+
1861
+ export declare interface SlideshowWarning {
1862
+ kind: string;
1863
+ count: number;
1864
+ sampleIds: string[];
1865
+ detail: string;
1866
+ }
1867
+
1512
1868
  export declare class StoryMap extends StoryMap_base {
1513
1869
  /**
1514
1870
  * The library base path (the directory containing the module).
@@ -1519,18 +1875,7 @@ export declare class StoryMap extends StoryMap_base {
1519
1875
  constructor(...args: ConstructorParameters<typeof StoryMapBase>);
1520
1876
  }
1521
1877
 
1522
- declare const StoryMap_base: {
1523
- new (...args: any[]): {
1524
- _vco_events?: Record<string, {
1525
- action: unknown;
1526
- context: unknown;
1527
- }[]> | undefined;
1528
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
1529
- hasEventListeners(type: string): boolean;
1530
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
1531
- fire(type: string, data?: unknown, target?: unknown): /*elided*/ any;
1532
- };
1533
- } & typeof StoryMapBase;
1878
+ declare const StoryMap_base: Constructor<EventedInstance<StoryMapEvents>> & typeof StoryMapBase;
1534
1879
 
1535
1880
  /**
1536
1881
  * Interactive StoryMap viewer.
@@ -1552,7 +1897,7 @@ declare class StoryMapBase {
1552
1897
  storyslider: boolean;
1553
1898
  map: boolean;
1554
1899
  };
1555
- "on": EventedInstance["on"];
1900
+ "on": EventedInstance<StoryMapEvents>["on"];
1556
1901
  "version": string;
1557
1902
  "ready": boolean;
1558
1903
  "_el": {
@@ -1603,6 +1948,26 @@ declare class StoryMapBase {
1603
1948
  "_autoplay_stopped": boolean;
1604
1949
  /** The narration player: one <audio> for the whole story, reused. */
1605
1950
  "_narration_el": HTMLAudioElement | null;
1951
+ /**
1952
+ * The ambient player: a second <audio> for a narration bed that outlives
1953
+ * its slide (`narration.stopOnExit: false`, slideshow ambient audio).
1954
+ * At most one ambient track plays; a new one replaces it.
1955
+ */
1956
+ "_ambient_el": HTMLAudioElement | null;
1957
+ /** What each player is (or was) playing, so same-URL beds continue. */
1958
+ "_narration_meta": {
1959
+ url: string;
1960
+ stopOnExit: boolean;
1961
+ } | null;
1962
+ "_ambient_meta": {
1963
+ url: string;
1964
+ } | null;
1965
+ /**
1966
+ * Whether the ambient bed is actually playing: `HTMLMediaElement.paused`
1967
+ * cannot be trusted here (test doubles and pre-gesture elements report
1968
+ * stale state), so the viewer tracks it explicitly.
1969
+ */
1970
+ "_ambient_playing": boolean;
1606
1971
  /** Guards a stale play() from a slide change that already moved on. */
1607
1972
  "_narration_token": number;
1608
1973
  /** Whether narration consent was granted (asked once per story). */
@@ -1617,12 +1982,16 @@ declare class StoryMapBase {
1617
1982
  "_collapsed": boolean;
1618
1983
  /** the data source was a IIIF Presentation manifest (legacy zoomify options are ignored) */
1619
1984
  "_data_from_manifest": boolean;
1985
+ /** the data source was a slideshow tour (slideshow-only features apply) */
1986
+ "_data_from_slideshow": boolean;
1620
1987
  "_resize_observer": ResizeObserver | null;
1621
1988
  /** Stored so `dispose()` can remove them again (see AGENTS: no leaks) */
1622
1989
  "_on_resize": (() => void) | null;
1623
1990
  "_on_keydown_global": ((e: KeyboardEvent) => void) | null;
1624
1991
  "_on_fullscreen": (() => void) | null;
1625
1992
  "_on_hashchange": (() => void) | null;
1993
+ /** Reduced-motion toggles mid-story stop the advance timer. */
1994
+ "_on_reduced_motion": ((e: MediaQueryListEvent) => void) | null;
1626
1995
  /** Set by `dispose()` so a second call returns early. */
1627
1996
  "_disposed": boolean;
1628
1997
  /** identity of this viewer's claim on the page-wide locale */
@@ -1633,8 +2002,7 @@ declare class StoryMapBase {
1633
2002
  "_interaction": number;
1634
2003
  "_onInteraction": (() => void) | null;
1635
2004
  "_resize_timer": ReturnType<typeof setTimeout> | null;
1636
- "fire": EventedInstance["fire"];
1637
- "hasEventListeners": EventedInstance["hasEventListeners"];
2005
+ "fire": EventedInstance<StoryMapEvents>["fire"];
1638
2006
  /**
1639
2007
  * Create a StoryMap inside the given element.
1640
2008
  *
@@ -1647,9 +2015,36 @@ declare class StoryMapBase {
1647
2015
  * @param listeners - Optional event listeners keyed by event name
1648
2016
  * (`change`, `title`, `loaded`, ...) attached on creation.
1649
2017
  */
1650
- constructor(elem: string | HTMLElement, data: string | StorymapDataWrapper | Record<string, unknown>, options?: Partial<StorymapOptions>, listeners?: Record<string, StoryMapListener | StoryMapListener[]>);
2018
+ constructor(elem: string | HTMLElement, data: string | StorymapDataWrapper | Record<string, unknown>, options?: Partial<StorymapOptions>, listeners?: {
2019
+ [K in keyof StoryMapEvents]?: StoryMapListener<K> | StoryMapListener<K>[];
2020
+ });
1651
2021
  _initData(data: string | StorymapDataWrapper | Record<string, unknown>): void;
2022
+ /**
2023
+ * One `console.warn` per warning kind: count, detail and sample ids.
2024
+ * Translation losses are loud exactly once, never per slide. Shared
2025
+ * formatting with the CLI (see `formatSlideshowWarning`).
2026
+ */
2027
+ _warnSlideshow(warnings: SlideshowWarning[]): void;
2028
+ /**
2029
+ * Follow a tour's `first.next` page chain, returning the following pages
2030
+ * for the translator. Bounded (20) and cycle-guarded; a broken chain
2031
+ * reports incompletely so the caller warns instead of truncating
2032
+ * silently. Relative links resolve against the tour URL.
2033
+ */
2034
+ _followSlideshowPages(doc: unknown, url: string): Promise<{
2035
+ pages: unknown[];
2036
+ complete: boolean;
2037
+ }>;
1652
2038
  _loadDataFromUrl(url: string, source: string): Promise<void>;
2039
+ /**
2040
+ * Reset every slideshow-only option to its long-standing default unless
2041
+ * the loaded tour came from a slideshow source. Internal documents keep
2042
+ * the pre-existing rendering even when they (or a host, via
2043
+ * setMapOptions) name the new keys; slideshow tours keep what the
2044
+ * translator emitted. Runs on every load and every runtime option change,
2045
+ * over the viewer options and (at runtime) the map's own options copy.
2046
+ */
2047
+ _normalizeNonSlideshowOptions(options?: StorymapOptions): void;
1653
2048
  _initOptions(): void;
1654
2049
  _loadLanguage(): void;
1655
2050
  /**
@@ -1815,9 +2210,27 @@ declare class StoryMapBase {
1815
2210
  /** The highlighted route line drawn up to the current slide. */
1816
2211
  getLineActive(): OlLayer | null;
1817
2212
  /** The map markers, indexed by slide. */
1818
- getMarkers(): OpenLayersMapMarker[];
2213
+ getMarkers(): StoryMapMarker[];
1819
2214
  /** One map marker by slide index, or `null`. */
1820
- getMarker(index: number): OpenLayersMapMarker | null;
2215
+ getMarker(index: number): StoryMapMarker | null;
2216
+ /**
2217
+ * Open the popup card for slide `n`'s marker, navigating there first
2218
+ * when it is not the current slide.
2219
+ *
2220
+ * Returns false (and changes nothing) when the viewer is disposed,
2221
+ * has no map (`map_type: "none"`), `n` is out of range, or the marker
2222
+ * has popups disabled. Navigating fires the usual `change` (and
2223
+ * transition) events; a successful open fires `popupopen`.
2224
+ */
2225
+ openMarkerPopup(n: number): boolean;
2226
+ /**
2227
+ * Close one marker's popup card (`n` given) or every open card
2228
+ * (omitted). No-op when the viewer is disposed or mapless. Fires
2229
+ * `popupclose` per card actually closed.
2230
+ */
2231
+ closeMarkerPopup(n?: number): void;
2232
+ /** Whether slide `n`'s marker card is currently open. */
2233
+ isPopupOpen(n: number): boolean;
1821
2234
  /**
1822
2235
  * Rebuild the minimap (`OverviewMap` control). The constructor already
1823
2236
  * builds it; this is for hosts that recreate it after a `map_type` swap
@@ -1835,6 +2248,18 @@ declare class StoryMapBase {
1835
2248
  * cannot drift.
1836
2249
  */
1837
2250
  _applyTextColors(): void;
2251
+ /**
2252
+ * Publish the slideshow-driven player chrome as container state.
2253
+ * Everything here is opt-in: unset options leave the container exactly
2254
+ * as the long-standing layout does, so existing stories are unaffected.
2255
+ */
2256
+ _applyChrome(): void;
2257
+ /**
2258
+ * The slide panel share of the width (side docks) or height (bottom
2259
+ * dock) as a fraction: `textsize` percent when valid (10..80), else the
2260
+ * built-in split (half for sides, 40% height for the bottom dock).
2261
+ */
2262
+ _panelShare(): number;
1838
2263
  _initLayout(): void;
1839
2264
  _initEvents(): void;
1840
2265
  _onKeyDownGlobal(e: KeyboardEvent): void;
@@ -1863,12 +2288,49 @@ declare class StoryMapBase {
1863
2288
  * playback, and the story still works.
1864
2289
  */
1865
2290
  _playNarration(slide: StorymapSlide | undefined, allow_without_gesture?: boolean): void;
1866
- _narrationElement(): HTMLAudioElement;
1867
- _stopNarration(): void;
2291
+ /**
2292
+ * Start (or arm) a narration track: loop flag, start offset once the
2293
+ * metadata is available, and `play: "click"` arms paused for the
2294
+ * visitor instead of playing (see `playNarration()`). A rejected play()
2295
+ * (policy, network) must not surface as an unhandled rejection.
2296
+ */
2297
+ _startTrack(el: HTMLAudioElement, url: string, bag: StorymapSlideNarration | null, allow_without_gesture: boolean): void;
2298
+ /**
2299
+ * Start the current slide's click-armed narration (`narration.play:
2300
+ * "click"`): the control for visitors (or hosts) to start a track that
2301
+ * waits for them. Auto-armed tracks play on their own. No-op when
2302
+ * nothing is armed. Prefers the current slide's own track: with an
2303
+ * ambient bed running, the foreground it armed is the one to start.
2304
+ */
2305
+ playNarration(): void;
2306
+ /**
2307
+ * Seek to a start offset in seconds (slideshow `audio.offset`):
2308
+ * immediately when the metadata is already there, otherwise once on
2309
+ * `loadedmetadata`. Guarded by the narration token, so a quick
2310
+ * pass-through cannot seek a newer track.
2311
+ */
2312
+ _seekAudio(el: HTMLAudioElement, offset: number | null | undefined): void;
2313
+ _narrationElement(): HTMLAudioElement;
2314
+ _stopNarration(): void;
2315
+ _ambientElement(): HTMLAudioElement;
2316
+ _stopAmbient(): void;
1868
2317
  /** A gesture has happened, so unmuted audio is allowed from now on. */
1869
2318
  _note_user_gesture_for_narration(): void;
1870
2319
  _has_user_gesture(): boolean;
1871
2320
  _startAutoplay(): void;
2321
+ /**
2322
+ * Stop other slides' ambient audio beds when the new slide claims the
2323
+ * audio: its narration (unless opted out via `stopAllPrevious: false`),
2324
+ * or playable media that is actually playing (a paused click-to-play
2325
+ * bed must not kill an inherited ambient track it never starts).
2326
+ * A silent slide inherits a playing bed.
2327
+ */
2328
+ _stopAmbientSlideMedia(slide: StorymapSlide | undefined): void;
2329
+ /**
2330
+ * True when the slide's media element exists and is currently playing
2331
+ * (not paused, not ended, not merely loadable).
2332
+ */
2333
+ _isSlideMediaPlaying(index: number): boolean;
1872
2334
  /**
1873
2335
  * Arm autoplay for the current slide.
1874
2336
  *
@@ -1944,7 +2406,9 @@ declare class StoryMapBase {
1944
2406
  */
1945
2407
  _map_required(): OpenLayers;
1946
2408
  _resolveMapElement(): HTMLElement | null;
1947
- _onTitle(e: unknown): void;
2409
+ _onTitle(e: {
2410
+ title: string;
2411
+ }): void;
1948
2412
  _onColorChange(e: {
1949
2413
  color?: unknown;
1950
2414
  image?: unknown;
@@ -1955,6 +2419,45 @@ declare class StoryMapBase {
1955
2419
  _onMapChange(e: {
1956
2420
  current_marker: number;
1957
2421
  }): void;
2422
+ _onImageReady(e: ImagereadyPayload): void;
2423
+ _onMarkerPopupOpen(e: {
2424
+ marker_number: number;
2425
+ }): void;
2426
+ _onMarkerPopupClose(e: {
2427
+ marker_number: number;
2428
+ }): void;
2429
+ _onMarkerClick(e: {
2430
+ marker_number: number;
2431
+ }): void;
2432
+ _onLayersBasemap(e: {
2433
+ map_type: string;
2434
+ }): void;
2435
+ _onLayersOverlay(e: {
2436
+ index: number;
2437
+ visible: boolean;
2438
+ }): void;
2439
+ _onAutoplayToggle(): void;
2440
+ _onProgressGo(e: {
2441
+ slide: number;
2442
+ }): void;
2443
+ _onTilesAllowed(): void;
2444
+ /**
2445
+ * The layer switcher rows: allowed basemaps first, then built overlays.
2446
+ * Empty while there is nothing to switch (mapless story, consent-denied
2447
+ * tiles), in which case the control hides itself.
2448
+ */
2449
+ _layersRows(): LayersRow[];
2450
+ /**
2451
+ * Basemap candidates compatible with the live view. A runtime basemap
2452
+ * swap rebuilds layers but never the view, so an image-space candidate
2453
+ * (`iiif` with `map_as_image`) on a mercator view — or the reverse —
2454
+ * would wrap the wrong projection around the tiles: markers land in the
2455
+ * wrong place and zoom is meaningless. Refused candidates are dropped
2456
+ * with a warning, like the existing `setMapOptions` declines.
2457
+ */
2458
+ _allowedBasemaps(): StorymapBasemap[];
2459
+ /** Whether deferred tile layers may attach (no consent gate, or granted). */
2460
+ _tilesAllowed(): boolean;
1958
2461
  _updateProgress(): void;
1959
2462
  _onOverview(e?: unknown): void;
1960
2463
  /**
@@ -1992,9 +2495,36 @@ declare class StoryMapBase {
1992
2495
  _onLoaded(): void;
1993
2496
  }
1994
2497
 
2498
+ /**
2499
+ * A selectable base map for the layer switcher (`StorymapOptions.basemaps`).
2500
+ */
2501
+ export declare interface StorymapBasemap {
2502
+ /** Any `map_type` value. */
2503
+ map_type: string;
2504
+ /**
2505
+ * Control row label. Defaults to `map_type`. A function is re-invoked
2506
+ * on every `refreshLabels()` for host i18n (constructor options only —
2507
+ * see `StorymapOverlayLayer.label`).
2508
+ */
2509
+ label?: string | (() => string);
2510
+ }
2511
+
2512
+ /**
2513
+ * Authorship and rights for the story as a whole (slideshow
2514
+ * `creator`/`rights`). Rendered into the map attribution line for
2515
+ * slideshow tours; the license URL stays data-only for hosts.
2516
+ */
2517
+ declare interface StorymapCredit {
2518
+ creator?: string;
2519
+ rights?: string;
2520
+ licenseUrl?: string;
2521
+ [key: string]: unknown;
2522
+ }
2523
+
1995
2524
  export declare interface StorymapData {
1996
2525
  uniqueid?: string;
1997
2526
  slides: StorymapSlide[];
2527
+ credit?: StorymapCredit | null;
1998
2528
  [key: string]: unknown;
1999
2529
  }
2000
2530
 
@@ -2022,6 +2552,59 @@ export declare interface StorymapError {
2022
2552
  message: string;
2023
2553
  }
2024
2554
 
2555
+ export declare interface StoryMapEvents {
2556
+ change: {
2557
+ current_slide: number;
2558
+ current_id: string | null;
2559
+ };
2560
+ loaded: StorymapData;
2561
+ title: {
2562
+ title: string;
2563
+ };
2564
+ dataloaded: undefined;
2565
+ fontLoaded: {
2566
+ font: string;
2567
+ };
2568
+ transitionstart: {
2569
+ current_slide: number;
2570
+ duration: number;
2571
+ };
2572
+ transitionend: {
2573
+ current_slide: number;
2574
+ };
2575
+ error: {
2576
+ message: string;
2577
+ source: string;
2578
+ conflict?: boolean;
2579
+ };
2580
+ imageready: ImagereadyPayload;
2581
+ annotationsloaded: {
2582
+ stops: StorymapSlide[];
2583
+ searchService: string | null;
2584
+ failed: string[];
2585
+ };
2586
+ markerclick: {
2587
+ marker_number: number;
2588
+ current_slide: number;
2589
+ };
2590
+ popupopen: {
2591
+ marker_number: number;
2592
+ current_slide: number;
2593
+ };
2594
+ popupclose: {
2595
+ marker_number: number;
2596
+ current_slide: number;
2597
+ };
2598
+ basemapchange: {
2599
+ map_type: string;
2600
+ previous: string;
2601
+ };
2602
+ overlaychange: {
2603
+ index: number;
2604
+ visible: boolean;
2605
+ };
2606
+ }
2607
+
2025
2608
  /**
2026
2609
  * A IIIF Georeference Extension annotation body plus the image it places
2027
2610
  * (`overlays[].georeference`). The `body` is the annotation payload of
@@ -2071,12 +2654,26 @@ export declare interface StorymapGroundControlPoint {
2071
2654
  };
2072
2655
  }
2073
2656
 
2657
+ /**
2658
+ * A per-slide image overlay (slideshow `imgoverlay`). `url` is a full-size
2659
+ * image; `extent` pins it to `[west, south, east, north]` (lon/lat, or raw
2660
+ * image pixels on image-space maps) and defaults to the current view;
2661
+ * `size` scales it as a fraction of the viewport width; `opacity` is 0..1.
2662
+ */
2663
+ declare interface StorymapImageOverlay {
2664
+ url: string;
2665
+ size?: number;
2666
+ opacity?: number;
2667
+ extent?: [number, number, number, number];
2668
+ [key: string]: unknown;
2669
+ }
2670
+
2074
2671
  /** A IIIF Presentation 3 language map; only the neutral `none` tag is written. */
2075
2672
  export declare interface StorymapLanguageMap {
2076
2673
  none: string[];
2077
2674
  }
2078
2675
 
2079
- declare type StoryMapListener = (e: unknown) => void;
2676
+ declare type StoryMapListener<K extends keyof StoryMapEvents = keyof StoryMapEvents> = (e: FiredEvent<StoryMapEvents, K>) => void;
2080
2677
 
2081
2678
  export declare interface StorymapManifest {
2082
2679
  "@context": string[];
@@ -2108,6 +2705,12 @@ export declare interface StorymapManifestAnnotation {
2108
2705
  accessibilitySummary?: StorymapLanguageMap;
2109
2706
  body: StorymapManifestContentResource;
2110
2707
  target: string | StorymapManifestSpecificResource;
2708
+ /** Playback flags (slideshow audio terms); foreign members, absent when unset. */
2709
+ "storymap:loop"?: boolean;
2710
+ "storymap:offset"?: number;
2711
+ "storymap:play"?: string;
2712
+ "storymap:stopOnExit"?: boolean;
2713
+ "storymap:stopAllPrevious"?: boolean;
2111
2714
  }
2112
2715
 
2113
2716
  /** A canvas `background`: a painting annotation of the slide's backdrop (§2.6). */
@@ -2139,6 +2742,16 @@ export declare interface StorymapManifestCanvas {
2139
2742
  "storymap:type"?: string;
2140
2743
  "storymap:mediaSrcset"?: unknown;
2141
2744
  "storymap:mediaSizes"?: unknown;
2745
+ /** View directives (slideshow rotation/basemap/filter/mask); navPlace carries them when lat/lon exist. */
2746
+ "storymap:rotation"?: number;
2747
+ "storymap:basemap"?: string;
2748
+ "storymap:filter"?: unknown;
2749
+ "storymap:mask"?: unknown;
2750
+ /** Per-slide autoplay dwell (slideshow slidetimeout) and image overlay. */
2751
+ "storymap:slidetimeout"?: number;
2752
+ "storymap:imgoverlay"?: unknown;
2753
+ /** Provenance identifiers (slideshow manifest/canvas/image ids). */
2754
+ "storymap:provenance"?: unknown;
2142
2755
  navPlace?: StorymapManifestFeatureCollection;
2143
2756
  }
2144
2757
 
@@ -2255,6 +2868,108 @@ export declare interface StorymapMapOptions {
2255
2868
  [key: string]: unknown;
2256
2869
  }
2257
2870
 
2871
+ export declare class StoryMapMarker extends MapMarker {
2872
+ "_overlay": default_3;
2873
+ "_onMarkerClickBound": ((e: Event) => void) | null;
2874
+ /** Enter/Space activation for keyboard visitors, detached in dispose(). */
2875
+ "_onMarkerKeyBound": ((e: KeyboardEvent) => void) | null;
2876
+ /** Base accessible name (slide headline or label), without audio suffix. */
2877
+ "_marker_label": string;
2878
+ /** marker.popup: the active marker opens its card when clicked. */
2879
+ "_popup_enabled": boolean;
2880
+ /** marker.audioBadge: flag a slide that has narration or audio media. */
2881
+ "_audio_badge": boolean;
2882
+ /**
2883
+ * The popup card while it is open. `declare` fields are undefined until
2884
+ * assigned, so every read below is a truthiness check, never `=== null`,
2885
+ * and there is no constructor to initialise them: `MapMarker`'s own
2886
+ * constructor already runs `_initLayout()` → `_createMarker()`, which
2887
+ * assigns the flags, and initialising afterwards would wipe them.
2888
+ */
2889
+ "_popup_el": HTMLElement | null;
2890
+ /** Escape-to-close, detached in dispose(). */
2891
+ "_onPopupKeyBound": ((e: KeyboardEvent) => void) | null;
2892
+ /** Mirrors `active()`, as a flag rather than a method reference. */
2893
+ "_is_active": boolean;
2894
+ /**
2895
+ * The merged marker presentation: `marker.*` wins, `location.*` is the
2896
+ * legacy spelling and still works.
2897
+ * `location` also stays the carrier of geography, so lat/lon are read
2898
+ * from it alone — presentation never moves a marker.
2899
+ */
2900
+ _presentation(d?: MapMarkerData): MarkerPresentation;
2901
+ _createMarker(d?: MapMarkerData, o?: StorymapOptions): void;
2902
+ _createMarkerElement(d: MapMarkerData, o?: StorymapOptions): HTMLDivElement;
2903
+ /**
2904
+ * The marker's {lat, lon}, or null when it is a non-georeferenced marker
2905
+ * (an overview slide, or a slide with only an image region). `_createMarker`
2906
+ * already established this for a real marker, but returning it from one
2907
+ * place means the type checker can see it too.
2908
+ */
2909
+ latLon(): LatLngLiteral | null;
2910
+ _addTo(m: Map_3): void;
2911
+ _removeFrom(m: Map_3): void;
2912
+ /**
2913
+ * Terminal teardown: detach the click listener and drop the overlay and
2914
+ * element. Called by the map's dispose(); the marker must not be used
2915
+ * afterwards.
2916
+ */
2917
+ /**
2918
+ * Toggle the popup card for the *active* marker. Inactive markers keep
2919
+ * their original behaviour — a click navigates — so a popup never
2920
+ * swallows navigation on a map full of pins.
2921
+ *
2922
+ * The card is a DOM element parented to the marker element and positioned
2923
+ * with CSS, which is how it survives a move to the vector renderer
2924
+ * (docs/plans/issue-159-vector-markers.md): only the anchor is the
2925
+ * marker's, and that is `latLon()`.
2926
+ */
2927
+ _togglePopup(): void;
2928
+ _closePopup(): void;
2929
+ /** True when this marker is configured to show a popup card. */
2930
+ isPopupEnabled(): boolean;
2931
+ /**
2932
+ * Open the popup card for this marker.
2933
+ *
2934
+ * Returns false (and opens nothing) when popups are disabled for the
2935
+ * marker or it is not a real map marker — e.g. an overview slide. A
2936
+ * click on an inactive marker navigates instead of opening (see the
2937
+ * click handler in `_createMarker`); programmatic callers that want the
2938
+ * card on another stop should navigate first (`StoryMap.openMarkerPopup`
2939
+ * does exactly that). Fires `popupopen` on success.
2940
+ */
2941
+ openPopup(): boolean;
2942
+ /**
2943
+ * Close the popup card if it is open. Fires `popupclose`. Also runs on
2944
+ * Escape, the card's close button, deactivation and `dispose()`.
2945
+ */
2946
+ closePopup(): void;
2947
+ /**
2948
+ * Open the card when closed, close it when open. Returns whether the
2949
+ * card is open afterwards (false when popups are disabled).
2950
+ */
2951
+ togglePopup(): boolean;
2952
+ get popupOpen(): boolean;
2953
+ /**
2954
+ * Headline, a sanitized excerpt, the media thumb and an audio control.
2955
+ * Every piece of text goes through `sanitizeSlideText` — a slide's text
2956
+ * is untrusted input and a marker card is no different (the stored-XSS
2957
+ * audit made that lesson once; a label is attacker-controlled text like
2958
+ * any other).
2959
+ */
2960
+ _createPopupElement(): HTMLElement | null;
2961
+ /**
2962
+ * A small indicator on markers whose slide has narration or audio media
2963
+ * (the Micrio affordance). Recomputed on activation, because a slide's
2964
+ * media may only be known once it is resolved.
2965
+ */
2966
+ _updateAudioBadge(): void;
2967
+ dispose(): void;
2968
+ _active(a: boolean): void;
2969
+ _customIconAnchor(size?: number[]): number[];
2970
+ _location(): LatLngLiteral | null;
2971
+ }
2972
+
2258
2973
  export declare interface StorymapOptions {
2259
2974
  width: number;
2260
2975
  height: number;
@@ -2303,10 +3018,33 @@ export declare interface StorymapOptions {
2303
3018
  autoplay_media: boolean;
2304
3019
  /** Show a progress bar in the menubar (issue #247) */
2305
3020
  show_progress: boolean;
2306
- /** Show the slide headline as a label on the active map marker (issue #243) */
3021
+ /**
3022
+ * Progress indicator style (slideshow `progressbar`): `false`/`"off"`
3023
+ * hides it (same as `show_progress: false`), `true`/`"bar"` is the
3024
+ * classic fill bar, `dots`/`squares` render one step per slide,
3025
+ * `block`/`thinblock` are fill-bar height variants. Absent means the
3026
+ * `show_progress` boolean decides and the style is `"bar"`. Honored
3027
+ * only with `slideshow_source`.
3028
+ */
3029
+ progressbar?: boolean | "bar" | "dots" | "squares" | "block" | "thinblock" | "off"; /** Show the slide headline as a label on the active map marker (issue #243) */
2307
3030
  marker_labels: boolean;
2308
3031
  /** Default text alignment for slide text: left, center or right (issue #244) */
2309
3032
  text_align: "left" | "center" | "right";
3033
+ /**
3034
+ * Slide panel dock (slideshow `textmode`): which side the text panel
3035
+ * occupies in landscape. `"right"` (default) is the current layout;
3036
+ * `"left"` mirrors it; `"bottom"` docks the panel below the map.
3037
+ * Portrait layouts always behave like `"bottom"`. Honored only with
3038
+ * `slideshow_source`.
3039
+ */
3040
+ textmode?: "left" | "right" | "bottom";
3041
+ /**
3042
+ * Slide panel size as a percentage (slideshow `textsize`): percent of
3043
+ * the width for side docks, of the height for the bottom dock.
3044
+ * Range 10..80; absent keeps the built-in 50/50 split. Honored only
3045
+ * with `slideshow_source`.
3046
+ */
3047
+ textsize?: number;
2310
3048
  /** Override the overview fit center (issues #107, #271) */
2311
3049
  map_overview_center: {
2312
3050
  lat: number;
@@ -2330,6 +3068,15 @@ export declare interface StorymapOptions {
2330
3068
  * (default) means base map only.
2331
3069
  */
2332
3070
  overlays: StorymapOverlayLayer[];
3071
+ /** Show the basemap/overlay switcher in the menubar (default false) */
3072
+ show_layers_control: boolean;
3073
+ /**
3074
+ * Selectable base maps for the layer switcher. Entry 0 is the initial
3075
+ * basemap unless `map_type` says otherwise; omit for an overlays-only
3076
+ * control. Constructor- and runtime-only when labels are functions
3077
+ * (functions cannot ride storymap JSON — see `label`).
3078
+ */
3079
+ basemaps?: StorymapBasemap[];
2333
3080
  map_mini: boolean;
2334
3081
  map_as_image: boolean;
2335
3082
  map_access_token: string;
@@ -2380,6 +3127,77 @@ export declare interface StorymapOptions {
2380
3127
  text_background_color: string;
2381
3128
  /** Show the great-circle route distance in the menubar (issue #341) */
2382
3129
  show_distance: boolean;
3130
+ /**
3131
+ * Slide transition effect (slideshow `fxmode`): `"slide"` (default) is
3132
+ * the current glide, `"fade"` cross-fades slides, `"none"` jumps without
3133
+ * animation. `prefers-reduced-motion` still forces `"none"`. Honored
3134
+ * only with `slideshow_source`.
3135
+ */
3136
+ fxmode?: "slide" | "fade" | "none";
3137
+ /**
3138
+ * Reading mode (slideshow `mode`): `"standard"` (default) is the
3139
+ * slider; `"static"` stacks all slides in a scrollable list and follows
3140
+ * the map to the slide in view. Honored only with `slideshow_source`.
3141
+ */
3142
+ mode?: "standard" | "static";
3143
+ /**
3144
+ * HUD foreground color override (slideshow `hudcolor`): sets the
3145
+ * `--vco-hud-fg` CSS variable. Absent follows the theme. Honored only
3146
+ * with `slideshow_source`.
3147
+ */
3148
+ hudcolor?: string;
3149
+ /**
3150
+ * HUD background color override (slideshow `hudbgcolor`): sets the
3151
+ * `--vco-hud-bg` CSS variable. Absent follows the theme. Honored only
3152
+ * with `slideshow_source`.
3153
+ */
3154
+ hudbgcolor?: string;
3155
+ /**
3156
+ * HUD opacity percent 0..100 (slideshow `hudopacity`): applied to the
3157
+ * HUD background. Absent means fully opaque theme background. Honored
3158
+ * only with `slideshow_source`.
3159
+ */
3160
+ hudopacity?: number;
3161
+ /**
3162
+ * Show the previous/next slide navigation (slideshow `shownav`).
3163
+ * Default true; `false` hides the nav chrome (keyboard/AT navigation
3164
+ * still works, like `show_progress: false` keeps the story usable).
3165
+ * Honored only with `slideshow_source`.
3166
+ */
3167
+ shownav?: boolean;
3168
+ /**
3169
+ * Render slide headlines (slideshow `showheadings`). Default true;
3170
+ * `false` hides headline elements via CSS. Honored only with
3171
+ * `slideshow_source`.
3172
+ */
3173
+ show_headings?: boolean;
3174
+ /**
3175
+ * Show scrollbars in the slide panel (slideshow `showscrollbars`).
3176
+ * Default true; `false` hides them via CSS (content still scrolls).
3177
+ * Honored only with `slideshow_source`.
3178
+ */
3179
+ show_scrollbars?: boolean;
3180
+ /**
3181
+ * Fixed viewer height (slideshow `viewerheight`), e.g. `"400px"`:
3182
+ * applied as a container height override when set. Absent keeps the
3183
+ * measured-container behavior. Only `px`, `%` and `vh` units accepted.
3184
+ * Honored only with `slideshow_source`.
3185
+ */
3186
+ viewerheight?: string;
3187
+ /**
3188
+ * Show media captions and credits (slideshow `showinfo`). Default true;
3189
+ * `false` hides the caption/credit block. Honored only with
3190
+ * `slideshow_source`.
3191
+ */
3192
+ show_info?: boolean;
3193
+ /**
3194
+ * Detect slideshow tours automatically (default `true`): an
3195
+ * `AnnotationCollection` shaped like one loads through the translator.
3196
+ * Set `false` to disable detection (such documents then fail validation
3197
+ * as before).
3198
+ */
3199
+ slideshow?: boolean;
3200
+ /* Excluded from this release type: slideshow_source */
2383
3201
  /**
2384
3202
  * Raw OpenLayers map configuration. `controls` replaces the StoryMapJS
2385
3203
  * defaults, `interactions` are *added to* the viewer's own pan/zoom
@@ -2399,14 +3217,24 @@ export declare interface StorymapOptions {
2399
3217
  show_lines: boolean;
2400
3218
  show_history_line: boolean;
2401
3219
  use_custom_markers: boolean;
3220
+ /**
3221
+ * IIIF image service for image maps. `url` is the `info.json`; `width`
3222
+ * and `height` record the canvas size so region clamping and the static
3223
+ * fallback work without another fetch; `fallbackUrl` is a full-size
3224
+ * image used when `info.json` cannot be loaded (slideshow
3225
+ * `image_static`).
3226
+ */
2402
3227
  iiif: {
2403
3228
  url: string;
2404
3229
  attribution: string;
3230
+ width?: number;
3231
+ height?: number;
3232
+ fallbackUrl?: string;
2405
3233
  };
2406
3234
  tilejson?: StorymapTilejson;
2407
3235
  /**
2408
3236
  * The `seeAlso` targets a IIIF manifest points at, recorded but not
2409
- * fetched — see `loadSeeAlso()` (§5.2 of docs/plans/iiif-interop.md).
3237
+ * fetched — see `loadSeeAlso()`.
2410
3238
  */
2411
3239
  see_also?: {
2412
3240
  id: string;
@@ -2418,8 +3246,18 @@ export declare interface StorymapOptions {
2418
3246
  slide_default_fade: string;
2419
3247
  menubar_default_y: number;
2420
3248
  script_path: string;
2421
- font_css: string;
3249
+ /**
3250
+ * Font theme stylesheet: `stock:<name>`, a URL/path, or `false` for no
3251
+ * injected stylesheet (the host bundles the theme itself).
3252
+ */
3253
+ font_css: string | false;
2422
3254
  language: string;
3255
+ /**
3256
+ * Colour theme: `"dark"` forces the dark palette, `"light"` pins the
3257
+ * light one (overriding an OS dark preference), unset follows
3258
+ * `prefers-color-scheme`. Construction-time only, like `map_type`.
3259
+ */
3260
+ theme?: "dark" | "light";
2423
3261
  api_key_flickr: string;
2424
3262
  [key: string]: unknown;
2425
3263
  }
@@ -2452,6 +3290,23 @@ export declare interface StorymapOverlayLayer {
2452
3290
  className?: string;
2453
3291
  /** CSS mix-blend-mode for the layer container (needs className) */
2454
3292
  blendMode?: string;
3293
+ /**
3294
+ * Control row label for the layer switcher (`show_layers_control`).
3295
+ * Defaults to `map_type`. A function is re-invoked on every
3296
+ * `refreshLabels()` for host i18n — but only when the entry comes from
3297
+ * constructor options: `mergeData()` overwrites option keys with the
3298
+ * storymap JSON, so a document carrying `overlays` replaces function
3299
+ * labels with its own strings.
3300
+ */
3301
+ label?: string | (() => string);
3302
+ /**
3303
+ * Render the row checked and disabled: an overlay the visitor may add
3304
+ * back but not remove (e.g. a georeferenced scan the story is built on).
3305
+ * The control never toggles a locked entry.
3306
+ */
3307
+ locked?: boolean;
3308
+ /** false hides the row from the control without removing the overlay. */
3309
+ control?: boolean;
2455
3310
  /** Clip box `[west, south, east, north]` in lon/lat (mercator maps) */
2456
3311
  extent?: [number, number, number, number];
2457
3312
  /**
@@ -2475,8 +3330,7 @@ export declare interface StorymapSlide {
2475
3330
  date?: string | Record<string, unknown> | null;
2476
3331
  group?: string;
2477
3332
  /**
2478
- * The language tag this slide's text was read in (§3.4 of
2479
- * docs/plans/iiif-interop.md). A IIIF manifest states its text as a
3333
+ * The language tag this slide's text was read in. A IIIF manifest states its text as a
2480
3334
  * language map; the reader picks the viewer's configured language and
2481
3335
  * reports which one it used, so a host can offer a language switch.
2482
3336
  * Absent for language-neutral (`none`) text, and for a single-language
@@ -2485,11 +3339,46 @@ export declare interface StorymapSlide {
2485
3339
  language?: string;
2486
3340
  location?: StorymapSlideLocation | null;
2487
3341
  media?: StorymapSlideMedia | null;
3342
+ /**
3343
+ * Additional visible media for this slide (#358), rendered after `media`
3344
+ * in order. Items without a non-empty `url` are skipped, so a document
3345
+ * without this field renders identically. In a IIIF manifest these are
3346
+ * further `painting` annotations on the canvas; the slide layout
3347
+ * (`media_layout`) has no IIIF term and stays viewer-side.
3348
+ */
3349
+ media_extra?: StorymapSlideMedia[] | null;
3350
+ /**
3351
+ * Layout of a multi-media slide (#358): `stack` piles the items
3352
+ * vertically (the panel scrolls), `row` puts two items side by side.
3353
+ * Defaults to `stack`; `row` with anything but two items falls back to
3354
+ * `stack`. Ignored for a single media item.
3355
+ */
3356
+ media_layout?: "stack" | "row";
2488
3357
  marker?: StorymapSlideMarker | null;
2489
3358
  narration?: StorymapSlideNarration | null;
2490
3359
  text?: StorymapSlideText | null;
2491
3360
  background?: StorymapSlideBackground | string | null;
2492
3361
  uniqueid?: string | null;
3362
+ /**
3363
+ * Provenance identifiers for the slide's source (slideshow
3364
+ * `manifest_id`/`canvas_id`/`image_id`): which manifest, canvas and
3365
+ * image the stop was translated from. Data-only (deep links, export);
3366
+ * never rendered.
3367
+ */
3368
+ provenance?: StorymapSlideProvenance | null;
3369
+ /**
3370
+ * Per-slide autoplay dwell in milliseconds (slideshow `slidetimeout`):
3371
+ * overrides the global `autoplay` interval for this slide; `0` holds on
3372
+ * this slide. Absent means the global interval. Honored only with
3373
+ * `slideshow_source`.
3374
+ */
3375
+ slidetimeout?: number;
3376
+ /**
3377
+ * Per-slide image overlay on the map (slideshow `imgoverlay`): a placed
3378
+ * image shown while this slide is active. Absent means no overlay.
3379
+ * Honored only with `slideshow_source`.
3380
+ */
3381
+ imgoverlay?: StorymapImageOverlay | null;
2493
3382
  [key: string]: unknown;
2494
3383
  }
2495
3384
 
@@ -2499,16 +3388,58 @@ export declare interface StorymapSlideBackground {
2499
3388
  opacity?: number;
2500
3389
  }
2501
3390
 
3391
+ /**
3392
+ * Declarative CSS filter grading for one slide (slideshow `filters`).
3393
+ * Rendered by `buildSlideFilter()`; unknown keys never reach CSS.
3394
+ */
3395
+ declare interface StorymapSlideFilter {
3396
+ brightness?: number;
3397
+ contrast?: number;
3398
+ saturate?: number;
3399
+ hueRotate?: number;
3400
+ sepia?: number;
3401
+ blur?: number;
3402
+ [key: string]: unknown;
3403
+ }
3404
+
2502
3405
  export declare interface StorymapSlideLocation {
2503
3406
  lat?: number;
2504
3407
  lon?: number;
2505
3408
  zoom?: number;
2506
3409
  /**
2507
3410
  * Image region `[x, y, w, h]` in image pixels (IIIF xywh convention,
2508
- * StrollView-style image stops): the view fits the region on
3411
+ * slideshow-style image stops): the view fits the region on
2509
3412
  * navigation; image maps (`map_type: "iiif"` + `map_as_image`) only.
2510
3413
  */
2511
3414
  region?: [number, number, number, number];
3415
+ /**
3416
+ * View rotation in degrees clockwise (slideshow `rotation`). Applied to
3417
+ * the map view on navigation; absent means north-up (0). Image and geo
3418
+ * maps alike; purely presentational. Honored only with
3419
+ * `slideshow_source`.
3420
+ */
3421
+ rotation?: number;
3422
+ /**
3423
+ * Per-slide image grading (slideshow `filters`): applied as a CSS
3424
+ * `filter()` on the map viewport. All fields optional; absent means
3425
+ * unfiltered. `hueRotate` is degrees (-180..180), `blur` is CSS pixels.
3426
+ * Honored only with `slideshow_source`.
3427
+ */
3428
+ filter?: StorymapSlideFilter;
3429
+ /**
3430
+ * Spotlight mask (slideshow `passepartout`): normalized viewport
3431
+ * fractions `{x, y, w, h}` (0..1) left visible while the rest is dimmed
3432
+ * with `color`. `invert` dims the inside instead of the outside.
3433
+ * Absent means no mask. Honored only with `slideshow_source`.
3434
+ */
3435
+ mask?: StorymapSlideMask;
3436
+ /**
3437
+ * Per-slide basemap override (multi-manifest slideshow tours): any
3438
+ * `map_type` value or IIIF `info.json` URL. Absent keeps the story
3439
+ * basemap. The layer is cached, so returning to a slide is free.
3440
+ * Honored only with `slideshow_source`.
3441
+ */
3442
+ basemap?: string;
2512
3443
  line?: boolean;
2513
3444
  icon?: string;
2514
3445
  iconSize?: number[];
@@ -2517,17 +3448,9 @@ export declare interface StorymapSlideLocation {
2517
3448
  [key: string]: unknown;
2518
3449
  }
2519
3450
 
2520
- /**
2521
- * Optional spoken narration for one slide, played through a dedicated audio
2522
- * element rather than the slide's media frame — a tour stop usually has a
2523
- * picture and a recording, not one media item. Storymap JSON only: the
2524
- * closest manifest spelling is a `Sound` body, which currently lands in
2525
- * `media.url` rather than here.
2526
- */
2527
3451
  /**
2528
3452
  * Per-slide marker presentation, consolidated. `location.*` keeps working as
2529
- * the legacy spelling and `marker.*` wins when present — see
2530
- * docs/plans/iiif-media-tours.md §2.
3453
+ * the legacy spelling and `marker.*` wins when present.
2531
3454
  *
2532
3455
  * In a IIIF manifest none of this is a `storymap:` term: it all arrives in the
2533
3456
  * `navPlace` Feature's `properties` bag (`icon`, `iconSize`, `image`, `name`,
@@ -2547,6 +3470,21 @@ export declare interface StorymapSlideMarker {
2547
3470
  [key: string]: unknown;
2548
3471
  }
2549
3472
 
3473
+ /**
3474
+ * Spotlight mask geometry (slideshow `passepartout`). Fractions of the
3475
+ * visible map area; `color` is a `#rgb`/`#rrggbb`/`#rrggbbaa`/`rgb(a)` string.
3476
+ */
3477
+ declare interface StorymapSlideMask {
3478
+ x: number;
3479
+ y: number;
3480
+ w: number;
3481
+ h: number;
3482
+ color?: string;
3483
+ invert?: boolean;
3484
+ opacity?: number;
3485
+ [key: string]: unknown;
3486
+ }
3487
+
2550
3488
  export declare interface StorymapSlideMedia {
2551
3489
  url?: string | null;
2552
3490
  caption?: string | null;
@@ -2566,11 +3504,83 @@ export declare interface StorymapSlideMedia {
2566
3504
  * `TextualBody` + `format: text/vtt` shape we also accept.
2567
3505
  */
2568
3506
  subtitles?: string | null;
3507
+ /**
3508
+ * Start offset in seconds for audio/video media (slideshow `audio.offset`).
3509
+ * Applied once the media metadata is available; absent or negative means 0.
3510
+ * Honored only with `slideshow_source`.
3511
+ */
3512
+ offset?: number;
3513
+ /**
3514
+ * Loop audio/video media (slideshow `audio.loop`). Absent means no loop.
3515
+ * Honored only with `slideshow_source`.
3516
+ */
3517
+ loop?: boolean;
3518
+ /**
3519
+ * `auto` (default) plays on activation; `click` arms the media paused and
3520
+ * lets the visitor start it (slideshow `audio.play`). Absent means `auto`.
3521
+ * Honored only with `slideshow_source`.
3522
+ */
3523
+ play?: "auto" | "click";
3524
+ /**
3525
+ * Stop this media when leaving the slide (default true). `false` lets an
3526
+ * audio bed continue across slides (slideshow ambient audio). Honored
3527
+ * only with `slideshow_source`.
3528
+ */
3529
+ stopOnExit?: boolean;
2569
3530
  [key: string]: unknown;
2570
3531
  }
2571
3532
 
3533
+ /**
3534
+ * Optional spoken narration for one slide, played through a dedicated audio
3535
+ * element rather than the slide's media frame — a tour stop usually has a
3536
+ * picture and a recording, not one media item. In a IIIF manifest this is a
3537
+ * `motivation: "supplementing"` Sound/Video body, read and written alongside
3538
+ * the painting annotation.
3539
+ */
2572
3540
  export declare interface StorymapSlideNarration {
2573
3541
  url: string;
3542
+ /**
3543
+ * Loop the narration (slideshow `audio.loop`). Absent means no loop.
3544
+ * Note: a looping narration never fires `ended`, so `autoplay_media`
3545
+ * falls back to its millisecond timer for that slide. Honored only with
3546
+ * `slideshow_source`.
3547
+ */
3548
+ loop?: boolean;
3549
+ /**
3550
+ * Start offset in seconds (slideshow `audio.offset`), applied once the
3551
+ * audio metadata is available. Absent or negative means 0. Honored only
3552
+ * with `slideshow_source`.
3553
+ */
3554
+ offset?: number;
3555
+ /**
3556
+ * `auto` (default) plays on navigation; `click` arms the narration
3557
+ * paused and lets the visitor start it (slideshow `audio.play`).
3558
+ * Honored only with `slideshow_source`.
3559
+ */
3560
+ play?: "auto" | "click";
3561
+ /**
3562
+ * Stop the narration when leaving the slide (default true). `false`
3563
+ * keeps an audio bed playing across slides while the URL is unchanged
3564
+ * (slideshow ambient audio). Honored only with `slideshow_source`.
3565
+ */
3566
+ stopOnExit?: boolean;
3567
+ /**
3568
+ * Stop any other playing narration/ambient track before starting this
3569
+ * one (default true). `false` allows the ambient overlap of two tracks.
3570
+ * Honored only with `slideshow_source`.
3571
+ */
3572
+ stopAllPrevious?: boolean;
3573
+ [key: string]: unknown;
3574
+ }
3575
+
3576
+ /**
3577
+ * Provenance identifiers for one slide's source: the manifest, canvas and
3578
+ * image a stop was translated from. Data-only.
3579
+ */
3580
+ declare interface StorymapSlideProvenance {
3581
+ manifest?: string;
3582
+ canvas?: string;
3583
+ image?: string;
2574
3584
  [key: string]: unknown;
2575
3585
  }
2576
3586
 
@@ -2582,7 +3592,7 @@ export declare interface StorymapSlideText {
2582
3592
 
2583
3593
  /**
2584
3594
  * TileJSON 2.1 tile source metadata, from a manifest's map configuration
2585
- * service (§2.9 of docs/plans/iiif-interop.md).
3595
+ * service.
2586
3596
  *
2587
3597
  * This is how a manifest states a tile source: `tiles` is the URL template and
2588
3598
  * the rest is the standard metadata around it, where a keyword basemap
@@ -2622,18 +3632,7 @@ declare class StorySlider extends StorySlider_base {
2622
3632
  constructor(...args: ConstructorParameters<typeof StorySliderBase>);
2623
3633
  }
2624
3634
 
2625
- declare const StorySlider_base: {
2626
- new (...args: any[]): {
2627
- _vco_events?: Record<string, {
2628
- action: unknown;
2629
- context: unknown;
2630
- }[]> | undefined;
2631
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
2632
- hasEventListeners(type: string): boolean;
2633
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
2634
- fire(type: string, data?: unknown, target?: unknown): /*elided*/ any;
2635
- };
2636
- } & typeof StorySliderBase;
3635
+ declare const StorySlider_base: Constructor<EventedInstance<StorySliderEvents>> & typeof StorySliderBase;
2637
3636
 
2638
3637
  declare class StorySliderBase {
2639
3638
  "_el": StorySliderElements;
@@ -2649,13 +3648,19 @@ declare class StorySliderBase {
2649
3648
  "_message": Message;
2650
3649
  "current_slide": number;
2651
3650
  "current_bg_color": string | null;
3651
+ /** Layout the background gradient was built for; a portrait↔landscape
3652
+ switch rebuilds it even when the color is unchanged. */
3653
+ "current_bg_layout": string | null;
2652
3654
  "data": Partial<StorymapData>;
2653
3655
  "options": StorySliderOptions;
2654
3656
  "animator": AnimationHandle | null;
2655
3657
  "animator_background": AnimationHandle | null;
2656
- "fire": EventedInstance["fire"];
3658
+ "fire": EventedInstance<StorySliderEvents>["fire"];
2657
3659
  "_loaded": boolean;
2658
- "hasEventListeners": EventedInstance["hasEventListeners"];
3660
+ /** Scroll-spy observer for `mode: "static"`; null in standard mode. */
3661
+ "_static_observer": IntersectionObserver | null;
3662
+ /** True while a scroll-spy navigation is settling (suppresses echo scrolls). */
3663
+ "_static_spying": boolean;
2659
3664
  constructor(elem: HTMLElement | string, data: Partial<StorymapData>, options?: Partial<StorySliderOptions>, init?: boolean);
2660
3665
  init(): void;
2661
3666
  updateDisplay(w?: number, h?: number, a?: unknown, l?: string): void;
@@ -2679,7 +3684,7 @@ declare class StorySliderBase {
2679
3684
  * `StoryMap.dispose()`; the slider must not be used afterwards.
2680
3685
  */
2681
3686
  dispose(): void;
2682
- goTo(n: number, fast?: boolean, displayupdate?: boolean): void;
3687
+ goTo(n: number, fast?: boolean, displayupdate?: boolean, fromScroll?: boolean): void;
2683
3688
  preloadSlides(): void;
2684
3689
  getNavInfo(slide: Slide): {
2685
3690
  title: string;
@@ -2690,6 +3695,17 @@ declare class StorySliderBase {
2690
3695
  showNav(nav_obj: SlideNav, show: boolean): void;
2691
3696
  changeBackground(bg: SlideBackgroundChange): void;
2692
3697
  fadeInBackground(bg_css: string): void;
3698
+ /** True in the stacked reading mode (`mode: "static"`): no strip translation. */
3699
+ _isStatic(): boolean;
3700
+ /**
3701
+ * Scroll-spy for the static reading mode: the most visible stacked slide
3702
+ * becomes current, so the map follows the reading position. Programmatic
3703
+ * scrolls set `_static_spying` while settling and are ignored, or the
3704
+ * observer would echo them back.
3705
+ */
3706
+ _initStaticSpy(): void;
3707
+ /** Scroll a stacked slide into view without moving the host page. */
3708
+ _scrollSlideIntoView(n: number): void;
2693
3709
  _updateDisplay(width?: number, height?: number, animate?: unknown, layout?: string): void;
2694
3710
  _introInterface(): void;
2695
3711
  _initLayout(): void;
@@ -2700,7 +3716,7 @@ declare class StorySliderBase {
2700
3716
  _onMessageClick(e?: unknown): void;
2701
3717
  _onSwipeNoDirection(e?: unknown): void;
2702
3718
  _onNavigation(e: {
2703
- direction: string;
3719
+ direction: string | null;
2704
3720
  }): void;
2705
3721
  _onSlideAdded(e?: unknown): void;
2706
3722
  _onSlideChange(displayupdate?: boolean): void;
@@ -2708,8 +3724,7 @@ declare class StorySliderBase {
2708
3724
  }
2709
3725
 
2710
3726
  /**
2711
- * The slider's element cache. `live_region` only exists when the slide
2712
- * announcements are enabled (the `a11y` option), so it starts out null.
3727
+ * The slider's element cache.
2713
3728
  */
2714
3729
  declare type StorySliderElements = {
2715
3730
  container: HTMLElement;
@@ -2721,6 +3736,23 @@ declare type StorySliderElements = {
2721
3736
  live_region: HTMLElement | null;
2722
3737
  };
2723
3738
 
3739
+ export declare interface StorySliderEvents {
3740
+ colorchange: SlideBackgroundChange;
3741
+ nav_next: Partial<StorymapData>;
3742
+ nav_previous: Partial<StorymapData>;
3743
+ nav_left: Partial<StorymapData>;
3744
+ nav_right: Partial<StorymapData>;
3745
+ slideAdded: Partial<StorymapData>;
3746
+ change: {
3747
+ current_slide: number;
3748
+ uniqueid: string | null | undefined;
3749
+ };
3750
+ loaded: Partial<StorymapData>;
3751
+ title: {
3752
+ title: string;
3753
+ };
3754
+ }
3755
+
2724
3756
  declare interface StorySliderOptions {
2725
3757
  id?: string;
2726
3758
  layout: string;
@@ -2747,18 +3779,7 @@ declare class Swipable extends Swipable_base {
2747
3779
  constructor(...args: ConstructorParameters<typeof SwipableBase>);
2748
3780
  }
2749
3781
 
2750
- declare const Swipable_base: {
2751
- new (...args: any[]): {
2752
- _vco_events?: Record<string, {
2753
- action: unknown;
2754
- context: unknown;
2755
- }[]> | undefined;
2756
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
2757
- hasEventListeners(type: string): boolean;
2758
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
2759
- fire(type: string, data?: unknown, target?: unknown): /*elided*/ any;
2760
- };
2761
- } & typeof SwipableBase;
3782
+ declare const Swipable_base: Constructor<EventedInstance<SwipableEvents>> & typeof SwipableBase;
2762
3783
 
2763
3784
  declare class SwipableBase {
2764
3785
  "mousedrag": DragEventNames;
@@ -2768,7 +3789,7 @@ declare class SwipableBase {
2768
3789
  "animator": AnimationHandle | null;
2769
3790
  "dragevent": DragEventNames;
2770
3791
  "data": DragData;
2771
- "fire": EventedInstance["fire"];
3792
+ "fire": EventedInstance<SwipableEvents>["fire"];
2772
3793
  constructor(drag_elem: HTMLElement, move_elem?: HTMLElement, options?: Record<string, unknown>);
2773
3794
  enable(e?: LegacyEvent): void;
2774
3795
  disable(): void;
@@ -2789,6 +3810,18 @@ declare class SwipableBase {
2789
3810
  _animateMomentum(): void;
2790
3811
  }
2791
3812
 
3813
+ export declare interface SwipableEvents {
3814
+ dragstart: DragData;
3815
+ dragend: DragData;
3816
+ dragmove: DragData;
3817
+ momentum: DragData;
3818
+ swipe_left: DragData;
3819
+ swipe_right: DragData;
3820
+ swipe_up: DragData;
3821
+ swipe_down: DragData;
3822
+ swipe_nodirection: DragData;
3823
+ }
3824
+
2792
3825
  declare interface SwipableOptions {
2793
3826
  snap: boolean;
2794
3827
  enable: {
@@ -2806,28 +3839,22 @@ declare interface SwipableOptions {
2806
3839
  ease: unknown;
2807
3840
  }
2808
3841
 
3842
+ /** The four swipe directions. `"none"` is not one: an undecided gesture
3843
+ * carries `null`, and the truthiness guard at the fire site treats it as
3844
+ * "no swipe" rather than a fifth direction. */
3845
+ export declare type SwipeDirection = "left" | "right" | "up" | "down";
3846
+
2809
3847
  declare class Text_2 extends Text_base {
2810
3848
  constructor(...args: ConstructorParameters<typeof TextBase>);
2811
3849
  }
2812
3850
 
2813
- declare const Text_base: {
2814
- new (...args: any[]): {
2815
- _vco_events?: Record<string, {
2816
- action: unknown;
2817
- context: unknown;
2818
- }[]> | undefined;
2819
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
2820
- hasEventListeners(type: string): boolean;
2821
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
2822
- fire(type: string, data?: unknown, target?: unknown): /*elided*/ any;
2823
- };
2824
- } & typeof TextBase;
3851
+ declare const Text_base: Constructor<EventedInstance<TextEvents>> & typeof TextBase;
2825
3852
 
2826
3853
  declare class TextBase {
2827
3854
  "_el": Record<string, HTMLElement>;
2828
3855
  "data": TextData;
2829
3856
  "options": TextOptions;
2830
- "fire": EventedInstance["fire"];
3857
+ "fire": EventedInstance<TextEvents>["fire"];
2831
3858
  constructor(data: TextData, options?: TextOptions, add_to_container?: HTMLElement);
2832
3859
  show(): void;
2833
3860
  hide(): void;
@@ -2852,9 +3879,17 @@ declare interface TextData {
2852
3879
  } | null;
2853
3880
  }
2854
3881
 
3882
+ export declare interface TextEvents {
3883
+ loaded: TextData;
3884
+ added: TextData;
3885
+ removed: TextData;
3886
+ }
3887
+
2855
3888
  declare interface TextOptions {
2856
3889
  title?: boolean;
2857
3890
  text_align?: string;
3891
+ /** BCP 47 tag for the slide text (from `StorymapSlide.language`). */
3892
+ language?: string;
2858
3893
  }
2859
3894
 
2860
3895
  /**
@@ -2883,6 +3918,8 @@ declare interface ViewToOptions {
2883
3918
  calculate_zoom?: boolean;
2884
3919
  duration?: number;
2885
3920
  zoom?: number;
3921
+ /** View rotation in degrees clockwise; absent leaves rotation unchanged. */
3922
+ rotation?: number;
2886
3923
  }
2887
3924
 
2888
3925
  export { }