@projektemacher/storymapjs 0.10.6 → 0.10.8

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 (552) hide show
  1. package/CHANGELOG +358 -16
  2. package/README.md +43 -9
  3. package/dist/assets/demo-DBpeF31K.js +1 -0
  4. package/dist/assets/harness-Cr0rYpvt.js +1 -0
  5. package/dist/assets/harness-multi-CYHgI0a9.js +1 -0
  6. package/dist/assets/harness-support-Do7sIp2j.js +1 -0
  7. package/dist/assets/index-wHPqGrBS.js +1 -0
  8. package/dist/assets/main-DXalctuR.js +17 -0
  9. package/dist/context.json +12 -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 +101 -21
  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 +2 -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 +1604 -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/loadCSS.html +63 -0
  278. package/dist/docs/api/functions/manifestToStorymapData.html +49 -0
  279. package/dist/docs/api/functions/setLanguage.html +54 -0
  280. package/dist/docs/api/functions/storymapToManifest.html +57 -0
  281. package/dist/docs/api/functions/validateStorymap.html +53 -0
  282. package/dist/docs/api/functions/validateStorymapAndReport.html +54 -0
  283. package/dist/docs/api/hierarchy.html +28 -0
  284. package/dist/docs/api/index.html +197 -0
  285. package/dist/docs/api/interfaces/AnimationHandle.html +60 -0
  286. package/dist/docs/api/interfaces/ImagereadyPayload.html +71 -0
  287. package/dist/docs/api/interfaces/LanguageEntry.html +102 -0
  288. package/dist/docs/api/interfaces/LatLngLiteral.html +73 -0
  289. package/dist/docs/api/interfaces/LoadOptions.html +59 -0
  290. package/dist/docs/api/interfaces/OlLayer.html +1400 -0
  291. package/dist/docs/api/interfaces/OlMap.html +1656 -0
  292. package/dist/docs/api/interfaces/OlProjection.html +332 -0
  293. package/dist/docs/api/interfaces/OlSource.html +784 -0
  294. package/dist/docs/api/interfaces/OlTileLayer.html +1497 -0
  295. package/dist/docs/api/interfaces/OlVectorLayer.html +1559 -0
  296. package/dist/docs/api/interfaces/OlView.html +1958 -0
  297. package/dist/docs/api/interfaces/StorymapData.html +71 -0
  298. package/dist/docs/api/interfaces/StorymapDataWrapper.html +60 -0
  299. package/dist/docs/api/interfaces/StorymapDocument.html +68 -0
  300. package/dist/docs/api/interfaces/StorymapError.html +63 -0
  301. package/dist/docs/api/interfaces/StorymapGeoreference.html +93 -0
  302. package/dist/docs/api/interfaces/StorymapGeoreferenceBody.html +74 -0
  303. package/dist/docs/api/interfaces/StorymapGroundControlPoint.html +69 -0
  304. package/dist/docs/api/interfaces/StorymapLanguageMap.html +57 -0
  305. package/dist/docs/api/interfaces/StorymapManifest.html +118 -0
  306. package/dist/docs/api/interfaces/StorymapManifestAnnotation.html +105 -0
  307. package/dist/docs/api/interfaces/StorymapManifestBackground.html +81 -0
  308. package/dist/docs/api/interfaces/StorymapManifestCanvas.html +140 -0
  309. package/dist/docs/api/interfaces/StorymapManifestContentResource.html +97 -0
  310. package/dist/docs/api/interfaces/StorymapManifestFeatureCollection.html +82 -0
  311. package/dist/docs/api/interfaces/StorymapManifestGeoreferencing.html +87 -0
  312. package/dist/docs/api/interfaces/StorymapManifestImageService.html +69 -0
  313. package/dist/docs/api/interfaces/StorymapManifestRange.html +75 -0
  314. package/dist/docs/api/interfaces/StorymapManifestService.html +77 -0
  315. package/dist/docs/api/interfaces/StorymapManifestSpecificResource.html +69 -0
  316. package/dist/docs/api/interfaces/StorymapManifestStatement.html +63 -0
  317. package/dist/docs/api/interfaces/StorymapMapOptions.html +92 -0
  318. package/dist/docs/api/interfaces/StorymapOptions.html +532 -0
  319. package/dist/docs/api/interfaces/StorymapOverlayLayer.html +126 -0
  320. package/dist/docs/api/interfaces/StorymapSlide.html +132 -0
  321. package/dist/docs/api/interfaces/StorymapSlideBackground.html +72 -0
  322. package/dist/docs/api/interfaces/StorymapSlideLocation.html +117 -0
  323. package/dist/docs/api/interfaces/StorymapSlideMarker.html +104 -0
  324. package/dist/docs/api/interfaces/StorymapSlideMedia.html +110 -0
  325. package/dist/docs/api/interfaces/StorymapSlideNarration.html +65 -0
  326. package/dist/docs/api/interfaces/StorymapSlideText.html +72 -0
  327. package/dist/docs/api/interfaces/StorymapTilejson.html +105 -0
  328. package/dist/docs/api/media/es.json +31 -0
  329. package/dist/docs/api/media/migration-from-knightlab.md +359 -0
  330. package/dist/docs/api/modules.html +50 -0
  331. package/dist/docs/api/types/ContentState.html +70 -0
  332. package/dist/docs/api/types/ImagereadyKind.html +34 -0
  333. package/dist/docs/api/types/MediaTypeMatch.html +78 -0
  334. package/dist/docs/api/types/TileSourceFactory.html +53 -0
  335. package/dist/docs/authoring.html +293 -0
  336. package/dist/docs/iiif.html +617 -62
  337. package/dist/docs/migration.html +314 -12
  338. package/dist/docs/readme.html +40 -9
  339. package/dist/embed/index.html +130 -5
  340. package/dist/examples/issue-242-nonlatin.json +55 -0
  341. package/dist/examples/issue-305-start-at-slide-data.json +96 -0
  342. package/dist/examples/issue-358-iframe.json +57 -0
  343. package/dist/examples/issue-iiif-geo.json +32 -0
  344. package/dist/examples/issue-image-alt.json +23 -0
  345. package/dist/examples/issue-image-region.json +42 -0
  346. package/dist/examples/issue-image-srcset.json +24 -0
  347. package/dist/examples/map-area-overlays.json +68 -0
  348. package/dist/examples/no-map.json +44 -0
  349. package/dist/examples-iiif/annotated-image.json +188 -0
  350. package/dist/examples-iiif/bob-boilen.json +11 -5
  351. package/dist/examples-iiif/courbet.json +9 -6
  352. package/dist/examples-iiif/empty.json +8 -4
  353. package/dist/examples-iiif/flickr-drewvigal.json +248 -24
  354. package/dist/examples-iiif/flickr-zach.wise.json +8 -4
  355. package/dist/examples-iiif/georeferenced-layer-unsupported.json +153 -0
  356. package/dist/examples-iiif/georeferenced-layer.json +318 -0
  357. package/dist/examples-iiif/iiif-wellcome.json +9 -6
  358. package/dist/examples-iiif/instagram-chenpamela.json +381 -36
  359. package/dist/examples-iiif/instagram_brentfoster.json +429 -40
  360. package/dist/examples-iiif/instagram_couch.json +261 -26
  361. package/dist/examples-iiif/instagram_joegermuska.json +441 -41
  362. package/dist/examples-iiif/instagram_matteich.json +261 -26
  363. package/dist/examples-iiif/instagram_mirandamulligan.json +261 -26
  364. package/dist/examples-iiif/instagram_raymondmccrea.json +261 -26
  365. package/dist/examples-iiif/instagram_test.json +261 -26
  366. package/dist/examples-iiif/issue-134-no-lines.json +9 -5
  367. package/dist/examples-iiif/issue-177-color-vars.json +9 -5
  368. package/dist/examples-iiif/issue-211-rtl.json +9 -5
  369. package/dist/examples-iiif/issue-242-nonlatin.json +239 -0
  370. package/dist/examples-iiif/issue-272-facebook.json +9 -5
  371. package/dist/examples-iiif/issue-305-start-at-slide-data.json +305 -0
  372. package/dist/examples-iiif/issue-305-start-at-slide.json +9 -5
  373. package/dist/examples-iiif/issue-341-distance.json +9 -5
  374. package/dist/examples-iiif/issue-358-iframe.json +190 -0
  375. package/dist/examples-iiif/issue-360-juxtapose.json +22 -7
  376. package/dist/examples-iiif/issue-368-null-fields.json +9 -5
  377. package/dist/examples-iiif/issue-375-code-lists.json +9 -5
  378. package/dist/examples-iiif/issue-381-dateline.json +9 -5
  379. package/dist/examples-iiif/issue-405-custom-icon.json +203 -0
  380. package/dist/examples-iiif/issue-425-many-slides.json +9 -5
  381. package/dist/examples-iiif/issue-428-background.json +20 -8
  382. package/dist/examples-iiif/issue-435-googlemaps.json +9 -5
  383. package/dist/examples-iiif/issue-437-documentcloud.json +22 -7
  384. package/dist/examples-iiif/issue-451-webp.json +9 -5
  385. package/dist/examples-iiif/issue-455-audio.json +9 -5
  386. package/dist/examples-iiif/issue-480-shorts.json +9 -5
  387. package/dist/examples-iiif/issue-506-marker-sync.json +9 -5
  388. package/dist/examples-iiif/issue-iiif-geo.json +200 -0
  389. package/dist/examples-iiif/issue-image-alt.json +90 -0
  390. package/dist/examples-iiif/issue-image-region.json +203 -0
  391. package/dist/examples-iiif/issue-image-srcset.json +87 -0
  392. package/dist/examples-iiif/jansteen.json +9 -6
  393. package/dist/examples-iiif/katrina.json +197 -41
  394. package/dist/examples-iiif/map-area-overlays.json +289 -0
  395. package/dist/examples-iiif/marktwain.json +255 -58
  396. package/dist/examples-iiif/no-map.json +148 -0
  397. package/dist/examples-iiif/population.json +440 -76
  398. package/dist/examples-iiif/president.json +456 -83
  399. package/dist/examples-iiif/scroll-hint.json +190 -0
  400. package/dist/examples-iiif/seurat.json +113 -22
  401. package/dist/examples-iiif/zoomify-clamp.json +153 -0
  402. package/dist/harness-multi.html +17 -0
  403. package/dist/harness.html +3 -2
  404. package/dist/index.html +33 -10
  405. package/dist/js/storymap.d.ts +1558 -114
  406. package/dist/js/storymap.js +10113 -6490
  407. package/dist/js/storymap.js.map +1 -1
  408. package/dist/navplace-properties.json +40 -0
  409. package/docs/migration-from-knightlab.md +359 -0
  410. package/docs/storymap-as-iiif-manifest.md +934 -0
  411. package/package.json +16 -10
  412. package/schema/storymap.schema.json +431 -78
  413. package/src/animation/easings.ts +25 -0
  414. package/src/animation/tween.ts +186 -0
  415. package/src/core/Browser.ts +20 -0
  416. package/src/core/Load.ts +232 -0
  417. package/src/core/Util.ts +416 -0
  418. package/src/core/mixins.ts +188 -0
  419. package/src/core/viewers.ts +94 -0
  420. package/src/dom/Dom.ts +31 -0
  421. package/src/dom/DomEvent.ts +80 -0
  422. package/src/globals.d.ts +24 -0
  423. package/src/language/Language.ts +281 -0
  424. package/src/language/locale/.expected-gaps.json +86 -0
  425. package/src/language/locale/be.json +31 -0
  426. package/src/language/locale/bg.json +31 -0
  427. package/src/language/locale/cs.json +31 -0
  428. package/src/language/locale/de.json +31 -0
  429. package/src/language/locale/el.json +31 -0
  430. package/src/language/locale/en.json +32 -0
  431. package/src/language/locale/es.json +31 -0
  432. package/src/language/locale/et.json +22 -0
  433. package/src/language/locale/fr.json +31 -0
  434. package/src/language/locale/he.json +31 -0
  435. package/src/language/locale/hu.json +31 -0
  436. package/src/language/locale/is.json +22 -0
  437. package/src/language/locale/it.json +31 -0
  438. package/src/language/locale/jp.json +31 -0
  439. package/src/language/locale/ko.json +31 -0
  440. package/src/language/locale/nl.json +31 -0
  441. package/src/language/locale/nn.json +22 -0
  442. package/src/language/locale/no.json +31 -0
  443. package/src/language/locale/pl.json +31 -0
  444. package/src/language/locale/pt.json +31 -0
  445. package/src/language/locale/ru.json +31 -0
  446. package/src/language/locale/sk.json +31 -0
  447. package/src/language/locale/sr.json +21 -0
  448. package/src/language/locale/sv.json +31 -0
  449. package/src/language/locale/tr.json +31 -0
  450. package/src/language/locale/uk.json +31 -0
  451. package/src/language/locale/ur.json +22 -0
  452. package/src/language/locale/zh-cn.json +31 -0
  453. package/src/language/locale/zh-tw.json +31 -0
  454. package/src/main.ts +143 -0
  455. package/src/map/Map.ts +794 -0
  456. package/src/map/MapMarker.ts +172 -0
  457. package/src/map/georeference.ts +325 -0
  458. package/src/map/openlayers/Map.OpenLayers.ts +2492 -0
  459. package/src/map/openlayers/MapMarker.OpenLayers.ts +400 -0
  460. package/src/map/openlayers/zoomifyTiles.ts +25 -0
  461. package/src/map/types.ts +17 -0
  462. package/src/media/EmbedUtil.ts +452 -0
  463. package/src/media/Media.ts +597 -0
  464. package/src/media/MediaType.ts +163 -0
  465. package/src/media/embedId.ts +104 -0
  466. package/src/media/types/Audio.ts +14 -0
  467. package/src/media/types/Blockquote.ts +39 -0
  468. package/src/media/types/DailyMotion.ts +53 -0
  469. package/src/media/types/DocumentCloud.ts +12 -0
  470. package/src/media/types/Facebook.ts +40 -0
  471. package/src/media/types/Flickr.ts +115 -0
  472. package/src/media/types/GoogleDoc.ts +58 -0
  473. package/src/media/types/HtmlMedia.ts +167 -0
  474. package/src/media/types/IFrame.ts +50 -0
  475. package/src/media/types/Image.ts +115 -0
  476. package/src/media/types/Juxtapose.ts +41 -0
  477. package/src/media/types/SoundCloud.ts +99 -0
  478. package/src/media/types/Text.ts +178 -0
  479. package/src/media/types/Twitter.ts +109 -0
  480. package/src/media/types/Video.ts +14 -0
  481. package/src/media/types/Vimeo.ts +65 -0
  482. package/src/media/types/Website.ts +46 -0
  483. package/src/media/types/Wikipedia.ts +134 -0
  484. package/src/media/types/YouTube.ts +224 -0
  485. package/src/scss/Typography.scss +235 -0
  486. package/src/scss/VCO.StoryMap.Dark.scss +150 -0
  487. package/src/scss/VCO.StoryMap.scss +195 -0
  488. package/src/scss/Variables.Dark.scss +57 -0
  489. package/src/scss/Variables.scss +48 -0
  490. package/src/scss/core/Mixins.scss +54 -0
  491. package/src/scss/core/Reset.scss +206 -0
  492. package/src/scss/fonts/_font.base.scss +113 -0
  493. package/src/scss/fonts/font.abril-droidsans.scss +75 -0
  494. package/src/scss/fonts/font.amatic-andika.scss +76 -0
  495. package/src/scss/fonts/font.bitter-raleway.scss +92 -0
  496. package/src/scss/fonts/font.cairo.scss +79 -0
  497. package/src/scss/fonts/font.clicker-garamond.scss +97 -0
  498. package/src/scss/fonts/font.dancing-ledger.scss +75 -0
  499. package/src/scss/fonts/font.default.scss +9 -0
  500. package/src/scss/fonts/font.fjalla-average.scss +80 -0
  501. package/src/scss/fonts/font.georgia-helvetica.scss +58 -0
  502. package/src/scss/fonts/font.knightlab.scss +111 -0
  503. package/src/scss/fonts/font.lustria-lato.scss +80 -0
  504. package/src/scss/fonts/font.medula-lato.scss +73 -0
  505. package/src/scss/fonts/font.oldstandard.scss +94 -0
  506. package/src/scss/fonts/font.opensans-gentiumbook.scss +85 -0
  507. package/src/scss/fonts/font.playfair-faunaone.scss +88 -0
  508. package/src/scss/fonts/font.playfair.scss +89 -0
  509. package/src/scss/fonts/font.pt.scss +96 -0
  510. package/src/scss/fonts/font.roboto-megrim.scss +73 -0
  511. package/src/scss/fonts/font.rufina-sintony.scss +73 -0
  512. package/src/scss/fonts/font.ubuntu.scss +82 -0
  513. package/src/scss/fonts/font.unicaone-vollkorn.scss +90 -0
  514. package/src/scss/icons/Icons.scss +239 -0
  515. package/src/scss/map/VCO.ImageMarker.scss +23 -0
  516. package/src/scss/map/VCO.Map.scss +21 -0
  517. package/src/scss/map/VCO.MapMarker.scss +242 -0
  518. package/src/scss/map/openlayers/VCO.Map.OpenLayers.scss +126 -0
  519. package/src/scss/media/VCO.Media.scss +219 -0
  520. package/src/scss/media/types/VCO.Media.Blockquote.scss +76 -0
  521. package/src/scss/media/types/VCO.Media.IFrame.scss +11 -0
  522. package/src/scss/media/types/VCO.Media.Image.scss +13 -0
  523. package/src/scss/media/types/VCO.Media.Text.scss +98 -0
  524. package/src/scss/media/types/VCO.Media.Twitter.scss +87 -0
  525. package/src/scss/media/types/VCO.Media.Wikipedia.scss +65 -0
  526. package/src/scss/site/site.scss +748 -0
  527. package/src/scss/slider/VCO.Slide.scss +457 -0
  528. package/src/scss/slider/VCO.SlideNav.scss +332 -0
  529. package/src/scss/slider/VCO.StorySlider.scss +66 -0
  530. package/src/scss/snapmap/VCO.SnapMap.scss +103 -0
  531. package/src/scss/ui/VCO.Consent.scss +121 -0
  532. package/src/scss/ui/VCO.MenuBar.Button.scss +107 -0
  533. package/src/scss/ui/VCO.MenuBar.scss +20 -0
  534. package/src/scss/ui/VCO.Message.scss +101 -0
  535. package/src/site/site.ts +88 -0
  536. package/src/slider/Slide.ts +554 -0
  537. package/src/slider/SlideNav.ts +246 -0
  538. package/src/slider/StorySlider.ts +833 -0
  539. package/src/storymap/Consent.ts +471 -0
  540. package/src/storymap/StoryMap.ts +2118 -0
  541. package/src/storymap/content-state.ts +185 -0
  542. package/src/storymap/iiif.ts +1844 -0
  543. package/src/storymap/to-iiif.ts +921 -0
  544. package/src/storymap/validate.ts +257 -0
  545. package/src/types.ts +494 -0
  546. package/src/ui/MenuBar.ts +376 -0
  547. package/src/ui/Message.ts +127 -0
  548. package/src/ui/Swipable.ts +455 -0
  549. package/dist/assets/demo-CVQ7kFek.js +0 -1
  550. package/dist/assets/harness-C-VZV-ou.js +0 -1
  551. package/dist/assets/index-DDsPBPZA.js +0 -1
  552. package/dist/assets/main-DwbXrrYn.js +0 -17
@@ -1,45 +1,153 @@
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 { Extent } from 'ol/extent';
6
5
  import { Map as Map_3 } from 'ol';
6
+ import { default as OlLayer } from 'ol/layer/Layer';
7
+ import { default as OlMap } from 'ol/Map';
8
+ import { default as OlProjection } from 'ol/proj/Projection';
9
+ import { default as OlSource } from 'ol/source/Source';
10
+ import { default as OlTileLayer } from 'ol/layer/Tile';
11
+ import { default as OlVectorLayer } from 'ol/layer/Vector';
12
+ import { default as OlView } from 'ol/View';
7
13
  import { Style } from 'ol/style';
8
14
  import { Tile } from 'ol/layer';
9
15
  import { Vector } from 'ol/layer';
16
+ import { XYZ } from 'ol/source';
10
17
 
11
- declare interface AnimationHandle {
18
+ export declare interface AnimationHandle {
12
19
  stop: (jump?: boolean) => void;
13
20
  }
14
21
 
15
22
  /**
16
23
  * Per-StoryMap GDPR consent manager. When the `consent_required` option is
17
24
  * set, every external service (media embeds, map tiles, external font CSS)
18
- * asks for permission before anything is loaded. Decisions are remembered
19
- * per service in a cookie for 90 days — clearing cookies asks again.
25
+ * asks for permission before anything is loaded.
26
+ *
27
+ * Decisions are remembered per service in localStorage with no expiry:
28
+ * clearing site data is what makes the viewer ask again.
20
29
  */
21
30
  declare class ConsentManager {
22
31
  private granted;
23
32
  private denied;
24
33
  /** unanswered asks per service (preloaded slides stack several) */
25
34
  private pending;
35
+ /** the start-of-story dialog's row per service, so a decision made
36
+ * anywhere (including a standalone per-service ask) clears it */
37
+ private startRows;
38
+ /** every start-of-story dialog root we put on screen, so dispose() can
39
+ * take the whole thing down rather than just its rows */
40
+ private startDialogs;
41
+ /** set by dispose(); late answers are ignored rather than persisted */
42
+ private disposed;
26
43
  constructor();
27
- /** Seed the per-service state from the consent cookie, if present. */
44
+ /**
45
+ * Seed the per-service state from localStorage, if present.
46
+ *
47
+ * Keys written by an earlier version are remapped onto the namespaced
48
+ * form, so an existing visitor is not asked everything again after the
49
+ * upgrade. The remap is written back once, which also clears the legacy
50
+ * keys so they cannot drift out of sync later.
51
+ */
28
52
  private restore;
29
- /** Persist the per-service state to the consent cookie. */
53
+ /**
54
+ * Persist the per-service state to localStorage.
55
+ *
56
+ * A page can hold more than one viewer, and they all share this one
57
+ * record — a visitor should not answer the same question twice for the
58
+ * same service. So this *merges* into whatever is already stored instead
59
+ * of replacing it: writing this viewer's full set back would silently
60
+ * erase a decision a sibling viewer made, while that sibling still
61
+ * believed otherwise. The merged result is then adopted, which is what
62
+ * makes every viewer converge on the same decisions.
63
+ */
30
64
  private persist;
65
+ /** Replace the in-memory decision set with `state`, in place. */
66
+ private adopt;
67
+ /**
68
+ * Re-read the shared record, so a decision the visitor made in a sibling
69
+ * viewer is honoured here without having to reconstruct this one.
70
+ */
71
+ private sync;
72
+ /**
73
+ * Record a decision for one service and resolve every ask waiting on it.
74
+ *
75
+ * Both dialog shapes funnel through here, which is what keeps a service
76
+ * from ending up in the granted *and* the denied set: the opposite set is
77
+ * always cleared.
78
+ */
79
+ private decide;
31
80
  isGranted(service: string): boolean;
32
81
  isDenied(service: string): boolean;
82
+ /** True when at least one of the services has no stored decision yet. */
83
+ hasUnanswered(services: string[]): boolean;
33
84
  /**
34
- * Ask the visitor for permission to load `service` (a human-readable
35
- * name like "YouTube" or "map tiles"), optionally naming the `host`.
36
- * The ask is rendered into `container`; resolves `true`/`false` on the
37
- * visitor's decision, or immediately when the service was already
38
- * granted or denied.
85
+ * Start-of-story consent dialog: lists every known external service
86
+ * with per-service Allow/Deny, plus global "Allow all" / "Decline
87
+ * all" buttons. Individual decisions reuse the per-service state
88
+ * (pending slide asks resolve immediately); the dialog closes once
89
+ * every service has a decision.
39
90
  */
40
- request(service: string, host: string, container: HTMLElement): Promise<boolean>;
91
+ requestAll(services: ConsentService[], container: HTMLElement): void;
92
+ /**
93
+ * Ask the visitor for permission to load `service`, optionally naming the
94
+ * `host` (shown in parentheses so they can see which domain is about to be
95
+ * contacted). The ask is rendered into `container`; resolves
96
+ * `true`/`false` on the visitor's decision, or immediately when the
97
+ * service was already granted or denied.
98
+ *
99
+ * The service is stored and looked up by `service.key`; `service.label`
100
+ * is only ever rendered.
101
+ */
102
+ request(service: ConsentService, host: string, container: HTMLElement): Promise<boolean>;
103
+ /**
104
+ * Release everything: drop the dialogs and settle every unanswered ask.
105
+ *
106
+ * `Media.loadMedia()` awaits `request()`. Without this, tearing the viewer
107
+ * down while a panel was on screen left that `await` pending forever, and
108
+ * the suspended frame kept the whole media subtree — DOM included — alive.
109
+ * Unanswered asks resolve `false`, which is the same outcome as declining.
110
+ */
111
+ dispose(): void;
41
112
  }
42
113
 
114
+ /**
115
+ * An external service the viewer asks permission to load.
116
+ *
117
+ * `key` is the *only* thing ever persisted, and it is stable, namespaced and
118
+ * never localized. `label` is display-only.
119
+ *
120
+ * These are two separate fields on purpose. The code used to pass a single
121
+ * string that served as both, which had two consequences:
122
+ *
123
+ * - the tile and font services used a *localized* string as the localStorage
124
+ * key, so translating `consent_service_tiles` would have silently
125
+ * invalidated every stored decision the moment the page language changed;
126
+ * - the per-slide panel used the media type *slug* as its display label, so
127
+ * it asked "Load content from youtube?" where the start-of-story dialog,
128
+ * 20 lines away, correctly said "YouTube".
129
+ *
130
+ * With the pair split, passing a label where a key is expected is no longer
131
+ * expressible.
132
+ */
133
+ declare interface ConsentService {
134
+ /** Stable, namespaced, non-localized. The only value that is stored. */
135
+ key: string;
136
+ /** Display name. Localized for tiles/fonts; a brand name for media. */
137
+ label: string;
138
+ }
139
+
140
+ export declare type ContentState = {
141
+ /** The canvas (or other resource) the state points at. */
142
+ id: string;
143
+ /**
144
+ * `[x, y, w, h]` in canvas pixels, when the state names a part of the
145
+ * canvas. Carried on the id as an `xywh=` fragment, which is the
146
+ * Media Fragments spelling the spec uses in every region example.
147
+ */
148
+ region?: [number, number, number, number];
149
+ };
150
+
43
151
  declare interface DragData {
44
152
  sliding: boolean;
45
153
  direction: string | null;
@@ -79,6 +187,7 @@ declare interface DragData {
79
187
  declare interface DragEventNames {
80
188
  down: string;
81
189
  up: string;
190
+ cancel?: string;
82
191
  leave: string;
83
192
  move: string;
84
193
  }
@@ -97,16 +206,76 @@ declare type IconSpec = {
97
206
  anchor: number[];
98
207
  };
99
208
 
100
- declare interface LanguageEntry {
101
- buttons?: Record<string, string>;
102
- messages?: Record<string, string>;
209
+ /** What kind of imagery an `imageready` source carries. */
210
+ export declare type ImagereadyKind = "iiif" | "zoomify" | "tiles";
211
+
212
+ /**
213
+ * Payload of the `imageready` event: the source that became usable, what
214
+ * kind of imagery it is, and the layer carrying it (`null` when the source
215
+ * outlives its layer).
216
+ */
217
+ export declare interface ImagereadyPayload {
218
+ source: {
219
+ getState?(): string;
220
+ };
221
+ kind: ImagereadyKind;
222
+ layer: OlLayer | null;
223
+ }
224
+
225
+ /** True when `data` is a Presentation API 3.0 Collection. */
226
+ export declare function isPresentation3Collection(data: unknown): boolean;
227
+
228
+ /**
229
+ * True when `data` looks like a Presentation API 3.0 **Manifest**.
230
+ *
231
+ * A `Collection` is explicitly *not* one, even though it carries the same
232
+ * `@context`. Detection used to accept anything with the P3 context, so a
233
+ * Collection passed and its member Manifests were fed to `canvasToSlide` as if
234
+ * they were Canvases — every member became a text-only slide, with no media, no
235
+ * locations and no warning. `within`-style Collections are now handled by the
236
+ * private `collectionToStorymapData` below, and anything else is rejected here.
237
+ */
238
+ export declare function isPresentation3Manifest(data: unknown): boolean;
239
+
240
+ /**
241
+ * UI strings for the active locale.
242
+ *
243
+ * English is the fallback for every missing key (see `getLanguage`), so
244
+ * `messages` and `buttons` are guaranteed to be fully populated once a
245
+ * language has been set — they are typed as required here rather than as
246
+ * `Record<string, string> | undefined` so call sites do not need a null
247
+ * check on every one of the ~30 `Language.messages.*` reads.
248
+ *
249
+ * The locale JSON files themselves are *not* complete: only `en.json` defines
250
+ * every key, and 28 of the 29 bundled locales are missing 8-10 of them
251
+ * (the per-service consent strings and the fullscreen button labels). The
252
+ * runtime falls back to English per key, so this is a translation gap rather
253
+ * than a defect — `npm run check:locales` reports it.
254
+ */
255
+ export declare interface LanguageEntry {
256
+ /** Display name of the language, e.g. "Deutsch". */
257
+ name?: string;
258
+ /** BCP 47 code, e.g. "de". */
259
+ lang?: string;
260
+ /** Writing direction; drives the `vco-rtl` layout. */
261
+ direction?: "ltr" | "rtl";
262
+ messages: Record<string, string>;
263
+ buttons: Record<string, string>;
103
264
  [key: string]: unknown;
104
265
  }
105
266
 
106
- declare interface LatLngLiteral {
107
- lat: number | undefined;
108
- lon?: number | undefined;
109
- lng?: number | undefined;
267
+ /**
268
+ * A resolved geographic coordinate.
269
+ *
270
+ * `lat`/`lon` are required: this type is for points the map can actually
271
+ * focus on. A *slide* may carry a `location` without coordinates (an image
272
+ * region, an icon only) — that is `StorymapSlideLocation`, which keeps them
273
+ * optional. `lng` is accepted as a legacy alias on input only.
274
+ */
275
+ export declare interface LatLngLiteral {
276
+ lat: number;
277
+ lon: number;
278
+ lng?: number;
110
279
  }
111
280
 
112
281
  /** Legacy drag handlers historically mixed mouse and touch event surfaces. */
@@ -127,23 +296,33 @@ declare interface LinePoint {
127
296
  /**
128
297
  * Append one stylesheet to the document head.
129
298
  *
299
+ * Concurrent and repeat requests for the same URL share one `<link>`.
300
+ *
130
301
  * @param url - The stylesheet URL.
131
302
  * @param options - Optional AbortSignal to cancel an in-flight load.
132
303
  * @returns Resolves when the stylesheet has loaded, rejects on error or abort.
133
304
  */
134
305
  export declare function loadCSS(url: string, options?: LoadOptions): Promise<void>;
135
306
 
136
- declare interface LoadOptions {
307
+ export declare interface LoadOptions {
137
308
  /** Abort the load (removes the element, rejects the promise). */
138
309
  signal?: AbortSignal;
139
310
  }
140
311
 
312
+ /**
313
+ * Converts a IIIF Presentation API 3.0 manifest into legacy StoryMapJS data
314
+ * (the `storymap` object). Malformed or missing pieces are skipped; the
315
+ * result always contains at least `{slides: []}`.
316
+ */
317
+ export declare function manifestToStorymapData(manifest: unknown): StorymapData;
318
+
141
319
  declare class Map_2 extends Map_base {
142
320
  constructor(...args: ConstructorParameters<typeof MapBase>);
143
321
  }
144
322
 
145
323
  declare const Map_base: {
146
324
  new (...args: any[]): {
325
+ container(): HTMLElement;
147
326
  show(animate?: unknown): void;
148
327
  hide(): void;
149
328
  addTo(container: HTMLElement): /*elided*/ any;
@@ -152,7 +331,7 @@ declare const Map_base: {
152
331
  onLoaded(): void;
153
332
  onAdd(): void;
154
333
  onRemove(): void;
155
- _el: Record<string, HTMLElement>;
334
+ _el: Record<string, unknown>;
156
335
  data?: unknown;
157
336
  on: (type: string, fn: unknown, context?: unknown) => unknown;
158
337
  off: (type: string, fn: unknown, context?: unknown) => unknown;
@@ -164,7 +343,7 @@ declare const Map_base: {
164
343
  _vco_events?: Record<string, {
165
344
  action: unknown;
166
345
  context: unknown;
167
- }[]>;
346
+ }[]> | undefined;
168
347
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
169
348
  hasEventListeners(type: string): boolean;
170
349
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -185,6 +364,12 @@ declare class MapBase {
185
364
  "_map": Map_3 | null;
186
365
  "_mini_map": default_2 | null;
187
366
  "_markers": MapMarker[];
367
+ /**
368
+ * Zooms computed by the engine's `_calculateMarkerZooms`, keyed by
369
+ * marker index. Kept off `marker.data` so navigating never mutates the
370
+ * author's storymap document (`StoryMap.data` is that same object graph).
371
+ */
372
+ "_marker_zooms": (number | undefined)[];
188
373
  "zoom_min_max": {
189
374
  min: number | null;
190
375
  max: number | null;
@@ -193,8 +378,8 @@ declare class MapBase {
193
378
  "_line_active": Vector | null;
194
379
  "current_marker": number;
195
380
  "bounds_array": number[][] | null;
196
- "_tile_layer": Tile | null;
197
- "_tile_layer_mini": Tile | null;
381
+ "_tile_layer": OlLayer | null;
382
+ "_tile_layer_mini": OlLayer | null;
198
383
  "_image_layer": Tile | null;
199
384
  "data": StorymapData;
200
385
  "options": StorymapOptions;
@@ -207,18 +392,57 @@ declare class MapBase {
207
392
  constructor(elem: string | HTMLElement, data?: Partial<StorymapData>, options?: Partial<StorymapOptions>);
208
393
  updateDisplay(w: number, h: number, animate?: boolean, d?: number, offset?: unknown): void;
209
394
  goTo(n: number, change?: boolean): void;
395
+ /**
396
+ * Alias over the OpenLayers view: `storymap.map.getView().animate({center})`
397
+ * (remember `ol/proj` does not apply in image mode — see `isImageSpace()`).
398
+ */
210
399
  panTo(loc: LatLngLiteral, animate?: boolean): void;
400
+ /** Alias over the OpenLayers view: `storymap.map.getView().animate({zoom})`. */
211
401
  zoomTo(z: number, animate?: boolean): void;
402
+ /**
403
+ * Alias over the OpenLayers view: `storymap.map.getView().animate(...)`,
404
+ * or `.fit(extent, {size})` for a region stop (`location.region`).
405
+ */
212
406
  viewTo(loc: StorymapSlideLocation, opts?: ViewToOptions): void;
213
- getBoundsZoom(m1: LatLngLiteral, m2: LatLngLiteral, inside?: boolean, padding?: unknown): void;
407
+ /** Alias over the OpenLayers view: `view.getZoomForResolution(resolution)`. */
408
+ getBoundsZoom(m1: LatLngLiteral, m2: LatLngLiteral, inside?: boolean, padding?: unknown): number | undefined;
409
+ /**
410
+ * Alias over the OpenLayers view: `view.fit(extent, {size})` over all
411
+ * marker positions. Also reachable from the menubar's overview button.
412
+ */
214
413
  markerOverview(): void;
414
+ /**
415
+ * The viewer's own marker zoom ladder — no OpenLayers equivalent (it also
416
+ * writes the computed zoom onto the current markers).
417
+ */
215
418
  calculateMarkerZooms(): void;
419
+ /**
420
+ * The minimap is built with the constructor; reach it with `getMinimap()`
421
+ * (an OpenLayers `OverviewMap` control) rather than re-creating it.
422
+ */
216
423
  createMiniMap(): void;
217
424
  setMapOffset(left: number, top: number): void;
218
425
  calculateMinMaxZoom(): void;
426
+ /**
427
+ * The zoom to use for min/max bounds at marker `index`: the value
428
+ * computed by the engine when there is one, else the zoom authored on
429
+ * the slide. The engine overrides this to serve its computed-zoom store
430
+ * so `StoryMap.data` is never written to.
431
+ */
432
+ _markerZoom(index: number): number | undefined;
219
433
  updateMinMaxZoom(zoom: number): void;
220
434
  initialMapLocation(): void;
435
+ /**
436
+ * @deprecated No-op since 0.9.x upstream (the original Leaflet engine
437
+ * defined an empty body too) and shadowed by the `DomMixed` mixin. To
438
+ * hide the map, toggle the OpenLayers target:
439
+ * `storymap.map.getTargetElement().style.display = "none"`.
440
+ */
221
441
  show(): void;
442
+ /**
443
+ * @deprecated See {@link show} — no-op since 0.9.x upstream. Use
444
+ * `storymap.map.getTargetElement().style.display = "none"`.
445
+ */
222
446
  hide(): void;
223
447
  createMarkers(array: StorymapSlide[]): void;
224
448
  createMarker(d: StorymapSlide): void;
@@ -229,6 +453,27 @@ declare class MapBase {
229
453
  * lon 0 are valid coordinates and must not be treated as missing.
230
454
  */
231
455
  _hasLocation(d: StorymapSlide): boolean;
456
+ /**
457
+ * The {lat, lon} points of every marker from the first up to and
458
+ * including `n`, skipping the ones without a real location. This was four
459
+ * near-identical loops building the same thing.
460
+ */
461
+ private _locationsUpTo;
462
+ /**
463
+ * The slide's {lat, lon} point, or null when it has no real location.
464
+ *
465
+ * Preferred over testing `_hasLocation()` and then reading
466
+ * `data.location.lat`: a boolean guard does not narrow the property for
467
+ * the type checker, so the old form had to be trusted and re-checked by
468
+ * hand at every one of its dozen call sites.
469
+ */
470
+ _locationOf(d: StorymapSlide): LatLngLiteral | null;
471
+ /**
472
+ * Image region stop: the slide carries an xywh region ([x, y, w, h]
473
+ * image pixels). Only the OpenLayers engine applies it (image mode);
474
+ * the region never contributes to route lines.
475
+ */
476
+ _hasRegion(d: StorymapSlide): boolean;
232
477
  _createMap(): void;
233
478
  _createMiniMap(): void;
234
479
  _createMarker(d?: StorymapSlide): void;
@@ -237,7 +482,9 @@ declare class MapBase {
237
482
  _resetMarkersActive(): void;
238
483
  _calculateMarkerZooms(): void;
239
484
  _createLine(d?: StorymapSlide): unknown;
240
- _addToLine(line: Vector | null, d: LinePoint): void;
485
+ /** Append a slide's location to a route line. Takes the *slide*, not a
486
+ * point — the engine reads `d.location`. */
487
+ _addToLine(line: Vector | null, d: StorymapSlide): void;
241
488
  _replaceLines(line: Vector | null, d: LinePoint[], animate?: {
242
489
  duration: number;
243
490
  retractFrom?: LinePoint[] | null;
@@ -251,7 +498,20 @@ declare class MapBase {
251
498
  _refreshMap(): void;
252
499
  _getMapZoom(): number;
253
500
  _getMapCenter(correct_for_center?: boolean): LatLngLiteral;
254
- _getBoundsZoom(m1: LatLngLiteral, m2: LatLngLiteral, inside?: boolean, padding?: unknown): number;
501
+ /**
502
+ * The `ease` option as an OpenLayers easing function.
503
+ *
504
+ * `ease` is documented as either a function or a name, so the cast to
505
+ * OpenLayers' expected shape was repeated at all ten `view.animate()` call
506
+ * sites.
507
+ */
508
+ protected get _easing(): ((t: number) => number) | undefined;
509
+ /**
510
+ * Zoom that fits the two given points, or `undefined` when the engine
511
+ * cannot compute one. Mirrors `getRouteDistance`: the base class is the
512
+ * no-op template, the OpenLayers subclass returns a real value.
513
+ */
514
+ _getBoundsZoom(m1: LatLngLiteral, m2: LatLngLiteral, inside?: boolean, padding?: unknown): number | undefined;
255
515
  _markerOverview(duration?: number): void;
256
516
  /**
257
517
  * Great-circle length of the route through all markers in kilometers;
@@ -267,7 +527,7 @@ declare class MapBase {
267
527
  _onWheel(e: WheelEvent): void;
268
528
  _scollZoom(e?: unknown): void;
269
529
  _scollZoomDone(e?: unknown): void;
270
- _calculateZoomChange(origin: LatLngLiteral, destination: LatLngLiteral, correct_for_center?: boolean): number;
530
+ _calculateZoomChange(origin: LatLngLiteral, destination: LatLngLiteral, correct_for_center?: boolean): number | undefined;
271
531
  _updateDisplay(w?: number, h?: number, animate?: boolean, d?: number, offset?: unknown): void;
272
532
  /** Re-apply runtime-changed options (no-op in the base class) */
273
533
  applyOptions(_keys: string[]): void;
@@ -287,7 +547,7 @@ declare const MapMarker_base: {
287
547
  _vco_events?: Record<string, {
288
548
  action: unknown;
289
549
  context: unknown;
290
- }[]>;
550
+ }[]> | undefined;
291
551
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
292
552
  hasEventListeners(type: string): boolean;
293
553
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -310,35 +570,65 @@ declare class MapMarkerBase {
310
570
  "animator": AnimationHandle | null;
311
571
  "fire": EventedInstance["fire"];
312
572
  constructor(data?: MapMarkerData, options?: Partial<StorymapOptions>);
573
+ /**
574
+ * @deprecated No-op since 0.9.x upstream (the original marker defined an
575
+ * empty body too). Markers are never individually hidden; use CSS on
576
+ * `.vco-mapmarker`, or `active(false)` to dim one.
577
+ */
313
578
  show(): void;
579
+ /** @deprecated See {@link show} — no-op since 0.9.x upstream. */
314
580
  hide(): void;
581
+ /**
582
+ * @deprecated Never implemented, in the original viewer either: the base
583
+ * `MapMarker._createPopup` had an empty body and the Leaflet override's
584
+ * body was commented out, so the `map_popup` option that called it never
585
+ * had any effect. Kept as a no-op so pre-0.10 code that calls it keeps
586
+ * working. Render the slide text yourself, or use CSS on
587
+ * `.vco-mapmarker` to show a label.
588
+ */
589
+ createPopup(_d?: MapMarkerData, _o?: StorymapOptions): void;
315
590
  addTo(m: unknown): void;
316
591
  removeFrom(m: unknown): void;
317
592
  updateDisplay(w: number, h: number, a?: boolean): void;
318
593
  createMarker(d?: MapMarkerData, o?: StorymapOptions): void;
319
594
  active(a: boolean): void;
320
- location(): LatLngLiteral;
595
+ location(): LatLngLiteral | null;
321
596
  _createMarker(d?: MapMarkerData, o?: StorymapOptions): void;
322
597
  _addTo(m: unknown): void;
323
598
  _removeFrom(m: unknown): void;
324
599
  _active(a: boolean): void;
325
- _location(): LatLngLiteral;
600
+ /**
601
+ * The marker's coordinate, or null when it has none (an overview slide, or
602
+ * a slide carrying only an image region). Every caller treats null as
603
+ * "nothing to focus", so this is the honest shape — the previous
604
+ * `{ lat: 0, lng: 0 }` was a real point at Null Island, spelled with a
605
+ * longitude key nothing in the map read.
606
+ */
607
+ _location(): LatLngLiteral | null;
326
608
  _onMarkerClick(e?: unknown): void;
327
609
  _initLayout(): void;
328
610
  _updateDisplay(width: number, height: number, animate?: boolean): void;
329
611
  }
330
612
 
331
- declare interface MapMarkerData {
613
+ /**
614
+ * A marker's data: the slide it was created from, plus the `real_marker` flag
615
+ * the marker sets once it has confirmed numeric lat/lon. A separate interface
616
+ * used to drift from `StorymapSlide` (narrower `text`, its own `location`),
617
+ * which then made `Map._createMarker(slide)` unassignable.
618
+ */
619
+ declare type MapMarkerData = StorymapSlide & {
332
620
  real_marker?: boolean;
333
- location?: StorymapSlideLocation;
334
- media?: StorymapSlideMedia & {
335
- mediatype?: MediaTypeMatch | null;
336
- };
337
- text?: {
338
- headline?: string;
339
- };
340
- type?: string;
341
- [key: string]: unknown;
621
+ };
622
+
623
+ /** The resolved marker presentation: `marker.*` over `location.*`. */
624
+ declare interface MarkerPresentation {
625
+ icon?: string;
626
+ iconSize?: number[];
627
+ image?: string;
628
+ label?: string;
629
+ popup: boolean;
630
+ audioBadge: boolean;
631
+ useCustomMarker?: boolean;
342
632
  }
343
633
 
344
634
  declare interface MediaInstance {
@@ -346,9 +636,12 @@ declare interface MediaInstance {
346
636
  loadMedia: () => void;
347
637
  stopMedia: () => void;
348
638
  updateDisplay: (w?: number, h?: number, l?: string) => void;
639
+ dispose?: () => void;
349
640
  on?: EventedInstance["on"];
641
+ off?: EventedInstance["off"];
350
642
  _state?: {
351
643
  loaded?: boolean;
644
+ eager?: boolean;
352
645
  };
353
646
  }
354
647
 
@@ -362,7 +655,7 @@ declare interface MediaInstance {
362
655
  */
363
656
  export declare function MediaType(m: StorymapSlideMedia): MediaTypeMatch | false;
364
657
 
365
- declare type MediaTypeMatch = {
658
+ export declare type MediaTypeMatch = {
366
659
  type: string;
367
660
  name: string;
368
661
  match_str: string;
@@ -375,6 +668,7 @@ declare class MenuBar extends MenuBar_base {
375
668
 
376
669
  declare const MenuBar_base: {
377
670
  new (...args: any[]): {
671
+ container(): HTMLElement;
378
672
  show(animate?: unknown): void;
379
673
  hide(): void;
380
674
  addTo(container: HTMLElement): /*elided*/ any;
@@ -383,7 +677,7 @@ declare const MenuBar_base: {
383
677
  onLoaded(): void;
384
678
  onAdd(): void;
385
679
  onRemove(): void;
386
- _el: Record<string, HTMLElement>;
680
+ _el: Record<string, unknown>;
387
681
  data?: unknown;
388
682
  on: (type: string, fn: unknown, context?: unknown) => unknown;
389
683
  off: (type: string, fn: unknown, context?: unknown) => unknown;
@@ -395,7 +689,7 @@ declare const MenuBar_base: {
395
689
  _vco_events?: Record<string, {
396
690
  action: unknown;
397
691
  context: unknown;
398
- }[]>;
692
+ }[]> | undefined;
399
693
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
400
694
  hasEventListeners(type: string): boolean;
401
695
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -409,6 +703,7 @@ declare class MenuBarBase {
409
703
  "options": MenuBarOptions;
410
704
  "animator": Record<string, unknown>;
411
705
  "fire": EventedInstance["fire"];
706
+ _fullscreenActive: boolean;
412
707
  constructor(elem: HTMLElement | string, parent_elem?: HTMLElement, options?: object);
413
708
  show(d?: number): void;
414
709
  hide(top: number): void;
@@ -418,6 +713,24 @@ declare class MenuBarBase {
418
713
  * Reflect the fullscreen state in the button label/icon.
419
714
  */
420
715
  setFullscreenState(active: boolean): void;
716
+ /**
717
+ * Repaint the overview button label. An image map has no interactive
718
+ * overview, so it gets the shorter wording.
719
+ */
720
+ _renderOverviewLabel(): void;
721
+ /**
722
+ * Repaint the "back to start" button label. Icon-only on mobile.
723
+ */
724
+ _renderBackToStartLabel(): void;
725
+ /**
726
+ * Repaint the collapse/expand toggle. Icon-only on mobile.
727
+ */
728
+ _renderCollapseLabel(collapsed: boolean): void;
729
+ /**
730
+ * Repaint every text label from the active language (see `setLanguage`).
731
+ * Icon-only mobile buttons carry no text and are left untouched.
732
+ */
733
+ refreshLabels(): void;
421
734
  /**
422
735
  * Update the progress indicator (issue #247); no-op when disabled.
423
736
  */
@@ -434,6 +747,11 @@ declare class MenuBarBase {
434
747
  _onButtonCollapseMap(e: Event): void;
435
748
  _initLayout(): void;
436
749
  _updateDisplay(width?: number, height?: number, animate?: boolean): void;
750
+ /**
751
+ * Release the button listeners, the progress animation and the element.
752
+ * Called by `StoryMap.dispose()`; the menubar must not be used afterwards.
753
+ */
754
+ dispose(): void;
437
755
  }
438
756
 
439
757
  declare interface MenuBarOptions {
@@ -451,6 +769,7 @@ declare class Message extends Message_base {
451
769
 
452
770
  declare const Message_base: {
453
771
  new (...args: any[]): {
772
+ container(): HTMLElement;
454
773
  show(animate?: unknown): void;
455
774
  hide(): void;
456
775
  addTo(container: HTMLElement): /*elided*/ any;
@@ -459,7 +778,7 @@ declare const Message_base: {
459
778
  onLoaded(): void;
460
779
  onAdd(): void;
461
780
  onRemove(): void;
462
- _el: Record<string, HTMLElement>;
781
+ _el: Record<string, unknown>;
463
782
  data?: unknown;
464
783
  on: (type: string, fn: unknown, context?: unknown) => unknown;
465
784
  off: (type: string, fn: unknown, context?: unknown) => unknown;
@@ -471,7 +790,7 @@ declare const Message_base: {
471
790
  _vco_events?: Record<string, {
472
791
  action: unknown;
473
792
  context: unknown;
474
- }[]>;
793
+ }[]> | undefined;
475
794
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
476
795
  hasEventListeners(type: string): boolean;
477
796
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -491,6 +810,11 @@ declare class MessageBase {
491
810
  _onMouseClick(): void;
492
811
  _initLayout(): void;
493
812
  _initEvents(): void;
813
+ /**
814
+ * Release the click listener and drop the element. Called by
815
+ * `StorySlider.dispose()`; the message must not be used afterwards.
816
+ */
817
+ dispose(): void;
494
818
  }
495
819
 
496
820
  declare interface MessageOptions {
@@ -501,18 +825,79 @@ declare interface MessageOptions {
501
825
  [key: string]: unknown;
502
826
  }
503
827
 
828
+ export { OlLayer }
829
+
830
+ export { OlMap }
831
+
832
+ export { OlProjection }
833
+
834
+ export { OlSource }
835
+
836
+ export { OlTileLayer }
837
+
838
+ export { OlVectorLayer }
839
+
840
+ export { OlView }
841
+
504
842
  declare class OpenLayers extends Map_2 {
505
- "_map": default_3;
506
- "_tile_layer": Tile;
843
+ "_map": OlMap;
844
+ "_tile_layer": OlLayer;
507
845
  "_line": Vector;
508
846
  "_line_active": Vector;
509
- "_tile_layer_mini": Tile | null;
847
+ "_tile_layer_mini": OlLayer | null;
510
848
  "_mini_map": default_2;
511
849
  "_markers": OpenLayersMapMarker[];
850
+ /** App-level stacked overlays (see the `overlays` option) */
851
+ "_overlay_layers": OlLayer[];
852
+ /**
853
+ * The `overlays[]` entries that produced a layer, parallel to
854
+ * `_overlay_layers`: a malformed entry is skipped, so the two arrays
855
+ * can be shorter than the option list.
856
+ */
857
+ "_overlay_entries": StorymapOverlayLayer[];
512
858
  /** rAF handle of the running active-line draw animation */
513
859
  "_line_animation": number | null;
860
+ /** Sources `imageready` has already been fired for. */
861
+ "_imageready_fired": WeakSet<object>;
514
862
  _createMap(): void;
515
- _getAttribution(map_type: string): string;
863
+ /** Extra attribution fragments (e.g. overlay credits), always listed last. */
864
+ "_extra_attributions": string[];
865
+ /**
866
+ * Append extra attribution fragments and refresh the line. Hosts with
867
+ * custom layers use this instead of rewriting `.vco-map-attribution`.
868
+ */
869
+ setExtraAttributions(parts: string[]): void;
870
+ /** The base tile layer (the one created for `map_type`), if consent has not deferred it. */
871
+ getBaseLayer(): OlLayer | null;
872
+ /** The stacked `overlays[]` layers, in `overlays[]` order. */
873
+ getOverlayLayers(): OlLayer[];
874
+ /** One stacked overlay layer by its `overlays[]` index, or `null`. */
875
+ getOverlayLayer(index: number): OlLayer | null;
876
+ /** The minimap's OpenLayers map (the `OverviewMap` control's inner map). */
877
+ getMinimap(): OlMap | null;
878
+ /** The full (inactive) route line layer. */
879
+ getLine(): OlLayer | null;
880
+ /** The highlighted route line layer drawn up to the current slide. */
881
+ getLineActive(): OlLayer | null;
882
+ /** The markers, in slide order (the index matches the slide index). */
883
+ getMarkers(): OpenLayersMapMarker[];
884
+ /** One marker by slide index, or `null`. */
885
+ getMarker(index: number): OpenLayersMapMarker | null;
886
+ /**
887
+ * (Re)render the attribution line for the current map type. Called at
888
+ * creation and on every `map_type` switch, which previously left the
889
+ * initial text stale.
890
+ */
891
+ _updateAttribution(): void;
892
+ _getAttribution(map_type: string): string[];
893
+ /**
894
+ * The provider credit for `map_type` as plain text (no HTML), for the
895
+ * OpenLayers source `attributions`. Our own `.vco-map-attribution` line
896
+ * stays the rendered default and uses the linked `_getAttribution`
897
+ * version; this makes `source.getAttributions()` (and a consumer's
898
+ * `ol/control/Attribution`) work instead of returning nothing.
899
+ */
900
+ _sourceAttributions(map_type: string): string[];
516
901
  /**
517
902
  * Create the tile layer and register its load handler. Deferred until
518
903
  * the visitor allows map tiles in consent mode.
@@ -521,7 +906,64 @@ declare class OpenLayers extends Map_2 {
521
906
  /**
522
907
  * Ask for tile consent, then attach the layers if allowed.
523
908
  */
524
- _requestTileConsent(consent: ConsentManager, tile_service: string): Promise<void>;
909
+ _requestTileConsent(consent: ConsentManager, tile_service: ConsentService): Promise<void>;
910
+ /**
911
+ * (Re)build the stacked raster overlays from the `overlays` option.
912
+ * Overlays sit above the base tiles (z 1..n) and below the route lines
913
+ * (z 10/11); every entry accepts any `map_type` value plus declarative
914
+ * presentation, so hosts no longer capture and patch layer objects.
915
+ * An entry carrying a `georeference` places a IIIF image on the
916
+ * geographic map instead of stacking a tile source.
917
+ */
918
+ _buildOverlays(): void;
919
+ /**
920
+ * Build a stacked overlay from a IIIF Georeference Extension payload
921
+ * (`overlays[].georeference`): the ground control points are fitted
922
+ * affinely and the image is placed as a geographic extent, which
923
+ * OpenLayers reprojects onto the view exactly like the IIIF basemap.
924
+ *
925
+ * The layer is returned empty and filled in asynchronously, mirroring
926
+ * the `iiif` basemap path — only the fit (pure, synchronous) decides
927
+ * whether a layer exists at all, so overlay indices stay stable.
928
+ */
929
+ _createGeoreferencedOverlay(entry: StorymapOverlayLayer): Tile | null;
930
+ /**
931
+ * Convert a lon/lat clip box to view units. Only meaningful on
932
+ * mercator maps; image-space maps (iiif/zoomify) and malformed
933
+ * boxes yield null (no constraint).
934
+ */
935
+ _lonLatBboxToExtent(bbox: [number, number, number, number]): Extent | null;
936
+ /**
937
+ * Apply an overlay's blend mode to its layer container. The container
938
+ * div only exists once the layer has rendered, so retry on later
939
+ * frames (bounded: rendering settles within a frame or two of any
940
+ * add/visibility change).
941
+ */
942
+ _paintOverlayBlend(entry: {
943
+ className?: string;
944
+ blendMode?: string;
945
+ }, retries?: number): void;
946
+ /** Refresh the attribution line with the visible overlays' credits. */
947
+ _syncOverlayAttributions(): void;
948
+ /**
949
+ * Number of stacked overlay layers (see the `overlays` option). Alias:
950
+ * `getOverlayLayers().length`.
951
+ */
952
+ getOverlayCount(): number;
953
+ /**
954
+ * Show or hide a stacked overlay by index (re-syncs attribution). The
955
+ * index counts built layers, i.e. it skips malformed entries.
956
+ *
957
+ * Prefer `getOverlayLayer(index).setVisible(v)` on the layer itself; this
958
+ * wrapper exists because it also re-syncs the attribution line and the
959
+ * overlay blend mode, which a bare `setVisible()` does not.
960
+ */
961
+ setOverlayVisible(index: number, visible: boolean): void;
962
+ /** Set a stacked overlay's opacity by index. */
963
+ /**
964
+ * Alias: `getOverlayLayer(index)?.setOpacity(opacity)`.
965
+ */
966
+ setOverlayOpacity(index: number, opacity: number): void;
525
967
  /**
526
968
  * Map tiles were allowed: attach the main tile layer, create the
527
969
  * minimap's deferred layer if it was withheld, then re-fit.
@@ -536,7 +978,7 @@ declare class OpenLayers extends Map_2 {
536
978
  sizes: Array<[number, number]>;
537
979
  maxZoom: number;
538
980
  extent: number[];
539
- tileGrid: default_5;
981
+ tileGrid: default_4;
540
982
  } | null;
541
983
  /**
542
984
  * The zoomify overview state: the best-fit pyramid level for a map
@@ -547,7 +989,82 @@ declare class OpenLayers extends Map_2 {
547
989
  zoom: number;
548
990
  center: number[];
549
991
  } | null;
550
- _createTileLayer(map_type: string): Tile;
992
+ _createTileLayer(map_type: string): OlLayer;
993
+ /**
994
+ * A layer's source, or null when it has none. Custom `Layer` subclasses
995
+ * passed through `_createTileLayer` (e.g. Allmaps' `WarpedMapLayer`)
996
+ * deliberately have no `getSource`, so every read goes through here
997
+ * instead of calling the method directly.
998
+ */
999
+ _sourceOf(layer: OlLayer | null | undefined): OlSource | null;
1000
+ /**
1001
+ * Move the map into another element, keeping OpenLayers in step.
1002
+ *
1003
+ * `DomMixed.addTo()` (the original semantics, unchanged: append the map
1004
+ * container, fire `added`) only moves DOM — the `ol/Map` still has the
1005
+ * viewport it measured at construction, so it would keep painting at the
1006
+ * old size. Re-attach the target, which `removeFrom()` detached, and
1007
+ * re-measure. The argument must be the new parent.
1008
+ */
1009
+ addTo(container: HTMLElement): this;
1010
+ /**
1011
+ * Move the map out of `container`. Untargets the OpenLayers map so it
1012
+ * does not render into a detached node; a later {@link addTo} re-attaches
1013
+ * it. The argument must be the current parent.
1014
+ */
1015
+ removeFrom(container: HTMLElement): this;
1016
+ /**
1017
+ * True when the map is a plain image in an `EPSG:4326` "image space"
1018
+ * rather than a geographic map: a IIIF image presented as a picture of
1019
+ * the world (`map_as_image`), not georeferenced.
1020
+ *
1021
+ * In this mode the view projection is `EPSG:4326` with degrees as
1022
+ * resolution and the view is fitted to the image extent, so
1023
+ * `getCenter()`/`getZoom()` are in degrees/pixels-per-degree — not
1024
+ * mercator metres. Marker locations are pixel offsets into the image,
1025
+ * not lat/lon. Georeferenced IIIF (`map_bbox` with `map_as_image`
1026
+ * omitted) is a normal mercator map; use `isImageSpace()` rather than
1027
+ * testing `map_type` to tell the two apart.
1028
+ */
1029
+ isImageSpace(): boolean;
1030
+ /**
1031
+ * Stop the line animation, drop the minimap control and dispose the
1032
+ * OpenLayers map. Called by `StoryMap.dispose()`; the engine must not be
1033
+ * used afterwards.
1034
+ */
1035
+ dispose(): void;
1036
+ /**
1037
+ * Fire `imageready` once `source` is usable (and immediately when it
1038
+ * already is). Image sources — IIIF, zoomify, the deferred tile layer —
1039
+ * attach asynchronously, so this is the only outward signal that the
1040
+ * imagery is really on the map; the `loaded` event can fire before the
1041
+ * source is attached at all.
1042
+ */
1043
+ _fireImageready(source: {
1044
+ getState?(): string;
1045
+ }, kind: ImagereadyKind, layer?: OlLayer): void;
1046
+ /** Computed zooms take precedence over the authored slide zoom. */
1047
+ _markerZoom(index: number): number | undefined;
1048
+ /**
1049
+ * The TileJSON metadata, but only when it is describing `url`.
1050
+ *
1051
+ * `tilejson` describes the map's tile source, so its `tiles` template is
1052
+ * the one the map_type resolved to. When it names a different template it
1053
+ * is not about this source, and neither the zoom ladder nor the initial
1054
+ * view should be taken from it.
1055
+ */
1056
+ _tilejsonFor(url: string): StorymapTilejson | undefined;
1057
+ /**
1058
+ * An XYZ source for a URL template, honouring the TileJSON metadata of the
1059
+ * map's own tile source if it is describing this template (§2.9).
1060
+ *
1061
+ * `minzoom`/`maxzoom` become the tile grid's zoom range, so OpenLayers asks
1062
+ * for levels the service actually has and stops past the ones it does not.
1063
+ * `scheme: "tms"` is the TMS row order, which is the same URL with the tile
1064
+ * row counted from the bottom.
1065
+ */
1066
+ _xyzSource(url: string): XYZ;
1067
+ _createDefaultTileLayer(map_type: string): Tile;
551
1068
  _createVectorStyleLayer(style_url: string): Tile;
552
1069
  _createMiniMap(): void;
553
1070
  _fitMiniMapToImage(): void;
@@ -587,7 +1104,7 @@ declare class OpenLayers extends Map_2 {
587
1104
  * by design — they must not skew the fit target, so the extent is
588
1105
  * intersected with the box and the in-box markers compose the view.
589
1106
  */
590
- _fitView(ol_map: default_3, coords: number[][], duration?: number, clamp_to_bbox?: boolean): void;
1107
+ _fitView(ol_map: OlMap, coords: number[][], duration?: number, clamp_to_bbox?: boolean): void;
591
1108
  _calculateMarkerZooms(): void;
592
1109
  /**
593
1110
  * Stroke style for the route lines: the dash pattern and line join are
@@ -597,7 +1114,7 @@ declare class OpenLayers extends Map_2 {
597
1114
  _lineStyle(color: string): Style;
598
1115
  _createLine(d?: StorymapSlide): Vector;
599
1116
  _addLineToMap(line: Vector): void;
600
- _addToLine(line: Vector, d: LinePoint): void;
1117
+ _addToLine(line: Vector, d: StorymapSlide): void;
601
1118
  /**
602
1119
  * Replace a line's geometry. With `animate.duration > 0` only the latest
603
1120
  * hop animates, in sync with the view animation: the already-traveled
@@ -623,11 +1140,35 @@ declare class OpenLayers extends Map_2 {
623
1140
  _panTo(loc: LatLngLiteral, animate?: boolean): void;
624
1141
  _zoomTo(z: number, animate?: boolean): void;
625
1142
  _viewTo(loc: StorymapSlideLocation, opts?: ViewToOptions): void;
1143
+ /**
1144
+ * Image region stop: fit the xywh bbox ([x, y, w, h] image pixels —
1145
+ * the EPSG:4326 image space) with the shared animation options, then
1146
+ * keep the minimap collapse state in sync like `_viewTo`.
1147
+ */
1148
+ _fitRegion(region: [number, number, number, number], opts?: ViewToOptions): void;
626
1149
  _toViewCoords(loc: LatLngLiteral): number[];
627
1150
  _getMapZoom(): number;
628
- _getMapCenter(offset?: boolean): LatLngLiteral;
1151
+ _getMapCenter(): LatLngLiteral;
629
1152
  _getMapCenterOffset(location: LatLngLiteral, zoom: number): LatLngLiteral;
630
- _fromViewCoords(coord: number[], projection: default_6): LatLngLiteral;
1153
+ _fromViewCoords(coord: number[], projection: OlProjection): LatLngLiteral;
1154
+ /**
1155
+ * May a tile-backed layer (base map, overlay, minimap, overview) be
1156
+ * created right now? Under `consent_required` that is only true once the
1157
+ * visitor has allowed the tile service. This was the same five-line
1158
+ * predicate at five call sites.
1159
+ */
1160
+ private _tilesAllowed;
1161
+ /** A slide's {lat, lon} when both are real numbers, else null. */
1162
+ private _latLngOf;
1163
+ /**
1164
+ * The map's pixel size, with a never-zero fallback.
1165
+ *
1166
+ * `getSize()` returns undefined until the map has a size, so the six
1167
+ * call sites that fitted an extent to the viewport all repeated the same
1168
+ * `(size[0] || 1)` guard — which silently fitted against a 1px viewport
1169
+ * rather than bailing out.
1170
+ */
1171
+ private _viewportSize;
631
1172
  _getBoundsZoom(origin: LatLngLiteral, destination: LatLngLiteral, correct_for_center?: boolean): number;
632
1173
  _initialMapLocation(): void;
633
1174
  /**
@@ -659,14 +1200,78 @@ declare class OpenLayers extends Map_2 {
659
1200
  }
660
1201
 
661
1202
  declare class OpenLayersMapMarker extends MapMarker {
662
- "_overlay": default_4;
1203
+ "_overlay": default_3;
1204
+ "_onMarkerClickBound": ((e: Event) => void) | null;
1205
+ /** marker.popup: the active marker opens its card when clicked. */
1206
+ "_popup_enabled": boolean;
1207
+ /** marker.audioBadge: flag a slide that has narration or audio media. */
1208
+ "_audio_badge": boolean;
1209
+ /**
1210
+ * The popup card while it is open. `declare` fields are undefined until
1211
+ * assigned, so every read below is a truthiness check, never `=== null`,
1212
+ * and there is no constructor to initialise them: `MapMarker`'s own
1213
+ * constructor already runs `_initLayout()` → `_createMarker()`, which
1214
+ * assigns the flags, and initialising afterwards would wipe them.
1215
+ */
1216
+ "_popup_el": HTMLElement | null;
1217
+ /** Escape-to-close, detached in dispose(). */
1218
+ "_onPopupKeyBound": ((e: KeyboardEvent) => void) | null;
1219
+ /** Mirrors `active()`, as a flag rather than a method reference. */
1220
+ "_is_active": boolean;
1221
+ /**
1222
+ * The merged marker presentation: `marker.*` wins, `location.*` is the
1223
+ * legacy spelling and still works (docs/plans/iiif-media-tours.md §2).
1224
+ * `location` also stays the carrier of geography, so lat/lon are read
1225
+ * from it alone — presentation never moves a marker.
1226
+ */
1227
+ _presentation(d?: MapMarkerData): MarkerPresentation;
663
1228
  _createMarker(d?: MapMarkerData, o?: StorymapOptions): void;
664
1229
  _createMarkerElement(d: MapMarkerData, o?: StorymapOptions): HTMLDivElement;
1230
+ /**
1231
+ * The marker's {lat, lon}, or null when it is a non-georeferenced marker
1232
+ * (an overview slide, or a slide with only an image region). `_createMarker`
1233
+ * already established this for a real marker, but returning it from one
1234
+ * place means the type checker can see it too.
1235
+ */
1236
+ latLon(): LatLngLiteral | null;
665
1237
  _addTo(m: Map_3): void;
666
1238
  _removeFrom(m: Map_3): void;
1239
+ /**
1240
+ * Terminal teardown: detach the click listener and drop the overlay and
1241
+ * element. Called by the map's dispose(); the marker must not be used
1242
+ * afterwards.
1243
+ */
1244
+ /**
1245
+ * Toggle the popup card for the *active* marker. Inactive markers keep
1246
+ * their original behaviour — a click navigates — so a popup never
1247
+ * swallows navigation on a map full of pins.
1248
+ *
1249
+ * The card is a DOM element parented to the marker element and positioned
1250
+ * with CSS, which is how it survives a move to the vector renderer
1251
+ * (docs/plans/issue-159-vector-markers.md): only the anchor is the
1252
+ * marker's, and that is `latLon()`.
1253
+ */
1254
+ _togglePopup(): void;
1255
+ _closePopup(): void;
1256
+ get popupOpen(): boolean;
1257
+ /**
1258
+ * Headline, a sanitized excerpt, the media thumb and an audio control.
1259
+ * Every piece of text goes through `sanitizeSlideText` — a slide's text
1260
+ * is untrusted input and a marker card is no different (the stored-XSS
1261
+ * audit made that lesson once; a label is attacker-controlled text like
1262
+ * any other).
1263
+ */
1264
+ _createPopupElement(): HTMLElement | null;
1265
+ /**
1266
+ * A small indicator on markers whose slide has narration or audio media
1267
+ * (the Micrio affordance). Recomputed on activation, because a slide's
1268
+ * media may only be known once it is resolved.
1269
+ */
1270
+ _updateAudioBadge(): void;
1271
+ dispose(): void;
667
1272
  _active(a: boolean): void;
668
1273
  _customIconAnchor(size?: number[]): number[];
669
- _location(): LatLngLiteral;
1274
+ _location(): LatLngLiteral | null;
670
1275
  }
671
1276
 
672
1277
  /** Wheel/scroll zoom bookkeeping (handles cleared via clearTimeout). */
@@ -677,7 +1282,8 @@ declare interface ScrollState {
677
1282
  }
678
1283
 
679
1284
  /**
680
- * Switch the active UI language.
1285
+ * Switch the active UI language. Synchronous: the viewer resolves its labels
1286
+ * while it is being constructed.
681
1287
  *
682
1288
  * @param code - A locale code for which a locale file exists (e.g. `"en"`).
683
1289
  * @returns The language entry that is now active.
@@ -690,6 +1296,7 @@ declare class Slide extends Slide_base {
690
1296
 
691
1297
  declare const Slide_base: {
692
1298
  new (...args: any[]): {
1299
+ container(): HTMLElement;
693
1300
  show(animate?: unknown): void;
694
1301
  hide(): void;
695
1302
  addTo(container: HTMLElement): /*elided*/ any;
@@ -698,7 +1305,7 @@ declare const Slide_base: {
698
1305
  onLoaded(): void;
699
1306
  onAdd(): void;
700
1307
  onRemove(): void;
701
- _el: Record<string, HTMLElement>;
1308
+ _el: Record<string, unknown>;
702
1309
  data?: unknown;
703
1310
  on: (type: string, fn: unknown, context?: unknown) => unknown;
704
1311
  off: (type: string, fn: unknown, context?: unknown) => unknown;
@@ -710,7 +1317,7 @@ declare const Slide_base: {
710
1317
  _vco_events?: Record<string, {
711
1318
  action: unknown;
712
1319
  context: unknown;
713
- }[]>;
1320
+ }[]> | undefined;
714
1321
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
715
1322
  hasEventListeners(type: string): boolean;
716
1323
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -724,7 +1331,8 @@ declare interface SlideBackgroundChange {
724
1331
  }
725
1332
 
726
1333
  declare class SlideBase {
727
- "_el": Record<string, HTMLElement>;
1334
+ /** `call_to_action` is only created when the slide shows one. */
1335
+ "_el": SlideElements;
728
1336
  "_media": MediaInstance | null;
729
1337
  "_mediaclass": unknown;
730
1338
  "_text": Text_2;
@@ -733,6 +1341,9 @@ declare class SlideBase {
733
1341
  };
734
1342
  "_scroll_hint": HTMLElement | null;
735
1343
  "_scroll_hint_dismissed": boolean;
1344
+ "_onSlideScrollBound": EventListener;
1345
+ /** Every `media_ended` handler registered via `onMediaEnded`, kept so `dispose()` can remove them. */
1346
+ "_media_ended_fns": (() => void)[];
736
1347
  "has": SlideHas;
737
1348
  "title": string;
738
1349
  "data": StorymapSlide;
@@ -744,15 +1355,34 @@ declare class SlideBase {
744
1355
  constructor(data: StorymapSlide, options: Record<string, unknown>, title_slide?: boolean);
745
1356
  show(): void;
746
1357
  hide(): void;
1358
+ /**
1359
+ * Release the slide's listeners, media and DOM. Called by
1360
+ * `StorySlider.dispose()`; the slide must not be used afterwards.
1361
+ */
1362
+ dispose(): void;
747
1363
  setActive(is_active: boolean): void;
748
1364
  updateDisplay(w?: number, h?: number, l?: string): void;
749
1365
  loadMedia(): void;
1366
+ _eagerLoadImages(): void;
750
1367
  stopMedia(): void;
751
1368
  getBackground(): {
752
1369
  image: boolean;
753
1370
  color: boolean;
754
1371
  color_value: string;
755
1372
  };
1373
+ /**
1374
+ * True when this slide's media is a timed, playable one (audio or video).
1375
+ * `autoplay_media` waits for such a slide's media to end instead of using
1376
+ * its timer; everything else keeps the timer.
1377
+ */
1378
+ hasPlayableMedia(): boolean;
1379
+ /**
1380
+ * Call `fn` when this slide's media finishes playing. A slide with no
1381
+ * media — or media that cannot end — never calls it, which is why
1382
+ * `autoplay_media` keeps its timer as a fallback rather than waiting on
1383
+ * an event that may not arrive.
1384
+ */
1385
+ onMediaEnded(fn: () => void): void;
756
1386
  scrollToTop(): void;
757
1387
  /**
758
1388
  * Show a bouncing downward arrow when the slide content overflows
@@ -770,6 +1400,19 @@ declare class SlideBase {
770
1400
  _updateDisplay(width?: number, height?: number, layout?: string): void;
771
1401
  }
772
1402
 
1403
+ /**
1404
+ * The slide's element cache. `call_to_action` is null until the slide is told
1405
+ * to show one (`addCallToAction`).
1406
+ */
1407
+ declare type SlideElements = {
1408
+ container: HTMLElement;
1409
+ scroll_container: HTMLElement;
1410
+ background: HTMLElement;
1411
+ content_container: HTMLElement;
1412
+ content: HTMLElement;
1413
+ call_to_action: HTMLElement | null;
1414
+ };
1415
+
773
1416
  declare interface SlideHas {
774
1417
  headline: boolean;
775
1418
  text: boolean;
@@ -788,6 +1431,7 @@ declare class SlideNav extends SlideNav_base {
788
1431
 
789
1432
  declare const SlideNav_base: {
790
1433
  new (...args: any[]): {
1434
+ container(): HTMLElement;
791
1435
  show(animate?: unknown): void;
792
1436
  hide(): void;
793
1437
  addTo(container: HTMLElement): /*elided*/ any;
@@ -796,7 +1440,7 @@ declare const SlideNav_base: {
796
1440
  onLoaded(): void;
797
1441
  onAdd(): void;
798
1442
  onRemove(): void;
799
- _el: Record<string, HTMLElement>;
1443
+ _el: Record<string, unknown>;
800
1444
  data?: unknown;
801
1445
  on: (type: string, fn: unknown, context?: unknown) => unknown;
802
1446
  off: (type: string, fn: unknown, context?: unknown) => unknown;
@@ -808,7 +1452,7 @@ declare const SlideNav_base: {
808
1452
  _vco_events?: Record<string, {
809
1453
  action: unknown;
810
1454
  context: unknown;
811
- }[]>;
1455
+ }[]> | undefined;
812
1456
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
813
1457
  hasEventListeners(type: string): boolean;
814
1458
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -833,6 +1477,12 @@ declare class SlideNavBase {
833
1477
  _update(d?: Partial<SlideNavData>): void;
834
1478
  _initLayout(): void;
835
1479
  _initEvents(): void;
1480
+ _onKeyDown(e: Event): void;
1481
+ /**
1482
+ * Release the listeners and the position animation. Called by
1483
+ * `StorySlider.dispose()`; the nav must not be used afterwards.
1484
+ */
1485
+ dispose(): void;
836
1486
  }
837
1487
 
838
1488
  declare interface SlideNavData {
@@ -874,7 +1524,7 @@ declare const StoryMap_base: {
874
1524
  _vco_events?: Record<string, {
875
1525
  action: unknown;
876
1526
  context: unknown;
877
- }[]>;
1527
+ }[]> | undefined;
878
1528
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
879
1529
  hasEventListeners(type: string): boolean;
880
1530
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -890,7 +1540,7 @@ declare const StoryMap_base: {
890
1540
  *
891
1541
  * @example
892
1542
  * ```ts
893
- * import { StoryMap } from "storymapjs";
1543
+ * import { StoryMap } from "@projektemacher/storymapjs";
894
1544
  * // from an inline data object
895
1545
  * const map = new StoryMap("embed", { storymap: { ... } }, { start_at_slide: 2 });
896
1546
  * // or straight from a source file (storymap JSON or IIIF manifest)
@@ -908,24 +1558,80 @@ declare class StoryMapBase {
908
1558
  "_el": {
909
1559
  container: HTMLElement;
910
1560
  menubar: HTMLElement;
911
- map: HTMLElement;
1561
+ map: HTMLElement | null;
912
1562
  storyslider: HTMLElement;
913
1563
  };
914
1564
  "_storyslider": StorySlider;
915
- "_map": OpenLayers;
916
- "map": Map_3;
1565
+ "_map": OpenLayers | null;
1566
+ /** `map_type: "none"`: the story is text-and-media, with no map at all. */
1567
+ "_map_disabled": boolean;
1568
+ /**
1569
+ * The raw OpenLayers map. `null` until the map is built (the
1570
+ * constructor assigns it during data load) — check it, or use the
1571
+ * accessors, which return `null` until then.
1572
+ */
1573
+ "map": Map_3 | null;
917
1574
  "_menubar": MenuBar;
918
1575
  "data": StorymapData;
919
1576
  "options": StorymapOptions;
920
1577
  "current_slide": number;
1578
+ /**
1579
+ * The manifest this viewer was built from, kept so `loadAnnotations()` can
1580
+ * resolve its `seeAlso` targets. `null` for a storymap-JSON viewer, which
1581
+ * has no `seeAlso`.
1582
+ */
1583
+ "_raw_manifest": unknown | null;
1584
+ /**
1585
+ * The deep link the page was opened with, captured before anything can
1586
+ * rewrite the URL.
1587
+ *
1588
+ * This has to be read *early*. The slider's opening `goTo()` can reach
1589
+ * `_navigate()` before `_onLoaded()` runs, and `_navigate()` calls
1590
+ * `_syncHash()` — which would overwrite the incoming link with the current
1591
+ * slide before `_onLoaded()` ever looked at it. Whether that happens
1592
+ * depends on the order the slider and map finish loading, which is exactly
1593
+ * the kind of race that makes a deep link work most of the time.
1594
+ */
1595
+ "_initial_deep_link": {
1596
+ state: ContentState | null;
1597
+ hash: string;
1598
+ } | null;
921
1599
  "animator_map": AnimationHandle | null;
922
1600
  "animator_storyslider": AnimationHandle | null;
923
1601
  "_autoplay_timer": ReturnType<typeof setTimeout> | null;
1602
+ "_transition_timer": ReturnType<typeof setTimeout> | null;
924
1603
  "_autoplay_stopped": boolean;
1604
+ /** The narration player: one <audio> for the whole story, reused. */
1605
+ "_narration_el": HTMLAudioElement | null;
1606
+ /** Guards a stale play() from a slide change that already moved on. */
1607
+ "_narration_token": number;
1608
+ /** Whether narration consent was granted (asked once per story). */
1609
+ "_narration_allowed": boolean;
1610
+ /** True once the visitor has clicked/keyed: unmuted audio needs this. */
1611
+ "_user_gestured": boolean;
1612
+ /** The advance armed for the current slide (media-ended or the timer). */
1613
+ "_autoplay_advance": (() => void) | null;
1614
+ /** A narration that was skipped for want of a gesture, to retry later. */
1615
+ "_replayNarrationAfterGesture": boolean;
925
1616
  "_hash_initialized": boolean;
1617
+ "_collapsed": boolean;
926
1618
  /** the data source was a IIIF Presentation manifest (legacy zoomify options are ignored) */
927
1619
  "_data_from_manifest": boolean;
928
1620
  "_resize_observer": ResizeObserver | null;
1621
+ /** Stored so `dispose()` can remove them again (see AGENTS: no leaks) */
1622
+ "_on_resize": (() => void) | null;
1623
+ "_on_keydown_global": ((e: KeyboardEvent) => void) | null;
1624
+ "_on_fullscreen": (() => void) | null;
1625
+ "_on_hashchange": (() => void) | null;
1626
+ /** Set by `dispose()` so a second call returns early. */
1627
+ "_disposed": boolean;
1628
+ /** identity of this viewer's claim on the page-wide locale */
1629
+ "_language_holder": symbol;
1630
+ /** the locale the caller actually asked for, if any; see _loadLanguage */
1631
+ "_language_requested": string | undefined;
1632
+ /** bumped on interaction, so page-wide keys can pick one viewer */
1633
+ "_interaction": number;
1634
+ "_onInteraction": (() => void) | null;
929
1635
  "_resize_timer": ReturnType<typeof setTimeout> | null;
930
1636
  "fire": EventedInstance["fire"];
931
1637
  "hasEventListeners": EventedInstance["hasEventListeners"];
@@ -946,15 +1652,51 @@ declare class StoryMapBase {
946
1652
  _loadDataFromUrl(url: string, source: string): Promise<void>;
947
1653
  _initOptions(): void;
948
1654
  _loadLanguage(): void;
1655
+ /**
1656
+ * The locale this viewer was actually asked for, or undefined when the
1657
+ * caller and the document both stayed silent.
1658
+ */
1659
+ _requestedLanguage(): string | undefined;
1660
+ refreshLanguage(code: string): void;
1661
+ /**
1662
+ * Repaint everything a runtime language switch affects: the menubar
1663
+ * labels and the `vco-rtl` class.
1664
+ *
1665
+ * This deliberately does *not* call `updateDisplay()`. A full re-layout
1666
+ * re-runs the slider's `goTo(current_slide)`, which goes through the
1667
+ * navigation path that re-arms autoplay — so calling it here silently
1668
+ * cancelled a pending autoplay tick and the story stopped advancing.
1669
+ */
1670
+ _applyLanguageLayout(): void;
949
1671
  _loadFontCss(): Promise<void>;
950
1672
  _onFontLoaded(font: string): void;
951
1673
  /**
952
- * Navigate to a slide by index.
1674
+ * Navigate to a slide by index. Out-of-range indices are ignored, as is
1675
+ * the current index.
953
1676
  *
954
1677
  * @param n - Zero-based slide index; the map animates to the slide's
955
- * marker (or the overview when `n` is 0 for storymaps with one).
1678
+ * marker. The overview is selected by the slide's own
1679
+ * `type: "overview"`, not by its index.
956
1680
  */
957
1681
  goTo(n: number): void;
1682
+ /**
1683
+ * The single navigation path shared by programmatic navigation, the
1684
+ * slider's `change` event, the map's `change` event and "back to start".
1685
+ *
1686
+ * `navigate` names the single component that the bubble source already
1687
+ * moved; the other component follows. `navigated` says whether the caller
1688
+ * has *not* already reported the change outward, so the outward `change`
1689
+ * event fires exactly once per navigation (the bubble paths would
1690
+ * otherwise re-enter through the other component's handler).
1691
+ */
1692
+ private _navigate;
1693
+ /**
1694
+ * Announce a slide transition: `transitionstart` now (with the glide
1695
+ * duration both animations were started with) and `transitionend` once
1696
+ * it elapses. Restarts on every navigation, so only the latest
1697
+ * transition ever ends.
1698
+ */
1699
+ _beginTransition(duration: number): void;
958
1700
  /**
959
1701
  * Re-measure the container and re-layout the map, slider and menubar.
960
1702
  * Called automatically on resize (see the `trackResize` option).
@@ -963,31 +1705,225 @@ declare class StoryMapBase {
963
1705
  /**
964
1706
  * Change a single map option at runtime and apply its effect immediately.
965
1707
  *
966
- * Runtime-changeable options: `map_type` (rebuilds the main + minimap tile
967
- * layers, keeping the overview fitted to the marker bounds),
968
- * `show_lines`, `line_color`, `line_color_inactive`, `line_weight`,
969
- * `line_opacity`, `line_dash`, `line_join`, `line_follows_path`,
970
- * `show_history_line` (restyled instantly), `map_center_offset` (applied on
971
- * the next navigation), `duration`, `ease`, `calculate_zoom`,
972
- * `map_background_color`. All other options only take effect on the next
973
- * navigation or require re-creating the StoryMap.
1708
+ * Runtime-changeable options: `map_type` (swaps one basemap for another and
1709
+ * rebuilds the main + minimap tile layers, keeping the overview fitted to
1710
+ * the marker bounds; it cannot add or remove a map, and `"none"` and
1711
+ * non-strings are declined), `overlays`
1712
+ * (rebuilds the stacked overlay layers), `show_lines`, `line_color`,
1713
+ * `line_color_inactive`, `line_weight`, `line_opacity`, `line_dash`,
1714
+ * `line_join`, `line_follows_path`, `show_history_line` (restyled
1715
+ * instantly), `map_center_offset` (applied on the next navigation),
1716
+ * `duration`, `ease`, `calculate_zoom`, `map_background_color`. All other
1717
+ * options only take effect on the next navigation or require re-creating
1718
+ * the StoryMap.
1719
+ */
1720
+ /**
1721
+ * Sugar over {@link setMapOptions} — `setMapOption(name, value)` is the
1722
+ * same call as `setMapOptions({ [name]: value })`.
974
1723
  */
975
1724
  setMapOption(name: string, value: unknown): void;
1725
+ /**
1726
+ * Show or hide a stacked overlay by index (see the `overlays` option).
1727
+ * Prefer `getOverlayLayer(index).setVisible(v)` on the layer itself; this
1728
+ * wrapper also re-syncs the attribution line and the overlay blend mode.
1729
+ */
1730
+ setOverlayVisible(index: number, visible: boolean): void;
1731
+ /**
1732
+ * Set a stacked overlay's opacity by index (see the `overlays` option).
1733
+ * Alias: `getOverlayLayer(index)?.setOpacity(opacity)`.
1734
+ */
1735
+ setOverlayOpacity(index: number, opacity: number): void;
976
1736
  /**
977
1737
  * Change several map options at runtime (see setMapOption).
978
1738
  */
979
1739
  setMapOptions(options: Partial<StorymapOptions>): void;
1740
+ /** The base tile layer, or `null` when deferred (tile consent not granted). */
1741
+ getBaseLayer(): OlLayer | null;
1742
+ /** The stacked `overlays[]` layers, in `overlays[]` order. */
1743
+ getOverlayLayers(): OlLayer[];
1744
+ /** One stacked overlay layer by its `overlays[]` index, or `null`. */
1745
+ getOverlayLayer(index: number): OlLayer | null;
1746
+ /** Number of stacked overlay layers (see the `overlays` option). */
1747
+ getOverlayCount(): number;
1748
+ /** The minimap's OpenLayers map (the `OverviewMap` control's inner map). */
1749
+ getMinimap(): Map_3 | null;
1750
+ /** The full (inactive) route line layer. */
1751
+ getLine(): OlLayer | null;
1752
+ /**
1753
+ * True when the map shows a IIIF image as a picture of the world
1754
+ * (`map_as_image`) rather than as a georeferenced map. In that mode the
1755
+ * view is `EPSG:4326` image space: `map.getView().getCenter()` is in
1756
+ * degrees, the resolution is in pixels per degree, and marker locations
1757
+ * are pixel offsets into the image. Ask this instead of checking
1758
+ * `map_type` — georeferenced IIIF (`map_bbox` without `map_as_image`)
1759
+ * is an ordinary mercator map.
1760
+ */
1761
+ isImageSpace(): boolean;
1762
+ /**
1763
+ * The `uniqueid` of a slide — the current one by default.
1764
+ *
1765
+ * A IIIF manifest supplies one per canvas (§2.3) and it is the only
1766
+ * identity a link can be built on, since an index moves when a slide is
1767
+ * inserted. A storymap-JSON slide usually has none, in which case this is
1768
+ * `null` rather than a generated id: a random one would be stable to nobody.
1769
+ */
1770
+ getSlideId(index?: number): string | null;
1771
+ /**
1772
+ * Read the annotation documents this manifest points at with `seeAlso` and
1773
+ * add the tour stops they carry.
1774
+ *
1775
+ * Explicit and asynchronous on purpose (§5.2). The alternative — following
1776
+ * `seeAlso` inside `manifestToStorymapData` — would mean one blocking
1777
+ * network round trip per referenced document before the viewer could paint
1778
+ * its first slide, against third-party servers the host may not want to
1779
+ * contact at all. Here the story stands on its own immediately and the
1780
+ * annotations arrive afterwards, behind a per-(id, type) cache, and
1781
+ * `annotationsloaded` fires when they are in.
1782
+ *
1783
+ * The stops are **appended**, not placed after the canvas they annotate.
1784
+ * A canvas's own annotations are inserted in position at parse time; doing
1785
+ * the same to a live tour would mean rebuilding the slider and every piece
1786
+ * of state that hangs off it, for an ordering nicety. A host that needs
1787
+ * the stops placed exactly can read them off the resolved value and place
1788
+ * them itself.
1789
+ *
1790
+ * @returns the stops that were added, keyed by canvas id, plus any
1791
+ * `SearchService1` endpoint seen and any document that failed to load.
1792
+ */
1793
+ loadAnnotations(options?: {
1794
+ fetchImpl?: typeof fetch;
1795
+ }): Promise<{
1796
+ stops: StorymapSlide[];
1797
+ searchService: string | null;
1798
+ failed: string[];
1799
+ }>;
1800
+ /**
1801
+ * Release everything the viewer attached to the page: window/document
1802
+ * listeners, timers, the resize observer, running Web Animations, the
1803
+ * slider, the menubar, the map and the map markers. Use this when tearing
1804
+ * a storymap down (SPA route change, modal close).
1805
+ *
1806
+ * Teardown is terminal: the host container is emptied, `map` becomes
1807
+ * null, and the public methods (`goTo`, `setMapOptions`,
1808
+ * `createMiniMap`, ...) become no-ops rather than throwing. There is no
1809
+ * re-init path; build a new StoryMap on the same element instead.
1810
+ * Calling `dispose()` twice is a no-op.
1811
+ */
1812
+ dispose(): void;
1813
+ /* Excluded from this release type: element */
1814
+ /* Excluded from this release type: interaction */
1815
+ /** The highlighted route line drawn up to the current slide. */
1816
+ getLineActive(): OlLayer | null;
1817
+ /** The map markers, indexed by slide. */
1818
+ getMarkers(): OpenLayersMapMarker[];
1819
+ /** One map marker by slide index, or `null`. */
1820
+ getMarker(index: number): OpenLayersMapMarker | null;
1821
+ /**
1822
+ * Rebuild the minimap (`OverviewMap` control). The constructor already
1823
+ * builds it; this is for hosts that recreate it after a `map_type` swap
1824
+ * or a deferred tile-consent grant.
1825
+ */
1826
+ createMiniMap(): void;
1827
+ /**
1828
+ * Append attribution fragments and refresh the credit line (e.g. for a
1829
+ * custom layer added through `tile_source_factory`).
1830
+ */
1831
+ setExtraAttributions(parts: string[]): void;
1832
+ /**
1833
+ * Publish the text colour custom properties. Called from both the initial
1834
+ * layout and every runtime option change (issue #177) so the two paths
1835
+ * cannot drift.
1836
+ */
1837
+ _applyTextColors(): void;
980
1838
  _initLayout(): void;
981
1839
  _initEvents(): void;
1840
+ _onKeyDownGlobal(e: KeyboardEvent): void;
982
1841
  _updateDisplay(map_height?: number, animate?: boolean, d?: number): void;
983
1842
  _onDataLoaded(e?: unknown): void;
1843
+ /**
1844
+ * Start-of-story consent (issue: allow all / individually / decline
1845
+ * all): with `consent_required`, one dialog lists every external
1846
+ * service the story uses — map tiles, external web fonts and the media
1847
+ * services in the slides. Shown only while some service is unanswered;
1848
+ * per-service slide asks remain the fallback.
1849
+ */
1850
+ _startConsentAsk(): void;
1851
+ /**
1852
+ * Play the current slide's narration, if it has one.
1853
+ *
1854
+ * One `<audio>` element is reused for the whole story rather than a
1855
+ * player per slide, so switching slides cannot leave a recording playing
1856
+ * behind. Two things gate it:
1857
+ *
1858
+ * - **browser autoplay policy**: unmuted audio only plays after a user
1859
+ * gesture, so before the first interaction the element is left paused
1860
+ * and nothing is reported as broken. Re-arm on the first interaction.
1861
+ * - **consent**: the `media:narration` service is requested at start-up
1862
+ * (see `_startConsentAsk`); a denied or unanswered service means no
1863
+ * playback, and the story still works.
1864
+ */
1865
+ _playNarration(slide: StorymapSlide | undefined, allow_without_gesture?: boolean): void;
1866
+ _narrationElement(): HTMLAudioElement;
1867
+ _stopNarration(): void;
1868
+ /** A gesture has happened, so unmuted audio is allowed from now on. */
1869
+ _note_user_gesture_for_narration(): void;
1870
+ _has_user_gesture(): boolean;
984
1871
  _startAutoplay(): void;
1872
+ /**
1873
+ * Arm autoplay for the current slide.
1874
+ *
1875
+ * With `autoplay_media` on and a slide whose media is playable audio or
1876
+ * video, the advance waits for that media to end instead of using the
1877
+ * `autoplay` millisecond timer. The timer is **kept as a fallback** in
1878
+ * that case too: a media element that never fires `ended` (a stalled
1879
+ * fetch, a codec the browser cannot play, or a slide whose media was
1880
+ * never loaded because the visitor skipped past it) would otherwise stop
1881
+ * the story dead. So both are armed, whichever fires first advances, and
1882
+ * the other is cleared.
1883
+ */
985
1884
  _scheduleAutoplay(): void;
986
1885
  _stopAutoplay(): void;
987
- /** Keep the URL hash in sync with the current slide (#slide-N). */
1886
+ /**
1887
+ * The current slide's `uniqueid`, or null when the data carries none.
1888
+ *
1889
+ * A storymap-JSON slide usually has no `uniqueid` — the slider generates
1890
+ * one per slide for its own DOM ids, but that is not a shareable identity,
1891
+ * so it is deliberately not used here. A IIIF manifest supplies one per
1892
+ * canvas (§2.3), and that is what a deep link should name.
1893
+ */
1894
+ _currentSlideId(): string | null;
1895
+ /** The current slide as a Content State, or null when it has no id. */
1896
+ _currentContentState(): ContentState | null;
1897
+ /**
1898
+ * Keep the URL in sync with the current slide: the `#slide-…` hash and,
1899
+ * when the slide has a shareable id, an `iiif-content` parameter (§5.1).
1900
+ *
1901
+ * The query string is rewritten rather than replaced, because pages like
1902
+ * the embed player and the test harness carry their own configuration in
1903
+ * it (`?url=…`, `?example=…`, `?manifest=…`).
1904
+ */
988
1905
  _syncHash(): void;
989
- /** A #slide-N hash deep-links the storymap (applied on load + hashchange). */
990
- _applyHashSlide(): boolean;
1906
+ /**
1907
+ * A `#slide-…` hash or an `iiif-content` parameter deep-links the storymap
1908
+ * (applied on load + hashchange).
1909
+ *
1910
+ * The hash token is an index when it is all digits and a `uniqueid`
1911
+ * otherwise, which is unambiguous because an index never contains anything
1912
+ * else. The index form stays supported, so links shared before ids were
1913
+ * emitted keep working; they just stop being stable the moment a slide is
1914
+ * inserted.
1915
+ */
1916
+ _applyHashSlide(captured?: {
1917
+ state: ContentState | null;
1918
+ hash: string;
1919
+ } | null): boolean;
1920
+ /**
1921
+ * A content state or hash token as a slide index, or null when it names
1922
+ * nothing. A content state wins over the hash, being the standard spelling.
1923
+ */
1924
+ _resolveDeepLink(state: ContentState | null, hash: string): number | null;
1925
+ /** A canvas id as a slide index, or null. */
1926
+ _slideIndexById(id: string): number | null;
991
1927
  _initResizeHandling(): void;
992
1928
  /**
993
1929
  * Resolve a caller-supplied map element (options.map_options.element).
@@ -995,6 +1931,18 @@ declare class StoryMapBase {
995
1931
  * map container (given the vco-map class) and moved into place between
996
1932
  * the menubar and the story slider.
997
1933
  */
1934
+ /**
1935
+ * The map pane, for the code paths that only run when there is a map.
1936
+ * `_el.map` is null exactly when the engine is; see `_map_required()`.
1937
+ */
1938
+ _map_el(): HTMLElement;
1939
+ /**
1940
+ * The map engine, for the code paths that only run when there is a map.
1941
+ * Throws rather than returning null: reaching one of these from a mapless
1942
+ * story is a bug in this class, and a loud one, rather than a layout that
1943
+ * quietly misbehaves. Public entry points use `this._map?.` instead.
1944
+ */
1945
+ _map_required(): OpenLayers;
998
1946
  _resolveMapElement(): HTMLElement | null;
999
1947
  _onTitle(e: unknown): void;
1000
1948
  _onColorChange(e: {
@@ -1017,7 +1965,8 @@ declare class StoryMapBase {
1017
1965
  _onFullscreenChange(): void;
1018
1966
  _onBackToStart(e?: unknown): void;
1019
1967
  _onMenuBarCollapse(e: {
1020
- y: number;
1968
+ y?: number;
1969
+ collapsed?: boolean;
1021
1970
  }): void;
1022
1971
  _onMapLoaded(): void;
1023
1972
  _onStorySliderLoaded(): void;
@@ -1026,10 +1975,24 @@ declare class StoryMapBase {
1026
1975
  * (issue #341); hidden when `show_distance` is off.
1027
1976
  */
1028
1977
  _updateDistance(): void;
1978
+ /**
1979
+ * The URL is ours to own as soon as the story is: the deep link is read
1980
+ * and the hash is kept in step.
1981
+ *
1982
+ * This deliberately does **not** wait for the map. The map only reports
1983
+ * itself loaded on OpenLayers' first `loadend`, which is the first paint of
1984
+ * the base tiles — so a deep link used to be applied only once
1985
+ * `tile.openstreetmap.org` answered, and on a slow or unreachable tile
1986
+ * host it was never applied at all. Nothing about a URL depends on imagery:
1987
+ * the data and the slider are what it needs, and both are ready before the
1988
+ * map is. `_applyHashSlide` → `goTo` → `_navigate` already tolerates a map
1989
+ * that has not reported loaded, and the map re-syncs when it does.
1990
+ */
1991
+ _initHash(): void;
1029
1992
  _onLoaded(): void;
1030
1993
  }
1031
1994
 
1032
- declare interface StorymapData {
1995
+ export declare interface StorymapData {
1033
1996
  uniqueid?: string;
1034
1997
  slides: StorymapSlide[];
1035
1998
  [key: string]: unknown;
@@ -1039,22 +2002,254 @@ export declare interface StorymapDataWrapper {
1039
2002
  storymap: StorymapData;
1040
2003
  }
1041
2004
 
1042
- declare interface StorymapError {
2005
+ /**
2006
+ * The document {@link storymapToManifest} reads: the `{ "storymap": {...} }`
2007
+ * wrapper a `storymap.json` file is, with every member optional.
2008
+ *
2009
+ * The root is `Partial<StorymapData>` — every legacy key is optional and the
2010
+ * files in the wild carry more than the schema documents — or a plain record,
2011
+ * which is what a document read straight out of `JSON.parse` is. The wrapper
2012
+ * itself is open, because the legacy files also carry a root-level `font_css`
2013
+ * and the map configuration service prefers it over the key inside `storymap`.
2014
+ */
2015
+ export declare interface StorymapDocument {
2016
+ storymap?: Partial<StorymapData> | Record<string, unknown>;
2017
+ [key: string]: unknown;
2018
+ }
2019
+
2020
+ export declare interface StorymapError {
1043
2021
  path: string;
1044
2022
  message: string;
1045
2023
  }
1046
2024
 
2025
+ /**
2026
+ * A IIIF Georeference Extension annotation body plus the image it places
2027
+ * (`overlays[].georeference`). The `body` is the annotation payload of
2028
+ * `iiif.io/api/extension/georef` verbatim: a GeoJSON FeatureCollection of
2029
+ * ground control points pairing `properties.resourceCoords` (image pixels)
2030
+ * with `geometry.coordinates` (WGS84 lon/lat), optionally carrying a
2031
+ * `transformation` hint.
2032
+ *
2033
+ * The viewer fits the affine (first-order polynomial) case and places the
2034
+ * image with OpenLayers' reprojection, which requires an axis-aligned
2035
+ * placement; rotated or skewed sheets, higher-order polynomials and thin
2036
+ * plate splines are reported and skipped — see the "Geo-referenced layers"
2037
+ * section of docs/storymap-as-iiif-manifest.md.
2038
+ */
2039
+ export declare interface StorymapGeoreference {
2040
+ /** IIIF Image API service base (or a full-size image URL) to place */
2041
+ url: string;
2042
+ /** Image width in pixels (the resourceCoords space) */
2043
+ width: number;
2044
+ /** Image height in pixels */
2045
+ height: number;
2046
+ /** Georeference annotation body: the GCP FeatureCollection */
2047
+ body: StorymapGeoreferenceBody;
2048
+ }
2049
+
2050
+ export declare interface StorymapGeoreferenceBody {
2051
+ type?: string;
2052
+ /** `polynomial` with `order: 1`, or absent; other values are skipped */
2053
+ transformation?: {
2054
+ type?: string;
2055
+ options?: {
2056
+ order?: number;
2057
+ };
2058
+ };
2059
+ features: StorymapGroundControlPoint[];
2060
+ }
2061
+
2062
+ /** One ground control point: an image pixel paired with a WGS84 position */
2063
+ export declare interface StorymapGroundControlPoint {
2064
+ type?: string;
2065
+ properties?: {
2066
+ resourceCoords?: [number, number];
2067
+ };
2068
+ geometry?: {
2069
+ type?: string;
2070
+ coordinates?: number[];
2071
+ };
2072
+ }
2073
+
2074
+ /** A IIIF Presentation 3 language map; only the neutral `none` tag is written. */
2075
+ export declare interface StorymapLanguageMap {
2076
+ none: string[];
2077
+ }
2078
+
1047
2079
  declare type StoryMapListener = (e: unknown) => void;
1048
2080
 
2081
+ export declare interface StorymapManifest {
2082
+ "@context": string[];
2083
+ id: string;
2084
+ type: "Manifest";
2085
+ label: StorymapLanguageMap;
2086
+ behavior: string[];
2087
+ metadata: {
2088
+ label: StorymapLanguageMap;
2089
+ value: StorymapLanguageMap;
2090
+ }[];
2091
+ items: StorymapManifestCanvas[];
2092
+ structures?: StorymapManifestRange[];
2093
+ navPlace?: StorymapManifestFeatureCollection;
2094
+ service?: StorymapManifestService[];
2095
+ requiredStatement?: StorymapManifestStatement;
2096
+ }
2097
+
2098
+ /** A painting annotation: the slide's own media, painted onto its canvas. */
2099
+ export declare interface StorymapManifestAnnotation {
2100
+ id: string;
2101
+ type: "Annotation";
2102
+ motivation: string;
2103
+ /** The media caption, as the annotation's own `label` (§2.7). */
2104
+ label?: StorymapLanguageMap;
2105
+ /** The media credit (§2.7). P3 allows a single object, not an array. */
2106
+ requiredStatement?: StorymapManifestStatement;
2107
+ /** The media alt text (§2.7). */
2108
+ accessibilitySummary?: StorymapLanguageMap;
2109
+ body: StorymapManifestContentResource;
2110
+ target: string | StorymapManifestSpecificResource;
2111
+ }
2112
+
2113
+ /** A canvas `background`: a painting annotation of the slide's backdrop (§2.6). */
2114
+ export declare interface StorymapManifestBackground {
2115
+ id: string;
2116
+ type: "Annotation";
2117
+ motivation: "painting";
2118
+ body: StorymapManifestContentResource | StorymapManifestContentResource[];
2119
+ target: string;
2120
+ }
2121
+
2122
+ export declare interface StorymapManifestCanvas {
2123
+ id: string;
2124
+ type: "Canvas";
2125
+ width: number;
2126
+ height: number;
2127
+ /** The slide's date, which P3 constrains to a plain string (§2.5). */
2128
+ navDate?: string;
2129
+ background?: StorymapManifestBackground;
2130
+ thumbnail?: StorymapManifestContentResource[];
2131
+ items: {
2132
+ id: string;
2133
+ type: "AnnotationPage";
2134
+ items: (StorymapManifestAnnotation | StorymapManifestGeoreferencing)[];
2135
+ }[];
2136
+ label?: StorymapLanguageMap;
2137
+ summary?: StorymapLanguageMap;
2138
+ /** An overview slide, which the map's `overview` type carries (§2.4). */
2139
+ "storymap:type"?: string;
2140
+ "storymap:mediaSrcset"?: unknown;
2141
+ "storymap:mediaSizes"?: unknown;
2142
+ navPlace?: StorymapManifestFeatureCollection;
2143
+ }
2144
+
2145
+ /**
2146
+ * A content resource: a painting body, a thumbnail or a background.
2147
+ *
2148
+ * One permissive interface rather than a discriminated union, because the
2149
+ * emitter only writes these: the shapes it produces are the classified media
2150
+ * body, a IIIF `Image`, a `TextualBody` and a `Color`, and they are
2151
+ * distinguished by `type` for the reader, not for us.
2152
+ */
2153
+ export declare interface StorymapManifestContentResource {
2154
+ id?: string;
2155
+ type: string;
2156
+ format?: string;
2157
+ width?: number;
2158
+ height?: number;
2159
+ value?: string;
2160
+ service?: StorymapManifestImageService[];
2161
+ }
2162
+
2163
+ /** A navPlace FeatureCollection: a point for a location, a Polygon for a bbox. */
2164
+ export declare interface StorymapManifestFeatureCollection {
2165
+ id: string;
2166
+ type: "FeatureCollection";
2167
+ features: {
2168
+ id: string;
2169
+ type: "Feature";
2170
+ geometry: {
2171
+ type: string;
2172
+ coordinates: number[] | number[][] | number[][][];
2173
+ };
2174
+ /** Marker presentation, described by navplace-properties.json (§3.3). */
2175
+ properties: Record<string, unknown>;
2176
+ }[];
2177
+ }
2178
+
2179
+ /** A Georeference Extension annotation for a placed raster (§2.10). */
2180
+ export declare interface StorymapManifestGeoreferencing {
2181
+ id: string;
2182
+ type: "Annotation";
2183
+ motivation: "georeferencing";
2184
+ target: {
2185
+ id: string;
2186
+ type: "Image";
2187
+ width: number;
2188
+ height: number;
2189
+ service: StorymapManifestImageService[];
2190
+ };
2191
+ requiredStatement?: StorymapManifestStatement;
2192
+ body: StorymapGeoreferenceBody;
2193
+ }
2194
+
2195
+ /** A IIIF Image API service reference. */
2196
+ export declare interface StorymapManifestImageService {
2197
+ id: string;
2198
+ type: string;
2199
+ profile: string;
2200
+ }
2201
+
2202
+ /** One P3 `Range` over the canvases of a `slide.group` (§3.5). */
2203
+ export declare interface StorymapManifestRange {
2204
+ id: string;
2205
+ type: "Range";
2206
+ label: StorymapLanguageMap;
2207
+ items: string[];
2208
+ }
2209
+
2210
+ /**
2211
+ * The map configuration service entry, keyed by the `storymap:` terms.
2212
+ *
2213
+ * Open by necessity: the official validator's Manifest schema is
2214
+ * `additionalProperties: false`, which is exactly why the map configuration
2215
+ * travels on a service of its own rather than on the Manifest (§3.1).
2216
+ */
2217
+ export declare interface StorymapManifestService {
2218
+ id: string;
2219
+ type: "Service";
2220
+ profile: string;
2221
+ [term: string]: unknown;
2222
+ }
2223
+
2224
+ /** A painting annotation whose target is a region of a larger image (§2.8). */
2225
+ export declare interface StorymapManifestSpecificResource {
2226
+ type: "SpecificResource";
2227
+ source: string;
2228
+ selector: {
2229
+ type: "ImageApiSelector";
2230
+ value: string;
2231
+ };
2232
+ }
2233
+
2234
+ /** A `{label, value}` pair — the P3 shape for a caption, credit or rights line. */
2235
+ export declare interface StorymapManifestStatement {
2236
+ label: StorymapLanguageMap;
2237
+ value: StorymapLanguageMap;
2238
+ }
2239
+
1049
2240
  /** OpenLayers passthrough options (see StorymapOptions.map_options) */
1050
- declare interface StorymapMapOptions {
2241
+ export declare interface StorymapMapOptions {
1051
2242
  /** HTMLElement or DOM id that becomes the real map container */
1052
2243
  element?: HTMLElement | string;
1053
2244
  /** Merged over the default view configuration */
1054
2245
  view?: Record<string, unknown>;
1055
2246
  /** Replaces the default (empty) controls list */
1056
2247
  controls?: unknown[];
1057
- /** Replaces the default (empty) interactions list */
2248
+ /**
2249
+ * Added to the viewer's own pan/zoom interactions (not a replacement:
2250
+ * the viewer's defaults are always added). `controls` *is* a
2251
+ * replacement, since the viewer adds none of its own.
2252
+ */
1058
2253
  interactions?: unknown[];
1059
2254
  /** Any other ol/Map constructor option (layers, pixelRatio, ...) */
1060
2255
  [key: string]: unknown;
@@ -1075,7 +2270,6 @@ export declare interface StorymapOptions {
1075
2270
  left: number;
1076
2271
  top: number;
1077
2272
  } | null;
1078
- less_bounce: boolean;
1079
2273
  start_at_slide: number;
1080
2274
  call_to_action: boolean;
1081
2275
  call_to_action_text: string;
@@ -1089,12 +2283,24 @@ export declare interface StorymapOptions {
1089
2283
  skinny_size: number;
1090
2284
  duration: number;
1091
2285
  ease: unknown;
1092
- dragging: boolean;
1093
2286
  trackResize: boolean;
2287
+ /**
2288
+ * Navigate slides with arrow keys anywhere on the page (default false:
2289
+ * arrows only work when the slide panel has focus). Form elements and
2290
+ * the map itself (which pans) are always skipped. Read at construction.
2291
+ */
2292
+ keyboard: boolean;
1094
2293
  /** Re-fetch the source file on every load, bypassing caches (issue #417) */
1095
2294
  nocache: boolean;
1096
2295
  /** Advance slides automatically every N milliseconds; 0 disables (issue #380) */
1097
2296
  autoplay: number;
2297
+ /**
2298
+ * With autoplay on, wait for the current slide's audio or video to end
2299
+ * before advancing instead of using the `autoplay` millisecond timer,
2300
+ * which stays as the fallback. Slides without playable media keep the
2301
+ * timer, so a mixed story never stalls.
2302
+ */
2303
+ autoplay_media: boolean;
1098
2304
  /** Show a progress bar in the menubar (issue #247) */
1099
2305
  show_progress: boolean;
1100
2306
  /** Show the slide headline as a label on the active map marker (issue #243) */
@@ -1107,9 +2313,24 @@ export declare interface StorymapOptions {
1107
2313
  lon: number;
1108
2314
  } | null;
1109
2315
  map_type: string;
2316
+ /**
2317
+ * Custom OpenLayers tile layer/source factory (issue #473): consulted
2318
+ * by the tile layer factory before the built-in `map_type` switch, for
2319
+ * every base, overlay and minimap layer. Return a `TileLayer` (or a
2320
+ * bare `Source`, auto-wrapped in one) for custom handling — e.g. WMS —
2321
+ * or `null`/`undefined` to fall through to the default types.
2322
+ * Constructor- and runtime-only: functions cannot ride storymap JSON.
2323
+ */
2324
+ tile_source_factory: TileSourceFactory | null;
1110
2325
  attribution: string;
2326
+ /**
2327
+ * Stacked raster overlays above the base map, below the route lines.
2328
+ * Each entry accepts any `map_type` value (XYZ template, `osm:style`,
2329
+ * …) plus per-layer presentation; see StorymapOverlayLayer. Empty
2330
+ * (default) means base map only.
2331
+ */
2332
+ overlays: StorymapOverlayLayer[];
1111
2333
  map_mini: boolean;
1112
- map_subdomains: string;
1113
2334
  map_as_image: boolean;
1114
2335
  map_access_token: string;
1115
2336
  map_background_color: string;
@@ -1127,6 +2348,12 @@ export declare interface StorymapOptions {
1127
2348
  * constrained to the box; `null` (default) leaves the map unconstrained.
1128
2349
  */
1129
2350
  map_bbox: number[] | null;
2351
+ /**
2352
+ * Constrain the minimap overview to a bounding box `[west, south, east,
2353
+ * north]` in lon/lat (mercator maps only); `null` (default) leaves the
2354
+ * overview unconstrained.
2355
+ */
2356
+ overview_extent: [number, number, number, number] | null;
1130
2357
  /**
1131
2358
  * Legacy zoomify image pyramid (map_type: "zoomify"): the tiles are
1132
2359
  * placed at the standard mercator tile positions, stretched from the
@@ -1142,7 +2369,9 @@ export declare interface StorymapOptions {
1142
2369
  /**
1143
2370
  * Ask for permission before loading anything from external services
1144
2371
  * (media embeds, map tiles, external font CSS) — GDPR consent mode.
1145
- * Grants are remembered per service in a cookie for 90 days.
2372
+ * Decisions are remembered per service in `localStorage` under
2373
+ * `storymapjs-consent` with no expiry: clearing site data is what makes
2374
+ * the viewer ask again.
1146
2375
  */
1147
2376
  consent_required: boolean;
1148
2377
  /** Slide text color override, sets --vco-color-text (issue #177) */
@@ -1152,14 +2381,13 @@ export declare interface StorymapOptions {
1152
2381
  /** Show the great-circle route distance in the menubar (issue #341) */
1153
2382
  show_distance: boolean;
1154
2383
  /**
1155
- * Raw OpenLayers map configuration. `controls` and `interactions` replace
1156
- * the StoryMapJS defaults, `view` is merged over the computed default view
2384
+ * Raw OpenLayers map configuration. `controls` replaces the StoryMapJS
2385
+ * defaults, `interactions` are *added to* the viewer's own pan/zoom
2386
+ * interactions, and `view` is merged over the computed default view
1157
2387
  * and `element` (an HTMLElement or DOM id) replaces the auto-created map
1158
2388
  * container div.
1159
2389
  */
1160
2390
  map_options: StorymapMapOptions;
1161
- map_popup: boolean;
1162
- zoom_distance: number;
1163
2391
  calculate_zoom: boolean;
1164
2392
  line_follows_path: boolean;
1165
2393
  line_color: string;
@@ -1175,12 +2403,20 @@ export declare interface StorymapOptions {
1175
2403
  url: string;
1176
2404
  attribution: string;
1177
2405
  };
2406
+ tilejson?: StorymapTilejson;
2407
+ /**
2408
+ * The `seeAlso` targets a IIIF manifest points at, recorded but not
2409
+ * fetched — see `loadSeeAlso()` (§5.2 of docs/plans/iiif-interop.md).
2410
+ */
2411
+ see_also?: {
2412
+ id: string;
2413
+ type: string;
2414
+ }[];
1178
2415
  map_height: number;
1179
2416
  storyslider_height: number;
1180
2417
  slide_padding_lr: number;
1181
2418
  slide_default_fade: string;
1182
2419
  menubar_default_y: number;
1183
- path_gfx: string;
1184
2420
  script_path: string;
1185
2421
  font_css: string;
1186
2422
  language: string;
@@ -1188,28 +2424,91 @@ export declare interface StorymapOptions {
1188
2424
  [key: string]: unknown;
1189
2425
  }
1190
2426
 
2427
+ /**
2428
+ * A stacked raster overlay above the base map (StorymapOptions.overlays).
2429
+ * Presentation is declarative: hosts no longer need to reach into the
2430
+ * layer objects for blend modes, clips or stacking tweaks.
2431
+ */
2432
+ export declare interface StorymapOverlayLayer {
2433
+ /**
2434
+ * Any `map_type` value the tile layer factory accepts. Required unless
2435
+ * the entry carries a `georeference` (a placed IIIF image instead of
2436
+ * a tile source).
2437
+ */
2438
+ map_type?: string;
2439
+ /** Layer opacity 0..1 (default 1) */
2440
+ opacity?: number;
2441
+ /** Initial visibility (default true) */
2442
+ visible?: boolean;
2443
+ /** Extra attribution fragment, listed while the overlay is visible */
2444
+ attribution?: string;
2445
+ /**
2446
+ * CSS class for the layer container. OpenLayers paints every layer
2447
+ * with the same class into one shared div/canvas, so a distinct
2448
+ * class isolates this layer (e.g. for blend modes). The class
2449
+ * replaces the default wholesale, so keep the `ol-layer` token
2450
+ * (e.g. `"ol-layer historic-sheet"`) unless you know why not.
2451
+ */
2452
+ className?: string;
2453
+ /** CSS mix-blend-mode for the layer container (needs className) */
2454
+ blendMode?: string;
2455
+ /** Clip box `[west, south, east, north]` in lon/lat (mercator maps) */
2456
+ extent?: [number, number, number, number];
2457
+ /**
2458
+ * IIIF Georeference Extension placement instead of a tile source. The
2459
+ * ground control points are fitted affinely and the image is placed on
2460
+ * the geographic map, so this is the manifest-side equivalent of a
2461
+ * georeferenced raster overlay.
2462
+ */
2463
+ georeference?: StorymapGeoreference;
2464
+ }
2465
+
2466
+ /**
2467
+ * One slide of a storymap.
2468
+ *
2469
+ * The nullable members (`| null`) are not decoration: the storymap JSON uses
2470
+ * `null` to mean "explicitly absent" and the viewer seeds its own defaults
2471
+ * with `null` before the data is merged in, so a plain `?` would not type.
2472
+ */
1191
2473
  export declare interface StorymapSlide {
1192
2474
  type?: string;
1193
2475
  date?: string | Record<string, unknown> | null;
1194
2476
  group?: string;
1195
- location?: StorymapSlideLocation;
1196
- media?: StorymapSlideMedia;
1197
- text?: StorymapSlideText;
2477
+ /**
2478
+ * The language tag this slide's text was read in (§3.4 of
2479
+ * docs/plans/iiif-interop.md). A IIIF manifest states its text as a
2480
+ * language map; the reader picks the viewer's configured language and
2481
+ * reports which one it used, so a host can offer a language switch.
2482
+ * Absent for language-neutral (`none`) text, and for a single-language
2483
+ * storymap.
2484
+ */
2485
+ language?: string;
2486
+ location?: StorymapSlideLocation | null;
2487
+ media?: StorymapSlideMedia | null;
2488
+ marker?: StorymapSlideMarker | null;
2489
+ narration?: StorymapSlideNarration | null;
2490
+ text?: StorymapSlideText | null;
1198
2491
  background?: StorymapSlideBackground | string | null;
1199
- uniqueid?: string;
2492
+ uniqueid?: string | null;
1200
2493
  [key: string]: unknown;
1201
2494
  }
1202
2495
 
1203
- declare interface StorymapSlideBackground {
2496
+ export declare interface StorymapSlideBackground {
1204
2497
  url?: string | null;
1205
2498
  color?: string | null;
1206
2499
  opacity?: number;
1207
2500
  }
1208
2501
 
1209
- declare interface StorymapSlideLocation {
2502
+ export declare interface StorymapSlideLocation {
1210
2503
  lat?: number;
1211
2504
  lon?: number;
1212
2505
  zoom?: number;
2506
+ /**
2507
+ * Image region `[x, y, w, h]` in image pixels (IIIF xywh convention,
2508
+ * StrollView-style image stops): the view fits the region on
2509
+ * navigation; image maps (`map_type: "iiif"` + `map_as_image`) only.
2510
+ */
2511
+ region?: [number, number, number, number];
1213
2512
  line?: boolean;
1214
2513
  icon?: string;
1215
2514
  iconSize?: number[];
@@ -1218,21 +2517,107 @@ declare interface StorymapSlideLocation {
1218
2517
  [key: string]: unknown;
1219
2518
  }
1220
2519
 
1221
- declare interface StorymapSlideMedia {
2520
+ /**
2521
+ * Optional spoken narration for one slide, played through a dedicated audio
2522
+ * element rather than the slide's media frame — a tour stop usually has a
2523
+ * picture and a recording, not one media item. Storymap JSON only: the
2524
+ * closest manifest spelling is a `Sound` body, which currently lands in
2525
+ * `media.url` rather than here.
2526
+ */
2527
+ /**
2528
+ * Per-slide marker presentation, consolidated. `location.*` keeps working as
2529
+ * the legacy spelling and `marker.*` wins when present — see
2530
+ * docs/plans/iiif-media-tours.md §2.
2531
+ *
2532
+ * In a IIIF manifest none of this is a `storymap:` term: it all arrives in the
2533
+ * `navPlace` Feature's `properties` bag (`icon`, `iconSize`, `image`, `name`,
2534
+ * `popup`, `audioBadge`), which is a GeoJSON foreign-member bag and so needs
2535
+ * no vocabulary registration.
2536
+ */
2537
+ export declare interface StorymapSlideMarker {
2538
+ icon?: string;
2539
+ iconSize?: number[];
2540
+ image?: string;
2541
+ /** The marker label; in a manifest this is `properties.name`. */
2542
+ label?: string;
2543
+ /** Show the popup card when this (active) marker is clicked. */
2544
+ popup?: boolean;
2545
+ /** Mark slides that carry narration or audio media with a small badge. */
2546
+ audioBadge?: boolean;
2547
+ [key: string]: unknown;
2548
+ }
2549
+
2550
+ export declare interface StorymapSlideMedia {
1222
2551
  url?: string | null;
1223
2552
  caption?: string | null;
1224
2553
  credit?: string | null;
2554
+ /**
2555
+ * Accessible description of the media, used as the image's `alt` when the
2556
+ * media is an image. In IIIF this is the painting annotation's
2557
+ * `accessibilitySummary`.
2558
+ */
2559
+ alt?: string | null;
1225
2560
  thumb?: string | null;
1226
2561
  mediatype?: MediaTypeMatch | null;
2562
+ /**
2563
+ * WebVTT subtitle file for an audio or video slide, rendered as a
2564
+ * `<track kind="subtitles">`. IIIF has no subtitle term, so this stays a
2565
+ * storymap-JSON field; the authoring guide notes the
2566
+ * `TextualBody` + `format: text/vtt` shape we also accept.
2567
+ */
2568
+ subtitles?: string | null;
2569
+ [key: string]: unknown;
2570
+ }
2571
+
2572
+ export declare interface StorymapSlideNarration {
2573
+ url: string;
1227
2574
  [key: string]: unknown;
1228
2575
  }
1229
2576
 
1230
- declare interface StorymapSlideText {
2577
+ export declare interface StorymapSlideText {
1231
2578
  headline?: string;
1232
2579
  text?: string;
1233
2580
  text_align?: string;
1234
2581
  }
1235
2582
 
2583
+ /**
2584
+ * TileJSON 2.1 tile source metadata, from a manifest's map configuration
2585
+ * service (§2.9 of docs/plans/iiif-interop.md).
2586
+ *
2587
+ * This is how a manifest states a tile source: `tiles` is the URL template and
2588
+ * the rest is the standard metadata around it, where a keyword basemap
2589
+ * (`osm`, `stadia`, `iiif`, …) has no such thing to say. `minzoom`,
2590
+ * `maxzoom`, `bounds` and `scheme` constrain the source; `center` and `zoom`
2591
+ * set the initial view.
2592
+ */
2593
+ export declare interface StorymapTilejson {
2594
+ /** URL template, e.g. `https://tiles.example.org/{z}/{x}/{y}.png` */
2595
+ tiles: string | string[];
2596
+ /** Lowest zoom level the source has tiles for */
2597
+ minzoom?: number;
2598
+ /** Highest zoom level the source has tiles for */
2599
+ maxzoom?: number;
2600
+ /** `[west, south, east, north]`, WGS84 lon/lat, of the covered area */
2601
+ bounds?: [number, number, number, number];
2602
+ /** `xyz` (default) or `tms`, which flips the tile row order */
2603
+ scheme?: "xyz" | "tms";
2604
+ /** `[lon, lat, zoom]` of the map's default view */
2605
+ center?: [number, number, number];
2606
+ }
2607
+
2608
+ /**
2609
+ * Convert a legacy storymap document to a IIIF Presentation 3.0 manifest.
2610
+ *
2611
+ * The counterpart of `manifestToStorymapData()`: what that reads, this writes.
2612
+ * Nothing but the input is read, so the same document always produces the same
2613
+ * manifest — which is what makes regenerating `public/examples-iiif/` a no-op.
2614
+ *
2615
+ * @param name - The manifest's label, and the stem of its canonical id.
2616
+ * @param legacy - The `storymap.json` document (`{ "storymap": {...} }`).
2617
+ * @returns The manifest, ready to serialise.
2618
+ */
2619
+ export declare function storymapToManifest(name: string, legacy: StorymapDocument): StorymapManifest;
2620
+
1236
2621
  declare class StorySlider extends StorySlider_base {
1237
2622
  constructor(...args: ConstructorParameters<typeof StorySliderBase>);
1238
2623
  }
@@ -1242,7 +2627,7 @@ declare const StorySlider_base: {
1242
2627
  _vco_events?: Record<string, {
1243
2628
  action: unknown;
1244
2629
  context: unknown;
1245
- }[]>;
2630
+ }[]> | undefined;
1246
2631
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
1247
2632
  hasEventListeners(type: string): boolean;
1248
2633
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -1251,7 +2636,7 @@ declare const StorySlider_base: {
1251
2636
  } & typeof StorySliderBase;
1252
2637
 
1253
2638
  declare class StorySliderBase {
1254
- "_el": Record<string, HTMLElement>;
2639
+ "_el": StorySliderElements;
1255
2640
  "_nav": {
1256
2641
  previous: SlideNav;
1257
2642
  next: SlideNav;
@@ -1259,7 +2644,8 @@ declare class StorySliderBase {
1259
2644
  "slide_spacing": number;
1260
2645
  "_slides": Slide[];
1261
2646
  "_swipable": Swipable;
1262
- "preloadTimer": ReturnType<typeof setTimeout>;
2647
+ "preloadTimer": ReturnType<typeof setTimeout> | undefined;
2648
+ "preloadIdleHandle": number | undefined;
1263
2649
  "_message": Message;
1264
2650
  "current_slide": number;
1265
2651
  "current_bg_color": string | null;
@@ -1279,6 +2665,20 @@ declare class StorySliderBase {
1279
2665
  _createSlide(d: StorymapSlide, title_slide?: boolean): void;
1280
2666
  _addSlide(slide: Slide): void;
1281
2667
  goToId(n: string | number, fast?: boolean, displayupdate?: boolean): void;
2668
+ /**
2669
+ * Cancel the pending preload, whichever scheduling primitive queued it.
2670
+ *
2671
+ * The two handles are kept apart deliberately: they are both numbers, so
2672
+ * calling `clearTimeout` on an idle-callback handle "works" by accident
2673
+ * while actually leaking the callback, and the reverse leaves a live
2674
+ * timeout behind.
2675
+ */
2676
+ _cancelPreload(): void;
2677
+ /**
2678
+ * Release listeners, timers and running animations. Called by
2679
+ * `StoryMap.dispose()`; the slider must not be used afterwards.
2680
+ */
2681
+ dispose(): void;
1282
2682
  goTo(n: number, fast?: boolean, displayupdate?: boolean): void;
1283
2683
  preloadSlides(): void;
1284
2684
  getNavInfo(slide: Slide): {
@@ -1307,6 +2707,20 @@ declare class StorySliderBase {
1307
2707
  _onLoaded(): void;
1308
2708
  }
1309
2709
 
2710
+ /**
2711
+ * The slider's element cache. `live_region` only exists when the slide
2712
+ * announcements are enabled (the `a11y` option), so it starts out null.
2713
+ */
2714
+ declare type StorySliderElements = {
2715
+ container: HTMLElement;
2716
+ /** Created in `_initLayout`; the slide background layer. */
2717
+ background: HTMLElement;
2718
+ slider_container_mask: HTMLElement;
2719
+ slider_container: HTMLElement;
2720
+ slider_item_container: HTMLElement;
2721
+ live_region: HTMLElement | null;
2722
+ };
2723
+
1310
2724
  declare interface StorySliderOptions {
1311
2725
  id?: string;
1312
2726
  layout: string;
@@ -1325,7 +2739,6 @@ declare interface StorySliderOptions {
1325
2739
  skinny_size?: number;
1326
2740
  call_to_action?: boolean;
1327
2741
  call_to_action_text?: string;
1328
- dragging?: boolean;
1329
2742
  trackResize?: boolean;
1330
2743
  [key: string]: unknown;
1331
2744
  }
@@ -1339,7 +2752,7 @@ declare const Swipable_base: {
1339
2752
  _vco_events?: Record<string, {
1340
2753
  action: unknown;
1341
2754
  context: unknown;
1342
- }[]>;
2755
+ }[]> | undefined;
1343
2756
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
1344
2757
  hasEventListeners(type: string): boolean;
1345
2758
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -1359,10 +2772,18 @@ declare class SwipableBase {
1359
2772
  constructor(drag_elem: HTMLElement, move_elem?: HTMLElement, options?: Record<string, unknown>);
1360
2773
  enable(e?: LegacyEvent): void;
1361
2774
  disable(): void;
2775
+ /**
2776
+ * Full teardown for `dispose()`: `disable()` only covers the listeners
2777
+ * `enable()` adds, but a gesture in flight also holds the `move`/`leave`
2778
+ * pair plus the momentum animation.
2779
+ */
2780
+ dispose(): void;
1362
2781
  stopMomentum(): void;
1363
2782
  updateConstraint(c: SwipableOptions["constraint"]): void;
1364
2783
  _onDragStart(e: LegacyEvent): void;
1365
2784
  _onDragEnd(e: LegacyEvent): void;
2785
+ _attachGestureListeners(): void;
2786
+ _detachGestureListeners(): void;
1366
2787
  _onDragMove(e: LegacyEvent): void;
1367
2788
  _momentum(): void;
1368
2789
  _animateMomentum(): void;
@@ -1394,7 +2815,7 @@ declare const Text_base: {
1394
2815
  _vco_events?: Record<string, {
1395
2816
  action: unknown;
1396
2817
  context: unknown;
1397
- }[]>;
2818
+ }[]> | undefined;
1398
2819
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
1399
2820
  hasEventListeners(type: string): boolean;
1400
2821
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -1436,6 +2857,21 @@ declare interface TextOptions {
1436
2857
  text_align?: string;
1437
2858
  }
1438
2859
 
2860
+ /**
2861
+ * Custom tile layer/source factory (see
2862
+ * `StorymapOptions.tile_source_factory`). `createDefault` runs the
2863
+ * built-in `map_type` handling, so a factory can decorate or delegate.
2864
+ *
2865
+ * May return any `ol/layer/Layer` (used as-is — this is what lets a
2866
+ * third-party layer such as an Allmaps `WarpedMapLayer` render), a bare
2867
+ * `Source` (wrapped in a `TileLayer`), or `null`/`undefined` to fall
2868
+ * through to the default `map_type` handling.
2869
+ */
2870
+ export declare type TileSourceFactory = (map_type: string, context: {
2871
+ options: StorymapOptions;
2872
+ createDefault: () => Tile;
2873
+ }) => OlLayer | Tile | OlSource | null | undefined;
2874
+
1439
2875
  /** Validate storymap JSON (the object containing a "storymap" property). */
1440
2876
  export declare function validateStorymap(data: unknown): StorymapError[];
1441
2877
 
@@ -1464,4 +2900,12 @@ declare global {
1464
2900
  const SC: {
1465
2901
  Widget: (el: HTMLElement) => { pause(): void };
1466
2902
  };
2903
+
2904
+ /**
2905
+ * The library version, substituted from package.json by the Vite lib build
2906
+ * (see the `define` in vite.config.ts). Hard-coded here only so the
2907
+ * source type-checks; a dev-server run without the define falls back to
2908
+ * "unknown" at runtime via the typeof guard in StoryMap.
2909
+ */
2910
+ const __STORYMAP_VERSION__: string;
1467
2911
  }