@projektemacher/storymapjs 0.10.7 → 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 (587) hide show
  1. package/CHANGELOG +431 -19
  2. package/README.md +168 -17
  3. package/dist/assets/demo-bWnOyfUw.js +1 -0
  4. package/dist/assets/harness-C3JUv5Ii.js +1 -0
  5. package/dist/assets/harness-multi-XZNex3tb.js +1 -0
  6. package/dist/assets/harness-support-CjfZIVeb.js +1 -0
  7. package/dist/assets/index-wHPqGrBS.js +1 -0
  8. package/dist/assets/main-DQ32hWBM.js +17 -0
  9. package/dist/context.json +23 -9
  10. package/dist/css/fonts/files/amatic-sc-cyrillic-400-normal.woff2 +0 -0
  11. package/dist/css/fonts/files/amatic-sc-cyrillic-700-normal.woff2 +0 -0
  12. package/dist/css/fonts/files/amatic-sc-hebrew-400-normal.woff2 +0 -0
  13. package/dist/css/fonts/files/amatic-sc-hebrew-700-normal.woff2 +0 -0
  14. package/dist/css/fonts/files/amatic-sc-vietnamese-400-normal.woff2 +0 -0
  15. package/dist/css/fonts/files/amatic-sc-vietnamese-700-normal.woff2 +0 -0
  16. package/dist/css/fonts/files/bitter-cyrillic-100-italic.woff2 +0 -0
  17. package/dist/css/fonts/files/bitter-cyrillic-100-normal.woff2 +0 -0
  18. package/dist/css/fonts/files/bitter-cyrillic-200-italic.woff2 +0 -0
  19. package/dist/css/fonts/files/bitter-cyrillic-200-normal.woff2 +0 -0
  20. package/dist/css/fonts/files/bitter-cyrillic-300-italic.woff2 +0 -0
  21. package/dist/css/fonts/files/bitter-cyrillic-300-normal.woff2 +0 -0
  22. package/dist/css/fonts/files/bitter-cyrillic-400-italic.woff2 +0 -0
  23. package/dist/css/fonts/files/bitter-cyrillic-400-normal.woff2 +0 -0
  24. package/dist/css/fonts/files/bitter-cyrillic-500-italic.woff2 +0 -0
  25. package/dist/css/fonts/files/bitter-cyrillic-500-normal.woff2 +0 -0
  26. package/dist/css/fonts/files/bitter-cyrillic-600-italic.woff2 +0 -0
  27. package/dist/css/fonts/files/bitter-cyrillic-600-normal.woff2 +0 -0
  28. package/dist/css/fonts/files/bitter-cyrillic-700-italic.woff2 +0 -0
  29. package/dist/css/fonts/files/bitter-cyrillic-700-normal.woff2 +0 -0
  30. package/dist/css/fonts/files/bitter-cyrillic-800-italic.woff2 +0 -0
  31. package/dist/css/fonts/files/bitter-cyrillic-800-normal.woff2 +0 -0
  32. package/dist/css/fonts/files/bitter-cyrillic-900-italic.woff2 +0 -0
  33. package/dist/css/fonts/files/bitter-cyrillic-900-normal.woff2 +0 -0
  34. package/dist/css/fonts/files/bitter-cyrillic-ext-100-italic.woff2 +0 -0
  35. package/dist/css/fonts/files/bitter-cyrillic-ext-100-normal.woff2 +0 -0
  36. package/dist/css/fonts/files/bitter-cyrillic-ext-200-italic.woff2 +0 -0
  37. package/dist/css/fonts/files/bitter-cyrillic-ext-200-normal.woff2 +0 -0
  38. package/dist/css/fonts/files/bitter-cyrillic-ext-300-italic.woff2 +0 -0
  39. package/dist/css/fonts/files/bitter-cyrillic-ext-300-normal.woff2 +0 -0
  40. package/dist/css/fonts/files/bitter-cyrillic-ext-400-italic.woff2 +0 -0
  41. package/dist/css/fonts/files/bitter-cyrillic-ext-400-normal.woff2 +0 -0
  42. package/dist/css/fonts/files/bitter-cyrillic-ext-500-italic.woff2 +0 -0
  43. package/dist/css/fonts/files/bitter-cyrillic-ext-500-normal.woff2 +0 -0
  44. package/dist/css/fonts/files/bitter-cyrillic-ext-600-italic.woff2 +0 -0
  45. package/dist/css/fonts/files/bitter-cyrillic-ext-600-normal.woff2 +0 -0
  46. package/dist/css/fonts/files/bitter-cyrillic-ext-700-italic.woff2 +0 -0
  47. package/dist/css/fonts/files/bitter-cyrillic-ext-700-normal.woff2 +0 -0
  48. package/dist/css/fonts/files/bitter-cyrillic-ext-800-italic.woff2 +0 -0
  49. package/dist/css/fonts/files/bitter-cyrillic-ext-800-normal.woff2 +0 -0
  50. package/dist/css/fonts/files/bitter-cyrillic-ext-900-italic.woff2 +0 -0
  51. package/dist/css/fonts/files/bitter-cyrillic-ext-900-normal.woff2 +0 -0
  52. package/dist/css/fonts/files/bitter-cyrillic-ext-wght-italic.woff2 +0 -0
  53. package/dist/css/fonts/files/bitter-cyrillic-ext-wght-normal.woff2 +0 -0
  54. package/dist/css/fonts/files/bitter-cyrillic-wght-italic.woff2 +0 -0
  55. package/dist/css/fonts/files/bitter-cyrillic-wght-normal.woff2 +0 -0
  56. package/dist/css/fonts/files/bitter-vietnamese-100-italic.woff2 +0 -0
  57. package/dist/css/fonts/files/bitter-vietnamese-100-normal.woff2 +0 -0
  58. package/dist/css/fonts/files/bitter-vietnamese-200-italic.woff2 +0 -0
  59. package/dist/css/fonts/files/bitter-vietnamese-200-normal.woff2 +0 -0
  60. package/dist/css/fonts/files/bitter-vietnamese-300-italic.woff2 +0 -0
  61. package/dist/css/fonts/files/bitter-vietnamese-300-normal.woff2 +0 -0
  62. package/dist/css/fonts/files/bitter-vietnamese-400-italic.woff2 +0 -0
  63. package/dist/css/fonts/files/bitter-vietnamese-400-normal.woff2 +0 -0
  64. package/dist/css/fonts/files/bitter-vietnamese-500-italic.woff2 +0 -0
  65. package/dist/css/fonts/files/bitter-vietnamese-500-normal.woff2 +0 -0
  66. package/dist/css/fonts/files/bitter-vietnamese-600-italic.woff2 +0 -0
  67. package/dist/css/fonts/files/bitter-vietnamese-600-normal.woff2 +0 -0
  68. package/dist/css/fonts/files/bitter-vietnamese-700-italic.woff2 +0 -0
  69. package/dist/css/fonts/files/bitter-vietnamese-700-normal.woff2 +0 -0
  70. package/dist/css/fonts/files/bitter-vietnamese-800-italic.woff2 +0 -0
  71. package/dist/css/fonts/files/bitter-vietnamese-800-normal.woff2 +0 -0
  72. package/dist/css/fonts/files/bitter-vietnamese-900-italic.woff2 +0 -0
  73. package/dist/css/fonts/files/bitter-vietnamese-900-normal.woff2 +0 -0
  74. package/dist/css/fonts/files/bitter-vietnamese-wght-italic.woff2 +0 -0
  75. package/dist/css/fonts/files/bitter-vietnamese-wght-normal.woff2 +0 -0
  76. package/dist/css/fonts/files/cairo-arabic-200-normal.woff2 +0 -0
  77. package/dist/css/fonts/files/cairo-arabic-300-normal.woff2 +0 -0
  78. package/dist/css/fonts/files/cairo-arabic-400-normal.woff2 +0 -0
  79. package/dist/css/fonts/files/cairo-arabic-500-normal.woff2 +0 -0
  80. package/dist/css/fonts/files/cairo-arabic-600-normal.woff2 +0 -0
  81. package/dist/css/fonts/files/cairo-arabic-700-normal.woff2 +0 -0
  82. package/dist/css/fonts/files/cairo-arabic-800-normal.woff2 +0 -0
  83. package/dist/css/fonts/files/cairo-arabic-900-normal.woff2 +0 -0
  84. package/dist/css/fonts/files/cairo-latin-200-normal.woff2 +0 -0
  85. package/dist/css/fonts/files/cairo-latin-300-normal.woff2 +0 -0
  86. package/dist/css/fonts/files/cairo-latin-400-normal.woff2 +0 -0
  87. package/dist/css/fonts/files/cairo-latin-500-normal.woff2 +0 -0
  88. package/dist/css/fonts/files/cairo-latin-600-normal.woff2 +0 -0
  89. package/dist/css/fonts/files/cairo-latin-700-normal.woff2 +0 -0
  90. package/dist/css/fonts/files/cairo-latin-800-normal.woff2 +0 -0
  91. package/dist/css/fonts/files/cairo-latin-900-normal.woff2 +0 -0
  92. package/dist/css/fonts/files/cairo-latin-ext-200-normal.woff2 +0 -0
  93. package/dist/css/fonts/files/cairo-latin-ext-300-normal.woff2 +0 -0
  94. package/dist/css/fonts/files/cairo-latin-ext-400-normal.woff2 +0 -0
  95. package/dist/css/fonts/files/cairo-latin-ext-500-normal.woff2 +0 -0
  96. package/dist/css/fonts/files/cairo-latin-ext-600-normal.woff2 +0 -0
  97. package/dist/css/fonts/files/cairo-latin-ext-700-normal.woff2 +0 -0
  98. package/dist/css/fonts/files/cairo-latin-ext-800-normal.woff2 +0 -0
  99. package/dist/css/fonts/files/cairo-latin-ext-900-normal.woff2 +0 -0
  100. package/dist/css/fonts/files/dancing-script-vietnamese-wght-normal.woff2 +0 -0
  101. package/dist/css/fonts/files/eb-garamond-cyrillic-ext-wght-italic.woff2 +0 -0
  102. package/dist/css/fonts/files/eb-garamond-cyrillic-ext-wght-normal.woff2 +0 -0
  103. package/dist/css/fonts/files/eb-garamond-cyrillic-wght-italic.woff2 +0 -0
  104. package/dist/css/fonts/files/eb-garamond-cyrillic-wght-normal.woff2 +0 -0
  105. package/dist/css/fonts/files/eb-garamond-greek-ext-wght-italic.woff2 +0 -0
  106. package/dist/css/fonts/files/eb-garamond-greek-ext-wght-normal.woff2 +0 -0
  107. package/dist/css/fonts/files/eb-garamond-greek-wght-italic.woff2 +0 -0
  108. package/dist/css/fonts/files/eb-garamond-greek-wght-normal.woff2 +0 -0
  109. package/dist/css/fonts/files/eb-garamond-vietnamese-wght-italic.woff2 +0 -0
  110. package/dist/css/fonts/files/eb-garamond-vietnamese-wght-normal.woff2 +0 -0
  111. package/dist/css/fonts/files/gentium-book-plus-cyrillic-400-italic.woff2 +0 -0
  112. package/dist/css/fonts/files/gentium-book-plus-cyrillic-400-normal.woff2 +0 -0
  113. package/dist/css/fonts/files/gentium-book-plus-cyrillic-700-italic.woff2 +0 -0
  114. package/dist/css/fonts/files/gentium-book-plus-cyrillic-700-normal.woff2 +0 -0
  115. package/dist/css/fonts/files/gentium-book-plus-cyrillic-ext-400-italic.woff2 +0 -0
  116. package/dist/css/fonts/files/gentium-book-plus-cyrillic-ext-400-normal.woff2 +0 -0
  117. package/dist/css/fonts/files/gentium-book-plus-cyrillic-ext-700-italic.woff2 +0 -0
  118. package/dist/css/fonts/files/gentium-book-plus-cyrillic-ext-700-normal.woff2 +0 -0
  119. package/dist/css/fonts/files/gentium-book-plus-greek-400-italic.woff2 +0 -0
  120. package/dist/css/fonts/files/gentium-book-plus-greek-400-normal.woff2 +0 -0
  121. package/dist/css/fonts/files/gentium-book-plus-greek-700-italic.woff2 +0 -0
  122. package/dist/css/fonts/files/gentium-book-plus-greek-700-normal.woff2 +0 -0
  123. package/dist/css/fonts/files/gentium-book-plus-greek-ext-400-italic.woff2 +0 -0
  124. package/dist/css/fonts/files/gentium-book-plus-greek-ext-400-normal.woff2 +0 -0
  125. package/dist/css/fonts/files/gentium-book-plus-greek-ext-700-italic.woff2 +0 -0
  126. package/dist/css/fonts/files/gentium-book-plus-greek-ext-700-normal.woff2 +0 -0
  127. package/dist/css/fonts/files/gentium-book-plus-vietnamese-400-italic.woff2 +0 -0
  128. package/dist/css/fonts/files/gentium-book-plus-vietnamese-400-normal.woff2 +0 -0
  129. package/dist/css/fonts/files/gentium-book-plus-vietnamese-700-italic.woff2 +0 -0
  130. package/dist/css/fonts/files/gentium-book-plus-vietnamese-700-normal.woff2 +0 -0
  131. package/dist/css/fonts/files/old-standard-tt-cyrillic-400-italic.woff2 +0 -0
  132. package/dist/css/fonts/files/old-standard-tt-cyrillic-400-normal.woff2 +0 -0
  133. package/dist/css/fonts/files/old-standard-tt-cyrillic-700-normal.woff2 +0 -0
  134. package/dist/css/fonts/files/old-standard-tt-cyrillic-ext-400-italic.woff2 +0 -0
  135. package/dist/css/fonts/files/old-standard-tt-cyrillic-ext-400-normal.woff2 +0 -0
  136. package/dist/css/fonts/files/old-standard-tt-cyrillic-ext-700-normal.woff2 +0 -0
  137. package/dist/css/fonts/files/old-standard-tt-vietnamese-400-italic.woff2 +0 -0
  138. package/dist/css/fonts/files/old-standard-tt-vietnamese-400-normal.woff2 +0 -0
  139. package/dist/css/fonts/files/old-standard-tt-vietnamese-700-normal.woff2 +0 -0
  140. package/dist/css/fonts/files/open-sans-cyrillic-ext-wght-italic.woff2 +0 -0
  141. package/dist/css/fonts/files/open-sans-cyrillic-ext-wght-normal.woff2 +0 -0
  142. package/dist/css/fonts/files/open-sans-cyrillic-wght-italic.woff2 +0 -0
  143. package/dist/css/fonts/files/open-sans-cyrillic-wght-normal.woff2 +0 -0
  144. package/dist/css/fonts/files/open-sans-greek-ext-wght-italic.woff2 +0 -0
  145. package/dist/css/fonts/files/open-sans-greek-ext-wght-normal.woff2 +0 -0
  146. package/dist/css/fonts/files/open-sans-greek-wght-italic.woff2 +0 -0
  147. package/dist/css/fonts/files/open-sans-greek-wght-normal.woff2 +0 -0
  148. package/dist/css/fonts/files/open-sans-hebrew-wght-italic.woff2 +0 -0
  149. package/dist/css/fonts/files/open-sans-hebrew-wght-normal.woff2 +0 -0
  150. package/dist/css/fonts/files/open-sans-vietnamese-wght-italic.woff2 +0 -0
  151. package/dist/css/fonts/files/open-sans-vietnamese-wght-normal.woff2 +0 -0
  152. package/dist/css/fonts/files/playfair-display-cyrillic-wght-italic.woff2 +0 -0
  153. package/dist/css/fonts/files/playfair-display-cyrillic-wght-normal.woff2 +0 -0
  154. package/dist/css/fonts/files/playfair-display-sc-cyrillic-400-italic.woff2 +0 -0
  155. package/dist/css/fonts/files/playfair-display-sc-cyrillic-400-normal.woff2 +0 -0
  156. package/dist/css/fonts/files/playfair-display-sc-cyrillic-700-italic.woff2 +0 -0
  157. package/dist/css/fonts/files/playfair-display-sc-cyrillic-700-normal.woff2 +0 -0
  158. package/dist/css/fonts/files/playfair-display-sc-cyrillic-900-italic.woff2 +0 -0
  159. package/dist/css/fonts/files/playfair-display-sc-cyrillic-900-normal.woff2 +0 -0
  160. package/dist/css/fonts/files/playfair-display-sc-vietnamese-400-italic.woff2 +0 -0
  161. package/dist/css/fonts/files/playfair-display-sc-vietnamese-400-normal.woff2 +0 -0
  162. package/dist/css/fonts/files/playfair-display-sc-vietnamese-700-italic.woff2 +0 -0
  163. package/dist/css/fonts/files/playfair-display-sc-vietnamese-700-normal.woff2 +0 -0
  164. package/dist/css/fonts/files/playfair-display-sc-vietnamese-900-italic.woff2 +0 -0
  165. package/dist/css/fonts/files/playfair-display-sc-vietnamese-900-normal.woff2 +0 -0
  166. package/dist/css/fonts/files/playfair-display-vietnamese-wght-italic.woff2 +0 -0
  167. package/dist/css/fonts/files/playfair-display-vietnamese-wght-normal.woff2 +0 -0
  168. package/dist/css/fonts/files/pt-sans-cyrillic-400-italic.woff2 +0 -0
  169. package/dist/css/fonts/files/pt-sans-cyrillic-400-normal.woff2 +0 -0
  170. package/dist/css/fonts/files/pt-sans-cyrillic-700-italic.woff2 +0 -0
  171. package/dist/css/fonts/files/pt-sans-cyrillic-700-normal.woff2 +0 -0
  172. package/dist/css/fonts/files/pt-sans-cyrillic-ext-400-italic.woff2 +0 -0
  173. package/dist/css/fonts/files/pt-sans-cyrillic-ext-400-normal.woff2 +0 -0
  174. package/dist/css/fonts/files/pt-sans-cyrillic-ext-700-italic.woff2 +0 -0
  175. package/dist/css/fonts/files/pt-sans-cyrillic-ext-700-normal.woff2 +0 -0
  176. package/dist/css/fonts/files/pt-sans-narrow-cyrillic-400-normal.woff2 +0 -0
  177. package/dist/css/fonts/files/pt-sans-narrow-cyrillic-700-normal.woff2 +0 -0
  178. package/dist/css/fonts/files/pt-sans-narrow-cyrillic-ext-400-normal.woff2 +0 -0
  179. package/dist/css/fonts/files/pt-sans-narrow-cyrillic-ext-700-normal.woff2 +0 -0
  180. package/dist/css/fonts/files/pt-serif-cyrillic-400-italic.woff2 +0 -0
  181. package/dist/css/fonts/files/pt-serif-cyrillic-400-normal.woff2 +0 -0
  182. package/dist/css/fonts/files/pt-serif-cyrillic-700-italic.woff2 +0 -0
  183. package/dist/css/fonts/files/pt-serif-cyrillic-700-normal.woff2 +0 -0
  184. package/dist/css/fonts/files/pt-serif-cyrillic-ext-400-italic.woff2 +0 -0
  185. package/dist/css/fonts/files/pt-serif-cyrillic-ext-400-normal.woff2 +0 -0
  186. package/dist/css/fonts/files/pt-serif-cyrillic-ext-700-italic.woff2 +0 -0
  187. package/dist/css/fonts/files/pt-serif-cyrillic-ext-700-normal.woff2 +0 -0
  188. package/dist/css/fonts/files/raleway-cyrillic-ext-wght-italic.woff2 +0 -0
  189. package/dist/css/fonts/files/raleway-cyrillic-ext-wght-normal.woff2 +0 -0
  190. package/dist/css/fonts/files/raleway-cyrillic-wght-italic.woff2 +0 -0
  191. package/dist/css/fonts/files/raleway-cyrillic-wght-normal.woff2 +0 -0
  192. package/dist/css/fonts/files/raleway-vietnamese-wght-italic.woff2 +0 -0
  193. package/dist/css/fonts/files/raleway-vietnamese-wght-normal.woff2 +0 -0
  194. package/dist/css/fonts/files/roboto-slab-cyrillic-ext-wght-normal.woff2 +0 -0
  195. package/dist/css/fonts/files/roboto-slab-cyrillic-wght-normal.woff2 +0 -0
  196. package/dist/css/fonts/files/roboto-slab-greek-ext-wght-normal.woff2 +0 -0
  197. package/dist/css/fonts/files/roboto-slab-greek-wght-normal.woff2 +0 -0
  198. package/dist/css/fonts/files/roboto-slab-vietnamese-wght-normal.woff2 +0 -0
  199. package/dist/css/fonts/files/ubuntu-cyrillic-300-italic.woff2 +0 -0
  200. package/dist/css/fonts/files/ubuntu-cyrillic-300-normal.woff2 +0 -0
  201. package/dist/css/fonts/files/ubuntu-cyrillic-400-italic.woff2 +0 -0
  202. package/dist/css/fonts/files/ubuntu-cyrillic-400-normal.woff2 +0 -0
  203. package/dist/css/fonts/files/ubuntu-cyrillic-500-italic.woff2 +0 -0
  204. package/dist/css/fonts/files/ubuntu-cyrillic-500-normal.woff2 +0 -0
  205. package/dist/css/fonts/files/ubuntu-cyrillic-700-italic.woff2 +0 -0
  206. package/dist/css/fonts/files/ubuntu-cyrillic-700-normal.woff2 +0 -0
  207. package/dist/css/fonts/files/ubuntu-cyrillic-ext-300-italic.woff2 +0 -0
  208. package/dist/css/fonts/files/ubuntu-cyrillic-ext-300-normal.woff2 +0 -0
  209. package/dist/css/fonts/files/ubuntu-cyrillic-ext-400-italic.woff2 +0 -0
  210. package/dist/css/fonts/files/ubuntu-cyrillic-ext-400-normal.woff2 +0 -0
  211. package/dist/css/fonts/files/ubuntu-cyrillic-ext-500-italic.woff2 +0 -0
  212. package/dist/css/fonts/files/ubuntu-cyrillic-ext-500-normal.woff2 +0 -0
  213. package/dist/css/fonts/files/ubuntu-cyrillic-ext-700-italic.woff2 +0 -0
  214. package/dist/css/fonts/files/ubuntu-cyrillic-ext-700-normal.woff2 +0 -0
  215. package/dist/css/fonts/files/ubuntu-greek-300-italic.woff2 +0 -0
  216. package/dist/css/fonts/files/ubuntu-greek-300-normal.woff2 +0 -0
  217. package/dist/css/fonts/files/ubuntu-greek-400-italic.woff2 +0 -0
  218. package/dist/css/fonts/files/ubuntu-greek-400-normal.woff2 +0 -0
  219. package/dist/css/fonts/files/ubuntu-greek-500-italic.woff2 +0 -0
  220. package/dist/css/fonts/files/ubuntu-greek-500-normal.woff2 +0 -0
  221. package/dist/css/fonts/files/ubuntu-greek-700-italic.woff2 +0 -0
  222. package/dist/css/fonts/files/ubuntu-greek-700-normal.woff2 +0 -0
  223. package/dist/css/fonts/files/ubuntu-greek-ext-300-italic.woff2 +0 -0
  224. package/dist/css/fonts/files/ubuntu-greek-ext-300-normal.woff2 +0 -0
  225. package/dist/css/fonts/files/ubuntu-greek-ext-400-italic.woff2 +0 -0
  226. package/dist/css/fonts/files/ubuntu-greek-ext-400-normal.woff2 +0 -0
  227. package/dist/css/fonts/files/ubuntu-greek-ext-500-italic.woff2 +0 -0
  228. package/dist/css/fonts/files/ubuntu-greek-ext-500-normal.woff2 +0 -0
  229. package/dist/css/fonts/files/ubuntu-greek-ext-700-italic.woff2 +0 -0
  230. package/dist/css/fonts/files/ubuntu-greek-ext-700-normal.woff2 +0 -0
  231. package/dist/css/fonts/files/unica-one-vietnamese-400-normal.woff2 +0 -0
  232. package/dist/css/fonts/files/vollkorn-cyrillic-ext-wght-italic.woff2 +0 -0
  233. package/dist/css/fonts/files/vollkorn-cyrillic-ext-wght-normal.woff2 +0 -0
  234. package/dist/css/fonts/files/vollkorn-cyrillic-wght-italic.woff2 +0 -0
  235. package/dist/css/fonts/files/vollkorn-cyrillic-wght-normal.woff2 +0 -0
  236. package/dist/css/fonts/files/vollkorn-greek-wght-italic.woff2 +0 -0
  237. package/dist/css/fonts/files/vollkorn-greek-wght-normal.woff2 +0 -0
  238. package/dist/css/fonts/files/vollkorn-vietnamese-wght-italic.woff2 +0 -0
  239. package/dist/css/fonts/files/vollkorn-vietnamese-wght-normal.woff2 +0 -0
  240. package/dist/css/fonts/font.abril-droidsans.css +3 -0
  241. package/dist/css/fonts/font.amatic-andika.css +57 -0
  242. package/dist/css/fonts/font.bitter-raleway.css +111 -0
  243. package/dist/css/fonts/font.cairo.css +312 -0
  244. package/dist/css/fonts/font.clicker-garamond.css +93 -0
  245. package/dist/css/fonts/font.dancing-ledger.css +12 -0
  246. package/dist/css/fonts/font.default.css +183 -0
  247. package/dist/css/fonts/font.fjalla-average.css +3 -0
  248. package/dist/css/fonts/font.georgia-helvetica.css +3 -0
  249. package/dist/css/fonts/font.knightlab.css +642 -0
  250. package/dist/css/fonts/font.lustria-lato.css +3 -0
  251. package/dist/css/fonts/font.medula-lato.css +3 -0
  252. package/dist/css/fonts/font.oldstandard.css +84 -0
  253. package/dist/css/fonts/font.opensans-gentiumbook.css +183 -0
  254. package/dist/css/fonts/font.playfair-faunaone.css +39 -0
  255. package/dist/css/fonts/font.playfair.css +147 -0
  256. package/dist/css/fonts/font.pt.css +183 -0
  257. package/dist/css/fonts/font.roboto-megrim.css +3 -0
  258. package/dist/css/fonts/font.rufina-sintony.css +3 -0
  259. package/dist/css/fonts/font.ubuntu.css +291 -0
  260. package/dist/css/fonts/font.unicaone-vollkorn.css +84 -0
  261. package/dist/css/storymap.css +1 -1
  262. package/dist/demo.html +3 -2
  263. package/dist/docs/api/.nojekyll +1 -0
  264. package/dist/docs/api/assets/custom.css +47 -0
  265. package/dist/docs/api/assets/hierarchy.js +1 -0
  266. package/dist/docs/api/assets/highlight.css +57 -0
  267. package/dist/docs/api/assets/icons.js +18 -0
  268. package/dist/docs/api/assets/icons.svg +1 -0
  269. package/dist/docs/api/assets/main.js +60 -0
  270. package/dist/docs/api/assets/navigation.js +1 -0
  271. package/dist/docs/api/assets/search.js +1 -0
  272. package/dist/docs/api/assets/style.css +1648 -0
  273. package/dist/docs/api/classes/StoryMap.html +2112 -0
  274. package/dist/docs/api/functions/MediaType.html +51 -0
  275. package/dist/docs/api/functions/isPresentation3Collection.html +47 -0
  276. package/dist/docs/api/functions/isPresentation3Manifest.html +53 -0
  277. package/dist/docs/api/functions/isSlideshowCollection.html +51 -0
  278. package/dist/docs/api/functions/loadCSS.html +63 -0
  279. package/dist/docs/api/functions/manifestToStorymapData.html +49 -0
  280. package/dist/docs/api/functions/setLanguage.html +54 -0
  281. package/dist/docs/api/functions/slideshowToStorymapData.html +51 -0
  282. package/dist/docs/api/functions/slideshowVersion.html +48 -0
  283. package/dist/docs/api/functions/storymapToManifest.html +57 -0
  284. package/dist/docs/api/functions/validateStorymap.html +53 -0
  285. package/dist/docs/api/functions/validateStorymapAndReport.html +54 -0
  286. package/dist/docs/api/hierarchy.html +28 -0
  287. package/dist/docs/api/index.html +300 -0
  288. package/dist/docs/api/interfaces/AnimationHandle.html +60 -0
  289. package/dist/docs/api/interfaces/ImagereadyPayload.html +71 -0
  290. package/dist/docs/api/interfaces/LanguageEntry.html +102 -0
  291. package/dist/docs/api/interfaces/LatLngLiteral.html +73 -0
  292. package/dist/docs/api/interfaces/LoadOptions.html +59 -0
  293. package/dist/docs/api/interfaces/MapEvents.html +116 -0
  294. package/dist/docs/api/interfaces/MapMarkerEvents.html +66 -0
  295. package/dist/docs/api/interfaces/MarkerEventPayload.html +57 -0
  296. package/dist/docs/api/interfaces/MediaEvents.html +78 -0
  297. package/dist/docs/api/interfaces/MenuBarEvents.html +114 -0
  298. package/dist/docs/api/interfaces/MessageEvents.html +72 -0
  299. package/dist/docs/api/interfaces/OlLayer.html +1400 -0
  300. package/dist/docs/api/interfaces/OlMap.html +1656 -0
  301. package/dist/docs/api/interfaces/OlProjection.html +332 -0
  302. package/dist/docs/api/interfaces/OlSource.html +784 -0
  303. package/dist/docs/api/interfaces/OlTileLayer.html +1497 -0
  304. package/dist/docs/api/interfaces/OlVectorLayer.html +1559 -0
  305. package/dist/docs/api/interfaces/OlView.html +1958 -0
  306. package/dist/docs/api/interfaces/SlideBackgroundState.html +66 -0
  307. package/dist/docs/api/interfaces/SlideEvents.html +78 -0
  308. package/dist/docs/api/interfaces/SlideNavEvents.html +72 -0
  309. package/dist/docs/api/interfaces/SlideshowPlayerSettings.html +182 -0
  310. package/dist/docs/api/interfaces/SlideshowToStorymapResult.html +60 -0
  311. package/dist/docs/api/interfaces/SlideshowTranslatorOptions.html +65 -0
  312. package/dist/docs/api/interfaces/SlideshowWarning.html +72 -0
  313. package/dist/docs/api/interfaces/StoryMapEvents.html +146 -0
  314. package/dist/docs/api/interfaces/StoryMapMarker.html +763 -0
  315. package/dist/docs/api/interfaces/StorySliderEvents.html +102 -0
  316. package/dist/docs/api/interfaces/StorymapBasemap.html +69 -0
  317. package/dist/docs/api/interfaces/StorymapData.html +77 -0
  318. package/dist/docs/api/interfaces/StorymapDataWrapper.html +60 -0
  319. package/dist/docs/api/interfaces/StorymapDocument.html +68 -0
  320. package/dist/docs/api/interfaces/StorymapError.html +63 -0
  321. package/dist/docs/api/interfaces/StorymapGeoreference.html +93 -0
  322. package/dist/docs/api/interfaces/StorymapGeoreferenceBody.html +74 -0
  323. package/dist/docs/api/interfaces/StorymapGroundControlPoint.html +69 -0
  324. package/dist/docs/api/interfaces/StorymapLanguageMap.html +57 -0
  325. package/dist/docs/api/interfaces/StorymapManifest.html +118 -0
  326. package/dist/docs/api/interfaces/StorymapManifestAnnotation.html +137 -0
  327. package/dist/docs/api/interfaces/StorymapManifestBackground.html +81 -0
  328. package/dist/docs/api/interfaces/StorymapManifestCanvas.html +188 -0
  329. package/dist/docs/api/interfaces/StorymapManifestContentResource.html +97 -0
  330. package/dist/docs/api/interfaces/StorymapManifestFeatureCollection.html +82 -0
  331. package/dist/docs/api/interfaces/StorymapManifestGeoreferencing.html +87 -0
  332. package/dist/docs/api/interfaces/StorymapManifestImageService.html +69 -0
  333. package/dist/docs/api/interfaces/StorymapManifestRange.html +75 -0
  334. package/dist/docs/api/interfaces/StorymapManifestService.html +77 -0
  335. package/dist/docs/api/interfaces/StorymapManifestSpecificResource.html +69 -0
  336. package/dist/docs/api/interfaces/StorymapManifestStatement.html +63 -0
  337. package/dist/docs/api/interfaces/StorymapMapOptions.html +92 -0
  338. package/dist/docs/api/interfaces/StorymapOptions.html +734 -0
  339. package/dist/docs/api/interfaces/StorymapOverlayLayer.html +157 -0
  340. package/dist/docs/api/interfaces/StorymapSlide.html +186 -0
  341. package/dist/docs/api/interfaces/StorymapSlideBackground.html +72 -0
  342. package/dist/docs/api/interfaces/StorymapSlideLocation.html +161 -0
  343. package/dist/docs/api/interfaces/StorymapSlideMarker.html +103 -0
  344. package/dist/docs/api/interfaces/StorymapSlideMedia.html +149 -0
  345. package/dist/docs/api/interfaces/StorymapSlideNarration.html +117 -0
  346. package/dist/docs/api/interfaces/StorymapSlideText.html +72 -0
  347. package/dist/docs/api/interfaces/StorymapTilejson.html +105 -0
  348. package/dist/docs/api/interfaces/SwipableEvents.html +102 -0
  349. package/dist/docs/api/interfaces/TextEvents.html +66 -0
  350. package/dist/docs/api/media/es.json +31 -0
  351. package/dist/docs/api/media/events.md +66 -0
  352. package/dist/docs/api/media/migration-from-knightlab.md +399 -0
  353. package/dist/docs/api/media/slideshow.md +109 -0
  354. package/dist/docs/api/media/storymap-as-iiif-manifest.md +1007 -0
  355. package/dist/docs/api/modules.html +50 -0
  356. package/dist/docs/api/types/ContentState.html +70 -0
  357. package/dist/docs/api/types/FiredEvent.html +43 -0
  358. package/dist/docs/api/types/ImagereadyKind.html +34 -0
  359. package/dist/docs/api/types/MediaTypeMatch.html +78 -0
  360. package/dist/docs/api/types/SwipeDirection.html +36 -0
  361. package/dist/docs/api/types/TileSourceFactory.html +53 -0
  362. package/dist/docs/authoring.html +306 -0
  363. package/dist/docs/events.html +263 -0
  364. package/dist/docs/iiif.html +738 -69
  365. package/dist/docs/migration.html +360 -11
  366. package/dist/docs/readme.html +149 -17
  367. package/dist/embed/index.html +8 -1
  368. package/dist/examples/font-css-false.json +33 -0
  369. package/dist/examples/issue-242-nonlatin.json +55 -0
  370. package/dist/examples/issue-305-start-at-slide-data.json +96 -0
  371. package/dist/examples/issue-358-iframe.json +57 -0
  372. package/dist/examples/issue-iiif-geo.json +32 -0
  373. package/dist/examples/issue-image-alt.json +23 -0
  374. package/dist/examples/issue-image-region.json +42 -0
  375. package/dist/examples/issue-image-srcset.json +24 -0
  376. package/dist/examples/layers-control.json +60 -0
  377. package/dist/examples/map-area-overlays.json +68 -0
  378. package/dist/examples/map-template-provider.json +36 -0
  379. package/dist/examples/multi-media.json +71 -0
  380. package/dist/examples/no-map.json +44 -0
  381. package/dist/examples-iiif/annotated-image.json +204 -0
  382. package/dist/examples-iiif/bob-boilen.json +11 -5
  383. package/dist/examples-iiif/courbet.json +9 -6
  384. package/dist/examples-iiif/empty.json +8 -4
  385. package/dist/examples-iiif/flickr-drewvigal.json +248 -24
  386. package/dist/examples-iiif/flickr-zach.wise.json +8 -4
  387. package/dist/examples-iiif/font-css-false.json +114 -0
  388. package/dist/examples-iiif/georeferenced-layer-unsupported.json +153 -0
  389. package/dist/examples-iiif/georeferenced-layer.json +318 -0
  390. package/dist/examples-iiif/iiif-wellcome.json +9 -6
  391. package/dist/examples-iiif/instagram-chenpamela.json +381 -36
  392. package/dist/examples-iiif/instagram_brentfoster.json +429 -40
  393. package/dist/examples-iiif/instagram_couch.json +261 -26
  394. package/dist/examples-iiif/instagram_joegermuska.json +441 -41
  395. package/dist/examples-iiif/instagram_matteich.json +261 -26
  396. package/dist/examples-iiif/instagram_mirandamulligan.json +261 -26
  397. package/dist/examples-iiif/instagram_raymondmccrea.json +261 -26
  398. package/dist/examples-iiif/instagram_test.json +261 -26
  399. package/dist/examples-iiif/issue-134-no-lines.json +9 -5
  400. package/dist/examples-iiif/issue-177-color-vars.json +9 -5
  401. package/dist/examples-iiif/issue-211-rtl.json +9 -5
  402. package/dist/examples-iiif/issue-242-nonlatin.json +239 -0
  403. package/dist/examples-iiif/issue-272-facebook.json +9 -5
  404. package/dist/examples-iiif/issue-305-start-at-slide-data.json +305 -0
  405. package/dist/examples-iiif/issue-305-start-at-slide.json +9 -5
  406. package/dist/examples-iiif/issue-341-distance.json +9 -5
  407. package/dist/examples-iiif/issue-358-iframe.json +190 -0
  408. package/dist/examples-iiif/issue-360-juxtapose.json +22 -7
  409. package/dist/examples-iiif/issue-368-null-fields.json +9 -5
  410. package/dist/examples-iiif/issue-375-code-lists.json +9 -5
  411. package/dist/examples-iiif/issue-381-dateline.json +9 -5
  412. package/dist/examples-iiif/issue-405-custom-icon.json +203 -0
  413. package/dist/examples-iiif/issue-425-many-slides.json +9 -5
  414. package/dist/examples-iiif/issue-428-background.json +20 -8
  415. package/dist/examples-iiif/issue-435-googlemaps.json +9 -5
  416. package/dist/examples-iiif/issue-437-documentcloud.json +22 -7
  417. package/dist/examples-iiif/issue-451-webp.json +9 -5
  418. package/dist/examples-iiif/issue-455-audio.json +9 -5
  419. package/dist/examples-iiif/issue-480-shorts.json +9 -5
  420. package/dist/examples-iiif/issue-506-marker-sync.json +9 -5
  421. package/dist/examples-iiif/issue-iiif-geo.json +200 -0
  422. package/dist/examples-iiif/issue-image-alt.json +90 -0
  423. package/dist/examples-iiif/issue-image-region.json +203 -0
  424. package/dist/examples-iiif/issue-image-srcset.json +87 -0
  425. package/dist/examples-iiif/jansteen.json +9 -6
  426. package/dist/examples-iiif/katrina.json +197 -41
  427. package/dist/examples-iiif/layers-control.json +226 -0
  428. package/dist/examples-iiif/map-area-overlays.json +289 -0
  429. package/dist/examples-iiif/map-template-provider.json +133 -0
  430. package/dist/examples-iiif/marktwain.json +255 -58
  431. package/dist/examples-iiif/multi-media.json +237 -0
  432. package/dist/examples-iiif/no-map.json +148 -0
  433. package/dist/examples-iiif/population.json +440 -76
  434. package/dist/examples-iiif/president.json +456 -83
  435. package/dist/examples-iiif/scroll-hint.json +190 -0
  436. package/dist/examples-iiif/seurat.json +113 -22
  437. package/dist/examples-iiif/zoomify-clamp.json +153 -0
  438. package/dist/examples-slideshow/single.json +79 -0
  439. package/dist/examples-slideshow/static/pixel.png +0 -0
  440. package/dist/examples-slideshow/static.json +44 -0
  441. package/dist/harness-multi.html +17 -0
  442. package/dist/harness.html +4 -2
  443. package/dist/index.html +19 -12
  444. package/dist/js/storymap.d.ts +2669 -307
  445. package/dist/js/storymap.js +10820 -6196
  446. package/dist/js/storymap.js.map +1 -1
  447. package/dist/navplace-properties.json +54 -0
  448. package/dist/site.css +54 -36
  449. package/docs/migration-from-knightlab.md +279 -19
  450. package/docs/storymap-as-iiif-manifest.md +633 -136
  451. package/package.json +12 -7
  452. package/schema/storymap.schema.json +733 -80
  453. package/src/animation/easings.ts +8 -1
  454. package/src/animation/tween.ts +186 -0
  455. package/src/core/Browser.ts +6 -5
  456. package/src/core/Load.ts +54 -2
  457. package/src/core/Util.ts +257 -193
  458. package/src/core/mixins.ts +66 -35
  459. package/src/core/viewers.ts +94 -0
  460. package/src/dom/DomEvent.ts +27 -8
  461. package/src/globals.d.ts +8 -0
  462. package/src/language/Language.ts +206 -25
  463. package/src/language/locale/.expected-gaps.json +346 -0
  464. package/src/language/locale/be.json +15 -2
  465. package/src/language/locale/bg.json +15 -2
  466. package/src/language/locale/cs.json +15 -2
  467. package/src/language/locale/de.json +23 -2
  468. package/src/language/locale/el.json +15 -2
  469. package/src/language/locale/en.json +17 -3
  470. package/src/language/locale/es.json +15 -2
  471. package/src/language/locale/et.json +5 -1
  472. package/src/language/locale/fr.json +15 -2
  473. package/src/language/locale/he.json +16 -3
  474. package/src/language/locale/hu.json +15 -2
  475. package/src/language/locale/is.json +5 -1
  476. package/src/language/locale/it.json +15 -2
  477. package/src/language/locale/jp.json +15 -2
  478. package/src/language/locale/ko.json +15 -2
  479. package/src/language/locale/nl.json +15 -2
  480. package/src/language/locale/nn.json +5 -1
  481. package/src/language/locale/no.json +15 -2
  482. package/src/language/locale/pl.json +15 -2
  483. package/src/language/locale/pt.json +15 -2
  484. package/src/language/locale/ru.json +15 -2
  485. package/src/language/locale/sk.json +15 -2
  486. package/src/language/locale/sr.json +5 -1
  487. package/src/language/locale/sv.json +15 -2
  488. package/src/language/locale/tr.json +15 -2
  489. package/src/language/locale/uk.json +15 -2
  490. package/src/language/locale/ur.json +5 -1
  491. package/src/language/locale/zh-cn.json +15 -2
  492. package/src/language/locale/zh-tw.json +15 -2
  493. package/src/main.ts +143 -0
  494. package/src/map/Map.ts +227 -112
  495. package/src/map/MapMarker.ts +44 -8
  496. package/src/map/georeference.ts +325 -0
  497. package/src/map/openlayers/Map.OpenLayers.ts +1601 -263
  498. package/src/map/openlayers/MapMarker.OpenLayers.ts +348 -24
  499. package/src/map/openlayers/zoomifyTiles.ts +1 -4
  500. package/src/map/slideView.ts +149 -0
  501. package/src/map/types.ts +2 -0
  502. package/src/media/EmbedUtil.ts +333 -24
  503. package/src/media/Media.ts +270 -59
  504. package/src/media/embedId.ts +110 -0
  505. package/src/media/types/Audio.ts +9 -82
  506. package/src/media/types/Blockquote.ts +2 -3
  507. package/src/media/types/DailyMotion.ts +5 -10
  508. package/src/media/types/DocumentCloud.ts +6 -35
  509. package/src/media/types/Facebook.ts +3 -4
  510. package/src/media/types/Flickr.ts +23 -12
  511. package/src/media/types/GoogleDoc.ts +3 -4
  512. package/src/media/types/HtmlMedia.ts +233 -0
  513. package/src/media/types/IFrame.ts +3 -4
  514. package/src/media/types/Image.ts +87 -9
  515. package/src/media/types/Juxtapose.ts +14 -5
  516. package/src/media/types/SoundCloud.ts +28 -6
  517. package/src/media/types/Text.ts +46 -21
  518. package/src/media/types/Twitter.ts +35 -20
  519. package/src/media/types/Video.ts +9 -79
  520. package/src/media/types/Vimeo.ts +11 -11
  521. package/src/media/types/Website.ts +23 -13
  522. package/src/media/types/Wikipedia.ts +18 -8
  523. package/src/media/types/YouTube.ts +72 -40
  524. package/src/scss/Typography.scss +16 -18
  525. package/src/scss/VCO.StoryMap.scss +208 -12
  526. package/src/scss/Variables.scss +3 -2
  527. package/src/scss/core/Mixins.scss +5 -63
  528. package/src/scss/core/Reset.scss +5 -18
  529. package/src/scss/fonts/font.amatic-andika.scss +3 -0
  530. package/src/scss/fonts/font.bitter-raleway.scss +6 -0
  531. package/src/scss/fonts/font.cairo.scss +79 -0
  532. package/src/scss/fonts/font.clicker-garamond.scss +5 -0
  533. package/src/scss/fonts/font.dancing-ledger.scss +1 -0
  534. package/src/scss/fonts/font.knightlab.scss +14 -0
  535. package/src/scss/fonts/font.oldstandard.scss +6 -0
  536. package/src/scss/fonts/font.opensans-gentiumbook.scss +5 -0
  537. package/src/scss/fonts/font.playfair-faunaone.scss +2 -0
  538. package/src/scss/fonts/font.playfair.scss +4 -0
  539. package/src/scss/fonts/font.pt.scss +6 -0
  540. package/src/scss/fonts/font.ubuntu.scss +4 -0
  541. package/src/scss/fonts/font.unicaone-vollkorn.scss +5 -0
  542. package/src/scss/map/VCO.Map.scss +1 -1
  543. package/src/scss/map/VCO.MapMarker.scss +114 -8
  544. package/src/scss/map/openlayers/VCO.Map.OpenLayers.scss +7 -4
  545. package/src/scss/media/VCO.Media.scss +14 -17
  546. package/src/scss/media/types/VCO.Media.Blockquote.scss +1 -1
  547. package/src/scss/media/types/VCO.Media.Text.scss +13 -5
  548. package/src/scss/media/types/VCO.Media.Twitter.scss +4 -4
  549. package/src/scss/media/types/VCO.Media.Wikipedia.scss +3 -19
  550. package/src/scss/site/site.scss +55 -36
  551. package/src/scss/slider/VCO.Slide.scss +61 -13
  552. package/src/scss/slider/VCO.SlideNav.scss +34 -24
  553. package/src/scss/slider/VCO.StorySlider.scss +53 -1
  554. package/src/scss/snapmap/VCO.SnapMap.scss +3 -3
  555. package/src/scss/ui/VCO.Consent.scss +63 -13
  556. package/src/scss/ui/VCO.Layers.scss +119 -0
  557. package/src/scss/ui/VCO.MenuBar.Button.scss +143 -14
  558. package/src/scss/ui/VCO.MenuBar.scss +9 -2
  559. package/src/scss/ui/VCO.Message.scss +16 -5
  560. package/src/site/site.ts +2 -1
  561. package/src/slider/Slide.ts +326 -74
  562. package/src/slider/SlideNav.ts +54 -9
  563. package/src/slider/StorySlider.ts +352 -60
  564. package/src/storymap/Consent.ts +429 -82
  565. package/src/storymap/StoryMap.ts +2163 -340
  566. package/src/storymap/content-state.ts +180 -0
  567. package/src/storymap/font-css.ts +72 -0
  568. package/src/storymap/from-slideshow.ts +785 -0
  569. package/src/storymap/iiif-shared.ts +228 -0
  570. package/src/storymap/iiif.ts +1742 -95
  571. package/src/storymap/to-iiif.ts +1008 -0
  572. package/src/storymap/validate.ts +80 -7
  573. package/src/types.ts +591 -29
  574. package/src/ui/LayersControl.ts +302 -0
  575. package/src/ui/MenuBar.ts +325 -61
  576. package/src/ui/Message.ts +44 -2
  577. package/src/ui/Swipable.ts +170 -85
  578. package/dist/assets/demo-D6cTmzn6.js +0 -1
  579. package/dist/assets/harness-BPFlzutp.js +0 -1
  580. package/dist/assets/index-DDsPBPZA.js +0 -1
  581. package/dist/assets/main-Y-MYUSJ4.js +0 -17
  582. package/src/animation/morpheus.d.ts +0 -41
  583. package/src/scss/VCO.StoryMap.Dark.scss +0 -138
  584. package/src/scss/Variables.Dark.scss +0 -56
  585. package/src/scss/media/types/VCO.Media.Instagram.scss +0 -7
  586. package/src/scss/media/types/VCO.Media.Profile.scss +0 -5
  587. package/src/ui/Draggable.ts +0 -374
@@ -1,49 +1,162 @@
1
1
  import { default as default_2 } from 'ol/control/OverviewMap';
2
- import { default as default_3 } from 'ol/Map';
3
- import { default as default_4 } from 'ol/Overlay';
4
- import { default as default_5 } from 'ol/tilegrid/TileGrid';
5
- import { default as default_6 } from 'ol/proj/Projection';
2
+ import { default as default_3 } from 'ol/Overlay';
3
+ import { default as default_4 } from 'ol/tilegrid/TileGrid';
4
+ import { default as default_5 } from 'ol/source/ImageStatic';
6
5
  import { Extent } from 'ol/extent';
6
+ import { Image as Image_2 } from 'ol/layer';
7
7
  import { Map as Map_3 } from 'ol';
8
+ import { default as OlLayer } from 'ol/layer/Layer';
9
+ import { default as OlMap } from 'ol/Map';
10
+ import { default as OlProjection } from 'ol/proj/Projection';
11
+ import { default as OlSource } from 'ol/source/Source';
12
+ import { default as OlTileLayer } from 'ol/layer/Tile';
13
+ import { default as OlVectorLayer } from 'ol/layer/Vector';
14
+ import { default as OlView } from 'ol/View';
8
15
  import { Style } from 'ol/style';
9
16
  import { Tile } from 'ol/layer';
17
+ import { unByKey } from 'ol/Observable';
10
18
  import { Vector } from 'ol/layer';
19
+ import { XYZ } from 'ol/source';
11
20
 
12
- declare interface AnimationHandle {
21
+ export declare interface AnimationHandle {
13
22
  stop: (jump?: boolean) => void;
14
23
  }
15
24
 
16
25
  /**
17
26
  * Per-StoryMap GDPR consent manager. When the `consent_required` option is
18
27
  * set, every external service (media embeds, map tiles, external font CSS)
19
- * asks for permission before anything is loaded. Decisions are remembered
20
- * per service in a cookie for 90 days — clearing cookies asks again.
28
+ * asks for permission before anything is loaded.
29
+ *
30
+ * Decisions are remembered per service in localStorage with no expiry:
31
+ * clearing site data is what makes the viewer ask again.
21
32
  */
22
33
  declare class ConsentManager {
23
34
  private granted;
24
35
  private denied;
25
36
  /** unanswered asks per service (preloaded slides stack several) */
26
37
  private pending;
38
+ /** the start-of-story dialog's row per service, so a decision made
39
+ * anywhere (including a standalone per-service ask) clears it */
40
+ private startRows;
41
+ /** every start-of-story dialog root we put on screen, so dispose() can
42
+ * take the whole thing down rather than just its rows */
43
+ private startDialogs;
44
+ /** set by dispose(); late answers are ignored rather than persisted */
45
+ private disposed;
27
46
  constructor();
28
- /** Seed the per-service state from the consent cookie, if present. */
47
+ /**
48
+ * Seed the per-service state from localStorage, if present.
49
+ *
50
+ * Keys written by an earlier version are remapped onto the namespaced
51
+ * form, so an existing visitor is not asked everything again after the
52
+ * upgrade. The remap is written back once, which also clears the legacy
53
+ * keys so they cannot drift out of sync later.
54
+ */
29
55
  private restore;
30
- /** Persist the per-service state to the consent cookie. */
56
+ /**
57
+ * Persist the per-service state to localStorage.
58
+ *
59
+ * A page can hold more than one viewer, and they all share this one
60
+ * record — a visitor should not answer the same question twice for the
61
+ * same service. So this *merges* into whatever is already stored instead
62
+ * of replacing it: writing this viewer's full set back would silently
63
+ * erase a decision a sibling viewer made, while that sibling still
64
+ * believed otherwise. The merged result is then adopted, which is what
65
+ * makes every viewer converge on the same decisions.
66
+ */
31
67
  private persist;
68
+ /** Replace the in-memory decision set with `state`, in place. */
69
+ private adopt;
70
+ /**
71
+ * Re-read the shared record, so a decision the visitor made in a sibling
72
+ * viewer is honoured here without having to reconstruct this one.
73
+ */
74
+ private sync;
75
+ /**
76
+ * Record a decision for one service and resolve every ask waiting on it.
77
+ *
78
+ * Both dialog shapes funnel through here, which is what keeps a service
79
+ * from ending up in the granted *and* the denied set: the opposite set is
80
+ * always cleared.
81
+ */
82
+ private decide;
32
83
  isGranted(service: string): boolean;
33
84
  isDenied(service: string): boolean;
85
+ /** True when at least one of the services has no stored decision yet. */
86
+ hasUnanswered(services: string[]): boolean;
87
+ /**
88
+ * Start-of-story consent dialog: lists every known external service
89
+ * with per-service Allow/Deny, plus global "Allow all" / "Decline
90
+ * all" buttons. Individual decisions reuse the per-service state
91
+ * (pending slide asks resolve immediately); the dialog closes once
92
+ * every service has a decision.
93
+ */
94
+ requestAll(services: ConsentService[], container: HTMLElement): void;
95
+ /**
96
+ * Ask the visitor for permission to load `service`, optionally naming the
97
+ * `host` (shown in parentheses so they can see which domain is about to be
98
+ * contacted). The ask is rendered into `container`; resolves
99
+ * `true`/`false` on the visitor's decision, or immediately when the
100
+ * service was already granted or denied.
101
+ *
102
+ * The service is stored and looked up by `service.key`; `service.label`
103
+ * is only ever rendered.
104
+ */
105
+ request(service: ConsentService, host: string, container: HTMLElement): Promise<boolean>;
34
106
  /**
35
- * Ask the visitor for permission to load `service` (a human-readable
36
- * name like "YouTube" or "map tiles"), optionally naming the `host`.
37
- * The ask is rendered into `container`; resolves `true`/`false` on the
38
- * visitor's decision, or immediately when the service was already
39
- * granted or denied.
107
+ * Release everything: drop the dialogs and settle every unanswered ask.
108
+ *
109
+ * `Media.loadMedia()` awaits `request()`. Without this, tearing the viewer
110
+ * down while a panel was on screen left that `await` pending forever, and
111
+ * the suspended frame kept the whole media subtree — DOM included — alive.
112
+ * Unanswered asks resolve `false`, which is the same outcome as declining.
40
113
  */
41
- request(service: string, host: string, container: HTMLElement): Promise<boolean>;
114
+ dispose(): void;
115
+ }
116
+
117
+ /**
118
+ * An external service the viewer asks permission to load.
119
+ *
120
+ * `key` is the *only* thing ever persisted, and it is stable, namespaced and
121
+ * never localized. `label` is display-only.
122
+ *
123
+ * These are two separate fields on purpose. The code used to pass a single
124
+ * string that served as both, which had two consequences:
125
+ *
126
+ * - the tile and font services used a *localized* string as the localStorage
127
+ * key, so translating `consent_service_tiles` would have silently
128
+ * invalidated every stored decision the moment the page language changed;
129
+ * - the per-slide panel used the media type *slug* as its display label, so
130
+ * it asked "Load content from youtube?" where the start-of-story dialog,
131
+ * 20 lines away, correctly said "YouTube".
132
+ *
133
+ * With the pair split, passing a label where a key is expected is no longer
134
+ * expressible.
135
+ */
136
+ declare interface ConsentService {
137
+ /** Stable, namespaced, non-localized. The only value that is stored. */
138
+ key: string;
139
+ /** Display name. Localized for tiles/fonts; a brand name for media. */
140
+ label: string;
42
141
  }
43
142
 
143
+ /** Constructor shape accepted by the mixin functions. */
144
+ declare type Constructor<T = object> = new (...args: any[]) => T;
145
+
146
+ export declare type ContentState = {
147
+ /** The canvas (or other resource) the state points at. */
148
+ id: string;
149
+ /**
150
+ * `[x, y, w, h]` in canvas pixels, when the state names a part of the
151
+ * canvas. Carried on the id as an `xywh=` fragment, which is the
152
+ * Media Fragments spelling the spec uses in every region example.
153
+ */
154
+ region?: [number, number, number, number];
155
+ };
156
+
44
157
  declare interface DragData {
45
158
  sliding: boolean;
46
- direction: string | null;
159
+ direction: SwipeDirection | null;
47
160
  pagex: {
48
161
  start: number;
49
162
  end: number;
@@ -80,36 +193,195 @@ declare interface DragData {
80
193
  declare interface DragEventNames {
81
194
  down: string;
82
195
  up: string;
196
+ cancel?: string;
83
197
  leave: string;
84
198
  move: string;
85
199
  }
86
200
 
87
201
  /** Eventing members provided by the Evented mixin. */
88
- declare interface EventedInstance {
89
- on: (type: string, fn: unknown, context?: unknown) => unknown;
90
- off: (type: string, fn: unknown, context?: unknown) => unknown;
91
- fire: (type: string, data?: unknown, target?: unknown) => unknown;
92
- 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;
93
207
  }
94
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
+
95
221
  declare type IconSpec = {
96
222
  url: string;
97
223
  size: number[];
98
224
  anchor: number[];
99
225
  };
100
226
 
101
- declare interface LanguageEntry {
102
- buttons?: Record<string, string>;
103
- messages?: Record<string, string>;
227
+ /** What kind of imagery an `imageready` source carries. */
228
+ export declare type ImagereadyKind = "iiif" | "zoomify" | "tiles";
229
+
230
+ /**
231
+ * Payload of the `imageready` event: the source that became usable, what
232
+ * kind of imagery it is, and the layer carrying it (`null` when the source
233
+ * outlives its layer).
234
+ */
235
+ export declare interface ImagereadyPayload {
236
+ source: {
237
+ getState?(): string;
238
+ };
239
+ kind: ImagereadyKind;
240
+ layer: OlLayer | null;
241
+ }
242
+
243
+ /** True when `data` is a Presentation API 3.0 Collection. */
244
+ export declare function isPresentation3Collection(data: unknown): boolean;
245
+
246
+ /**
247
+ * True when `data` looks like a Presentation API 3.0 **Manifest**.
248
+ *
249
+ * A `Collection` is explicitly *not* one, even though it carries the same
250
+ * `@context`. Detection used to accept anything with the P3 context, so a
251
+ * Collection passed and its member Manifests were fed to `canvasToSlide` as if
252
+ * they were Canvases — every member became a text-only slide, with no media, no
253
+ * locations and no warning. `within`-style Collections are now handled by the
254
+ * private `collectionToStorymapData` below, and anything else is rejected here.
255
+ */
256
+ export declare function isPresentation3Manifest(data: unknown): boolean;
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
+
266
+ /**
267
+ * UI strings for the active locale.
268
+ *
269
+ * English is the fallback for every missing key (see `getLanguage`), so
270
+ * `messages` and `buttons` are guaranteed to be fully populated once a
271
+ * language has been set — they are typed as required here rather than as
272
+ * `Record<string, string> | undefined` so call sites do not need a null
273
+ * check on every one of the ~30 `Language.messages.*` reads.
274
+ *
275
+ * The locale JSON files themselves are *not* complete: only `en.json` defines
276
+ * every key, and 28 of the 29 bundled locales are missing 8-10 of them
277
+ * (the per-service consent strings and the fullscreen button labels). The
278
+ * runtime falls back to English per key, so this is a translation gap rather
279
+ * than a defect — `npm run check:locales` reports it.
280
+ */
281
+ export declare interface LanguageEntry {
282
+ /** Display name of the language, e.g. "Deutsch". */
283
+ name?: string;
284
+ /** BCP 47 code, e.g. "de". */
285
+ lang?: string;
286
+ /** Writing direction; drives the `vco-rtl` layout. */
287
+ direction?: "ltr" | "rtl";
288
+ messages: Record<string, string>;
289
+ buttons: Record<string, string>;
104
290
  [key: string]: unknown;
105
291
  }
106
292
 
107
- declare interface LatLngLiteral {
108
- lat: number | undefined;
109
- lon?: number | undefined;
110
- lng?: number | undefined;
293
+ /**
294
+ * A resolved geographic coordinate.
295
+ *
296
+ * `lat`/`lon` are required: this type is for points the map can actually
297
+ * focus on. A *slide* may carry a `location` without coordinates (an image
298
+ * region, an icon only) — that is `StorymapSlideLocation`, which keeps them
299
+ * optional. `lng` is accepted as a legacy alias on input only.
300
+ */
301
+ export declare interface LatLngLiteral {
302
+ lat: number;
303
+ lon: number;
304
+ lng?: number;
305
+ }
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[];
111
362
  }
112
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
+
113
385
  /** Legacy drag handlers historically mixed mouse and touch event surfaces. */
114
386
  declare type LegacyEvent = Event & {
115
387
  originalEvent?: TouchEvent;
@@ -128,23 +400,33 @@ declare interface LinePoint {
128
400
  /**
129
401
  * Append one stylesheet to the document head.
130
402
  *
403
+ * Concurrent and repeat requests for the same URL share one `<link>`.
404
+ *
131
405
  * @param url - The stylesheet URL.
132
406
  * @param options - Optional AbortSignal to cancel an in-flight load.
133
407
  * @returns Resolves when the stylesheet has loaded, rejects on error or abort.
134
408
  */
135
409
  export declare function loadCSS(url: string, options?: LoadOptions): Promise<void>;
136
410
 
137
- declare interface LoadOptions {
411
+ export declare interface LoadOptions {
138
412
  /** Abort the load (removes the element, rejects the promise). */
139
413
  signal?: AbortSignal;
140
414
  }
141
415
 
416
+ /**
417
+ * Converts a IIIF Presentation API 3.0 manifest into legacy StoryMapJS data
418
+ * (the `storymap` object). Malformed or missing pieces are skipped; the
419
+ * result always contains at least `{slides: []}`.
420
+ */
421
+ export declare function manifestToStorymapData(manifest: unknown): StorymapData;
422
+
142
423
  declare class Map_2 extends Map_base {
143
424
  constructor(...args: ConstructorParameters<typeof MapBase>);
144
425
  }
145
426
 
146
427
  declare const Map_base: {
147
428
  new (...args: any[]): {
429
+ container(): HTMLElement;
148
430
  show(animate?: unknown): void;
149
431
  hide(): void;
150
432
  addTo(container: HTMLElement): /*elided*/ any;
@@ -153,25 +435,14 @@ declare const Map_base: {
153
435
  onLoaded(): void;
154
436
  onAdd(): void;
155
437
  onRemove(): void;
156
- _el: Record<string, HTMLElement>;
438
+ _el: Record<string, unknown>;
157
439
  data?: unknown;
158
- on: (type: string, fn: unknown, context?: unknown) => unknown;
159
- off: (type: string, fn: unknown, context?: unknown) => unknown;
160
- fire: (type: string, data?: unknown, target?: unknown) => unknown;
161
- hasEventListeners: (type: string) => boolean;
162
- };
163
- } & {
164
- new (...args: any[]): {
165
- _vco_events?: Record<string, {
166
- action: unknown;
167
- context: unknown;
168
- }[]>;
169
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
170
- hasEventListeners(type: string): boolean;
171
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
172
- 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;
173
444
  };
174
- } & typeof MapBase;
445
+ } & Constructor<EventedInstance<MapEvents>> & typeof MapBase;
175
446
 
176
447
  declare class MapBase {
177
448
  "_el": {
@@ -186,6 +457,12 @@ declare class MapBase {
186
457
  "_map": Map_3 | null;
187
458
  "_mini_map": default_2 | null;
188
459
  "_markers": MapMarker[];
460
+ /**
461
+ * Zooms computed by the engine's `_calculateMarkerZooms`, keyed by
462
+ * marker index. Kept off `marker.data` so navigating never mutates the
463
+ * author's storymap document (`StoryMap.data` is that same object graph).
464
+ */
465
+ "_marker_zooms": (number | undefined)[];
189
466
  "zoom_min_max": {
190
467
  min: number | null;
191
468
  max: number | null;
@@ -193,9 +470,11 @@ declare class MapBase {
193
470
  "_line": Vector | null;
194
471
  "_line_active": Vector | null;
195
472
  "current_marker": number;
473
+ /** The wheel handler on the map element, stored for dispose(). */
474
+ "_onWheelBound": ((e: WheelEvent) => void) | null;
196
475
  "bounds_array": number[][] | null;
197
- "_tile_layer": Tile | null;
198
- "_tile_layer_mini": Tile | null;
476
+ "_tile_layer": OlLayer | null;
477
+ "_tile_layer_mini": OlLayer | null;
199
478
  "_image_layer": Tile | null;
200
479
  "data": StorymapData;
201
480
  "options": StorymapOptions;
@@ -204,22 +483,61 @@ declare class MapBase {
204
483
  "timer": ReturnType<typeof setTimeout> | null;
205
484
  "touch_scale": number;
206
485
  "scroll": ScrollState;
207
- "fire": EventedInstance["fire"];
486
+ "fire": EventedInstance<MapEvents>["fire"];
208
487
  constructor(elem: string | HTMLElement, data?: Partial<StorymapData>, options?: Partial<StorymapOptions>);
209
488
  updateDisplay(w: number, h: number, animate?: boolean, d?: number, offset?: unknown): void;
210
489
  goTo(n: number, change?: boolean): void;
490
+ /**
491
+ * Alias over the OpenLayers view: `storymap.map.getView().animate({center})`
492
+ * (remember `ol/proj` does not apply in image mode — see `isImageSpace()`).
493
+ */
211
494
  panTo(loc: LatLngLiteral, animate?: boolean): void;
495
+ /** Alias over the OpenLayers view: `storymap.map.getView().animate({zoom})`. */
212
496
  zoomTo(z: number, animate?: boolean): void;
497
+ /**
498
+ * Alias over the OpenLayers view: `storymap.map.getView().animate(...)`,
499
+ * or `.fit(extent, {size})` for a region stop (`location.region`).
500
+ */
213
501
  viewTo(loc: StorymapSlideLocation, opts?: ViewToOptions): void;
214
- getBoundsZoom(m1: LatLngLiteral, m2: LatLngLiteral, inside?: boolean, padding?: unknown): void;
502
+ /** Alias over the OpenLayers view: `view.getZoomForResolution(resolution)`. */
503
+ getBoundsZoom(m1: LatLngLiteral, m2: LatLngLiteral, inside?: boolean, padding?: unknown): number | undefined;
504
+ /**
505
+ * Alias over the OpenLayers view: `view.fit(extent, {size})` over all
506
+ * marker positions. Also reachable from the menubar's overview button.
507
+ */
215
508
  markerOverview(): void;
509
+ /**
510
+ * The viewer's own marker zoom ladder — no OpenLayers equivalent (it also
511
+ * writes the computed zoom onto the current markers).
512
+ */
216
513
  calculateMarkerZooms(): void;
514
+ /**
515
+ * The minimap is built with the constructor; reach it with `getMinimap()`
516
+ * (an OpenLayers `OverviewMap` control) rather than re-creating it.
517
+ */
217
518
  createMiniMap(): void;
218
519
  setMapOffset(left: number, top: number): void;
219
520
  calculateMinMaxZoom(): void;
521
+ /**
522
+ * The zoom to use for min/max bounds at marker `index`: the value
523
+ * computed by the engine when there is one, else the zoom authored on
524
+ * the slide. The engine overrides this to serve its computed-zoom store
525
+ * so `StoryMap.data` is never written to.
526
+ */
527
+ _markerZoom(index: number): number | undefined;
220
528
  updateMinMaxZoom(zoom: number): void;
221
529
  initialMapLocation(): void;
530
+ /**
531
+ * @deprecated No-op since 0.9.x upstream (the original Leaflet engine
532
+ * defined an empty body too) and shadowed by the `DomMixed` mixin. To
533
+ * hide the map, toggle the OpenLayers target:
534
+ * `storymap.map.getTargetElement().style.display = "none"`.
535
+ */
222
536
  show(): void;
537
+ /**
538
+ * @deprecated See {@link show} — no-op since 0.9.x upstream. Use
539
+ * `storymap.map.getTargetElement().style.display = "none"`.
540
+ */
223
541
  hide(): void;
224
542
  createMarkers(array: StorymapSlide[]): void;
225
543
  createMarker(d: StorymapSlide): void;
@@ -230,6 +548,27 @@ declare class MapBase {
230
548
  * lon 0 are valid coordinates and must not be treated as missing.
231
549
  */
232
550
  _hasLocation(d: StorymapSlide): boolean;
551
+ /**
552
+ * The {lat, lon} points of every marker from the first up to and
553
+ * including `n`, skipping the ones without a real location. This was four
554
+ * near-identical loops building the same thing.
555
+ */
556
+ private _locationsUpTo;
557
+ /**
558
+ * The slide's {lat, lon} point, or null when it has no real location.
559
+ *
560
+ * Preferred over testing `_hasLocation()` and then reading
561
+ * `data.location.lat`: a boolean guard does not narrow the property for
562
+ * the type checker, so the old form had to be trusted and re-checked by
563
+ * hand at every one of its dozen call sites.
564
+ */
565
+ _locationOf(d: StorymapSlide): LatLngLiteral | null;
566
+ /**
567
+ * Image region stop: the slide carries an xywh region ([x, y, w, h]
568
+ * image pixels). Only the OpenLayers engine applies it (image mode);
569
+ * the region never contributes to route lines.
570
+ */
571
+ _hasRegion(d: StorymapSlide): boolean;
233
572
  _createMap(): void;
234
573
  _createMiniMap(): void;
235
574
  _createMarker(d?: StorymapSlide): void;
@@ -238,7 +577,9 @@ declare class MapBase {
238
577
  _resetMarkersActive(): void;
239
578
  _calculateMarkerZooms(): void;
240
579
  _createLine(d?: StorymapSlide): unknown;
241
- _addToLine(line: Vector | null, d: LinePoint): void;
580
+ /** Append a slide's location to a route line. Takes the *slide*, not a
581
+ * point — the engine reads `d.location`. */
582
+ _addToLine(line: Vector | null, d: StorymapSlide): void;
242
583
  _replaceLines(line: Vector | null, d: LinePoint[], animate?: {
243
584
  duration: number;
244
585
  retractFrom?: LinePoint[] | null;
@@ -252,7 +593,20 @@ declare class MapBase {
252
593
  _refreshMap(): void;
253
594
  _getMapZoom(): number;
254
595
  _getMapCenter(correct_for_center?: boolean): LatLngLiteral;
255
- _getBoundsZoom(m1: LatLngLiteral, m2: LatLngLiteral, inside?: boolean, padding?: unknown): number;
596
+ /**
597
+ * The `ease` option as an OpenLayers easing function.
598
+ *
599
+ * `ease` is documented as either a function or a name, so the cast to
600
+ * OpenLayers' expected shape was repeated at all ten `view.animate()` call
601
+ * sites.
602
+ */
603
+ protected get _easing(): ((t: number) => number) | undefined;
604
+ /**
605
+ * Zoom that fits the two given points, or `undefined` when the engine
606
+ * cannot compute one. Mirrors `getRouteDistance`: the base class is the
607
+ * no-op template, the OpenLayers subclass returns a real value.
608
+ */
609
+ _getBoundsZoom(m1: LatLngLiteral, m2: LatLngLiteral, inside?: boolean, padding?: unknown): number | undefined;
256
610
  _markerOverview(duration?: number): void;
257
611
  /**
258
612
  * Great-circle length of the route through all markers in kilometers;
@@ -264,11 +618,17 @@ declare class MapBase {
264
618
  _onMarkerClick(e: {
265
619
  marker_number: number;
266
620
  }): void;
621
+ _onMarkerPopupOpen(e: {
622
+ marker_number: number;
623
+ }): void;
624
+ _onMarkerPopupClose(e: {
625
+ marker_number: number;
626
+ }): void;
267
627
  _onMapLoaded(e?: unknown): void;
268
628
  _onWheel(e: WheelEvent): void;
269
629
  _scollZoom(e?: unknown): void;
270
630
  _scollZoomDone(e?: unknown): void;
271
- _calculateZoomChange(origin: LatLngLiteral, destination: LatLngLiteral, correct_for_center?: boolean): number;
631
+ _calculateZoomChange(origin: LatLngLiteral, destination: LatLngLiteral, correct_for_center?: boolean): number | undefined;
272
632
  _updateDisplay(w?: number, h?: number, animate?: boolean, d?: number, offset?: unknown): void;
273
633
  /** Re-apply runtime-changed options (no-op in the base class) */
274
634
  applyOptions(_keys: string[]): void;
@@ -279,22 +639,28 @@ declare class MapBase {
279
639
  _initEvents(): void;
280
640
  }
281
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
+
282
659
  declare class MapMarker extends MapMarker_base {
283
660
  constructor(...args: ConstructorParameters<typeof MapMarkerBase>);
284
661
  }
285
662
 
286
- declare const MapMarker_base: {
287
- new (...args: any[]): {
288
- _vco_events?: Record<string, {
289
- action: unknown;
290
- context: unknown;
291
- }[]>;
292
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
293
- hasEventListeners(type: string): boolean;
294
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
295
- fire(type: string, data?: unknown, target?: unknown): /*elided*/ any;
296
- };
297
- } & typeof MapMarkerBase;
663
+ declare const MapMarker_base: Constructor<EventedInstance<MapMarkerEvents>> & typeof MapMarkerBase;
298
664
 
299
665
  declare class MapMarkerBase {
300
666
  "_el": Record<string, HTMLElement>;
@@ -309,47 +675,111 @@ declare class MapMarkerBase {
309
675
  "data": MapMarkerData;
310
676
  "options": StorymapOptions;
311
677
  "animator": AnimationHandle | null;
312
- "fire": EventedInstance["fire"];
678
+ "fire": EventedInstance<MapMarkerEvents>["fire"];
313
679
  constructor(data?: MapMarkerData, options?: Partial<StorymapOptions>);
680
+ /**
681
+ * @deprecated No-op since 0.9.x upstream (the original marker defined an
682
+ * empty body too). Markers are never individually hidden; use CSS on
683
+ * `.vco-mapmarker`, or `active(false)` to dim one.
684
+ */
314
685
  show(): void;
686
+ /** @deprecated See {@link show} — no-op since 0.9.x upstream. */
315
687
  hide(): void;
688
+ /**
689
+ * @deprecated Never implemented, in the original viewer either: the base
690
+ * `MapMarker._createPopup` had an empty body and the Leaflet override's
691
+ * body was commented out, so the `map_popup` option that called it never
692
+ * had any effect. Kept as a no-op so pre-0.10 code that calls it keeps
693
+ * working. Render the slide text yourself, or use CSS on
694
+ * `.vco-mapmarker` to show a label.
695
+ */
696
+ createPopup(_d?: MapMarkerData, _o?: StorymapOptions): void;
316
697
  addTo(m: unknown): void;
317
698
  removeFrom(m: unknown): void;
318
699
  updateDisplay(w: number, h: number, a?: boolean): void;
319
700
  createMarker(d?: MapMarkerData, o?: StorymapOptions): void;
320
701
  active(a: boolean): void;
321
- location(): LatLngLiteral;
702
+ location(): LatLngLiteral | null;
322
703
  _createMarker(d?: MapMarkerData, o?: StorymapOptions): void;
323
704
  _addTo(m: unknown): void;
324
705
  _removeFrom(m: unknown): void;
325
706
  _active(a: boolean): void;
326
- _location(): LatLngLiteral;
707
+ /**
708
+ * The marker's coordinate, or null when it has none (an overview slide, or
709
+ * a slide carrying only an image region). Every caller treats null as
710
+ * "nothing to focus", so this is the honest shape — the previous
711
+ * `{ lat: 0, lng: 0 }` was a real point at Null Island, spelled with a
712
+ * longitude key nothing in the map read.
713
+ */
714
+ _location(): LatLngLiteral | null;
327
715
  _onMarkerClick(e?: unknown): void;
328
716
  _initLayout(): void;
329
717
  _updateDisplay(width: number, height: number, animate?: boolean): void;
330
718
  }
331
719
 
332
- declare interface MapMarkerData {
720
+ /**
721
+ * A marker's data: the slide it was created from, plus the `real_marker` flag
722
+ * the marker sets once it has confirmed numeric lat/lon. A separate interface
723
+ * used to drift from `StorymapSlide` (narrower `text`, its own `location`),
724
+ * which then made `Map._createMarker(slide)` unassignable.
725
+ */
726
+ declare type MapMarkerData = StorymapSlide & {
333
727
  real_marker?: boolean;
334
- location?: StorymapSlideLocation;
335
- media?: StorymapSlideMedia & {
336
- mediatype?: MediaTypeMatch | null;
337
- };
338
- text?: {
339
- headline?: string;
340
- };
341
- type?: string;
728
+ };
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
+
741
+ /** The resolved marker presentation: `marker.*` over `location.*`. */
742
+ declare interface MarkerPresentation {
743
+ icon?: string;
744
+ iconSize?: number[];
745
+ image?: string;
746
+ label?: string;
747
+ popup: boolean;
748
+ audioBadge: boolean;
749
+ useCustomMarker?: boolean;
750
+ }
751
+
752
+ declare interface MediaData extends StorymapSlideMedia {
753
+ uniqueid?: string | null;
754
+ link?: string | null;
755
+ link_target?: string | null;
342
756
  [key: string]: unknown;
343
757
  }
344
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
+
345
767
  declare interface MediaInstance {
346
768
  addTo: (container: HTMLElement) => void;
347
769
  loadMedia: () => void;
348
770
  stopMedia: () => void;
349
771
  updateDisplay: (w?: number, h?: number, l?: string) => void;
350
- on?: EventedInstance["on"];
772
+ dispose?: () => void;
773
+ on?: EventedInstance<MediaEvents>["on"];
774
+ off?: EventedInstance<MediaEvents>["off"];
351
775
  _state?: {
352
776
  loaded?: boolean;
777
+ eager?: boolean;
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;
353
783
  };
354
784
  }
355
785
 
@@ -363,7 +793,7 @@ declare interface MediaInstance {
363
793
  */
364
794
  export declare function MediaType(m: StorymapSlideMedia): MediaTypeMatch | false;
365
795
 
366
- declare type MediaTypeMatch = {
796
+ export declare type MediaTypeMatch = {
367
797
  type: string;
368
798
  name: string;
369
799
  match_str: string;
@@ -376,6 +806,7 @@ declare class MenuBar extends MenuBar_base {
376
806
 
377
807
  declare const MenuBar_base: {
378
808
  new (...args: any[]): {
809
+ container(): HTMLElement;
379
810
  show(animate?: unknown): void;
380
811
  hide(): void;
381
812
  addTo(container: HTMLElement): /*elided*/ any;
@@ -384,33 +815,25 @@ declare const MenuBar_base: {
384
815
  onLoaded(): void;
385
816
  onAdd(): void;
386
817
  onRemove(): void;
387
- _el: Record<string, HTMLElement>;
818
+ _el: Record<string, unknown>;
388
819
  data?: unknown;
389
- on: (type: string, fn: unknown, context?: unknown) => unknown;
390
- off: (type: string, fn: unknown, context?: unknown) => unknown;
391
- fire: (type: string, data?: unknown, target?: unknown) => unknown;
392
- hasEventListeners: (type: string) => boolean;
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;
393
824
  };
394
- } & {
395
- new (...args: any[]): {
396
- _vco_events?: Record<string, {
397
- action: unknown;
398
- context: unknown;
399
- }[]>;
400
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
401
- hasEventListeners(type: string): boolean;
402
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
403
- fire(type: string, data?: unknown, target?: unknown): /*elided*/ any;
404
- };
405
- } & typeof MenuBarBase;
825
+ } & Constructor<EventedInstance<MenuBarEvents>> & typeof MenuBarBase;
406
826
 
407
827
  declare class MenuBarBase {
408
828
  "_el": Record<string, HTMLElement>;
409
829
  "collapsed": boolean;
410
830
  "options": MenuBarOptions;
411
831
  "animator": Record<string, unknown>;
412
- "fire": EventedInstance["fire"];
832
+ "fire": EventedInstance<MenuBarEvents>["fire"];
413
833
  _fullscreenActive: boolean;
834
+ _autoplayStopped: boolean;
835
+ /** The layer switcher, if `show_layers_control` is on. */
836
+ "_layersControl": LayersControl | null;
414
837
  constructor(elem: HTMLElement | string, parent_elem?: HTMLElement, options?: object);
415
838
  show(d?: number): void;
416
839
  hide(top: number): void;
@@ -420,15 +843,48 @@ declare class MenuBarBase {
420
843
  * Reflect the fullscreen state in the button label/icon.
421
844
  */
422
845
  setFullscreenState(active: boolean): void;
846
+ /**
847
+ * Repaint the overview button label. An image map has no interactive
848
+ * overview, so it gets the shorter wording. Icon-only on mobile.
849
+ */
850
+ _renderOverviewLabel(): void;
851
+ /**
852
+ * Repaint the "back to start" button label. Icon-only on mobile.
853
+ */
854
+ _renderBackToStartLabel(): void;
855
+ /**
856
+ * Repaint the collapse/expand toggle. Icon-only on mobile.
857
+ */
858
+ _renderCollapseLabel(collapsed: boolean): void;
859
+ /**
860
+ * Reflect the autoplay state in the toggle label.
861
+ */
862
+ setAutoplayState(stopped: boolean): void;
423
863
  /**
424
864
  * Repaint every text label from the active language (see `setLanguage`).
425
- * Icon-only mobile buttons carry no text and are left untouched.
865
+ * Icon-only mobile buttons carry text via aria-label instead.
426
866
  */
427
867
  refreshLabels(): void;
428
868
  /**
429
- * 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.
430
882
  */
431
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;
432
888
  /**
433
889
  * Update the route distance display (issue #341); no-op when disabled or
434
890
  * before the first reading.
@@ -438,9 +894,46 @@ declare class MenuBarBase {
438
894
  _onButtonOverview(e: Event): void;
439
895
  _onButtonBackToStart(e: Event): void;
440
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;
441
905
  _onButtonCollapseMap(e: Event): void;
442
906
  _initLayout(): void;
443
907
  _updateDisplay(width?: number, height?: number, animate?: boolean): void;
908
+ /**
909
+ * Release the button listeners, the progress animation and the element.
910
+ * Called by `StoryMap.dispose()`; the menubar must not be used afterwards.
911
+ */
912
+ dispose(): void;
913
+ }
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;
444
937
  }
445
938
 
446
939
  declare interface MenuBarOptions {
@@ -458,6 +951,7 @@ declare class Message extends Message_base {
458
951
 
459
952
  declare const Message_base: {
460
953
  new (...args: any[]): {
954
+ container(): HTMLElement;
461
955
  show(animate?: unknown): void;
462
956
  hide(): void;
463
957
  addTo(container: HTMLElement): /*elided*/ any;
@@ -466,38 +960,40 @@ declare const Message_base: {
466
960
  onLoaded(): void;
467
961
  onAdd(): void;
468
962
  onRemove(): void;
469
- _el: Record<string, HTMLElement>;
963
+ _el: Record<string, unknown>;
470
964
  data?: unknown;
471
- on: (type: string, fn: unknown, context?: unknown) => unknown;
472
- off: (type: string, fn: unknown, context?: unknown) => unknown;
473
- fire: (type: string, data?: unknown, target?: unknown) => unknown;
474
- hasEventListeners: (type: string) => boolean;
475
- };
476
- } & {
477
- new (...args: any[]): {
478
- _vco_events?: Record<string, {
479
- action: unknown;
480
- context: unknown;
481
- }[]>;
482
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
483
- hasEventListeners(type: string): boolean;
484
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
485
- fire(type: string, data?: unknown, target?: unknown): /*elided*/ any;
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;
486
969
  };
487
- } & typeof MessageBase;
970
+ } & Constructor<EventedInstance<MessageEvents>> & typeof MessageBase;
488
971
 
489
972
  declare class MessageBase {
490
973
  "_el": Record<string, HTMLElement>;
491
974
  "options": MessageOptions;
492
975
  "data": Record<string, unknown>;
493
976
  "animator": Record<string, unknown>;
494
- "fire": EventedInstance["fire"];
977
+ "fire": EventedInstance<MessageEvents>["fire"];
495
978
  constructor(data?: Record<string, unknown>, options?: Record<string, unknown>, add_to_container?: HTMLElement);
496
979
  updateMessage(t: string): void;
497
980
  _updateMessage(t?: string): void;
498
981
  _onMouseClick(): void;
982
+ _onKeyDown(e: Event): void;
499
983
  _initLayout(): void;
500
984
  _initEvents(): void;
985
+ /**
986
+ * Release the listeners and drop the element. Called by
987
+ * `StorySlider.dispose()`; the message must not be used afterwards.
988
+ */
989
+ dispose(): void;
990
+ }
991
+
992
+ export declare interface MessageEvents {
993
+ clicked: MessageOptions;
994
+ loaded: Record<string, unknown>;
995
+ added: Record<string, unknown>;
996
+ removed: Record<string, unknown>;
501
997
  }
502
998
 
503
999
  declare interface MessageOptions {
@@ -508,18 +1004,70 @@ declare interface MessageOptions {
508
1004
  [key: string]: unknown;
509
1005
  }
510
1006
 
1007
+ export { OlLayer }
1008
+
1009
+ export { OlMap }
1010
+
1011
+ export { OlProjection }
1012
+
1013
+ export { OlSource }
1014
+
1015
+ export { OlTileLayer }
1016
+
1017
+ export { OlVectorLayer }
1018
+
1019
+ export { OlView }
1020
+
511
1021
  declare class OpenLayers extends Map_2 {
512
- "_map": default_3;
513
- "_tile_layer": Tile;
1022
+ "_map": OlMap;
1023
+ "_tile_layer": OlLayer;
514
1024
  "_line": Vector;
515
1025
  "_line_active": Vector;
516
- "_tile_layer_mini": Tile | null;
1026
+ "_tile_layer_mini": OlLayer | null;
517
1027
  "_mini_map": default_2;
518
- "_markers": OpenLayersMapMarker[];
1028
+ "_markers": StoryMapMarker[];
519
1029
  /** App-level stacked overlays (see the `overlays` option) */
520
- "_overlay_layers": Tile[];
1030
+ "_overlay_layers": OlLayer[];
1031
+ /**
1032
+ * The `overlays[]` entries that produced a layer, parallel to
1033
+ * `_overlay_layers`: a malformed entry is skipped, so the two arrays
1034
+ * can be shorter than the option list.
1035
+ */
1036
+ "_overlay_entries": StorymapOverlayLayer[];
521
1037
  /** rAF handle of the running active-line draw animation */
522
1038
  "_line_animation": number | null;
1039
+ /** Sources `imageready` has already been fired for. */
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>;
523
1071
  _createMap(): void;
524
1072
  /** Extra attribution fragments (e.g. overlay credits), always listed last. */
525
1073
  "_extra_attributions": string[];
@@ -528,13 +1076,59 @@ declare class OpenLayers extends Map_2 {
528
1076
  * custom layers use this instead of rewriting `.vco-map-attribution`.
529
1077
  */
530
1078
  setExtraAttributions(parts: string[]): void;
1079
+ /** The base tile layer (the one created for `map_type`), if consent has not deferred it. */
1080
+ getBaseLayer(): OlLayer | null;
1081
+ /** The stacked `overlays[]` layers, in `overlays[]` order. */
1082
+ getOverlayLayers(): OlLayer[];
1083
+ /** One stacked overlay layer by its `overlays[]` index, or `null`. */
1084
+ getOverlayLayer(index: number): OlLayer | null;
1085
+ /** The minimap's OpenLayers map (the `OverviewMap` control's inner map). */
1086
+ getMinimap(): OlMap | null;
1087
+ /** The full (inactive) route line layer. */
1088
+ getLine(): OlLayer | null;
1089
+ /** The highlighted route line layer drawn up to the current slide. */
1090
+ getLineActive(): OlLayer | null;
1091
+ /** The markers, in slide order (the index matches the slide index). */
1092
+ getMarkers(): StoryMapMarker[];
1093
+ /** One marker by slide index, or `null`. */
1094
+ getMarker(index: number): StoryMapMarker | null;
531
1095
  /**
532
1096
  * (Re)render the attribution line for the current map type. Called at
533
1097
  * creation and on every `map_type` switch, which previously left the
534
1098
  * initial text stale.
535
1099
  */
536
1100
  _updateAttribution(): void;
537
- _getAttribution(map_type: string): string;
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;
1123
+ _getAttribution(map_type: string): string[];
1124
+ /**
1125
+ * The provider credit for `map_type` as plain text (no HTML), for the
1126
+ * OpenLayers source `attributions`. Our own `.vco-map-attribution` line
1127
+ * stays the rendered default and uses the linked `_getAttribution`
1128
+ * version; this makes `source.getAttributions()` (and a consumer's
1129
+ * `ol/control/Attribution`) work instead of returning nothing.
1130
+ */
1131
+ _sourceAttributions(map_type: string): string[];
538
1132
  /**
539
1133
  * Create the tile layer and register its load handler. Deferred until
540
1134
  * the visitor allows map tiles in consent mode.
@@ -543,14 +1137,27 @@ declare class OpenLayers extends Map_2 {
543
1137
  /**
544
1138
  * Ask for tile consent, then attach the layers if allowed.
545
1139
  */
546
- _requestTileConsent(consent: ConsentManager, tile_service: string): Promise<void>;
1140
+ _requestTileConsent(consent: ConsentManager, tile_service: ConsentService): Promise<void>;
547
1141
  /**
548
1142
  * (Re)build the stacked raster overlays from the `overlays` option.
549
1143
  * Overlays sit above the base tiles (z 1..n) and below the route lines
550
1144
  * (z 10/11); every entry accepts any `map_type` value plus declarative
551
1145
  * presentation, so hosts no longer capture and patch layer objects.
1146
+ * An entry carrying a `georeference` places a IIIF image on the
1147
+ * geographic map instead of stacking a tile source.
552
1148
  */
553
1149
  _buildOverlays(): void;
1150
+ /**
1151
+ * Build a stacked overlay from a IIIF Georeference Extension payload
1152
+ * (`overlays[].georeference`): the ground control points are fitted
1153
+ * affinely and the image is placed as a geographic extent, which
1154
+ * OpenLayers reprojects onto the view exactly like the IIIF basemap.
1155
+ *
1156
+ * The layer is returned empty and filled in asynchronously, mirroring
1157
+ * the `iiif` basemap path — only the fit (pure, synchronous) decides
1158
+ * whether a layer exists at all, so overlay indices stay stable.
1159
+ */
1160
+ _createGeoreferencedOverlay(entry: StorymapOverlayLayer): Tile | null;
554
1161
  /**
555
1162
  * Convert a lon/lat clip box to view units. Only meaningful on
556
1163
  * mercator maps; image-space maps (iiif/zoomify) and malformed
@@ -569,11 +1176,30 @@ declare class OpenLayers extends Map_2 {
569
1176
  }, retries?: number): void;
570
1177
  /** Refresh the attribution line with the visible overlays' credits. */
571
1178
  _syncOverlayAttributions(): void;
572
- /** Number of stacked overlay layers (see the `overlays` option). */
1179
+ /**
1180
+ * Number of stacked overlay layers (see the `overlays` option). Alias:
1181
+ * `getOverlayLayers().length`.
1182
+ */
573
1183
  getOverlayCount(): number;
574
- /** Show or hide a stacked overlay by index (re-syncs attribution). */
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[];
1190
+ /**
1191
+ * Show or hide a stacked overlay by index (re-syncs attribution). The
1192
+ * index counts built layers, i.e. it skips malformed entries.
1193
+ *
1194
+ * Prefer `getOverlayLayer(index).setVisible(v)` on the layer itself; this
1195
+ * wrapper exists because it also re-syncs the attribution line and the
1196
+ * overlay blend mode, which a bare `setVisible()` does not.
1197
+ */
575
1198
  setOverlayVisible(index: number, visible: boolean): void;
576
1199
  /** Set a stacked overlay's opacity by index. */
1200
+ /**
1201
+ * Alias: `getOverlayLayer(index)?.setOpacity(opacity)`.
1202
+ */
577
1203
  setOverlayOpacity(index: number, opacity: number): void;
578
1204
  /**
579
1205
  * Map tiles were allowed: attach the main tile layer, create the
@@ -589,7 +1215,7 @@ declare class OpenLayers extends Map_2 {
589
1215
  sizes: Array<[number, number]>;
590
1216
  maxZoom: number;
591
1217
  extent: number[];
592
- tileGrid: default_5;
1218
+ tileGrid: default_4;
593
1219
  } | null;
594
1220
  /**
595
1221
  * The zoomify overview state: the best-fit pyramid level for a map
@@ -600,20 +1226,140 @@ declare class OpenLayers extends Map_2 {
600
1226
  zoom: number;
601
1227
  center: number[];
602
1228
  } | null;
603
- _createTileLayer(map_type: string): Tile;
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;
1274
+ _createTileLayer(map_type: string): OlLayer;
1275
+ /**
1276
+ * A layer's source, or null when it has none. Custom `Layer` subclasses
1277
+ * passed through `_createTileLayer` (e.g. Allmaps' `WarpedMapLayer`)
1278
+ * deliberately have no `getSource`, so every read goes through here
1279
+ * instead of calling the method directly.
1280
+ */
1281
+ _sourceOf(layer: OlLayer | null | undefined): OlSource | null;
1282
+ /**
1283
+ * Move the map into another element, keeping OpenLayers in step.
1284
+ *
1285
+ * `DomMixed.addTo()` (the original semantics, unchanged: append the map
1286
+ * container, fire `added`) only moves DOM — the `ol/Map` still has the
1287
+ * viewport it measured at construction, so it would keep painting at the
1288
+ * old size. Re-attach the target, which `removeFrom()` detached, and
1289
+ * re-measure. The argument must be the new parent.
1290
+ */
1291
+ addTo(container: HTMLElement): this;
1292
+ /**
1293
+ * Move the map out of `container`. Untargets the OpenLayers map so it
1294
+ * does not render into a detached node; a later {@link addTo} re-attaches
1295
+ * it. The argument must be the current parent.
1296
+ */
1297
+ removeFrom(container: HTMLElement): this;
1298
+ /**
1299
+ * True when the map is a plain image in an `EPSG:4326` "image space"
1300
+ * rather than a geographic map: a IIIF image presented as a picture of
1301
+ * the world (`map_as_image`), not georeferenced.
1302
+ *
1303
+ * In this mode the view projection is `EPSG:4326` with degrees as
1304
+ * resolution and the view is fitted to the image extent, so
1305
+ * `getCenter()`/`getZoom()` are in degrees/pixels-per-degree — not
1306
+ * mercator metres. Marker locations are pixel offsets into the image,
1307
+ * not lat/lon. Georeferenced IIIF (`map_bbox` with `map_as_image`
1308
+ * omitted) is a normal mercator map; use `isImageSpace()` rather than
1309
+ * testing `map_type` to tell the two apart.
1310
+ */
1311
+ isImageSpace(): boolean;
1312
+ /**
1313
+ * Stop the line animation, drop the minimap control and dispose the
1314
+ * OpenLayers map. Called by `StoryMap.dispose()`; the engine must not be
1315
+ * used afterwards.
1316
+ */
1317
+ dispose(): void;
1318
+ /**
1319
+ * Fire `imageready` once `source` is usable (and immediately when it
1320
+ * already is). Image sources — IIIF, zoomify, the deferred tile layer —
1321
+ * attach asynchronously, so this is the only outward signal that the
1322
+ * imagery is really on the map; the `loaded` event can fire before the
1323
+ * source is attached at all.
1324
+ */
1325
+ _fireImageready(source: {
1326
+ getState?(): string;
1327
+ }, kind: ImagereadyKind, layer?: OlLayer): void;
1328
+ /** Computed zooms take precedence over the authored slide zoom. */
1329
+ _markerZoom(index: number): number | undefined;
1330
+ /**
1331
+ * The TileJSON metadata, but only when it is describing `url`.
1332
+ *
1333
+ * `tilejson` describes the map's tile source, so its `tiles` template is
1334
+ * the one the map_type resolved to. When it names a different template it
1335
+ * is not about this source, and neither the zoom ladder nor the initial
1336
+ * view should be taken from it.
1337
+ */
1338
+ _tilejsonFor(url: string): StorymapTilejson | undefined;
1339
+ /**
1340
+ * An XYZ source for a URL template, honouring the TileJSON metadata of the
1341
+ * map's own tile source if it is describing this template (§2.9).
1342
+ *
1343
+ * `minzoom`/`maxzoom` become the tile grid's zoom range, so OpenLayers asks
1344
+ * for levels the service actually has and stops past the ones it does not.
1345
+ * `scheme: "tms"` is the TMS row order, which is the same URL with the tile
1346
+ * row counted from the bottom.
1347
+ */
1348
+ _xyzSource(url: string): XYZ;
1349
+ _createDefaultTileLayer(map_type: string): Tile;
604
1350
  _createVectorStyleLayer(style_url: string): Tile;
605
1351
  _createMiniMap(): void;
606
1352
  _fitMiniMapToImage(): void;
607
1353
  _createMarker(d: StorymapSlide): void;
608
- _addMarker(marker: OpenLayersMapMarker): void;
1354
+ _addMarker(marker: StoryMapMarker): void;
609
1355
  /**
610
1356
  * Position marker overlays on the unwrapped longitude path so they sit on
611
1357
  * the same world copy as the fitted view and the line (issue #381).
612
1358
  * Image-space coordinates are not degrees and stay untouched.
613
1359
  */
614
1360
  _afterCreateMarkers(): void;
615
- _removeMarker(marker: OpenLayersMapMarker): void;
616
- _getAllMarkersBounds(markers_array: OpenLayersMapMarker[]): number[][];
1361
+ _removeMarker(marker: StoryMapMarker): void;
1362
+ _getAllMarkersBounds(markers_array: StoryMapMarker[]): number[][];
617
1363
  /**
618
1364
  * Normalize a longitude sequence so consecutive values differ by at most
619
1365
  * 180 degrees: markers keep their raw coordinates (OpenLayers wraps the
@@ -640,7 +1386,7 @@ declare class OpenLayers extends Map_2 {
640
1386
  * by design — they must not skew the fit target, so the extent is
641
1387
  * intersected with the box and the in-box markers compose the view.
642
1388
  */
643
- _fitView(ol_map: default_3, coords: number[][], duration?: number, clamp_to_bbox?: boolean): void;
1389
+ _fitView(ol_map: OlMap, coords: number[][], duration?: number, clamp_to_bbox?: boolean): void;
644
1390
  _calculateMarkerZooms(): void;
645
1391
  /**
646
1392
  * Stroke style for the route lines: the dash pattern and line join are
@@ -650,7 +1396,7 @@ declare class OpenLayers extends Map_2 {
650
1396
  _lineStyle(color: string): Style;
651
1397
  _createLine(d?: StorymapSlide): Vector;
652
1398
  _addLineToMap(line: Vector): void;
653
- _addToLine(line: Vector, d: LinePoint): void;
1399
+ _addToLine(line: Vector, d: StorymapSlide): void;
654
1400
  /**
655
1401
  * Replace a line's geometry. With `animate.duration > 0` only the latest
656
1402
  * hop animates, in sync with the view animation: the already-traveled
@@ -676,13 +1422,111 @@ declare class OpenLayers extends Map_2 {
676
1422
  _panTo(loc: LatLngLiteral, animate?: boolean): void;
677
1423
  _zoomTo(z: number, animate?: boolean): void;
678
1424
  _viewTo(loc: StorymapSlideLocation, opts?: ViewToOptions): void;
1425
+ /**
1426
+ * Image region stop: fit the xywh bbox ([x, y, w, h] image pixels —
1427
+ * the EPSG:4326 image space) with the shared animation options, then
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.
1431
+ */
1432
+ _fitRegion(region: [number, number, number, number], opts?: ViewToOptions, loc?: StorymapSlideLocation): void;
679
1433
  _toViewCoords(loc: LatLngLiteral): number[];
680
- _getMapZoom(): number;
681
- _getMapCenter(offset?: boolean): LatLngLiteral;
682
- _getMapCenterOffset(location: LatLngLiteral, zoom: number): LatLngLiteral;
683
- _fromViewCoords(coord: number[], projection: default_6): LatLngLiteral;
684
- _getBoundsZoom(origin: LatLngLiteral, destination: LatLngLiteral, correct_for_center?: boolean): number;
685
- _initialMapLocation(): void;
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;
1506
+ _getMapZoom(): number;
1507
+ _getMapCenter(): LatLngLiteral;
1508
+ _getMapCenterOffset(location: LatLngLiteral, zoom: number): LatLngLiteral;
1509
+ _fromViewCoords(coord: number[], projection: OlProjection): LatLngLiteral;
1510
+ /**
1511
+ * May a tile-backed layer (base map, overlay, minimap, overview) be
1512
+ * created right now? Under `consent_required` that is only true once the
1513
+ * visitor has allowed the tile service. This was the same five-line
1514
+ * predicate at five call sites.
1515
+ */
1516
+ private _tilesAllowed;
1517
+ /** A slide's {lat, lon} when both are real numbers, else null. */
1518
+ private _latLngOf;
1519
+ /**
1520
+ * The map's pixel size, with a never-zero fallback.
1521
+ *
1522
+ * `getSize()` returns undefined until the map has a size, so the six
1523
+ * call sites that fitted an extent to the viewport all repeated the same
1524
+ * `(size[0] || 1)` guard — which silently fitted against a 1px viewport
1525
+ * rather than bailing out.
1526
+ */
1527
+ private _viewportSize;
1528
+ _getBoundsZoom(origin: LatLngLiteral, destination: LatLngLiteral, correct_for_center?: boolean): number;
1529
+ _initialMapLocation(): void;
686
1530
  /**
687
1531
  * Great-circle (haversine) length of the route through all markers in
688
1532
  * kilometers (issue #341).
@@ -711,17 +1555,6 @@ declare class OpenLayers extends Map_2 {
711
1555
  _setViewInstant(loc: StorymapSlideLocation, zoom: number): void;
712
1556
  }
713
1557
 
714
- declare class OpenLayersMapMarker extends MapMarker {
715
- "_overlay": default_4;
716
- _createMarker(d?: MapMarkerData, o?: StorymapOptions): void;
717
- _createMarkerElement(d: MapMarkerData, o?: StorymapOptions): HTMLDivElement;
718
- _addTo(m: Map_3): void;
719
- _removeFrom(m: Map_3): void;
720
- _active(a: boolean): void;
721
- _customIconAnchor(size?: number[]): number[];
722
- _location(): LatLngLiteral;
723
- }
724
-
725
1558
  /** Wheel/scroll zoom bookkeeping (handles cleared via clearTimeout). */
726
1559
  declare interface ScrollState {
727
1560
  start_time: number | null;
@@ -730,7 +1563,8 @@ declare interface ScrollState {
730
1563
  }
731
1564
 
732
1565
  /**
733
- * Switch the active UI language.
1566
+ * Switch the active UI language. Synchronous: the viewer resolves its labels
1567
+ * while it is being constructed.
734
1568
  *
735
1569
  * @param code - A locale code for which a locale file exists (e.g. `"en"`).
736
1570
  * @returns The language entry that is now active.
@@ -743,6 +1577,7 @@ declare class Slide extends Slide_base {
743
1577
 
744
1578
  declare const Slide_base: {
745
1579
  new (...args: any[]): {
1580
+ container(): HTMLElement;
746
1581
  show(animate?: unknown): void;
747
1582
  hide(): void;
748
1583
  addTo(container: HTMLElement): /*elided*/ any;
@@ -751,61 +1586,101 @@ declare const Slide_base: {
751
1586
  onLoaded(): void;
752
1587
  onAdd(): void;
753
1588
  onRemove(): void;
754
- _el: Record<string, HTMLElement>;
1589
+ _el: Record<string, unknown>;
755
1590
  data?: unknown;
756
- on: (type: string, fn: unknown, context?: unknown) => unknown;
757
- off: (type: string, fn: unknown, context?: unknown) => unknown;
758
- fire: (type: string, data?: unknown, target?: unknown) => unknown;
759
- hasEventListeners: (type: string) => boolean;
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;
760
1595
  };
761
- } & {
762
- new (...args: any[]): {
763
- _vco_events?: Record<string, {
764
- action: unknown;
765
- context: unknown;
766
- }[]>;
767
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
768
- hasEventListeners(type: string): boolean;
769
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
770
- fire(type: string, data?: unknown, target?: unknown): /*elided*/ any;
771
- };
772
- } & typeof SlideBase;
1596
+ } & Constructor<EventedInstance<SlideEvents>> & typeof SlideBase;
773
1597
 
774
1598
  declare interface SlideBackgroundChange {
775
1599
  color_value?: string;
776
1600
  image?: boolean;
777
1601
  }
778
1602
 
1603
+ export declare interface SlideBackgroundState {
1604
+ image: boolean;
1605
+ color: boolean;
1606
+ color_value: string;
1607
+ }
1608
+
779
1609
  declare class SlideBase {
780
- "_el": Record<string, HTMLElement>;
1610
+ /** `call_to_action` is only created when the slide shows one. */
1611
+ "_el": SlideElements;
1612
+ /** The primary media item; always `_medias[0]` when present (#358). */
781
1613
  "_media": MediaInstance | null;
782
- "_mediaclass": unknown;
1614
+ /** Every media item: `[media, ...media_extra]` with a non-empty url. */
1615
+ "_medias": MediaInstance[];
783
1616
  "_text": Text_2;
784
1617
  "_state": {
785
1618
  loaded: boolean;
786
1619
  };
787
1620
  "_scroll_hint": HTMLElement | null;
788
1621
  "_scroll_hint_dismissed": boolean;
1622
+ "_onSlideScrollBound": EventListener;
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
+ }[];
789
1634
  "has": SlideHas;
790
1635
  "title": string;
791
1636
  "data": StorymapSlide;
792
1637
  "options": SlideOptions;
793
1638
  "active": boolean;
794
1639
  "animator": unknown;
795
- "fire": EventedInstance["fire"];
1640
+ "fire": EventedInstance<SlideEvents>["fire"];
796
1641
  "onLoaded": () => void;
797
1642
  constructor(data: StorymapSlide, options: Record<string, unknown>, title_slide?: boolean);
798
1643
  show(): void;
799
1644
  hide(): void;
1645
+ /**
1646
+ * Release the slide's listeners, media and DOM. Called by
1647
+ * `StorySlider.dispose()`; the slide must not be used afterwards.
1648
+ */
1649
+ dispose(): void;
800
1650
  setActive(is_active: boolean): void;
801
1651
  updateDisplay(w?: number, h?: number, l?: string): void;
802
1652
  loadMedia(): void;
1653
+ _eagerLoadImages(): void;
803
1654
  stopMedia(): void;
804
- getBackground(): {
805
- image: boolean;
806
- color: boolean;
807
- color_value: string;
808
- };
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;
1662
+ /**
1663
+ * True when this slide's media is a timed, playable one (audio or video).
1664
+ * `autoplay_media` waits for such a slide's media to end instead of using
1665
+ * its timer; everything else keeps the timer.
1666
+ */
1667
+ hasPlayableMedia(): boolean;
1668
+ /**
1669
+ * Call `fn` when this slide's media finishes playing. A slide with no
1670
+ * media — or media that cannot end — never calls it, which is why
1671
+ * `autoplay_media` keeps its timer as a fallback rather than waiting on
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).
1675
+ */
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;
809
1684
  scrollToTop(): void;
810
1685
  /**
811
1686
  * Show a bouncing downward arrow when the slide content overflows
@@ -823,16 +1698,33 @@ declare class SlideBase {
823
1698
  _updateDisplay(width?: number, height?: number, layout?: string): void;
824
1699
  }
825
1700
 
1701
+ /**
1702
+ * The slide's element cache. `call_to_action` is null until the slide is told
1703
+ * to show one (`addCallToAction`).
1704
+ */
1705
+ declare type SlideElements = {
1706
+ container: HTMLElement;
1707
+ scroll_container: HTMLElement;
1708
+ background: HTMLElement;
1709
+ content_container: HTMLElement;
1710
+ content: HTMLElement;
1711
+ call_to_action: HTMLElement | null;
1712
+ };
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
+
826
1722
  declare interface SlideHas {
827
1723
  headline: boolean;
828
1724
  text: boolean;
829
1725
  media: boolean;
830
1726
  title: boolean;
831
- background: {
832
- image: boolean;
833
- color: boolean;
834
- color_value: string;
835
- };
1727
+ background: SlideBackgroundState;
836
1728
  }
837
1729
 
838
1730
  declare class SlideNav extends SlideNav_base {
@@ -841,6 +1733,7 @@ declare class SlideNav extends SlideNav_base {
841
1733
 
842
1734
  declare const SlideNav_base: {
843
1735
  new (...args: any[]): {
1736
+ container(): HTMLElement;
844
1737
  show(animate?: unknown): void;
845
1738
  hide(): void;
846
1739
  addTo(container: HTMLElement): /*elided*/ any;
@@ -849,25 +1742,14 @@ declare const SlideNav_base: {
849
1742
  onLoaded(): void;
850
1743
  onAdd(): void;
851
1744
  onRemove(): void;
852
- _el: Record<string, HTMLElement>;
1745
+ _el: Record<string, unknown>;
853
1746
  data?: unknown;
854
- on: (type: string, fn: unknown, context?: unknown) => unknown;
855
- off: (type: string, fn: unknown, context?: unknown) => unknown;
856
- fire: (type: string, data?: unknown, target?: unknown) => unknown;
857
- hasEventListeners: (type: string) => boolean;
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;
858
1751
  };
859
- } & {
860
- new (...args: any[]): {
861
- _vco_events?: Record<string, {
862
- action: unknown;
863
- context: unknown;
864
- }[]>;
865
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
866
- hasEventListeners(type: string): boolean;
867
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
868
- fire(type: string, data?: unknown, target?: unknown): /*elided*/ any;
869
- };
870
- } & typeof SlideNavBase;
1752
+ } & Constructor<EventedInstance<SlideNavEvents>> & typeof SlideNavBase;
871
1753
 
872
1754
  declare class SlideNavBase {
873
1755
  "_el": Record<string, HTMLElement>;
@@ -876,7 +1758,7 @@ declare class SlideNavBase {
876
1758
  "options": SlideNavOptions;
877
1759
  "animator": AnimationHandle | null;
878
1760
  "animator_position": AnimationHandle | null;
879
- "fire": EventedInstance["fire"];
1761
+ "fire": EventedInstance<SlideNavEvents>["fire"];
880
1762
  constructor(data?: Partial<SlideNavData>, options?: Partial<SlideNavOptions>, add_to_container?: HTMLElement);
881
1763
  update(d?: Partial<SlideNavData>): void;
882
1764
  setColor(inverted: boolean): void;
@@ -886,6 +1768,12 @@ declare class SlideNavBase {
886
1768
  _update(d?: Partial<SlideNavData>): void;
887
1769
  _initLayout(): void;
888
1770
  _initEvents(): void;
1771
+ _onKeyDown(e: Event): void;
1772
+ /**
1773
+ * Release the listeners and the position animation. Called by
1774
+ * `StorySlider.dispose()`; the nav must not be used afterwards.
1775
+ */
1776
+ dispose(): void;
889
1777
  }
890
1778
 
891
1779
  declare interface SlideNavData {
@@ -895,6 +1783,13 @@ declare interface SlideNavData {
895
1783
  [key: string]: unknown;
896
1784
  }
897
1785
 
1786
+ export declare interface SlideNavEvents {
1787
+ clicked: SlideNavOptions;
1788
+ loaded: SlideNavData;
1789
+ added: SlideNavData;
1790
+ removed: SlideNavData;
1791
+ }
1792
+
898
1793
  declare interface SlideNavOptions {
899
1794
  direction: string;
900
1795
  [key: string]: unknown;
@@ -912,6 +1807,64 @@ declare interface SlideOptions {
912
1807
  [key: string]: unknown;
913
1808
  }
914
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
+
915
1868
  export declare class StoryMap extends StoryMap_base {
916
1869
  /**
917
1870
  * The library base path (the directory containing the module).
@@ -922,18 +1875,7 @@ export declare class StoryMap extends StoryMap_base {
922
1875
  constructor(...args: ConstructorParameters<typeof StoryMapBase>);
923
1876
  }
924
1877
 
925
- declare const StoryMap_base: {
926
- new (...args: any[]): {
927
- _vco_events?: Record<string, {
928
- action: unknown;
929
- context: unknown;
930
- }[]>;
931
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
932
- hasEventListeners(type: string): boolean;
933
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
934
- fire(type: string, data?: unknown, target?: unknown): /*elided*/ any;
935
- };
936
- } & typeof StoryMapBase;
1878
+ declare const StoryMap_base: Constructor<EventedInstance<StoryMapEvents>> & typeof StoryMapBase;
937
1879
 
938
1880
  /**
939
1881
  * Interactive StoryMap viewer.
@@ -943,7 +1885,7 @@ declare const StoryMap_base: {
943
1885
  *
944
1886
  * @example
945
1887
  * ```ts
946
- * import { StoryMap } from "storymapjs";
1888
+ * import { StoryMap } from "@projektemacher/storymapjs";
947
1889
  * // from an inline data object
948
1890
  * const map = new StoryMap("embed", { storymap: { ... } }, { start_at_slide: 2 });
949
1891
  * // or straight from a source file (storymap JSON or IIIF manifest)
@@ -955,34 +1897,112 @@ declare class StoryMapBase {
955
1897
  storyslider: boolean;
956
1898
  map: boolean;
957
1899
  };
958
- "on": EventedInstance["on"];
1900
+ "on": EventedInstance<StoryMapEvents>["on"];
959
1901
  "version": string;
960
1902
  "ready": boolean;
961
1903
  "_el": {
962
1904
  container: HTMLElement;
963
1905
  menubar: HTMLElement;
964
- map: HTMLElement;
1906
+ map: HTMLElement | null;
965
1907
  storyslider: HTMLElement;
966
1908
  };
967
1909
  "_storyslider": StorySlider;
968
- "_map": OpenLayers;
969
- "map": Map_3;
1910
+ "_map": OpenLayers | null;
1911
+ /** `map_type: "none"`: the story is text-and-media, with no map at all. */
1912
+ "_map_disabled": boolean;
1913
+ /**
1914
+ * The raw OpenLayers map. `null` until the map is built (the
1915
+ * constructor assigns it during data load) — check it, or use the
1916
+ * accessors, which return `null` until then.
1917
+ */
1918
+ "map": Map_3 | null;
970
1919
  "_menubar": MenuBar;
971
1920
  "data": StorymapData;
972
1921
  "options": StorymapOptions;
973
1922
  "current_slide": number;
1923
+ /**
1924
+ * The manifest this viewer was built from, kept so `loadAnnotations()` can
1925
+ * resolve its `seeAlso` targets. `null` for a storymap-JSON viewer, which
1926
+ * has no `seeAlso`.
1927
+ */
1928
+ "_raw_manifest": unknown | null;
1929
+ /**
1930
+ * The deep link the page was opened with, captured before anything can
1931
+ * rewrite the URL.
1932
+ *
1933
+ * This has to be read *early*. The slider's opening `goTo()` can reach
1934
+ * `_navigate()` before `_onLoaded()` runs, and `_navigate()` calls
1935
+ * `_syncHash()` — which would overwrite the incoming link with the current
1936
+ * slide before `_onLoaded()` ever looked at it. Whether that happens
1937
+ * depends on the order the slider and map finish loading, which is exactly
1938
+ * the kind of race that makes a deep link work most of the time.
1939
+ */
1940
+ "_initial_deep_link": {
1941
+ state: ContentState | null;
1942
+ hash: string;
1943
+ } | null;
974
1944
  "animator_map": AnimationHandle | null;
975
1945
  "animator_storyslider": AnimationHandle | null;
976
1946
  "_autoplay_timer": ReturnType<typeof setTimeout> | null;
977
1947
  "_transition_timer": ReturnType<typeof setTimeout> | null;
978
1948
  "_autoplay_stopped": boolean;
1949
+ /** The narration player: one <audio> for the whole story, reused. */
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;
1971
+ /** Guards a stale play() from a slide change that already moved on. */
1972
+ "_narration_token": number;
1973
+ /** Whether narration consent was granted (asked once per story). */
1974
+ "_narration_allowed": boolean;
1975
+ /** True once the visitor has clicked/keyed: unmuted audio needs this. */
1976
+ "_user_gestured": boolean;
1977
+ /** The advance armed for the current slide (media-ended or the timer). */
1978
+ "_autoplay_advance": (() => void) | null;
1979
+ /** A narration that was skipped for want of a gesture, to retry later. */
1980
+ "_replayNarrationAfterGesture": boolean;
979
1981
  "_hash_initialized": boolean;
1982
+ "_collapsed": boolean;
980
1983
  /** the data source was a IIIF Presentation manifest (legacy zoomify options are ignored) */
981
1984
  "_data_from_manifest": boolean;
1985
+ /** the data source was a slideshow tour (slideshow-only features apply) */
1986
+ "_data_from_slideshow": boolean;
982
1987
  "_resize_observer": ResizeObserver | null;
1988
+ /** Stored so `dispose()` can remove them again (see AGENTS: no leaks) */
1989
+ "_on_resize": (() => void) | null;
1990
+ "_on_keydown_global": ((e: KeyboardEvent) => void) | null;
1991
+ "_on_fullscreen": (() => void) | null;
1992
+ "_on_hashchange": (() => void) | null;
1993
+ /** Reduced-motion toggles mid-story stop the advance timer. */
1994
+ "_on_reduced_motion": ((e: MediaQueryListEvent) => void) | null;
1995
+ /** Set by `dispose()` so a second call returns early. */
1996
+ "_disposed": boolean;
1997
+ /** identity of this viewer's claim on the page-wide locale */
1998
+ "_language_holder": symbol;
1999
+ /** the locale the caller actually asked for, if any; see _loadLanguage */
2000
+ "_language_requested": string | undefined;
2001
+ /** bumped on interaction, so page-wide keys can pick one viewer */
2002
+ "_interaction": number;
2003
+ "_onInteraction": (() => void) | null;
983
2004
  "_resize_timer": ReturnType<typeof setTimeout> | null;
984
- "fire": EventedInstance["fire"];
985
- "hasEventListeners": EventedInstance["hasEventListeners"];
2005
+ "fire": EventedInstance<StoryMapEvents>["fire"];
986
2006
  /**
987
2007
  * Create a StoryMap inside the given element.
988
2008
  *
@@ -995,21 +2015,76 @@ declare class StoryMapBase {
995
2015
  * @param listeners - Optional event listeners keyed by event name
996
2016
  * (`change`, `title`, `loaded`, ...) attached on creation.
997
2017
  */
998
- 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
+ });
999
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
+ }>;
1000
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;
1001
2048
  _initOptions(): void;
1002
2049
  _loadLanguage(): void;
2050
+ /**
2051
+ * The locale this viewer was actually asked for, or undefined when the
2052
+ * caller and the document both stayed silent.
2053
+ */
2054
+ _requestedLanguage(): string | undefined;
1003
2055
  refreshLanguage(code: string): void;
2056
+ /**
2057
+ * Repaint everything a runtime language switch affects: the menubar
2058
+ * labels and the `vco-rtl` class.
2059
+ *
2060
+ * This deliberately does *not* call `updateDisplay()`. A full re-layout
2061
+ * re-runs the slider's `goTo(current_slide)`, which goes through the
2062
+ * navigation path that re-arms autoplay — so calling it here silently
2063
+ * cancelled a pending autoplay tick and the story stopped advancing.
2064
+ */
2065
+ _applyLanguageLayout(): void;
1004
2066
  _loadFontCss(): Promise<void>;
1005
2067
  _onFontLoaded(font: string): void;
1006
2068
  /**
1007
- * Navigate to a slide by index.
2069
+ * Navigate to a slide by index. Out-of-range indices are ignored, as is
2070
+ * the current index.
1008
2071
  *
1009
2072
  * @param n - Zero-based slide index; the map animates to the slide's
1010
- * marker (or the overview when `n` is 0 for storymaps with one).
2073
+ * marker. The overview is selected by the slide's own
2074
+ * `type: "overview"`, not by its index.
1011
2075
  */
1012
2076
  goTo(n: number): void;
2077
+ /**
2078
+ * The single navigation path shared by programmatic navigation, the
2079
+ * slider's `change` event, the map's `change` event and "back to start".
2080
+ *
2081
+ * `navigate` names the single component that the bubble source already
2082
+ * moved; the other component follows. `navigated` says whether the caller
2083
+ * has *not* already reported the change outward, so the outward `change`
2084
+ * event fires exactly once per navigation (the bubble paths would
2085
+ * otherwise re-enter through the other component's handler).
2086
+ */
2087
+ private _navigate;
1013
2088
  /**
1014
2089
  * Announce a slide transition: `transitionstart` now (with the glide
1015
2090
  * duration both animations were started with) and `transitionend` once
@@ -1025,8 +2100,10 @@ declare class StoryMapBase {
1025
2100
  /**
1026
2101
  * Change a single map option at runtime and apply its effect immediately.
1027
2102
  *
1028
- * Runtime-changeable options: `map_type` (rebuilds the main + minimap tile
1029
- * layers, keeping the overview fitted to the marker bounds), `overlays`
2103
+ * Runtime-changeable options: `map_type` (swaps one basemap for another and
2104
+ * rebuilds the main + minimap tile layers, keeping the overview fitted to
2105
+ * the marker bounds; it cannot add or remove a map, and `"none"` and
2106
+ * non-strings are declined), `overlays`
1030
2107
  * (rebuilds the stacked overlay layers), `show_lines`, `line_color`,
1031
2108
  * `line_color_inactive`, `line_weight`, `line_opacity`, `line_dash`,
1032
2109
  * `line_join`, `line_follows_path`, `show_history_line` (restyled
@@ -1035,31 +2112,280 @@ declare class StoryMapBase {
1035
2112
  * options only take effect on the next navigation or require re-creating
1036
2113
  * the StoryMap.
1037
2114
  */
2115
+ /**
2116
+ * Sugar over {@link setMapOptions} — `setMapOption(name, value)` is the
2117
+ * same call as `setMapOptions({ [name]: value })`.
2118
+ */
1038
2119
  setMapOption(name: string, value: unknown): void;
1039
2120
  /**
1040
2121
  * Show or hide a stacked overlay by index (see the `overlays` option).
2122
+ * Prefer `getOverlayLayer(index).setVisible(v)` on the layer itself; this
2123
+ * wrapper also re-syncs the attribution line and the overlay blend mode.
1041
2124
  */
1042
2125
  setOverlayVisible(index: number, visible: boolean): void;
1043
2126
  /**
1044
2127
  * Set a stacked overlay's opacity by index (see the `overlays` option).
2128
+ * Alias: `getOverlayLayer(index)?.setOpacity(opacity)`.
1045
2129
  */
1046
2130
  setOverlayOpacity(index: number, opacity: number): void;
1047
2131
  /**
1048
2132
  * Change several map options at runtime (see setMapOption).
1049
2133
  */
1050
2134
  setMapOptions(options: Partial<StorymapOptions>): void;
2135
+ /** The base tile layer, or `null` when deferred (tile consent not granted). */
2136
+ getBaseLayer(): OlLayer | null;
2137
+ /** The stacked `overlays[]` layers, in `overlays[]` order. */
2138
+ getOverlayLayers(): OlLayer[];
2139
+ /** One stacked overlay layer by its `overlays[]` index, or `null`. */
2140
+ getOverlayLayer(index: number): OlLayer | null;
2141
+ /** Number of stacked overlay layers (see the `overlays` option). */
2142
+ getOverlayCount(): number;
2143
+ /** The minimap's OpenLayers map (the `OverviewMap` control's inner map). */
2144
+ getMinimap(): Map_3 | null;
2145
+ /** The full (inactive) route line layer. */
2146
+ getLine(): OlLayer | null;
2147
+ /**
2148
+ * True when the map shows a IIIF image as a picture of the world
2149
+ * (`map_as_image`) rather than as a georeferenced map. In that mode the
2150
+ * view is `EPSG:4326` image space: `map.getView().getCenter()` is in
2151
+ * degrees, the resolution is in pixels per degree, and marker locations
2152
+ * are pixel offsets into the image. Ask this instead of checking
2153
+ * `map_type` — georeferenced IIIF (`map_bbox` without `map_as_image`)
2154
+ * is an ordinary mercator map.
2155
+ */
2156
+ isImageSpace(): boolean;
2157
+ /**
2158
+ * The `uniqueid` of a slide — the current one by default.
2159
+ *
2160
+ * A IIIF manifest supplies one per canvas (§2.3) and it is the only
2161
+ * identity a link can be built on, since an index moves when a slide is
2162
+ * inserted. A storymap-JSON slide usually has none, in which case this is
2163
+ * `null` rather than a generated id: a random one would be stable to nobody.
2164
+ */
2165
+ getSlideId(index?: number): string | null;
2166
+ /**
2167
+ * Read the annotation documents this manifest points at with `seeAlso` and
2168
+ * add the tour stops they carry.
2169
+ *
2170
+ * Explicit and asynchronous on purpose (§5.2). The alternative — following
2171
+ * `seeAlso` inside `manifestToStorymapData` — would mean one blocking
2172
+ * network round trip per referenced document before the viewer could paint
2173
+ * its first slide, against third-party servers the host may not want to
2174
+ * contact at all. Here the story stands on its own immediately and the
2175
+ * annotations arrive afterwards, behind a per-(id, type) cache, and
2176
+ * `annotationsloaded` fires when they are in.
2177
+ *
2178
+ * The stops are **appended**, not placed after the canvas they annotate.
2179
+ * A canvas's own annotations are inserted in position at parse time; doing
2180
+ * the same to a live tour would mean rebuilding the slider and every piece
2181
+ * of state that hangs off it, for an ordering nicety. A host that needs
2182
+ * the stops placed exactly can read them off the resolved value and place
2183
+ * them itself.
2184
+ *
2185
+ * @returns the stops that were added, keyed by canvas id, plus any
2186
+ * `SearchService1` endpoint seen and any document that failed to load.
2187
+ */
2188
+ loadAnnotations(options?: {
2189
+ fetchImpl?: typeof fetch;
2190
+ }): Promise<{
2191
+ stops: StorymapSlide[];
2192
+ searchService: string | null;
2193
+ failed: string[];
2194
+ }>;
2195
+ /**
2196
+ * Release everything the viewer attached to the page: window/document
2197
+ * listeners, timers, the resize observer, running Web Animations, the
2198
+ * slider, the menubar, the map and the map markers. Use this when tearing
2199
+ * a storymap down (SPA route change, modal close).
2200
+ *
2201
+ * Teardown is terminal: the host container is emptied, `map` becomes
2202
+ * null, and the public methods (`goTo`, `setMapOptions`,
2203
+ * `createMiniMap`, ...) become no-ops rather than throwing. There is no
2204
+ * re-init path; build a new StoryMap on the same element instead.
2205
+ * Calling `dispose()` twice is a no-op.
2206
+ */
2207
+ dispose(): void;
2208
+ /* Excluded from this release type: element */
2209
+ /* Excluded from this release type: interaction */
2210
+ /** The highlighted route line drawn up to the current slide. */
2211
+ getLineActive(): OlLayer | null;
2212
+ /** The map markers, indexed by slide. */
2213
+ getMarkers(): StoryMapMarker[];
2214
+ /** One map marker by slide index, or `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;
2234
+ /**
2235
+ * Rebuild the minimap (`OverviewMap` control). The constructor already
2236
+ * builds it; this is for hosts that recreate it after a `map_type` swap
2237
+ * or a deferred tile-consent grant.
2238
+ */
2239
+ createMiniMap(): void;
2240
+ /**
2241
+ * Append attribution fragments and refresh the credit line (e.g. for a
2242
+ * custom layer added through `tile_source_factory`).
2243
+ */
2244
+ setExtraAttributions(parts: string[]): void;
2245
+ /**
2246
+ * Publish the text colour custom properties. Called from both the initial
2247
+ * layout and every runtime option change (issue #177) so the two paths
2248
+ * cannot drift.
2249
+ */
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;
1051
2263
  _initLayout(): void;
1052
2264
  _initEvents(): void;
1053
2265
  _onKeyDownGlobal(e: KeyboardEvent): void;
1054
2266
  _updateDisplay(map_height?: number, animate?: boolean, d?: number): void;
1055
2267
  _onDataLoaded(e?: unknown): void;
2268
+ /**
2269
+ * Start-of-story consent (issue: allow all / individually / decline
2270
+ * all): with `consent_required`, one dialog lists every external
2271
+ * service the story uses — map tiles, external web fonts and the media
2272
+ * services in the slides. Shown only while some service is unanswered;
2273
+ * per-service slide asks remain the fallback.
2274
+ */
2275
+ _startConsentAsk(): void;
2276
+ /**
2277
+ * Play the current slide's narration, if it has one.
2278
+ *
2279
+ * One `<audio>` element is reused for the whole story rather than a
2280
+ * player per slide, so switching slides cannot leave a recording playing
2281
+ * behind. Two things gate it:
2282
+ *
2283
+ * - **browser autoplay policy**: unmuted audio only plays after a user
2284
+ * gesture, so before the first interaction the element is left paused
2285
+ * and nothing is reported as broken. Re-arm on the first interaction.
2286
+ * - **consent**: the `media:narration` service is requested at start-up
2287
+ * (see `_startConsentAsk`); a denied or unanswered service means no
2288
+ * playback, and the story still works.
2289
+ */
2290
+ _playNarration(slide: StorymapSlide | undefined, allow_without_gesture?: boolean): 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;
2317
+ /** A gesture has happened, so unmuted audio is allowed from now on. */
2318
+ _note_user_gesture_for_narration(): void;
2319
+ _has_user_gesture(): boolean;
1056
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;
2334
+ /**
2335
+ * Arm autoplay for the current slide.
2336
+ *
2337
+ * With `autoplay_media` on and a slide whose media is playable audio or
2338
+ * video, the advance waits for that media to end instead of using the
2339
+ * `autoplay` millisecond timer. The timer is **kept as a fallback** in
2340
+ * that case too: a media element that never fires `ended` (a stalled
2341
+ * fetch, a codec the browser cannot play, or a slide whose media was
2342
+ * never loaded because the visitor skipped past it) would otherwise stop
2343
+ * the story dead. So both are armed, whichever fires first advances, and
2344
+ * the other is cleared.
2345
+ */
1057
2346
  _scheduleAutoplay(): void;
1058
2347
  _stopAutoplay(): void;
1059
- /** Keep the URL hash in sync with the current slide (#slide-N). */
2348
+ /**
2349
+ * The current slide's `uniqueid`, or null when the data carries none.
2350
+ *
2351
+ * A storymap-JSON slide usually has no `uniqueid` — the slider generates
2352
+ * one per slide for its own DOM ids, but that is not a shareable identity,
2353
+ * so it is deliberately not used here. A IIIF manifest supplies one per
2354
+ * canvas (§2.3), and that is what a deep link should name.
2355
+ */
2356
+ _currentSlideId(): string | null;
2357
+ /** The current slide as a Content State, or null when it has no id. */
2358
+ _currentContentState(): ContentState | null;
2359
+ /**
2360
+ * Keep the URL in sync with the current slide: the `#slide-…` hash and,
2361
+ * when the slide has a shareable id, an `iiif-content` parameter (§5.1).
2362
+ *
2363
+ * The query string is rewritten rather than replaced, because pages like
2364
+ * the embed player and the test harness carry their own configuration in
2365
+ * it (`?url=…`, `?example=…`, `?manifest=…`).
2366
+ */
1060
2367
  _syncHash(): void;
1061
- /** A #slide-N hash deep-links the storymap (applied on load + hashchange). */
1062
- _applyHashSlide(): boolean;
2368
+ /**
2369
+ * A `#slide-…` hash or an `iiif-content` parameter deep-links the storymap
2370
+ * (applied on load + hashchange).
2371
+ *
2372
+ * The hash token is an index when it is all digits and a `uniqueid`
2373
+ * otherwise, which is unambiguous because an index never contains anything
2374
+ * else. The index form stays supported, so links shared before ids were
2375
+ * emitted keep working; they just stop being stable the moment a slide is
2376
+ * inserted.
2377
+ */
2378
+ _applyHashSlide(captured?: {
2379
+ state: ContentState | null;
2380
+ hash: string;
2381
+ } | null): boolean;
2382
+ /**
2383
+ * A content state or hash token as a slide index, or null when it names
2384
+ * nothing. A content state wins over the hash, being the standard spelling.
2385
+ */
2386
+ _resolveDeepLink(state: ContentState | null, hash: string): number | null;
2387
+ /** A canvas id as a slide index, or null. */
2388
+ _slideIndexById(id: string): number | null;
1063
2389
  _initResizeHandling(): void;
1064
2390
  /**
1065
2391
  * Resolve a caller-supplied map element (options.map_options.element).
@@ -1067,8 +2393,22 @@ declare class StoryMapBase {
1067
2393
  * map container (given the vco-map class) and moved into place between
1068
2394
  * the menubar and the story slider.
1069
2395
  */
2396
+ /**
2397
+ * The map pane, for the code paths that only run when there is a map.
2398
+ * `_el.map` is null exactly when the engine is; see `_map_required()`.
2399
+ */
2400
+ _map_el(): HTMLElement;
2401
+ /**
2402
+ * The map engine, for the code paths that only run when there is a map.
2403
+ * Throws rather than returning null: reaching one of these from a mapless
2404
+ * story is a bug in this class, and a loud one, rather than a layout that
2405
+ * quietly misbehaves. Public entry points use `this._map?.` instead.
2406
+ */
2407
+ _map_required(): OpenLayers;
1070
2408
  _resolveMapElement(): HTMLElement | null;
1071
- _onTitle(e: unknown): void;
2409
+ _onTitle(e: {
2410
+ title: string;
2411
+ }): void;
1072
2412
  _onColorChange(e: {
1073
2413
  color?: unknown;
1074
2414
  image?: unknown;
@@ -1079,6 +2419,45 @@ declare class StoryMapBase {
1079
2419
  _onMapChange(e: {
1080
2420
  current_marker: number;
1081
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;
1082
2461
  _updateProgress(): void;
1083
2462
  _onOverview(e?: unknown): void;
1084
2463
  /**
@@ -1089,7 +2468,8 @@ declare class StoryMapBase {
1089
2468
  _onFullscreenChange(): void;
1090
2469
  _onBackToStart(e?: unknown): void;
1091
2470
  _onMenuBarCollapse(e: {
1092
- y: number;
2471
+ y?: number;
2472
+ collapsed?: boolean;
1093
2473
  }): void;
1094
2474
  _onMapLoaded(): void;
1095
2475
  _onStorySliderLoaded(): void;
@@ -1098,40 +2478,498 @@ declare class StoryMapBase {
1098
2478
  * (issue #341); hidden when `show_distance` is off.
1099
2479
  */
1100
2480
  _updateDistance(): void;
2481
+ /**
2482
+ * The URL is ours to own as soon as the story is: the deep link is read
2483
+ * and the hash is kept in step.
2484
+ *
2485
+ * This deliberately does **not** wait for the map. The map only reports
2486
+ * itself loaded on OpenLayers' first `loadend`, which is the first paint of
2487
+ * the base tiles — so a deep link used to be applied only once
2488
+ * `tile.openstreetmap.org` answered, and on a slow or unreachable tile
2489
+ * host it was never applied at all. Nothing about a URL depends on imagery:
2490
+ * the data and the slider are what it needs, and both are ready before the
2491
+ * map is. `_applyHashSlide` → `goTo` → `_navigate` already tolerates a map
2492
+ * that has not reported loaded, and the map re-syncs when it does.
2493
+ */
2494
+ _initHash(): void;
1101
2495
  _onLoaded(): void;
1102
2496
  }
1103
2497
 
1104
- declare interface StorymapData {
1105
- uniqueid?: string;
1106
- slides: StorymapSlide[];
1107
- [key: string]: unknown;
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
+
2524
+ export declare interface StorymapData {
2525
+ uniqueid?: string;
2526
+ slides: StorymapSlide[];
2527
+ credit?: StorymapCredit | null;
2528
+ [key: string]: unknown;
2529
+ }
2530
+
2531
+ export declare interface StorymapDataWrapper {
2532
+ storymap: StorymapData;
2533
+ }
2534
+
2535
+ /**
2536
+ * The document {@link storymapToManifest} reads: the `{ "storymap": {...} }`
2537
+ * wrapper a `storymap.json` file is, with every member optional.
2538
+ *
2539
+ * The root is `Partial<StorymapData>` — every legacy key is optional and the
2540
+ * files in the wild carry more than the schema documents — or a plain record,
2541
+ * which is what a document read straight out of `JSON.parse` is. The wrapper
2542
+ * itself is open, because the legacy files also carry a root-level `font_css`
2543
+ * and the map configuration service prefers it over the key inside `storymap`.
2544
+ */
2545
+ export declare interface StorymapDocument {
2546
+ storymap?: Partial<StorymapData> | Record<string, unknown>;
2547
+ [key: string]: unknown;
2548
+ }
2549
+
2550
+ export declare interface StorymapError {
2551
+ path: string;
2552
+ message: string;
2553
+ }
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
+
2608
+ /**
2609
+ * A IIIF Georeference Extension annotation body plus the image it places
2610
+ * (`overlays[].georeference`). The `body` is the annotation payload of
2611
+ * `iiif.io/api/extension/georef` verbatim: a GeoJSON FeatureCollection of
2612
+ * ground control points pairing `properties.resourceCoords` (image pixels)
2613
+ * with `geometry.coordinates` (WGS84 lon/lat), optionally carrying a
2614
+ * `transformation` hint.
2615
+ *
2616
+ * The viewer fits the affine (first-order polynomial) case and places the
2617
+ * image with OpenLayers' reprojection, which requires an axis-aligned
2618
+ * placement; rotated or skewed sheets, higher-order polynomials and thin
2619
+ * plate splines are reported and skipped — see the "Geo-referenced layers"
2620
+ * section of docs/storymap-as-iiif-manifest.md.
2621
+ */
2622
+ export declare interface StorymapGeoreference {
2623
+ /** IIIF Image API service base (or a full-size image URL) to place */
2624
+ url: string;
2625
+ /** Image width in pixels (the resourceCoords space) */
2626
+ width: number;
2627
+ /** Image height in pixels */
2628
+ height: number;
2629
+ /** Georeference annotation body: the GCP FeatureCollection */
2630
+ body: StorymapGeoreferenceBody;
2631
+ }
2632
+
2633
+ export declare interface StorymapGeoreferenceBody {
2634
+ type?: string;
2635
+ /** `polynomial` with `order: 1`, or absent; other values are skipped */
2636
+ transformation?: {
2637
+ type?: string;
2638
+ options?: {
2639
+ order?: number;
2640
+ };
2641
+ };
2642
+ features: StorymapGroundControlPoint[];
2643
+ }
2644
+
2645
+ /** One ground control point: an image pixel paired with a WGS84 position */
2646
+ export declare interface StorymapGroundControlPoint {
2647
+ type?: string;
2648
+ properties?: {
2649
+ resourceCoords?: [number, number];
2650
+ };
2651
+ geometry?: {
2652
+ type?: string;
2653
+ coordinates?: number[];
2654
+ };
2655
+ }
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
+
2671
+ /** A IIIF Presentation 3 language map; only the neutral `none` tag is written. */
2672
+ export declare interface StorymapLanguageMap {
2673
+ none: string[];
1108
2674
  }
1109
2675
 
1110
- export declare interface StorymapDataWrapper {
1111
- storymap: StorymapData;
2676
+ declare type StoryMapListener<K extends keyof StoryMapEvents = keyof StoryMapEvents> = (e: FiredEvent<StoryMapEvents, K>) => void;
2677
+
2678
+ export declare interface StorymapManifest {
2679
+ "@context": string[];
2680
+ id: string;
2681
+ type: "Manifest";
2682
+ label: StorymapLanguageMap;
2683
+ behavior: string[];
2684
+ metadata: {
2685
+ label: StorymapLanguageMap;
2686
+ value: StorymapLanguageMap;
2687
+ }[];
2688
+ items: StorymapManifestCanvas[];
2689
+ structures?: StorymapManifestRange[];
2690
+ navPlace?: StorymapManifestFeatureCollection;
2691
+ service?: StorymapManifestService[];
2692
+ requiredStatement?: StorymapManifestStatement;
1112
2693
  }
1113
2694
 
1114
- declare interface StorymapError {
1115
- path: string;
1116
- message: string;
2695
+ /** A painting annotation: the slide's own media, painted onto its canvas. */
2696
+ export declare interface StorymapManifestAnnotation {
2697
+ id: string;
2698
+ type: "Annotation";
2699
+ motivation: string;
2700
+ /** The media caption, as the annotation's own `label` (§2.7). */
2701
+ label?: StorymapLanguageMap;
2702
+ /** The media credit (§2.7). P3 allows a single object, not an array. */
2703
+ requiredStatement?: StorymapManifestStatement;
2704
+ /** The media alt text (§2.7). */
2705
+ accessibilitySummary?: StorymapLanguageMap;
2706
+ body: StorymapManifestContentResource;
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;
2714
+ }
2715
+
2716
+ /** A canvas `background`: a painting annotation of the slide's backdrop (§2.6). */
2717
+ export declare interface StorymapManifestBackground {
2718
+ id: string;
2719
+ type: "Annotation";
2720
+ motivation: "painting";
2721
+ body: StorymapManifestContentResource | StorymapManifestContentResource[];
2722
+ target: string;
2723
+ }
2724
+
2725
+ export declare interface StorymapManifestCanvas {
2726
+ id: string;
2727
+ type: "Canvas";
2728
+ width: number;
2729
+ height: number;
2730
+ /** The slide's date, which P3 constrains to a plain string (§2.5). */
2731
+ navDate?: string;
2732
+ background?: StorymapManifestBackground;
2733
+ thumbnail?: StorymapManifestContentResource[];
2734
+ items: {
2735
+ id: string;
2736
+ type: "AnnotationPage";
2737
+ items: (StorymapManifestAnnotation | StorymapManifestGeoreferencing)[];
2738
+ }[];
2739
+ label?: StorymapLanguageMap;
2740
+ summary?: StorymapLanguageMap;
2741
+ /** An overview slide, which the map's `overview` type carries (§2.4). */
2742
+ "storymap:type"?: string;
2743
+ "storymap:mediaSrcset"?: unknown;
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;
2755
+ navPlace?: StorymapManifestFeatureCollection;
2756
+ }
2757
+
2758
+ /**
2759
+ * A content resource: a painting body, a thumbnail or a background.
2760
+ *
2761
+ * One permissive interface rather than a discriminated union, because the
2762
+ * emitter only writes these: the shapes it produces are the classified media
2763
+ * body, a IIIF `Image`, a `TextualBody` and a `Color`, and they are
2764
+ * distinguished by `type` for the reader, not for us.
2765
+ */
2766
+ export declare interface StorymapManifestContentResource {
2767
+ id?: string;
2768
+ type: string;
2769
+ format?: string;
2770
+ width?: number;
2771
+ height?: number;
2772
+ value?: string;
2773
+ service?: StorymapManifestImageService[];
2774
+ }
2775
+
2776
+ /** A navPlace FeatureCollection: a point for a location, a Polygon for a bbox. */
2777
+ export declare interface StorymapManifestFeatureCollection {
2778
+ id: string;
2779
+ type: "FeatureCollection";
2780
+ features: {
2781
+ id: string;
2782
+ type: "Feature";
2783
+ geometry: {
2784
+ type: string;
2785
+ coordinates: number[] | number[][] | number[][][];
2786
+ };
2787
+ /** Marker presentation, described by navplace-properties.json (§3.3). */
2788
+ properties: Record<string, unknown>;
2789
+ }[];
2790
+ }
2791
+
2792
+ /** A Georeference Extension annotation for a placed raster (§2.10). */
2793
+ export declare interface StorymapManifestGeoreferencing {
2794
+ id: string;
2795
+ type: "Annotation";
2796
+ motivation: "georeferencing";
2797
+ target: {
2798
+ id: string;
2799
+ type: "Image";
2800
+ width: number;
2801
+ height: number;
2802
+ service: StorymapManifestImageService[];
2803
+ };
2804
+ requiredStatement?: StorymapManifestStatement;
2805
+ body: StorymapGeoreferenceBody;
2806
+ }
2807
+
2808
+ /** A IIIF Image API service reference. */
2809
+ export declare interface StorymapManifestImageService {
2810
+ id: string;
2811
+ type: string;
2812
+ profile: string;
1117
2813
  }
1118
2814
 
1119
- declare type StoryMapListener = (e: unknown) => void;
2815
+ /** One P3 `Range` over the canvases of a `slide.group` (§3.5). */
2816
+ export declare interface StorymapManifestRange {
2817
+ id: string;
2818
+ type: "Range";
2819
+ label: StorymapLanguageMap;
2820
+ items: string[];
2821
+ }
2822
+
2823
+ /**
2824
+ * The map configuration service entry, keyed by the `storymap:` terms.
2825
+ *
2826
+ * Open by necessity: the official validator's Manifest schema is
2827
+ * `additionalProperties: false`, which is exactly why the map configuration
2828
+ * travels on a service of its own rather than on the Manifest (§3.1).
2829
+ */
2830
+ export declare interface StorymapManifestService {
2831
+ id: string;
2832
+ type: "Service";
2833
+ profile: string;
2834
+ [term: string]: unknown;
2835
+ }
2836
+
2837
+ /** A painting annotation whose target is a region of a larger image (§2.8). */
2838
+ export declare interface StorymapManifestSpecificResource {
2839
+ type: "SpecificResource";
2840
+ source: string;
2841
+ selector: {
2842
+ type: "ImageApiSelector";
2843
+ value: string;
2844
+ };
2845
+ }
2846
+
2847
+ /** A `{label, value}` pair — the P3 shape for a caption, credit or rights line. */
2848
+ export declare interface StorymapManifestStatement {
2849
+ label: StorymapLanguageMap;
2850
+ value: StorymapLanguageMap;
2851
+ }
1120
2852
 
1121
2853
  /** OpenLayers passthrough options (see StorymapOptions.map_options) */
1122
- declare interface StorymapMapOptions {
2854
+ export declare interface StorymapMapOptions {
1123
2855
  /** HTMLElement or DOM id that becomes the real map container */
1124
2856
  element?: HTMLElement | string;
1125
2857
  /** Merged over the default view configuration */
1126
2858
  view?: Record<string, unknown>;
1127
2859
  /** Replaces the default (empty) controls list */
1128
2860
  controls?: unknown[];
1129
- /** Replaces the default (empty) interactions list */
2861
+ /**
2862
+ * Added to the viewer's own pan/zoom interactions (not a replacement:
2863
+ * the viewer's defaults are always added). `controls` *is* a
2864
+ * replacement, since the viewer adds none of its own.
2865
+ */
1130
2866
  interactions?: unknown[];
1131
2867
  /** Any other ol/Map constructor option (layers, pixelRatio, ...) */
1132
2868
  [key: string]: unknown;
1133
2869
  }
1134
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
+
1135
2973
  export declare interface StorymapOptions {
1136
2974
  width: number;
1137
2975
  height: number;
@@ -1147,7 +2985,6 @@ export declare interface StorymapOptions {
1147
2985
  left: number;
1148
2986
  top: number;
1149
2987
  } | null;
1150
- less_bounce: boolean;
1151
2988
  start_at_slide: number;
1152
2989
  call_to_action: boolean;
1153
2990
  call_to_action_text: string;
@@ -1161,7 +2998,6 @@ export declare interface StorymapOptions {
1161
2998
  skinny_size: number;
1162
2999
  duration: number;
1163
3000
  ease: unknown;
1164
- dragging: boolean;
1165
3001
  trackResize: boolean;
1166
3002
  /**
1167
3003
  * Navigate slides with arrow keys anywhere on the page (default false:
@@ -1173,18 +3009,57 @@ export declare interface StorymapOptions {
1173
3009
  nocache: boolean;
1174
3010
  /** Advance slides automatically every N milliseconds; 0 disables (issue #380) */
1175
3011
  autoplay: number;
3012
+ /**
3013
+ * With autoplay on, wait for the current slide's audio or video to end
3014
+ * before advancing instead of using the `autoplay` millisecond timer,
3015
+ * which stays as the fallback. Slides without playable media keep the
3016
+ * timer, so a mixed story never stalls.
3017
+ */
3018
+ autoplay_media: boolean;
1176
3019
  /** Show a progress bar in the menubar (issue #247) */
1177
3020
  show_progress: boolean;
1178
- /** 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) */
1179
3030
  marker_labels: boolean;
1180
3031
  /** Default text alignment for slide text: left, center or right (issue #244) */
1181
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;
1182
3048
  /** Override the overview fit center (issues #107, #271) */
1183
3049
  map_overview_center: {
1184
3050
  lat: number;
1185
3051
  lon: number;
1186
3052
  } | null;
1187
3053
  map_type: string;
3054
+ /**
3055
+ * Custom OpenLayers tile layer/source factory (issue #473): consulted
3056
+ * by the tile layer factory before the built-in `map_type` switch, for
3057
+ * every base, overlay and minimap layer. Return a `TileLayer` (or a
3058
+ * bare `Source`, auto-wrapped in one) for custom handling — e.g. WMS —
3059
+ * or `null`/`undefined` to fall through to the default types.
3060
+ * Constructor- and runtime-only: functions cannot ride storymap JSON.
3061
+ */
3062
+ tile_source_factory: TileSourceFactory | null;
1188
3063
  attribution: string;
1189
3064
  /**
1190
3065
  * Stacked raster overlays above the base map, below the route lines.
@@ -1193,8 +3068,16 @@ export declare interface StorymapOptions {
1193
3068
  * (default) means base map only.
1194
3069
  */
1195
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[];
1196
3080
  map_mini: boolean;
1197
- map_subdomains: string;
1198
3081
  map_as_image: boolean;
1199
3082
  map_access_token: string;
1200
3083
  map_background_color: string;
@@ -1233,7 +3116,9 @@ export declare interface StorymapOptions {
1233
3116
  /**
1234
3117
  * Ask for permission before loading anything from external services
1235
3118
  * (media embeds, map tiles, external font CSS) — GDPR consent mode.
1236
- * Grants are remembered per service in a cookie for 90 days.
3119
+ * Decisions are remembered per service in `localStorage` under
3120
+ * `storymapjs-consent` with no expiry: clearing site data is what makes
3121
+ * the viewer ask again.
1237
3122
  */
1238
3123
  consent_required: boolean;
1239
3124
  /** Slide text color override, sets --vco-color-text (issue #177) */
@@ -1243,14 +3128,84 @@ export declare interface StorymapOptions {
1243
3128
  /** Show the great-circle route distance in the menubar (issue #341) */
1244
3129
  show_distance: boolean;
1245
3130
  /**
1246
- * Raw OpenLayers map configuration. `controls` and `interactions` replace
1247
- * the StoryMapJS defaults, `view` is merged over the computed default view
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 */
3201
+ /**
3202
+ * Raw OpenLayers map configuration. `controls` replaces the StoryMapJS
3203
+ * defaults, `interactions` are *added to* the viewer's own pan/zoom
3204
+ * interactions, and `view` is merged over the computed default view
1248
3205
  * and `element` (an HTMLElement or DOM id) replaces the auto-created map
1249
3206
  * container div.
1250
3207
  */
1251
3208
  map_options: StorymapMapOptions;
1252
- map_popup: boolean;
1253
- zoom_distance: number;
1254
3209
  calculate_zoom: boolean;
1255
3210
  line_follows_path: boolean;
1256
3211
  line_color: string;
@@ -1262,19 +3217,47 @@ export declare interface StorymapOptions {
1262
3217
  show_lines: boolean;
1263
3218
  show_history_line: boolean;
1264
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
+ */
1265
3227
  iiif: {
1266
3228
  url: string;
1267
3229
  attribution: string;
3230
+ width?: number;
3231
+ height?: number;
3232
+ fallbackUrl?: string;
1268
3233
  };
3234
+ tilejson?: StorymapTilejson;
3235
+ /**
3236
+ * The `seeAlso` targets a IIIF manifest points at, recorded but not
3237
+ * fetched — see `loadSeeAlso()`.
3238
+ */
3239
+ see_also?: {
3240
+ id: string;
3241
+ type: string;
3242
+ }[];
1269
3243
  map_height: number;
1270
3244
  storyslider_height: number;
1271
3245
  slide_padding_lr: number;
1272
3246
  slide_default_fade: string;
1273
3247
  menubar_default_y: number;
1274
- path_gfx: string;
1275
3248
  script_path: string;
1276
- 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;
1277
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";
1278
3261
  api_key_flickr: string;
1279
3262
  [key: string]: unknown;
1280
3263
  }
@@ -1284,9 +3267,13 @@ export declare interface StorymapOptions {
1284
3267
  * Presentation is declarative: hosts no longer need to reach into the
1285
3268
  * layer objects for blend modes, clips or stacking tweaks.
1286
3269
  */
1287
- declare interface StorymapOverlayLayer {
1288
- /** Any `map_type` value the tile layer factory accepts */
1289
- map_type: string;
3270
+ export declare interface StorymapOverlayLayer {
3271
+ /**
3272
+ * Any `map_type` value the tile layer factory accepts. Required unless
3273
+ * the entry carries a `georeference` (a placed IIIF image instead of
3274
+ * a tile source).
3275
+ */
3276
+ map_type?: string;
1290
3277
  /** Layer opacity 0..1 (default 1) */
1291
3278
  opacity?: number;
1292
3279
  /** Initial visibility (default true) */
@@ -1303,32 +3290,156 @@ declare interface StorymapOverlayLayer {
1303
3290
  className?: string;
1304
3291
  /** CSS mix-blend-mode for the layer container (needs className) */
1305
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;
1306
3310
  /** Clip box `[west, south, east, north]` in lon/lat (mercator maps) */
1307
3311
  extent?: [number, number, number, number];
3312
+ /**
3313
+ * IIIF Georeference Extension placement instead of a tile source. The
3314
+ * ground control points are fitted affinely and the image is placed on
3315
+ * the geographic map, so this is the manifest-side equivalent of a
3316
+ * georeferenced raster overlay.
3317
+ */
3318
+ georeference?: StorymapGeoreference;
1308
3319
  }
1309
3320
 
3321
+ /**
3322
+ * One slide of a storymap.
3323
+ *
3324
+ * The nullable members (`| null`) are not decoration: the storymap JSON uses
3325
+ * `null` to mean "explicitly absent" and the viewer seeds its own defaults
3326
+ * with `null` before the data is merged in, so a plain `?` would not type.
3327
+ */
1310
3328
  export declare interface StorymapSlide {
1311
3329
  type?: string;
1312
3330
  date?: string | Record<string, unknown> | null;
1313
3331
  group?: string;
1314
- location?: StorymapSlideLocation;
1315
- media?: StorymapSlideMedia;
1316
- text?: StorymapSlideText;
3332
+ /**
3333
+ * The language tag this slide's text was read in. A IIIF manifest states its text as a
3334
+ * language map; the reader picks the viewer's configured language and
3335
+ * reports which one it used, so a host can offer a language switch.
3336
+ * Absent for language-neutral (`none`) text, and for a single-language
3337
+ * storymap.
3338
+ */
3339
+ language?: string;
3340
+ location?: StorymapSlideLocation | null;
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";
3357
+ marker?: StorymapSlideMarker | null;
3358
+ narration?: StorymapSlideNarration | null;
3359
+ text?: StorymapSlideText | null;
1317
3360
  background?: StorymapSlideBackground | string | null;
1318
- uniqueid?: string;
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;
1319
3382
  [key: string]: unknown;
1320
3383
  }
1321
3384
 
1322
- declare interface StorymapSlideBackground {
3385
+ export declare interface StorymapSlideBackground {
1323
3386
  url?: string | null;
1324
3387
  color?: string | null;
1325
3388
  opacity?: number;
1326
3389
  }
1327
3390
 
1328
- declare interface StorymapSlideLocation {
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
+
3405
+ export declare interface StorymapSlideLocation {
1329
3406
  lat?: number;
1330
3407
  lon?: number;
1331
3408
  zoom?: number;
3409
+ /**
3410
+ * Image region `[x, y, w, h]` in image pixels (IIIF xywh convention,
3411
+ * slideshow-style image stops): the view fits the region on
3412
+ * navigation; image maps (`map_type: "iiif"` + `map_as_image`) only.
3413
+ */
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;
1332
3443
  line?: boolean;
1333
3444
  icon?: string;
1334
3445
  iconSize?: number[];
@@ -1337,40 +3448,194 @@ declare interface StorymapSlideLocation {
1337
3448
  [key: string]: unknown;
1338
3449
  }
1339
3450
 
1340
- declare interface StorymapSlideMedia {
3451
+ /**
3452
+ * Per-slide marker presentation, consolidated. `location.*` keeps working as
3453
+ * the legacy spelling and `marker.*` wins when present.
3454
+ *
3455
+ * In a IIIF manifest none of this is a `storymap:` term: it all arrives in the
3456
+ * `navPlace` Feature's `properties` bag (`icon`, `iconSize`, `image`, `name`,
3457
+ * `popup`, `audioBadge`), which is a GeoJSON foreign-member bag and so needs
3458
+ * no vocabulary registration.
3459
+ */
3460
+ export declare interface StorymapSlideMarker {
3461
+ icon?: string;
3462
+ iconSize?: number[];
3463
+ image?: string;
3464
+ /** The marker label; in a manifest this is `properties.name`. */
3465
+ label?: string;
3466
+ /** Show the popup card when this (active) marker is clicked. */
3467
+ popup?: boolean;
3468
+ /** Mark slides that carry narration or audio media with a small badge. */
3469
+ audioBadge?: boolean;
3470
+ [key: string]: unknown;
3471
+ }
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
+
3488
+ export declare interface StorymapSlideMedia {
1341
3489
  url?: string | null;
1342
3490
  caption?: string | null;
1343
3491
  credit?: string | null;
3492
+ /**
3493
+ * Accessible description of the media, used as the image's `alt` when the
3494
+ * media is an image. In IIIF this is the painting annotation's
3495
+ * `accessibilitySummary`.
3496
+ */
3497
+ alt?: string | null;
1344
3498
  thumb?: string | null;
1345
3499
  mediatype?: MediaTypeMatch | null;
3500
+ /**
3501
+ * WebVTT subtitle file for an audio or video slide, rendered as a
3502
+ * `<track kind="subtitles">`. IIIF has no subtitle term, so this stays a
3503
+ * storymap-JSON field; the authoring guide notes the
3504
+ * `TextualBody` + `format: text/vtt` shape we also accept.
3505
+ */
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;
3530
+ [key: string]: unknown;
3531
+ }
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
+ */
3540
+ export declare interface StorymapSlideNarration {
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;
1346
3584
  [key: string]: unknown;
1347
3585
  }
1348
3586
 
1349
- declare interface StorymapSlideText {
3587
+ export declare interface StorymapSlideText {
1350
3588
  headline?: string;
1351
3589
  text?: string;
1352
3590
  text_align?: string;
1353
3591
  }
1354
3592
 
3593
+ /**
3594
+ * TileJSON 2.1 tile source metadata, from a manifest's map configuration
3595
+ * service.
3596
+ *
3597
+ * This is how a manifest states a tile source: `tiles` is the URL template and
3598
+ * the rest is the standard metadata around it, where a keyword basemap
3599
+ * (`osm`, `stadia`, `iiif`, …) has no such thing to say. `minzoom`,
3600
+ * `maxzoom`, `bounds` and `scheme` constrain the source; `center` and `zoom`
3601
+ * set the initial view.
3602
+ */
3603
+ export declare interface StorymapTilejson {
3604
+ /** URL template, e.g. `https://tiles.example.org/{z}/{x}/{y}.png` */
3605
+ tiles: string | string[];
3606
+ /** Lowest zoom level the source has tiles for */
3607
+ minzoom?: number;
3608
+ /** Highest zoom level the source has tiles for */
3609
+ maxzoom?: number;
3610
+ /** `[west, south, east, north]`, WGS84 lon/lat, of the covered area */
3611
+ bounds?: [number, number, number, number];
3612
+ /** `xyz` (default) or `tms`, which flips the tile row order */
3613
+ scheme?: "xyz" | "tms";
3614
+ /** `[lon, lat, zoom]` of the map's default view */
3615
+ center?: [number, number, number];
3616
+ }
3617
+
3618
+ /**
3619
+ * Convert a legacy storymap document to a IIIF Presentation 3.0 manifest.
3620
+ *
3621
+ * The counterpart of `manifestToStorymapData()`: what that reads, this writes.
3622
+ * Nothing but the input is read, so the same document always produces the same
3623
+ * manifest — which is what makes regenerating `public/examples-iiif/` a no-op.
3624
+ *
3625
+ * @param name - The manifest's label, and the stem of its canonical id.
3626
+ * @param legacy - The `storymap.json` document (`{ "storymap": {...} }`).
3627
+ * @returns The manifest, ready to serialise.
3628
+ */
3629
+ export declare function storymapToManifest(name: string, legacy: StorymapDocument): StorymapManifest;
3630
+
1355
3631
  declare class StorySlider extends StorySlider_base {
1356
3632
  constructor(...args: ConstructorParameters<typeof StorySliderBase>);
1357
3633
  }
1358
3634
 
1359
- declare const StorySlider_base: {
1360
- new (...args: any[]): {
1361
- _vco_events?: Record<string, {
1362
- action: unknown;
1363
- context: unknown;
1364
- }[]>;
1365
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
1366
- hasEventListeners(type: string): boolean;
1367
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
1368
- fire(type: string, data?: unknown, target?: unknown): /*elided*/ any;
1369
- };
1370
- } & typeof StorySliderBase;
3635
+ declare const StorySlider_base: Constructor<EventedInstance<StorySliderEvents>> & typeof StorySliderBase;
1371
3636
 
1372
3637
  declare class StorySliderBase {
1373
- "_el": Record<string, HTMLElement>;
3638
+ "_el": StorySliderElements;
1374
3639
  "_nav": {
1375
3640
  previous: SlideNav;
1376
3641
  next: SlideNav;
@@ -1378,17 +3643,24 @@ declare class StorySliderBase {
1378
3643
  "slide_spacing": number;
1379
3644
  "_slides": Slide[];
1380
3645
  "_swipable": Swipable;
1381
- "preloadTimer": ReturnType<typeof setTimeout>;
3646
+ "preloadTimer": ReturnType<typeof setTimeout> | undefined;
3647
+ "preloadIdleHandle": number | undefined;
1382
3648
  "_message": Message;
1383
3649
  "current_slide": number;
1384
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;
1385
3654
  "data": Partial<StorymapData>;
1386
3655
  "options": StorySliderOptions;
1387
3656
  "animator": AnimationHandle | null;
1388
3657
  "animator_background": AnimationHandle | null;
1389
- "fire": EventedInstance["fire"];
3658
+ "fire": EventedInstance<StorySliderEvents>["fire"];
1390
3659
  "_loaded": boolean;
1391
- "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;
1392
3664
  constructor(elem: HTMLElement | string, data: Partial<StorymapData>, options?: Partial<StorySliderOptions>, init?: boolean);
1393
3665
  init(): void;
1394
3666
  updateDisplay(w?: number, h?: number, a?: unknown, l?: string): void;
@@ -1398,7 +3670,21 @@ declare class StorySliderBase {
1398
3670
  _createSlide(d: StorymapSlide, title_slide?: boolean): void;
1399
3671
  _addSlide(slide: Slide): void;
1400
3672
  goToId(n: string | number, fast?: boolean, displayupdate?: boolean): void;
1401
- goTo(n: number, fast?: boolean, displayupdate?: boolean): void;
3673
+ /**
3674
+ * Cancel the pending preload, whichever scheduling primitive queued it.
3675
+ *
3676
+ * The two handles are kept apart deliberately: they are both numbers, so
3677
+ * calling `clearTimeout` on an idle-callback handle "works" by accident
3678
+ * while actually leaking the callback, and the reverse leaves a live
3679
+ * timeout behind.
3680
+ */
3681
+ _cancelPreload(): void;
3682
+ /**
3683
+ * Release listeners, timers and running animations. Called by
3684
+ * `StoryMap.dispose()`; the slider must not be used afterwards.
3685
+ */
3686
+ dispose(): void;
3687
+ goTo(n: number, fast?: boolean, displayupdate?: boolean, fromScroll?: boolean): void;
1402
3688
  preloadSlides(): void;
1403
3689
  getNavInfo(slide: Slide): {
1404
3690
  title: string;
@@ -1409,6 +3695,17 @@ declare class StorySliderBase {
1409
3695
  showNav(nav_obj: SlideNav, show: boolean): void;
1410
3696
  changeBackground(bg: SlideBackgroundChange): void;
1411
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;
1412
3709
  _updateDisplay(width?: number, height?: number, animate?: unknown, layout?: string): void;
1413
3710
  _introInterface(): void;
1414
3711
  _initLayout(): void;
@@ -1419,13 +3716,43 @@ declare class StorySliderBase {
1419
3716
  _onMessageClick(e?: unknown): void;
1420
3717
  _onSwipeNoDirection(e?: unknown): void;
1421
3718
  _onNavigation(e: {
1422
- direction: string;
3719
+ direction: string | null;
1423
3720
  }): void;
1424
3721
  _onSlideAdded(e?: unknown): void;
1425
3722
  _onSlideChange(displayupdate?: boolean): void;
1426
3723
  _onLoaded(): void;
1427
3724
  }
1428
3725
 
3726
+ /**
3727
+ * The slider's element cache.
3728
+ */
3729
+ declare type StorySliderElements = {
3730
+ container: HTMLElement;
3731
+ /** Created in `_initLayout`; the slide background layer. */
3732
+ background: HTMLElement;
3733
+ slider_container_mask: HTMLElement;
3734
+ slider_container: HTMLElement;
3735
+ slider_item_container: HTMLElement;
3736
+ live_region: HTMLElement | null;
3737
+ };
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
+
1429
3756
  declare interface StorySliderOptions {
1430
3757
  id?: string;
1431
3758
  layout: string;
@@ -1444,7 +3771,6 @@ declare interface StorySliderOptions {
1444
3771
  skinny_size?: number;
1445
3772
  call_to_action?: boolean;
1446
3773
  call_to_action_text?: string;
1447
- dragging?: boolean;
1448
3774
  trackResize?: boolean;
1449
3775
  [key: string]: unknown;
1450
3776
  }
@@ -1453,18 +3779,7 @@ declare class Swipable extends Swipable_base {
1453
3779
  constructor(...args: ConstructorParameters<typeof SwipableBase>);
1454
3780
  }
1455
3781
 
1456
- declare const Swipable_base: {
1457
- new (...args: any[]): {
1458
- _vco_events?: Record<string, {
1459
- action: unknown;
1460
- context: unknown;
1461
- }[]>;
1462
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
1463
- hasEventListeners(type: string): boolean;
1464
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
1465
- fire(type: string, data?: unknown, target?: unknown): /*elided*/ any;
1466
- };
1467
- } & typeof SwipableBase;
3782
+ declare const Swipable_base: Constructor<EventedInstance<SwipableEvents>> & typeof SwipableBase;
1468
3783
 
1469
3784
  declare class SwipableBase {
1470
3785
  "mousedrag": DragEventNames;
@@ -1474,19 +3789,39 @@ declare class SwipableBase {
1474
3789
  "animator": AnimationHandle | null;
1475
3790
  "dragevent": DragEventNames;
1476
3791
  "data": DragData;
1477
- "fire": EventedInstance["fire"];
3792
+ "fire": EventedInstance<SwipableEvents>["fire"];
1478
3793
  constructor(drag_elem: HTMLElement, move_elem?: HTMLElement, options?: Record<string, unknown>);
1479
3794
  enable(e?: LegacyEvent): void;
1480
3795
  disable(): void;
3796
+ /**
3797
+ * Full teardown for `dispose()`: `disable()` only covers the listeners
3798
+ * `enable()` adds, but a gesture in flight also holds the `move`/`leave`
3799
+ * pair plus the momentum animation.
3800
+ */
3801
+ dispose(): void;
1481
3802
  stopMomentum(): void;
1482
3803
  updateConstraint(c: SwipableOptions["constraint"]): void;
1483
3804
  _onDragStart(e: LegacyEvent): void;
1484
3805
  _onDragEnd(e: LegacyEvent): void;
3806
+ _attachGestureListeners(): void;
3807
+ _detachGestureListeners(): void;
1485
3808
  _onDragMove(e: LegacyEvent): void;
1486
3809
  _momentum(): void;
1487
3810
  _animateMomentum(): void;
1488
3811
  }
1489
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
+
1490
3825
  declare interface SwipableOptions {
1491
3826
  snap: boolean;
1492
3827
  enable: {
@@ -1504,28 +3839,22 @@ declare interface SwipableOptions {
1504
3839
  ease: unknown;
1505
3840
  }
1506
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
+
1507
3847
  declare class Text_2 extends Text_base {
1508
3848
  constructor(...args: ConstructorParameters<typeof TextBase>);
1509
3849
  }
1510
3850
 
1511
- declare const Text_base: {
1512
- new (...args: any[]): {
1513
- _vco_events?: Record<string, {
1514
- action: unknown;
1515
- context: unknown;
1516
- }[]>;
1517
- on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
1518
- hasEventListeners(type: string): boolean;
1519
- off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
1520
- fire(type: string, data?: unknown, target?: unknown): /*elided*/ any;
1521
- };
1522
- } & typeof TextBase;
3851
+ declare const Text_base: Constructor<EventedInstance<TextEvents>> & typeof TextBase;
1523
3852
 
1524
3853
  declare class TextBase {
1525
3854
  "_el": Record<string, HTMLElement>;
1526
3855
  "data": TextData;
1527
3856
  "options": TextOptions;
1528
- "fire": EventedInstance["fire"];
3857
+ "fire": EventedInstance<TextEvents>["fire"];
1529
3858
  constructor(data: TextData, options?: TextOptions, add_to_container?: HTMLElement);
1530
3859
  show(): void;
1531
3860
  hide(): void;
@@ -1550,11 +3879,34 @@ declare interface TextData {
1550
3879
  } | null;
1551
3880
  }
1552
3881
 
3882
+ export declare interface TextEvents {
3883
+ loaded: TextData;
3884
+ added: TextData;
3885
+ removed: TextData;
3886
+ }
3887
+
1553
3888
  declare interface TextOptions {
1554
3889
  title?: boolean;
1555
3890
  text_align?: string;
3891
+ /** BCP 47 tag for the slide text (from `StorymapSlide.language`). */
3892
+ language?: string;
1556
3893
  }
1557
3894
 
3895
+ /**
3896
+ * Custom tile layer/source factory (see
3897
+ * `StorymapOptions.tile_source_factory`). `createDefault` runs the
3898
+ * built-in `map_type` handling, so a factory can decorate or delegate.
3899
+ *
3900
+ * May return any `ol/layer/Layer` (used as-is — this is what lets a
3901
+ * third-party layer such as an Allmaps `WarpedMapLayer` render), a bare
3902
+ * `Source` (wrapped in a `TileLayer`), or `null`/`undefined` to fall
3903
+ * through to the default `map_type` handling.
3904
+ */
3905
+ export declare type TileSourceFactory = (map_type: string, context: {
3906
+ options: StorymapOptions;
3907
+ createDefault: () => Tile;
3908
+ }) => OlLayer | Tile | OlSource | null | undefined;
3909
+
1558
3910
  /** Validate storymap JSON (the object containing a "storymap" property). */
1559
3911
  export declare function validateStorymap(data: unknown): StorymapError[];
1560
3912
 
@@ -1566,6 +3918,8 @@ declare interface ViewToOptions {
1566
3918
  calculate_zoom?: boolean;
1567
3919
  duration?: number;
1568
3920
  zoom?: number;
3921
+ /** View rotation in degrees clockwise; absent leaves rotation unchanged. */
3922
+ rotation?: number;
1569
3923
  }
1570
3924
 
1571
3925
  export { }
@@ -1583,4 +3937,12 @@ declare global {
1583
3937
  const SC: {
1584
3938
  Widget: (el: HTMLElement) => { pause(): void };
1585
3939
  };
3940
+
3941
+ /**
3942
+ * The library version, substituted from package.json by the Vite lib build
3943
+ * (see the `define` in vite.config.ts). Hard-coded here only so the
3944
+ * source type-checks; a dev-server run without the define falls back to
3945
+ * "unknown" at runtime via the typeof guard in StoryMap.
3946
+ */
3947
+ const __STORYMAP_VERSION__: string;
1586
3948
  }