@projektemacher/storymapjs 0.10.7 → 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 (532) hide show
  1. package/CHANGELOG +350 -19
  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 +84 -0
  253. package/dist/css/fonts/font.opensans-gentiumbook.css +183 -0
  254. package/dist/css/fonts/font.playfair-faunaone.css +39 -0
  255. package/dist/css/fonts/font.playfair.css +147 -0
  256. package/dist/css/fonts/font.pt.css +183 -0
  257. package/dist/css/fonts/font.roboto-megrim.css +3 -0
  258. package/dist/css/fonts/font.rufina-sintony.css +3 -0
  259. package/dist/css/fonts/font.ubuntu.css +291 -0
  260. package/dist/css/fonts/font.unicaone-vollkorn.css +84 -0
  261. package/dist/css/storymap.css +1 -1
  262. package/dist/demo.html +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 +313 -11
  338. package/dist/docs/readme.html +40 -9
  339. package/dist/embed/index.html +1 -1
  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 +16 -10
  405. package/dist/js/storymap.d.ts +1439 -114
  406. package/dist/js/storymap.js +24654 -21936
  407. package/dist/js/storymap.js.map +1 -1
  408. package/dist/navplace-properties.json +40 -0
  409. package/docs/migration-from-knightlab.md +229 -9
  410. package/docs/storymap-as-iiif-manifest.md +559 -135
  411. package/package.json +11 -8
  412. package/schema/storymap.schema.json +431 -78
  413. package/src/animation/easings.ts +8 -1
  414. package/src/animation/tween.ts +186 -0
  415. package/src/core/Browser.ts +6 -5
  416. package/src/core/Load.ts +54 -2
  417. package/src/core/Util.ts +255 -193
  418. package/src/core/mixins.ts +24 -7
  419. package/src/core/viewers.ts +94 -0
  420. package/src/dom/DomEvent.ts +27 -8
  421. package/src/globals.d.ts +8 -0
  422. package/src/language/Language.ts +199 -25
  423. package/src/language/locale/.expected-gaps.json +86 -0
  424. package/src/language/locale/be.json +15 -2
  425. package/src/language/locale/bg.json +15 -2
  426. package/src/language/locale/cs.json +15 -2
  427. package/src/language/locale/de.json +12 -1
  428. package/src/language/locale/el.json +15 -2
  429. package/src/language/locale/en.json +6 -2
  430. package/src/language/locale/es.json +15 -2
  431. package/src/language/locale/et.json +5 -1
  432. package/src/language/locale/fr.json +15 -2
  433. package/src/language/locale/he.json +16 -3
  434. package/src/language/locale/hu.json +15 -2
  435. package/src/language/locale/is.json +5 -1
  436. package/src/language/locale/it.json +15 -2
  437. package/src/language/locale/jp.json +15 -2
  438. package/src/language/locale/ko.json +15 -2
  439. package/src/language/locale/nl.json +15 -2
  440. package/src/language/locale/nn.json +5 -1
  441. package/src/language/locale/no.json +15 -2
  442. package/src/language/locale/pl.json +15 -2
  443. package/src/language/locale/pt.json +15 -2
  444. package/src/language/locale/ru.json +15 -2
  445. package/src/language/locale/sk.json +15 -2
  446. package/src/language/locale/sr.json +5 -1
  447. package/src/language/locale/sv.json +15 -2
  448. package/src/language/locale/tr.json +15 -2
  449. package/src/language/locale/uk.json +15 -2
  450. package/src/language/locale/ur.json +5 -1
  451. package/src/language/locale/zh-cn.json +15 -2
  452. package/src/language/locale/zh-tw.json +15 -2
  453. package/src/main.ts +92 -0
  454. package/src/map/Map.ts +183 -106
  455. package/src/map/MapMarker.ts +28 -5
  456. package/src/map/georeference.ts +325 -0
  457. package/src/map/openlayers/Map.OpenLayers.ts +850 -237
  458. package/src/map/openlayers/MapMarker.OpenLayers.ts +248 -24
  459. package/src/map/openlayers/zoomifyTiles.ts +1 -4
  460. package/src/media/EmbedUtil.ts +308 -24
  461. package/src/media/Media.ts +243 -55
  462. package/src/media/embedId.ts +104 -0
  463. package/src/media/types/Audio.ts +9 -82
  464. package/src/media/types/Blockquote.ts +2 -3
  465. package/src/media/types/DailyMotion.ts +5 -10
  466. package/src/media/types/DocumentCloud.ts +6 -35
  467. package/src/media/types/Facebook.ts +3 -4
  468. package/src/media/types/Flickr.ts +9 -9
  469. package/src/media/types/GoogleDoc.ts +3 -4
  470. package/src/media/types/HtmlMedia.ts +167 -0
  471. package/src/media/types/IFrame.ts +3 -4
  472. package/src/media/types/Image.ts +72 -6
  473. package/src/media/types/Juxtapose.ts +14 -5
  474. package/src/media/types/SoundCloud.ts +28 -6
  475. package/src/media/types/Text.ts +19 -13
  476. package/src/media/types/Twitter.ts +27 -14
  477. package/src/media/types/Video.ts +9 -79
  478. package/src/media/types/Vimeo.ts +10 -10
  479. package/src/media/types/Website.ts +23 -13
  480. package/src/media/types/Wikipedia.ts +18 -8
  481. package/src/media/types/YouTube.ts +71 -39
  482. package/src/scss/Typography.scss +1 -3
  483. package/src/scss/VCO.StoryMap.Dark.scss +18 -6
  484. package/src/scss/VCO.StoryMap.scss +37 -6
  485. package/src/scss/Variables.Dark.scss +3 -2
  486. package/src/scss/Variables.scss +3 -2
  487. package/src/scss/core/Mixins.scss +5 -63
  488. package/src/scss/fonts/font.amatic-andika.scss +3 -0
  489. package/src/scss/fonts/font.bitter-raleway.scss +6 -0
  490. package/src/scss/fonts/font.cairo.scss +79 -0
  491. package/src/scss/fonts/font.clicker-garamond.scss +5 -0
  492. package/src/scss/fonts/font.dancing-ledger.scss +1 -0
  493. package/src/scss/fonts/font.knightlab.scss +14 -0
  494. package/src/scss/fonts/font.oldstandard.scss +6 -0
  495. package/src/scss/fonts/font.opensans-gentiumbook.scss +5 -0
  496. package/src/scss/fonts/font.playfair-faunaone.scss +2 -0
  497. package/src/scss/fonts/font.playfair.scss +4 -0
  498. package/src/scss/fonts/font.pt.scss +6 -0
  499. package/src/scss/fonts/font.ubuntu.scss +4 -0
  500. package/src/scss/fonts/font.unicaone-vollkorn.scss +5 -0
  501. package/src/scss/map/VCO.MapMarker.scss +98 -3
  502. package/src/scss/media/VCO.Media.scss +7 -10
  503. package/src/scss/media/types/VCO.Media.Text.scss +8 -0
  504. package/src/scss/media/types/VCO.Media.Wikipedia.scss +2 -1
  505. package/src/scss/slider/VCO.Slide.scss +13 -3
  506. package/src/scss/slider/VCO.SlideNav.scss +11 -17
  507. package/src/scss/slider/VCO.StorySlider.scss +4 -2
  508. package/src/scss/ui/VCO.Consent.scss +44 -0
  509. package/src/scss/ui/VCO.MenuBar.Button.scss +8 -0
  510. package/src/scss/ui/VCO.Message.scss +2 -5
  511. package/src/site/site.ts +2 -1
  512. package/src/slider/Slide.ts +121 -27
  513. package/src/slider/SlideNav.ts +39 -5
  514. package/src/slider/StorySlider.ts +153 -42
  515. package/src/storymap/Consent.ts +407 -82
  516. package/src/storymap/StoryMap.ts +1192 -182
  517. package/src/storymap/content-state.ts +185 -0
  518. package/src/storymap/iiif.ts +1526 -68
  519. package/src/storymap/to-iiif.ts +921 -0
  520. package/src/storymap/validate.ts +80 -7
  521. package/src/types.ts +223 -26
  522. package/src/ui/MenuBar.ts +98 -45
  523. package/src/ui/Message.ts +9 -0
  524. package/src/ui/Swipable.ts +145 -78
  525. package/dist/assets/demo-D6cTmzn6.js +0 -1
  526. package/dist/assets/harness-BPFlzutp.js +0 -1
  527. package/dist/assets/index-DDsPBPZA.js +0 -1
  528. package/dist/assets/main-Y-MYUSJ4.js +0 -17
  529. package/src/animation/morpheus.d.ts +0 -41
  530. package/src/scss/media/types/VCO.Media.Instagram.scss +0 -7
  531. package/src/scss/media/types/VCO.Media.Profile.scss +0 -5
  532. package/src/ui/Draggable.ts +0 -374
@@ -1,46 +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';
6
4
  import { Extent } from 'ol/extent';
7
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';
8
13
  import { Style } from 'ol/style';
9
14
  import { Tile } from 'ol/layer';
10
15
  import { Vector } from 'ol/layer';
16
+ import { XYZ } from 'ol/source';
11
17
 
12
- declare interface AnimationHandle {
18
+ export declare interface AnimationHandle {
13
19
  stop: (jump?: boolean) => void;
14
20
  }
15
21
 
16
22
  /**
17
23
  * Per-StoryMap GDPR consent manager. When the `consent_required` option is
18
24
  * set, every external service (media embeds, map tiles, external font CSS)
19
- * asks for permission before anything is loaded. Decisions are remembered
20
- * per service in a cookie for 90 days — clearing cookies asks again.
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.
21
29
  */
22
30
  declare class ConsentManager {
23
31
  private granted;
24
32
  private denied;
25
33
  /** unanswered asks per service (preloaded slides stack several) */
26
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;
27
43
  constructor();
28
- /** 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
+ */
29
52
  private restore;
30
- /** 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
+ */
31
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;
32
80
  isGranted(service: string): boolean;
33
81
  isDenied(service: string): boolean;
82
+ /** True when at least one of the services has no stored decision yet. */
83
+ hasUnanswered(services: string[]): boolean;
34
84
  /**
35
- * Ask the visitor for permission to load `service` (a human-readable
36
- * name like "YouTube" or "map tiles"), optionally naming the `host`.
37
- * The ask is rendered into `container`; resolves `true`/`false` on the
38
- * visitor's decision, or immediately when the service was already
39
- * granted or denied.
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.
40
90
  */
41
- 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;
42
112
  }
43
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
+
44
151
  declare interface DragData {
45
152
  sliding: boolean;
46
153
  direction: string | null;
@@ -80,6 +187,7 @@ declare interface DragData {
80
187
  declare interface DragEventNames {
81
188
  down: string;
82
189
  up: string;
190
+ cancel?: string;
83
191
  leave: string;
84
192
  move: string;
85
193
  }
@@ -98,16 +206,76 @@ declare type IconSpec = {
98
206
  anchor: number[];
99
207
  };
100
208
 
101
- declare interface LanguageEntry {
102
- buttons?: Record<string, string>;
103
- 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>;
104
264
  [key: string]: unknown;
105
265
  }
106
266
 
107
- declare interface LatLngLiteral {
108
- lat: number | undefined;
109
- lon?: number | undefined;
110
- 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;
111
279
  }
112
280
 
113
281
  /** Legacy drag handlers historically mixed mouse and touch event surfaces. */
@@ -128,23 +296,33 @@ declare interface LinePoint {
128
296
  /**
129
297
  * Append one stylesheet to the document head.
130
298
  *
299
+ * Concurrent and repeat requests for the same URL share one `<link>`.
300
+ *
131
301
  * @param url - The stylesheet URL.
132
302
  * @param options - Optional AbortSignal to cancel an in-flight load.
133
303
  * @returns Resolves when the stylesheet has loaded, rejects on error or abort.
134
304
  */
135
305
  export declare function loadCSS(url: string, options?: LoadOptions): Promise<void>;
136
306
 
137
- declare interface LoadOptions {
307
+ export declare interface LoadOptions {
138
308
  /** Abort the load (removes the element, rejects the promise). */
139
309
  signal?: AbortSignal;
140
310
  }
141
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
+
142
319
  declare class Map_2 extends Map_base {
143
320
  constructor(...args: ConstructorParameters<typeof MapBase>);
144
321
  }
145
322
 
146
323
  declare const Map_base: {
147
324
  new (...args: any[]): {
325
+ container(): HTMLElement;
148
326
  show(animate?: unknown): void;
149
327
  hide(): void;
150
328
  addTo(container: HTMLElement): /*elided*/ any;
@@ -153,7 +331,7 @@ declare const Map_base: {
153
331
  onLoaded(): void;
154
332
  onAdd(): void;
155
333
  onRemove(): void;
156
- _el: Record<string, HTMLElement>;
334
+ _el: Record<string, unknown>;
157
335
  data?: unknown;
158
336
  on: (type: string, fn: unknown, context?: unknown) => unknown;
159
337
  off: (type: string, fn: unknown, context?: unknown) => unknown;
@@ -165,7 +343,7 @@ declare const Map_base: {
165
343
  _vco_events?: Record<string, {
166
344
  action: unknown;
167
345
  context: unknown;
168
- }[]>;
346
+ }[]> | undefined;
169
347
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
170
348
  hasEventListeners(type: string): boolean;
171
349
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -186,6 +364,12 @@ declare class MapBase {
186
364
  "_map": Map_3 | null;
187
365
  "_mini_map": default_2 | null;
188
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)[];
189
373
  "zoom_min_max": {
190
374
  min: number | null;
191
375
  max: number | null;
@@ -194,8 +378,8 @@ declare class MapBase {
194
378
  "_line_active": Vector | null;
195
379
  "current_marker": number;
196
380
  "bounds_array": number[][] | null;
197
- "_tile_layer": Tile | null;
198
- "_tile_layer_mini": Tile | null;
381
+ "_tile_layer": OlLayer | null;
382
+ "_tile_layer_mini": OlLayer | null;
199
383
  "_image_layer": Tile | null;
200
384
  "data": StorymapData;
201
385
  "options": StorymapOptions;
@@ -208,18 +392,57 @@ declare class MapBase {
208
392
  constructor(elem: string | HTMLElement, data?: Partial<StorymapData>, options?: Partial<StorymapOptions>);
209
393
  updateDisplay(w: number, h: number, animate?: boolean, d?: number, offset?: unknown): void;
210
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
+ */
211
399
  panTo(loc: LatLngLiteral, animate?: boolean): void;
400
+ /** Alias over the OpenLayers view: `storymap.map.getView().animate({zoom})`. */
212
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
+ */
213
406
  viewTo(loc: StorymapSlideLocation, opts?: ViewToOptions): void;
214
- 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
+ */
215
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
+ */
216
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
+ */
217
423
  createMiniMap(): void;
218
424
  setMapOffset(left: number, top: number): void;
219
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;
220
433
  updateMinMaxZoom(zoom: number): void;
221
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
+ */
222
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
+ */
223
446
  hide(): void;
224
447
  createMarkers(array: StorymapSlide[]): void;
225
448
  createMarker(d: StorymapSlide): void;
@@ -230,6 +453,27 @@ declare class MapBase {
230
453
  * lon 0 are valid coordinates and must not be treated as missing.
231
454
  */
232
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;
233
477
  _createMap(): void;
234
478
  _createMiniMap(): void;
235
479
  _createMarker(d?: StorymapSlide): void;
@@ -238,7 +482,9 @@ declare class MapBase {
238
482
  _resetMarkersActive(): void;
239
483
  _calculateMarkerZooms(): void;
240
484
  _createLine(d?: StorymapSlide): unknown;
241
- _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;
242
488
  _replaceLines(line: Vector | null, d: LinePoint[], animate?: {
243
489
  duration: number;
244
490
  retractFrom?: LinePoint[] | null;
@@ -252,7 +498,20 @@ declare class MapBase {
252
498
  _refreshMap(): void;
253
499
  _getMapZoom(): number;
254
500
  _getMapCenter(correct_for_center?: boolean): LatLngLiteral;
255
- _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;
256
515
  _markerOverview(duration?: number): void;
257
516
  /**
258
517
  * Great-circle length of the route through all markers in kilometers;
@@ -268,7 +527,7 @@ declare class MapBase {
268
527
  _onWheel(e: WheelEvent): void;
269
528
  _scollZoom(e?: unknown): void;
270
529
  _scollZoomDone(e?: unknown): void;
271
- _calculateZoomChange(origin: LatLngLiteral, destination: LatLngLiteral, correct_for_center?: boolean): number;
530
+ _calculateZoomChange(origin: LatLngLiteral, destination: LatLngLiteral, correct_for_center?: boolean): number | undefined;
272
531
  _updateDisplay(w?: number, h?: number, animate?: boolean, d?: number, offset?: unknown): void;
273
532
  /** Re-apply runtime-changed options (no-op in the base class) */
274
533
  applyOptions(_keys: string[]): void;
@@ -288,7 +547,7 @@ declare const MapMarker_base: {
288
547
  _vco_events?: Record<string, {
289
548
  action: unknown;
290
549
  context: unknown;
291
- }[]>;
550
+ }[]> | undefined;
292
551
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
293
552
  hasEventListeners(type: string): boolean;
294
553
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -311,35 +570,65 @@ declare class MapMarkerBase {
311
570
  "animator": AnimationHandle | null;
312
571
  "fire": EventedInstance["fire"];
313
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
+ */
314
578
  show(): void;
579
+ /** @deprecated See {@link show} — no-op since 0.9.x upstream. */
315
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;
316
590
  addTo(m: unknown): void;
317
591
  removeFrom(m: unknown): void;
318
592
  updateDisplay(w: number, h: number, a?: boolean): void;
319
593
  createMarker(d?: MapMarkerData, o?: StorymapOptions): void;
320
594
  active(a: boolean): void;
321
- location(): LatLngLiteral;
595
+ location(): LatLngLiteral | null;
322
596
  _createMarker(d?: MapMarkerData, o?: StorymapOptions): void;
323
597
  _addTo(m: unknown): void;
324
598
  _removeFrom(m: unknown): void;
325
599
  _active(a: boolean): void;
326
- _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;
327
608
  _onMarkerClick(e?: unknown): void;
328
609
  _initLayout(): void;
329
610
  _updateDisplay(width: number, height: number, animate?: boolean): void;
330
611
  }
331
612
 
332
- 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 & {
333
620
  real_marker?: boolean;
334
- location?: StorymapSlideLocation;
335
- media?: StorymapSlideMedia & {
336
- mediatype?: MediaTypeMatch | null;
337
- };
338
- text?: {
339
- headline?: string;
340
- };
341
- type?: string;
342
- [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;
343
632
  }
344
633
 
345
634
  declare interface MediaInstance {
@@ -347,9 +636,12 @@ declare interface MediaInstance {
347
636
  loadMedia: () => void;
348
637
  stopMedia: () => void;
349
638
  updateDisplay: (w?: number, h?: number, l?: string) => void;
639
+ dispose?: () => void;
350
640
  on?: EventedInstance["on"];
641
+ off?: EventedInstance["off"];
351
642
  _state?: {
352
643
  loaded?: boolean;
644
+ eager?: boolean;
353
645
  };
354
646
  }
355
647
 
@@ -363,7 +655,7 @@ declare interface MediaInstance {
363
655
  */
364
656
  export declare function MediaType(m: StorymapSlideMedia): MediaTypeMatch | false;
365
657
 
366
- declare type MediaTypeMatch = {
658
+ export declare type MediaTypeMatch = {
367
659
  type: string;
368
660
  name: string;
369
661
  match_str: string;
@@ -376,6 +668,7 @@ declare class MenuBar extends MenuBar_base {
376
668
 
377
669
  declare const MenuBar_base: {
378
670
  new (...args: any[]): {
671
+ container(): HTMLElement;
379
672
  show(animate?: unknown): void;
380
673
  hide(): void;
381
674
  addTo(container: HTMLElement): /*elided*/ any;
@@ -384,7 +677,7 @@ declare const MenuBar_base: {
384
677
  onLoaded(): void;
385
678
  onAdd(): void;
386
679
  onRemove(): void;
387
- _el: Record<string, HTMLElement>;
680
+ _el: Record<string, unknown>;
388
681
  data?: unknown;
389
682
  on: (type: string, fn: unknown, context?: unknown) => unknown;
390
683
  off: (type: string, fn: unknown, context?: unknown) => unknown;
@@ -396,7 +689,7 @@ declare const MenuBar_base: {
396
689
  _vco_events?: Record<string, {
397
690
  action: unknown;
398
691
  context: unknown;
399
- }[]>;
692
+ }[]> | undefined;
400
693
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
401
694
  hasEventListeners(type: string): boolean;
402
695
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -420,6 +713,19 @@ declare class MenuBarBase {
420
713
  * Reflect the fullscreen state in the button label/icon.
421
714
  */
422
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;
423
729
  /**
424
730
  * Repaint every text label from the active language (see `setLanguage`).
425
731
  * Icon-only mobile buttons carry no text and are left untouched.
@@ -441,6 +747,11 @@ declare class MenuBarBase {
441
747
  _onButtonCollapseMap(e: Event): void;
442
748
  _initLayout(): void;
443
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;
444
755
  }
445
756
 
446
757
  declare interface MenuBarOptions {
@@ -458,6 +769,7 @@ declare class Message extends Message_base {
458
769
 
459
770
  declare const Message_base: {
460
771
  new (...args: any[]): {
772
+ container(): HTMLElement;
461
773
  show(animate?: unknown): void;
462
774
  hide(): void;
463
775
  addTo(container: HTMLElement): /*elided*/ any;
@@ -466,7 +778,7 @@ declare const Message_base: {
466
778
  onLoaded(): void;
467
779
  onAdd(): void;
468
780
  onRemove(): void;
469
- _el: Record<string, HTMLElement>;
781
+ _el: Record<string, unknown>;
470
782
  data?: unknown;
471
783
  on: (type: string, fn: unknown, context?: unknown) => unknown;
472
784
  off: (type: string, fn: unknown, context?: unknown) => unknown;
@@ -478,7 +790,7 @@ declare const Message_base: {
478
790
  _vco_events?: Record<string, {
479
791
  action: unknown;
480
792
  context: unknown;
481
- }[]>;
793
+ }[]> | undefined;
482
794
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
483
795
  hasEventListeners(type: string): boolean;
484
796
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -498,6 +810,11 @@ declare class MessageBase {
498
810
  _onMouseClick(): void;
499
811
  _initLayout(): void;
500
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;
501
818
  }
502
819
 
503
820
  declare interface MessageOptions {
@@ -508,18 +825,40 @@ declare interface MessageOptions {
508
825
  [key: string]: unknown;
509
826
  }
510
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
+
511
842
  declare class OpenLayers extends Map_2 {
512
- "_map": default_3;
513
- "_tile_layer": Tile;
843
+ "_map": OlMap;
844
+ "_tile_layer": OlLayer;
514
845
  "_line": Vector;
515
846
  "_line_active": Vector;
516
- "_tile_layer_mini": Tile | null;
847
+ "_tile_layer_mini": OlLayer | null;
517
848
  "_mini_map": default_2;
518
849
  "_markers": OpenLayersMapMarker[];
519
850
  /** App-level stacked overlays (see the `overlays` option) */
520
- "_overlay_layers": Tile[];
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[];
521
858
  /** rAF handle of the running active-line draw animation */
522
859
  "_line_animation": number | null;
860
+ /** Sources `imageready` has already been fired for. */
861
+ "_imageready_fired": WeakSet<object>;
523
862
  _createMap(): void;
524
863
  /** Extra attribution fragments (e.g. overlay credits), always listed last. */
525
864
  "_extra_attributions": string[];
@@ -528,13 +867,37 @@ declare class OpenLayers extends Map_2 {
528
867
  * custom layers use this instead of rewriting `.vco-map-attribution`.
529
868
  */
530
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;
531
886
  /**
532
887
  * (Re)render the attribution line for the current map type. Called at
533
888
  * creation and on every `map_type` switch, which previously left the
534
889
  * initial text stale.
535
890
  */
536
891
  _updateAttribution(): void;
537
- _getAttribution(map_type: string): string;
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[];
538
901
  /**
539
902
  * Create the tile layer and register its load handler. Deferred until
540
903
  * the visitor allows map tiles in consent mode.
@@ -543,14 +906,27 @@ declare class OpenLayers extends Map_2 {
543
906
  /**
544
907
  * Ask for tile consent, then attach the layers if allowed.
545
908
  */
546
- _requestTileConsent(consent: ConsentManager, tile_service: string): Promise<void>;
909
+ _requestTileConsent(consent: ConsentManager, tile_service: ConsentService): Promise<void>;
547
910
  /**
548
911
  * (Re)build the stacked raster overlays from the `overlays` option.
549
912
  * Overlays sit above the base tiles (z 1..n) and below the route lines
550
913
  * (z 10/11); every entry accepts any `map_type` value plus declarative
551
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.
552
917
  */
553
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;
554
930
  /**
555
931
  * Convert a lon/lat clip box to view units. Only meaningful on
556
932
  * mercator maps; image-space maps (iiif/zoomify) and malformed
@@ -569,11 +945,24 @@ declare class OpenLayers extends Map_2 {
569
945
  }, retries?: number): void;
570
946
  /** Refresh the attribution line with the visible overlays' credits. */
571
947
  _syncOverlayAttributions(): void;
572
- /** Number of stacked overlay layers (see the `overlays` option). */
948
+ /**
949
+ * Number of stacked overlay layers (see the `overlays` option). Alias:
950
+ * `getOverlayLayers().length`.
951
+ */
573
952
  getOverlayCount(): number;
574
- /** Show or hide a stacked overlay by index (re-syncs attribution). */
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
+ */
575
961
  setOverlayVisible(index: number, visible: boolean): void;
576
962
  /** Set a stacked overlay's opacity by index. */
963
+ /**
964
+ * Alias: `getOverlayLayer(index)?.setOpacity(opacity)`.
965
+ */
577
966
  setOverlayOpacity(index: number, opacity: number): void;
578
967
  /**
579
968
  * Map tiles were allowed: attach the main tile layer, create the
@@ -589,7 +978,7 @@ declare class OpenLayers extends Map_2 {
589
978
  sizes: Array<[number, number]>;
590
979
  maxZoom: number;
591
980
  extent: number[];
592
- tileGrid: default_5;
981
+ tileGrid: default_4;
593
982
  } | null;
594
983
  /**
595
984
  * The zoomify overview state: the best-fit pyramid level for a map
@@ -600,7 +989,82 @@ declare class OpenLayers extends Map_2 {
600
989
  zoom: number;
601
990
  center: number[];
602
991
  } | null;
603
- _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;
604
1068
  _createVectorStyleLayer(style_url: string): Tile;
605
1069
  _createMiniMap(): void;
606
1070
  _fitMiniMapToImage(): void;
@@ -640,7 +1104,7 @@ declare class OpenLayers extends Map_2 {
640
1104
  * by design — they must not skew the fit target, so the extent is
641
1105
  * intersected with the box and the in-box markers compose the view.
642
1106
  */
643
- _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;
644
1108
  _calculateMarkerZooms(): void;
645
1109
  /**
646
1110
  * Stroke style for the route lines: the dash pattern and line join are
@@ -650,7 +1114,7 @@ declare class OpenLayers extends Map_2 {
650
1114
  _lineStyle(color: string): Style;
651
1115
  _createLine(d?: StorymapSlide): Vector;
652
1116
  _addLineToMap(line: Vector): void;
653
- _addToLine(line: Vector, d: LinePoint): void;
1117
+ _addToLine(line: Vector, d: StorymapSlide): void;
654
1118
  /**
655
1119
  * Replace a line's geometry. With `animate.duration > 0` only the latest
656
1120
  * hop animates, in sync with the view animation: the already-traveled
@@ -676,11 +1140,35 @@ declare class OpenLayers extends Map_2 {
676
1140
  _panTo(loc: LatLngLiteral, animate?: boolean): void;
677
1141
  _zoomTo(z: number, animate?: boolean): void;
678
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;
679
1149
  _toViewCoords(loc: LatLngLiteral): number[];
680
1150
  _getMapZoom(): number;
681
- _getMapCenter(offset?: boolean): LatLngLiteral;
1151
+ _getMapCenter(): LatLngLiteral;
682
1152
  _getMapCenterOffset(location: LatLngLiteral, zoom: number): LatLngLiteral;
683
- _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;
684
1172
  _getBoundsZoom(origin: LatLngLiteral, destination: LatLngLiteral, correct_for_center?: boolean): number;
685
1173
  _initialMapLocation(): void;
686
1174
  /**
@@ -712,14 +1200,78 @@ declare class OpenLayers extends Map_2 {
712
1200
  }
713
1201
 
714
1202
  declare class OpenLayersMapMarker extends MapMarker {
715
- "_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;
716
1228
  _createMarker(d?: MapMarkerData, o?: StorymapOptions): void;
717
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;
718
1237
  _addTo(m: Map_3): void;
719
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;
720
1272
  _active(a: boolean): void;
721
1273
  _customIconAnchor(size?: number[]): number[];
722
- _location(): LatLngLiteral;
1274
+ _location(): LatLngLiteral | null;
723
1275
  }
724
1276
 
725
1277
  /** Wheel/scroll zoom bookkeeping (handles cleared via clearTimeout). */
@@ -730,7 +1282,8 @@ declare interface ScrollState {
730
1282
  }
731
1283
 
732
1284
  /**
733
- * Switch the active UI language.
1285
+ * Switch the active UI language. Synchronous: the viewer resolves its labels
1286
+ * while it is being constructed.
734
1287
  *
735
1288
  * @param code - A locale code for which a locale file exists (e.g. `"en"`).
736
1289
  * @returns The language entry that is now active.
@@ -743,6 +1296,7 @@ declare class Slide extends Slide_base {
743
1296
 
744
1297
  declare const Slide_base: {
745
1298
  new (...args: any[]): {
1299
+ container(): HTMLElement;
746
1300
  show(animate?: unknown): void;
747
1301
  hide(): void;
748
1302
  addTo(container: HTMLElement): /*elided*/ any;
@@ -751,7 +1305,7 @@ declare const Slide_base: {
751
1305
  onLoaded(): void;
752
1306
  onAdd(): void;
753
1307
  onRemove(): void;
754
- _el: Record<string, HTMLElement>;
1308
+ _el: Record<string, unknown>;
755
1309
  data?: unknown;
756
1310
  on: (type: string, fn: unknown, context?: unknown) => unknown;
757
1311
  off: (type: string, fn: unknown, context?: unknown) => unknown;
@@ -763,7 +1317,7 @@ declare const Slide_base: {
763
1317
  _vco_events?: Record<string, {
764
1318
  action: unknown;
765
1319
  context: unknown;
766
- }[]>;
1320
+ }[]> | undefined;
767
1321
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
768
1322
  hasEventListeners(type: string): boolean;
769
1323
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -777,7 +1331,8 @@ declare interface SlideBackgroundChange {
777
1331
  }
778
1332
 
779
1333
  declare class SlideBase {
780
- "_el": Record<string, HTMLElement>;
1334
+ /** `call_to_action` is only created when the slide shows one. */
1335
+ "_el": SlideElements;
781
1336
  "_media": MediaInstance | null;
782
1337
  "_mediaclass": unknown;
783
1338
  "_text": Text_2;
@@ -786,6 +1341,9 @@ declare class SlideBase {
786
1341
  };
787
1342
  "_scroll_hint": HTMLElement | null;
788
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)[];
789
1347
  "has": SlideHas;
790
1348
  "title": string;
791
1349
  "data": StorymapSlide;
@@ -797,15 +1355,34 @@ declare class SlideBase {
797
1355
  constructor(data: StorymapSlide, options: Record<string, unknown>, title_slide?: boolean);
798
1356
  show(): void;
799
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;
800
1363
  setActive(is_active: boolean): void;
801
1364
  updateDisplay(w?: number, h?: number, l?: string): void;
802
1365
  loadMedia(): void;
1366
+ _eagerLoadImages(): void;
803
1367
  stopMedia(): void;
804
1368
  getBackground(): {
805
1369
  image: boolean;
806
1370
  color: boolean;
807
1371
  color_value: string;
808
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;
809
1386
  scrollToTop(): void;
810
1387
  /**
811
1388
  * Show a bouncing downward arrow when the slide content overflows
@@ -823,6 +1400,19 @@ declare class SlideBase {
823
1400
  _updateDisplay(width?: number, height?: number, layout?: string): void;
824
1401
  }
825
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
+
826
1416
  declare interface SlideHas {
827
1417
  headline: boolean;
828
1418
  text: boolean;
@@ -841,6 +1431,7 @@ declare class SlideNav extends SlideNav_base {
841
1431
 
842
1432
  declare const SlideNav_base: {
843
1433
  new (...args: any[]): {
1434
+ container(): HTMLElement;
844
1435
  show(animate?: unknown): void;
845
1436
  hide(): void;
846
1437
  addTo(container: HTMLElement): /*elided*/ any;
@@ -849,7 +1440,7 @@ declare const SlideNav_base: {
849
1440
  onLoaded(): void;
850
1441
  onAdd(): void;
851
1442
  onRemove(): void;
852
- _el: Record<string, HTMLElement>;
1443
+ _el: Record<string, unknown>;
853
1444
  data?: unknown;
854
1445
  on: (type: string, fn: unknown, context?: unknown) => unknown;
855
1446
  off: (type: string, fn: unknown, context?: unknown) => unknown;
@@ -861,7 +1452,7 @@ declare const SlideNav_base: {
861
1452
  _vco_events?: Record<string, {
862
1453
  action: unknown;
863
1454
  context: unknown;
864
- }[]>;
1455
+ }[]> | undefined;
865
1456
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
866
1457
  hasEventListeners(type: string): boolean;
867
1458
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -886,6 +1477,12 @@ declare class SlideNavBase {
886
1477
  _update(d?: Partial<SlideNavData>): void;
887
1478
  _initLayout(): void;
888
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;
889
1486
  }
890
1487
 
891
1488
  declare interface SlideNavData {
@@ -927,7 +1524,7 @@ declare const StoryMap_base: {
927
1524
  _vco_events?: Record<string, {
928
1525
  action: unknown;
929
1526
  context: unknown;
930
- }[]>;
1527
+ }[]> | undefined;
931
1528
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
932
1529
  hasEventListeners(type: string): boolean;
933
1530
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -943,7 +1540,7 @@ declare const StoryMap_base: {
943
1540
  *
944
1541
  * @example
945
1542
  * ```ts
946
- * import { StoryMap } from "storymapjs";
1543
+ * import { StoryMap } from "@projektemacher/storymapjs";
947
1544
  * // from an inline data object
948
1545
  * const map = new StoryMap("embed", { storymap: { ... } }, { start_at_slide: 2 });
949
1546
  * // or straight from a source file (storymap JSON or IIIF manifest)
@@ -961,25 +1558,80 @@ declare class StoryMapBase {
961
1558
  "_el": {
962
1559
  container: HTMLElement;
963
1560
  menubar: HTMLElement;
964
- map: HTMLElement;
1561
+ map: HTMLElement | null;
965
1562
  storyslider: HTMLElement;
966
1563
  };
967
1564
  "_storyslider": StorySlider;
968
- "_map": OpenLayers;
969
- "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;
970
1574
  "_menubar": MenuBar;
971
1575
  "data": StorymapData;
972
1576
  "options": StorymapOptions;
973
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;
974
1599
  "animator_map": AnimationHandle | null;
975
1600
  "animator_storyslider": AnimationHandle | null;
976
1601
  "_autoplay_timer": ReturnType<typeof setTimeout> | null;
977
1602
  "_transition_timer": ReturnType<typeof setTimeout> | null;
978
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;
979
1616
  "_hash_initialized": boolean;
1617
+ "_collapsed": boolean;
980
1618
  /** the data source was a IIIF Presentation manifest (legacy zoomify options are ignored) */
981
1619
  "_data_from_manifest": boolean;
982
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;
983
1635
  "_resize_timer": ReturnType<typeof setTimeout> | null;
984
1636
  "fire": EventedInstance["fire"];
985
1637
  "hasEventListeners": EventedInstance["hasEventListeners"];
@@ -1000,16 +1652,44 @@ declare class StoryMapBase {
1000
1652
  _loadDataFromUrl(url: string, source: string): Promise<void>;
1001
1653
  _initOptions(): void;
1002
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;
1003
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;
1004
1671
  _loadFontCss(): Promise<void>;
1005
1672
  _onFontLoaded(font: string): void;
1006
1673
  /**
1007
- * 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.
1008
1676
  *
1009
1677
  * @param n - Zero-based slide index; the map animates to the slide's
1010
- * marker (or the overview when `n` is 0 for storymaps with one).
1678
+ * marker. The overview is selected by the slide's own
1679
+ * `type: "overview"`, not by its index.
1011
1680
  */
1012
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;
1013
1693
  /**
1014
1694
  * Announce a slide transition: `transitionstart` now (with the glide
1015
1695
  * duration both animations were started with) and `transitionend` once
@@ -1025,8 +1705,10 @@ declare class StoryMapBase {
1025
1705
  /**
1026
1706
  * Change a single map option at runtime and apply its effect immediately.
1027
1707
  *
1028
- * Runtime-changeable options: `map_type` (rebuilds the main + minimap tile
1029
- * layers, keeping the overview fitted to the marker bounds), `overlays`
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`
1030
1712
  * (rebuilds the stacked overlay layers), `show_lines`, `line_color`,
1031
1713
  * `line_color_inactive`, `line_weight`, `line_opacity`, `line_dash`,
1032
1714
  * `line_join`, `line_follows_path`, `show_history_line` (restyled
@@ -1035,31 +1717,213 @@ declare class StoryMapBase {
1035
1717
  * options only take effect on the next navigation or require re-creating
1036
1718
  * the StoryMap.
1037
1719
  */
1720
+ /**
1721
+ * Sugar over {@link setMapOptions} — `setMapOption(name, value)` is the
1722
+ * same call as `setMapOptions({ [name]: value })`.
1723
+ */
1038
1724
  setMapOption(name: string, value: unknown): void;
1039
1725
  /**
1040
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.
1041
1729
  */
1042
1730
  setOverlayVisible(index: number, visible: boolean): void;
1043
1731
  /**
1044
1732
  * Set a stacked overlay's opacity by index (see the `overlays` option).
1733
+ * Alias: `getOverlayLayer(index)?.setOpacity(opacity)`.
1045
1734
  */
1046
1735
  setOverlayOpacity(index: number, opacity: number): void;
1047
1736
  /**
1048
1737
  * Change several map options at runtime (see setMapOption).
1049
1738
  */
1050
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;
1051
1838
  _initLayout(): void;
1052
1839
  _initEvents(): void;
1053
1840
  _onKeyDownGlobal(e: KeyboardEvent): void;
1054
1841
  _updateDisplay(map_height?: number, animate?: boolean, d?: number): void;
1055
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;
1056
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
+ */
1057
1884
  _scheduleAutoplay(): void;
1058
1885
  _stopAutoplay(): void;
1059
- /** 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
+ */
1060
1905
  _syncHash(): void;
1061
- /** A #slide-N hash deep-links the storymap (applied on load + hashchange). */
1062
- _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;
1063
1927
  _initResizeHandling(): void;
1064
1928
  /**
1065
1929
  * Resolve a caller-supplied map element (options.map_options.element).
@@ -1067,6 +1931,18 @@ declare class StoryMapBase {
1067
1931
  * map container (given the vco-map class) and moved into place between
1068
1932
  * the menubar and the story slider.
1069
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;
1070
1946
  _resolveMapElement(): HTMLElement | null;
1071
1947
  _onTitle(e: unknown): void;
1072
1948
  _onColorChange(e: {
@@ -1089,7 +1965,8 @@ declare class StoryMapBase {
1089
1965
  _onFullscreenChange(): void;
1090
1966
  _onBackToStart(e?: unknown): void;
1091
1967
  _onMenuBarCollapse(e: {
1092
- y: number;
1968
+ y?: number;
1969
+ collapsed?: boolean;
1093
1970
  }): void;
1094
1971
  _onMapLoaded(): void;
1095
1972
  _onStorySliderLoaded(): void;
@@ -1098,10 +1975,24 @@ declare class StoryMapBase {
1098
1975
  * (issue #341); hidden when `show_distance` is off.
1099
1976
  */
1100
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;
1101
1992
  _onLoaded(): void;
1102
1993
  }
1103
1994
 
1104
- declare interface StorymapData {
1995
+ export declare interface StorymapData {
1105
1996
  uniqueid?: string;
1106
1997
  slides: StorymapSlide[];
1107
1998
  [key: string]: unknown;
@@ -1111,22 +2002,254 @@ export declare interface StorymapDataWrapper {
1111
2002
  storymap: StorymapData;
1112
2003
  }
1113
2004
 
1114
- 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 {
1115
2021
  path: string;
1116
2022
  message: string;
1117
2023
  }
1118
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
+
1119
2079
  declare type StoryMapListener = (e: unknown) => void;
1120
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
+
1121
2240
  /** OpenLayers passthrough options (see StorymapOptions.map_options) */
1122
- declare interface StorymapMapOptions {
2241
+ export declare interface StorymapMapOptions {
1123
2242
  /** HTMLElement or DOM id that becomes the real map container */
1124
2243
  element?: HTMLElement | string;
1125
2244
  /** Merged over the default view configuration */
1126
2245
  view?: Record<string, unknown>;
1127
2246
  /** Replaces the default (empty) controls list */
1128
2247
  controls?: unknown[];
1129
- /** 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
+ */
1130
2253
  interactions?: unknown[];
1131
2254
  /** Any other ol/Map constructor option (layers, pixelRatio, ...) */
1132
2255
  [key: string]: unknown;
@@ -1147,7 +2270,6 @@ export declare interface StorymapOptions {
1147
2270
  left: number;
1148
2271
  top: number;
1149
2272
  } | null;
1150
- less_bounce: boolean;
1151
2273
  start_at_slide: number;
1152
2274
  call_to_action: boolean;
1153
2275
  call_to_action_text: string;
@@ -1161,7 +2283,6 @@ export declare interface StorymapOptions {
1161
2283
  skinny_size: number;
1162
2284
  duration: number;
1163
2285
  ease: unknown;
1164
- dragging: boolean;
1165
2286
  trackResize: boolean;
1166
2287
  /**
1167
2288
  * Navigate slides with arrow keys anywhere on the page (default false:
@@ -1173,6 +2294,13 @@ export declare interface StorymapOptions {
1173
2294
  nocache: boolean;
1174
2295
  /** Advance slides automatically every N milliseconds; 0 disables (issue #380) */
1175
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;
1176
2304
  /** Show a progress bar in the menubar (issue #247) */
1177
2305
  show_progress: boolean;
1178
2306
  /** Show the slide headline as a label on the active map marker (issue #243) */
@@ -1185,6 +2313,15 @@ export declare interface StorymapOptions {
1185
2313
  lon: number;
1186
2314
  } | null;
1187
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;
1188
2325
  attribution: string;
1189
2326
  /**
1190
2327
  * Stacked raster overlays above the base map, below the route lines.
@@ -1194,7 +2331,6 @@ export declare interface StorymapOptions {
1194
2331
  */
1195
2332
  overlays: StorymapOverlayLayer[];
1196
2333
  map_mini: boolean;
1197
- map_subdomains: string;
1198
2334
  map_as_image: boolean;
1199
2335
  map_access_token: string;
1200
2336
  map_background_color: string;
@@ -1233,7 +2369,9 @@ export declare interface StorymapOptions {
1233
2369
  /**
1234
2370
  * Ask for permission before loading anything from external services
1235
2371
  * (media embeds, map tiles, external font CSS) — GDPR consent mode.
1236
- * 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.
1237
2375
  */
1238
2376
  consent_required: boolean;
1239
2377
  /** Slide text color override, sets --vco-color-text (issue #177) */
@@ -1243,14 +2381,13 @@ export declare interface StorymapOptions {
1243
2381
  /** Show the great-circle route distance in the menubar (issue #341) */
1244
2382
  show_distance: boolean;
1245
2383
  /**
1246
- * Raw OpenLayers map configuration. `controls` and `interactions` replace
1247
- * 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
1248
2387
  * and `element` (an HTMLElement or DOM id) replaces the auto-created map
1249
2388
  * container div.
1250
2389
  */
1251
2390
  map_options: StorymapMapOptions;
1252
- map_popup: boolean;
1253
- zoom_distance: number;
1254
2391
  calculate_zoom: boolean;
1255
2392
  line_follows_path: boolean;
1256
2393
  line_color: string;
@@ -1266,12 +2403,20 @@ export declare interface StorymapOptions {
1266
2403
  url: string;
1267
2404
  attribution: string;
1268
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
+ }[];
1269
2415
  map_height: number;
1270
2416
  storyslider_height: number;
1271
2417
  slide_padding_lr: number;
1272
2418
  slide_default_fade: string;
1273
2419
  menubar_default_y: number;
1274
- path_gfx: string;
1275
2420
  script_path: string;
1276
2421
  font_css: string;
1277
2422
  language: string;
@@ -1284,9 +2429,13 @@ export declare interface StorymapOptions {
1284
2429
  * Presentation is declarative: hosts no longer need to reach into the
1285
2430
  * layer objects for blend modes, clips or stacking tweaks.
1286
2431
  */
1287
- declare interface StorymapOverlayLayer {
1288
- /** Any `map_type` value the tile layer factory accepts */
1289
- map_type: string;
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;
1290
2439
  /** Layer opacity 0..1 (default 1) */
1291
2440
  opacity?: number;
1292
2441
  /** Initial visibility (default true) */
@@ -1305,30 +2454,61 @@ declare interface StorymapOverlayLayer {
1305
2454
  blendMode?: string;
1306
2455
  /** Clip box `[west, south, east, north]` in lon/lat (mercator maps) */
1307
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;
1308
2464
  }
1309
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
+ */
1310
2473
  export declare interface StorymapSlide {
1311
2474
  type?: string;
1312
2475
  date?: string | Record<string, unknown> | null;
1313
2476
  group?: string;
1314
- location?: StorymapSlideLocation;
1315
- media?: StorymapSlideMedia;
1316
- 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;
1317
2491
  background?: StorymapSlideBackground | string | null;
1318
- uniqueid?: string;
2492
+ uniqueid?: string | null;
1319
2493
  [key: string]: unknown;
1320
2494
  }
1321
2495
 
1322
- declare interface StorymapSlideBackground {
2496
+ export declare interface StorymapSlideBackground {
1323
2497
  url?: string | null;
1324
2498
  color?: string | null;
1325
2499
  opacity?: number;
1326
2500
  }
1327
2501
 
1328
- declare interface StorymapSlideLocation {
2502
+ export declare interface StorymapSlideLocation {
1329
2503
  lat?: number;
1330
2504
  lon?: number;
1331
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];
1332
2512
  line?: boolean;
1333
2513
  icon?: string;
1334
2514
  iconSize?: number[];
@@ -1337,21 +2517,107 @@ declare interface StorymapSlideLocation {
1337
2517
  [key: string]: unknown;
1338
2518
  }
1339
2519
 
1340
- 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 {
1341
2551
  url?: string | null;
1342
2552
  caption?: string | null;
1343
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;
1344
2560
  thumb?: string | null;
1345
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;
1346
2574
  [key: string]: unknown;
1347
2575
  }
1348
2576
 
1349
- declare interface StorymapSlideText {
2577
+ export declare interface StorymapSlideText {
1350
2578
  headline?: string;
1351
2579
  text?: string;
1352
2580
  text_align?: string;
1353
2581
  }
1354
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
+
1355
2621
  declare class StorySlider extends StorySlider_base {
1356
2622
  constructor(...args: ConstructorParameters<typeof StorySliderBase>);
1357
2623
  }
@@ -1361,7 +2627,7 @@ declare const StorySlider_base: {
1361
2627
  _vco_events?: Record<string, {
1362
2628
  action: unknown;
1363
2629
  context: unknown;
1364
- }[]>;
2630
+ }[]> | undefined;
1365
2631
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
1366
2632
  hasEventListeners(type: string): boolean;
1367
2633
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -1370,7 +2636,7 @@ declare const StorySlider_base: {
1370
2636
  } & typeof StorySliderBase;
1371
2637
 
1372
2638
  declare class StorySliderBase {
1373
- "_el": Record<string, HTMLElement>;
2639
+ "_el": StorySliderElements;
1374
2640
  "_nav": {
1375
2641
  previous: SlideNav;
1376
2642
  next: SlideNav;
@@ -1378,7 +2644,8 @@ declare class StorySliderBase {
1378
2644
  "slide_spacing": number;
1379
2645
  "_slides": Slide[];
1380
2646
  "_swipable": Swipable;
1381
- "preloadTimer": ReturnType<typeof setTimeout>;
2647
+ "preloadTimer": ReturnType<typeof setTimeout> | undefined;
2648
+ "preloadIdleHandle": number | undefined;
1382
2649
  "_message": Message;
1383
2650
  "current_slide": number;
1384
2651
  "current_bg_color": string | null;
@@ -1398,6 +2665,20 @@ declare class StorySliderBase {
1398
2665
  _createSlide(d: StorymapSlide, title_slide?: boolean): void;
1399
2666
  _addSlide(slide: Slide): void;
1400
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;
1401
2682
  goTo(n: number, fast?: boolean, displayupdate?: boolean): void;
1402
2683
  preloadSlides(): void;
1403
2684
  getNavInfo(slide: Slide): {
@@ -1426,6 +2707,20 @@ declare class StorySliderBase {
1426
2707
  _onLoaded(): void;
1427
2708
  }
1428
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
+
1429
2724
  declare interface StorySliderOptions {
1430
2725
  id?: string;
1431
2726
  layout: string;
@@ -1444,7 +2739,6 @@ declare interface StorySliderOptions {
1444
2739
  skinny_size?: number;
1445
2740
  call_to_action?: boolean;
1446
2741
  call_to_action_text?: string;
1447
- dragging?: boolean;
1448
2742
  trackResize?: boolean;
1449
2743
  [key: string]: unknown;
1450
2744
  }
@@ -1458,7 +2752,7 @@ declare const Swipable_base: {
1458
2752
  _vco_events?: Record<string, {
1459
2753
  action: unknown;
1460
2754
  context: unknown;
1461
- }[]>;
2755
+ }[]> | undefined;
1462
2756
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
1463
2757
  hasEventListeners(type: string): boolean;
1464
2758
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -1478,10 +2772,18 @@ declare class SwipableBase {
1478
2772
  constructor(drag_elem: HTMLElement, move_elem?: HTMLElement, options?: Record<string, unknown>);
1479
2773
  enable(e?: LegacyEvent): void;
1480
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;
1481
2781
  stopMomentum(): void;
1482
2782
  updateConstraint(c: SwipableOptions["constraint"]): void;
1483
2783
  _onDragStart(e: LegacyEvent): void;
1484
2784
  _onDragEnd(e: LegacyEvent): void;
2785
+ _attachGestureListeners(): void;
2786
+ _detachGestureListeners(): void;
1485
2787
  _onDragMove(e: LegacyEvent): void;
1486
2788
  _momentum(): void;
1487
2789
  _animateMomentum(): void;
@@ -1513,7 +2815,7 @@ declare const Text_base: {
1513
2815
  _vco_events?: Record<string, {
1514
2816
  action: unknown;
1515
2817
  context: unknown;
1516
- }[]>;
2818
+ }[]> | undefined;
1517
2819
  on(type: string, fn: unknown, context?: unknown): /*elided*/ any;
1518
2820
  hasEventListeners(type: string): boolean;
1519
2821
  off(type: string, fn: unknown, context?: unknown): /*elided*/ any;
@@ -1555,6 +2857,21 @@ declare interface TextOptions {
1555
2857
  text_align?: string;
1556
2858
  }
1557
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
+
1558
2875
  /** Validate storymap JSON (the object containing a "storymap" property). */
1559
2876
  export declare function validateStorymap(data: unknown): StorymapError[];
1560
2877
 
@@ -1583,4 +2900,12 @@ declare global {
1583
2900
  const SC: {
1584
2901
  Widget: (el: HTMLElement) => { pause(): void };
1585
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;
1586
2911
  }