@projektemacher/storymapjs 0.10.7 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG +431 -19
- package/README.md +168 -17
- package/dist/assets/demo-bWnOyfUw.js +1 -0
- package/dist/assets/harness-C3JUv5Ii.js +1 -0
- package/dist/assets/harness-multi-XZNex3tb.js +1 -0
- package/dist/assets/harness-support-CjfZIVeb.js +1 -0
- package/dist/assets/index-wHPqGrBS.js +1 -0
- package/dist/assets/main-DQ32hWBM.js +17 -0
- package/dist/context.json +23 -9
- package/dist/css/fonts/files/amatic-sc-cyrillic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/amatic-sc-cyrillic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/amatic-sc-hebrew-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/amatic-sc-hebrew-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/amatic-sc-vietnamese-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/amatic-sc-vietnamese-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-100-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-100-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-200-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-200-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-300-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-500-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-600-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-600-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-800-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-800-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-900-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-900-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-100-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-100-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-200-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-200-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-300-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-500-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-600-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-600-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-800-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-800-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-900-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-900-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-100-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-100-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-200-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-200-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-300-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-500-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-600-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-600-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-800-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-800-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-900-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-900-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-arabic-200-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-arabic-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-arabic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-arabic-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-arabic-600-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-arabic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-arabic-800-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-arabic-900-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-200-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-600-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-800-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-900-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-ext-200-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-ext-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-ext-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-ext-600-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-ext-800-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-ext-900-normal.woff2 +0 -0
- package/dist/css/fonts/files/dancing-script-vietnamese-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-cyrillic-ext-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-cyrillic-ext-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-cyrillic-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-cyrillic-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-greek-ext-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-greek-ext-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-greek-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-greek-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-vietnamese-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-vietnamese-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-cyrillic-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-cyrillic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-cyrillic-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-cyrillic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-cyrillic-ext-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-cyrillic-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-cyrillic-ext-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-cyrillic-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-greek-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-greek-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-greek-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-greek-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-greek-ext-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-greek-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-greek-ext-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-greek-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-vietnamese-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-vietnamese-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-vietnamese-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-vietnamese-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/old-standard-tt-cyrillic-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/old-standard-tt-cyrillic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/old-standard-tt-cyrillic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/old-standard-tt-cyrillic-ext-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/old-standard-tt-cyrillic-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/old-standard-tt-cyrillic-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/old-standard-tt-vietnamese-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/old-standard-tt-vietnamese-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/old-standard-tt-vietnamese-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-cyrillic-ext-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-cyrillic-ext-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-cyrillic-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-cyrillic-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-greek-ext-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-greek-ext-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-greek-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-greek-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-hebrew-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-hebrew-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-vietnamese-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-vietnamese-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-cyrillic-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-cyrillic-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-cyrillic-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-cyrillic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-cyrillic-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-cyrillic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-cyrillic-900-italic.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-cyrillic-900-normal.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-vietnamese-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-vietnamese-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-vietnamese-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-vietnamese-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-vietnamese-900-italic.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-vietnamese-900-normal.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-vietnamese-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-vietnamese-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-cyrillic-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-cyrillic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-cyrillic-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-cyrillic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-cyrillic-ext-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-cyrillic-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-cyrillic-ext-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-cyrillic-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-narrow-cyrillic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-narrow-cyrillic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-narrow-cyrillic-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-narrow-cyrillic-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-serif-cyrillic-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/pt-serif-cyrillic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-serif-cyrillic-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/pt-serif-cyrillic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-serif-cyrillic-ext-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/pt-serif-cyrillic-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-serif-cyrillic-ext-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/pt-serif-cyrillic-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/raleway-cyrillic-ext-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/raleway-cyrillic-ext-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/raleway-cyrillic-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/raleway-cyrillic-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/raleway-vietnamese-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/raleway-vietnamese-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/roboto-slab-cyrillic-ext-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/roboto-slab-cyrillic-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/roboto-slab-greek-ext-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/roboto-slab-greek-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/roboto-slab-vietnamese-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-300-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-500-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-ext-300-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-ext-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-ext-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-ext-500-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-ext-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-ext-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-300-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-500-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-ext-300-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-ext-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-ext-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-ext-500-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-ext-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-ext-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/unica-one-vietnamese-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/vollkorn-cyrillic-ext-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/vollkorn-cyrillic-ext-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/vollkorn-cyrillic-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/vollkorn-cyrillic-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/vollkorn-greek-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/vollkorn-greek-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/vollkorn-vietnamese-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/vollkorn-vietnamese-wght-normal.woff2 +0 -0
- package/dist/css/fonts/font.abril-droidsans.css +3 -0
- package/dist/css/fonts/font.amatic-andika.css +57 -0
- package/dist/css/fonts/font.bitter-raleway.css +111 -0
- package/dist/css/fonts/font.cairo.css +312 -0
- package/dist/css/fonts/font.clicker-garamond.css +93 -0
- package/dist/css/fonts/font.dancing-ledger.css +12 -0
- package/dist/css/fonts/font.default.css +183 -0
- package/dist/css/fonts/font.fjalla-average.css +3 -0
- package/dist/css/fonts/font.georgia-helvetica.css +3 -0
- package/dist/css/fonts/font.knightlab.css +642 -0
- package/dist/css/fonts/font.lustria-lato.css +3 -0
- package/dist/css/fonts/font.medula-lato.css +3 -0
- package/dist/css/fonts/font.oldstandard.css +84 -0
- package/dist/css/fonts/font.opensans-gentiumbook.css +183 -0
- package/dist/css/fonts/font.playfair-faunaone.css +39 -0
- package/dist/css/fonts/font.playfair.css +147 -0
- package/dist/css/fonts/font.pt.css +183 -0
- package/dist/css/fonts/font.roboto-megrim.css +3 -0
- package/dist/css/fonts/font.rufina-sintony.css +3 -0
- package/dist/css/fonts/font.ubuntu.css +291 -0
- package/dist/css/fonts/font.unicaone-vollkorn.css +84 -0
- package/dist/css/storymap.css +1 -1
- package/dist/demo.html +3 -2
- package/dist/docs/api/.nojekyll +1 -0
- package/dist/docs/api/assets/custom.css +47 -0
- package/dist/docs/api/assets/hierarchy.js +1 -0
- package/dist/docs/api/assets/highlight.css +57 -0
- package/dist/docs/api/assets/icons.js +18 -0
- package/dist/docs/api/assets/icons.svg +1 -0
- package/dist/docs/api/assets/main.js +60 -0
- package/dist/docs/api/assets/navigation.js +1 -0
- package/dist/docs/api/assets/search.js +1 -0
- package/dist/docs/api/assets/style.css +1648 -0
- package/dist/docs/api/classes/StoryMap.html +2112 -0
- package/dist/docs/api/functions/MediaType.html +51 -0
- package/dist/docs/api/functions/isPresentation3Collection.html +47 -0
- package/dist/docs/api/functions/isPresentation3Manifest.html +53 -0
- package/dist/docs/api/functions/isSlideshowCollection.html +51 -0
- package/dist/docs/api/functions/loadCSS.html +63 -0
- package/dist/docs/api/functions/manifestToStorymapData.html +49 -0
- package/dist/docs/api/functions/setLanguage.html +54 -0
- package/dist/docs/api/functions/slideshowToStorymapData.html +51 -0
- package/dist/docs/api/functions/slideshowVersion.html +48 -0
- package/dist/docs/api/functions/storymapToManifest.html +57 -0
- package/dist/docs/api/functions/validateStorymap.html +53 -0
- package/dist/docs/api/functions/validateStorymapAndReport.html +54 -0
- package/dist/docs/api/hierarchy.html +28 -0
- package/dist/docs/api/index.html +300 -0
- package/dist/docs/api/interfaces/AnimationHandle.html +60 -0
- package/dist/docs/api/interfaces/ImagereadyPayload.html +71 -0
- package/dist/docs/api/interfaces/LanguageEntry.html +102 -0
- package/dist/docs/api/interfaces/LatLngLiteral.html +73 -0
- package/dist/docs/api/interfaces/LoadOptions.html +59 -0
- package/dist/docs/api/interfaces/MapEvents.html +116 -0
- package/dist/docs/api/interfaces/MapMarkerEvents.html +66 -0
- package/dist/docs/api/interfaces/MarkerEventPayload.html +57 -0
- package/dist/docs/api/interfaces/MediaEvents.html +78 -0
- package/dist/docs/api/interfaces/MenuBarEvents.html +114 -0
- package/dist/docs/api/interfaces/MessageEvents.html +72 -0
- package/dist/docs/api/interfaces/OlLayer.html +1400 -0
- package/dist/docs/api/interfaces/OlMap.html +1656 -0
- package/dist/docs/api/interfaces/OlProjection.html +332 -0
- package/dist/docs/api/interfaces/OlSource.html +784 -0
- package/dist/docs/api/interfaces/OlTileLayer.html +1497 -0
- package/dist/docs/api/interfaces/OlVectorLayer.html +1559 -0
- package/dist/docs/api/interfaces/OlView.html +1958 -0
- package/dist/docs/api/interfaces/SlideBackgroundState.html +66 -0
- package/dist/docs/api/interfaces/SlideEvents.html +78 -0
- package/dist/docs/api/interfaces/SlideNavEvents.html +72 -0
- package/dist/docs/api/interfaces/SlideshowPlayerSettings.html +182 -0
- package/dist/docs/api/interfaces/SlideshowToStorymapResult.html +60 -0
- package/dist/docs/api/interfaces/SlideshowTranslatorOptions.html +65 -0
- package/dist/docs/api/interfaces/SlideshowWarning.html +72 -0
- package/dist/docs/api/interfaces/StoryMapEvents.html +146 -0
- package/dist/docs/api/interfaces/StoryMapMarker.html +763 -0
- package/dist/docs/api/interfaces/StorySliderEvents.html +102 -0
- package/dist/docs/api/interfaces/StorymapBasemap.html +69 -0
- package/dist/docs/api/interfaces/StorymapData.html +77 -0
- package/dist/docs/api/interfaces/StorymapDataWrapper.html +60 -0
- package/dist/docs/api/interfaces/StorymapDocument.html +68 -0
- package/dist/docs/api/interfaces/StorymapError.html +63 -0
- package/dist/docs/api/interfaces/StorymapGeoreference.html +93 -0
- package/dist/docs/api/interfaces/StorymapGeoreferenceBody.html +74 -0
- package/dist/docs/api/interfaces/StorymapGroundControlPoint.html +69 -0
- package/dist/docs/api/interfaces/StorymapLanguageMap.html +57 -0
- package/dist/docs/api/interfaces/StorymapManifest.html +118 -0
- package/dist/docs/api/interfaces/StorymapManifestAnnotation.html +137 -0
- package/dist/docs/api/interfaces/StorymapManifestBackground.html +81 -0
- package/dist/docs/api/interfaces/StorymapManifestCanvas.html +188 -0
- package/dist/docs/api/interfaces/StorymapManifestContentResource.html +97 -0
- package/dist/docs/api/interfaces/StorymapManifestFeatureCollection.html +82 -0
- package/dist/docs/api/interfaces/StorymapManifestGeoreferencing.html +87 -0
- package/dist/docs/api/interfaces/StorymapManifestImageService.html +69 -0
- package/dist/docs/api/interfaces/StorymapManifestRange.html +75 -0
- package/dist/docs/api/interfaces/StorymapManifestService.html +77 -0
- package/dist/docs/api/interfaces/StorymapManifestSpecificResource.html +69 -0
- package/dist/docs/api/interfaces/StorymapManifestStatement.html +63 -0
- package/dist/docs/api/interfaces/StorymapMapOptions.html +92 -0
- package/dist/docs/api/interfaces/StorymapOptions.html +734 -0
- package/dist/docs/api/interfaces/StorymapOverlayLayer.html +157 -0
- package/dist/docs/api/interfaces/StorymapSlide.html +186 -0
- package/dist/docs/api/interfaces/StorymapSlideBackground.html +72 -0
- package/dist/docs/api/interfaces/StorymapSlideLocation.html +161 -0
- package/dist/docs/api/interfaces/StorymapSlideMarker.html +103 -0
- package/dist/docs/api/interfaces/StorymapSlideMedia.html +149 -0
- package/dist/docs/api/interfaces/StorymapSlideNarration.html +117 -0
- package/dist/docs/api/interfaces/StorymapSlideText.html +72 -0
- package/dist/docs/api/interfaces/StorymapTilejson.html +105 -0
- package/dist/docs/api/interfaces/SwipableEvents.html +102 -0
- package/dist/docs/api/interfaces/TextEvents.html +66 -0
- package/dist/docs/api/media/es.json +31 -0
- package/dist/docs/api/media/events.md +66 -0
- package/dist/docs/api/media/migration-from-knightlab.md +399 -0
- package/dist/docs/api/media/slideshow.md +109 -0
- package/dist/docs/api/media/storymap-as-iiif-manifest.md +1007 -0
- package/dist/docs/api/modules.html +50 -0
- package/dist/docs/api/types/ContentState.html +70 -0
- package/dist/docs/api/types/FiredEvent.html +43 -0
- package/dist/docs/api/types/ImagereadyKind.html +34 -0
- package/dist/docs/api/types/MediaTypeMatch.html +78 -0
- package/dist/docs/api/types/SwipeDirection.html +36 -0
- package/dist/docs/api/types/TileSourceFactory.html +53 -0
- package/dist/docs/authoring.html +306 -0
- package/dist/docs/events.html +263 -0
- package/dist/docs/iiif.html +738 -69
- package/dist/docs/migration.html +360 -11
- package/dist/docs/readme.html +149 -17
- package/dist/embed/index.html +8 -1
- package/dist/examples/font-css-false.json +33 -0
- package/dist/examples/issue-242-nonlatin.json +55 -0
- package/dist/examples/issue-305-start-at-slide-data.json +96 -0
- package/dist/examples/issue-358-iframe.json +57 -0
- package/dist/examples/issue-iiif-geo.json +32 -0
- package/dist/examples/issue-image-alt.json +23 -0
- package/dist/examples/issue-image-region.json +42 -0
- package/dist/examples/issue-image-srcset.json +24 -0
- package/dist/examples/layers-control.json +60 -0
- package/dist/examples/map-area-overlays.json +68 -0
- package/dist/examples/map-template-provider.json +36 -0
- package/dist/examples/multi-media.json +71 -0
- package/dist/examples/no-map.json +44 -0
- package/dist/examples-iiif/annotated-image.json +204 -0
- package/dist/examples-iiif/bob-boilen.json +11 -5
- package/dist/examples-iiif/courbet.json +9 -6
- package/dist/examples-iiif/empty.json +8 -4
- package/dist/examples-iiif/flickr-drewvigal.json +248 -24
- package/dist/examples-iiif/flickr-zach.wise.json +8 -4
- package/dist/examples-iiif/font-css-false.json +114 -0
- package/dist/examples-iiif/georeferenced-layer-unsupported.json +153 -0
- package/dist/examples-iiif/georeferenced-layer.json +318 -0
- package/dist/examples-iiif/iiif-wellcome.json +9 -6
- package/dist/examples-iiif/instagram-chenpamela.json +381 -36
- package/dist/examples-iiif/instagram_brentfoster.json +429 -40
- package/dist/examples-iiif/instagram_couch.json +261 -26
- package/dist/examples-iiif/instagram_joegermuska.json +441 -41
- package/dist/examples-iiif/instagram_matteich.json +261 -26
- package/dist/examples-iiif/instagram_mirandamulligan.json +261 -26
- package/dist/examples-iiif/instagram_raymondmccrea.json +261 -26
- package/dist/examples-iiif/instagram_test.json +261 -26
- package/dist/examples-iiif/issue-134-no-lines.json +9 -5
- package/dist/examples-iiif/issue-177-color-vars.json +9 -5
- package/dist/examples-iiif/issue-211-rtl.json +9 -5
- package/dist/examples-iiif/issue-242-nonlatin.json +239 -0
- package/dist/examples-iiif/issue-272-facebook.json +9 -5
- package/dist/examples-iiif/issue-305-start-at-slide-data.json +305 -0
- package/dist/examples-iiif/issue-305-start-at-slide.json +9 -5
- package/dist/examples-iiif/issue-341-distance.json +9 -5
- package/dist/examples-iiif/issue-358-iframe.json +190 -0
- package/dist/examples-iiif/issue-360-juxtapose.json +22 -7
- package/dist/examples-iiif/issue-368-null-fields.json +9 -5
- package/dist/examples-iiif/issue-375-code-lists.json +9 -5
- package/dist/examples-iiif/issue-381-dateline.json +9 -5
- package/dist/examples-iiif/issue-405-custom-icon.json +203 -0
- package/dist/examples-iiif/issue-425-many-slides.json +9 -5
- package/dist/examples-iiif/issue-428-background.json +20 -8
- package/dist/examples-iiif/issue-435-googlemaps.json +9 -5
- package/dist/examples-iiif/issue-437-documentcloud.json +22 -7
- package/dist/examples-iiif/issue-451-webp.json +9 -5
- package/dist/examples-iiif/issue-455-audio.json +9 -5
- package/dist/examples-iiif/issue-480-shorts.json +9 -5
- package/dist/examples-iiif/issue-506-marker-sync.json +9 -5
- package/dist/examples-iiif/issue-iiif-geo.json +200 -0
- package/dist/examples-iiif/issue-image-alt.json +90 -0
- package/dist/examples-iiif/issue-image-region.json +203 -0
- package/dist/examples-iiif/issue-image-srcset.json +87 -0
- package/dist/examples-iiif/jansteen.json +9 -6
- package/dist/examples-iiif/katrina.json +197 -41
- package/dist/examples-iiif/layers-control.json +226 -0
- package/dist/examples-iiif/map-area-overlays.json +289 -0
- package/dist/examples-iiif/map-template-provider.json +133 -0
- package/dist/examples-iiif/marktwain.json +255 -58
- package/dist/examples-iiif/multi-media.json +237 -0
- package/dist/examples-iiif/no-map.json +148 -0
- package/dist/examples-iiif/population.json +440 -76
- package/dist/examples-iiif/president.json +456 -83
- package/dist/examples-iiif/scroll-hint.json +190 -0
- package/dist/examples-iiif/seurat.json +113 -22
- package/dist/examples-iiif/zoomify-clamp.json +153 -0
- package/dist/examples-slideshow/single.json +79 -0
- package/dist/examples-slideshow/static/pixel.png +0 -0
- package/dist/examples-slideshow/static.json +44 -0
- package/dist/harness-multi.html +17 -0
- package/dist/harness.html +4 -2
- package/dist/index.html +19 -12
- package/dist/js/storymap.d.ts +2669 -307
- package/dist/js/storymap.js +10820 -6196
- package/dist/js/storymap.js.map +1 -1
- package/dist/navplace-properties.json +54 -0
- package/dist/site.css +54 -36
- package/docs/migration-from-knightlab.md +279 -19
- package/docs/storymap-as-iiif-manifest.md +633 -136
- package/package.json +12 -7
- package/schema/storymap.schema.json +733 -80
- package/src/animation/easings.ts +8 -1
- package/src/animation/tween.ts +186 -0
- package/src/core/Browser.ts +6 -5
- package/src/core/Load.ts +54 -2
- package/src/core/Util.ts +257 -193
- package/src/core/mixins.ts +66 -35
- package/src/core/viewers.ts +94 -0
- package/src/dom/DomEvent.ts +27 -8
- package/src/globals.d.ts +8 -0
- package/src/language/Language.ts +206 -25
- package/src/language/locale/.expected-gaps.json +346 -0
- package/src/language/locale/be.json +15 -2
- package/src/language/locale/bg.json +15 -2
- package/src/language/locale/cs.json +15 -2
- package/src/language/locale/de.json +23 -2
- package/src/language/locale/el.json +15 -2
- package/src/language/locale/en.json +17 -3
- package/src/language/locale/es.json +15 -2
- package/src/language/locale/et.json +5 -1
- package/src/language/locale/fr.json +15 -2
- package/src/language/locale/he.json +16 -3
- package/src/language/locale/hu.json +15 -2
- package/src/language/locale/is.json +5 -1
- package/src/language/locale/it.json +15 -2
- package/src/language/locale/jp.json +15 -2
- package/src/language/locale/ko.json +15 -2
- package/src/language/locale/nl.json +15 -2
- package/src/language/locale/nn.json +5 -1
- package/src/language/locale/no.json +15 -2
- package/src/language/locale/pl.json +15 -2
- package/src/language/locale/pt.json +15 -2
- package/src/language/locale/ru.json +15 -2
- package/src/language/locale/sk.json +15 -2
- package/src/language/locale/sr.json +5 -1
- package/src/language/locale/sv.json +15 -2
- package/src/language/locale/tr.json +15 -2
- package/src/language/locale/uk.json +15 -2
- package/src/language/locale/ur.json +5 -1
- package/src/language/locale/zh-cn.json +15 -2
- package/src/language/locale/zh-tw.json +15 -2
- package/src/main.ts +143 -0
- package/src/map/Map.ts +227 -112
- package/src/map/MapMarker.ts +44 -8
- package/src/map/georeference.ts +325 -0
- package/src/map/openlayers/Map.OpenLayers.ts +1601 -263
- package/src/map/openlayers/MapMarker.OpenLayers.ts +348 -24
- package/src/map/openlayers/zoomifyTiles.ts +1 -4
- package/src/map/slideView.ts +149 -0
- package/src/map/types.ts +2 -0
- package/src/media/EmbedUtil.ts +333 -24
- package/src/media/Media.ts +270 -59
- package/src/media/embedId.ts +110 -0
- package/src/media/types/Audio.ts +9 -82
- package/src/media/types/Blockquote.ts +2 -3
- package/src/media/types/DailyMotion.ts +5 -10
- package/src/media/types/DocumentCloud.ts +6 -35
- package/src/media/types/Facebook.ts +3 -4
- package/src/media/types/Flickr.ts +23 -12
- package/src/media/types/GoogleDoc.ts +3 -4
- package/src/media/types/HtmlMedia.ts +233 -0
- package/src/media/types/IFrame.ts +3 -4
- package/src/media/types/Image.ts +87 -9
- package/src/media/types/Juxtapose.ts +14 -5
- package/src/media/types/SoundCloud.ts +28 -6
- package/src/media/types/Text.ts +46 -21
- package/src/media/types/Twitter.ts +35 -20
- package/src/media/types/Video.ts +9 -79
- package/src/media/types/Vimeo.ts +11 -11
- package/src/media/types/Website.ts +23 -13
- package/src/media/types/Wikipedia.ts +18 -8
- package/src/media/types/YouTube.ts +72 -40
- package/src/scss/Typography.scss +16 -18
- package/src/scss/VCO.StoryMap.scss +208 -12
- package/src/scss/Variables.scss +3 -2
- package/src/scss/core/Mixins.scss +5 -63
- package/src/scss/core/Reset.scss +5 -18
- package/src/scss/fonts/font.amatic-andika.scss +3 -0
- package/src/scss/fonts/font.bitter-raleway.scss +6 -0
- package/src/scss/fonts/font.cairo.scss +79 -0
- package/src/scss/fonts/font.clicker-garamond.scss +5 -0
- package/src/scss/fonts/font.dancing-ledger.scss +1 -0
- package/src/scss/fonts/font.knightlab.scss +14 -0
- package/src/scss/fonts/font.oldstandard.scss +6 -0
- package/src/scss/fonts/font.opensans-gentiumbook.scss +5 -0
- package/src/scss/fonts/font.playfair-faunaone.scss +2 -0
- package/src/scss/fonts/font.playfair.scss +4 -0
- package/src/scss/fonts/font.pt.scss +6 -0
- package/src/scss/fonts/font.ubuntu.scss +4 -0
- package/src/scss/fonts/font.unicaone-vollkorn.scss +5 -0
- package/src/scss/map/VCO.Map.scss +1 -1
- package/src/scss/map/VCO.MapMarker.scss +114 -8
- package/src/scss/map/openlayers/VCO.Map.OpenLayers.scss +7 -4
- package/src/scss/media/VCO.Media.scss +14 -17
- package/src/scss/media/types/VCO.Media.Blockquote.scss +1 -1
- package/src/scss/media/types/VCO.Media.Text.scss +13 -5
- package/src/scss/media/types/VCO.Media.Twitter.scss +4 -4
- package/src/scss/media/types/VCO.Media.Wikipedia.scss +3 -19
- package/src/scss/site/site.scss +55 -36
- package/src/scss/slider/VCO.Slide.scss +61 -13
- package/src/scss/slider/VCO.SlideNav.scss +34 -24
- package/src/scss/slider/VCO.StorySlider.scss +53 -1
- package/src/scss/snapmap/VCO.SnapMap.scss +3 -3
- package/src/scss/ui/VCO.Consent.scss +63 -13
- package/src/scss/ui/VCO.Layers.scss +119 -0
- package/src/scss/ui/VCO.MenuBar.Button.scss +143 -14
- package/src/scss/ui/VCO.MenuBar.scss +9 -2
- package/src/scss/ui/VCO.Message.scss +16 -5
- package/src/site/site.ts +2 -1
- package/src/slider/Slide.ts +326 -74
- package/src/slider/SlideNav.ts +54 -9
- package/src/slider/StorySlider.ts +352 -60
- package/src/storymap/Consent.ts +429 -82
- package/src/storymap/StoryMap.ts +2163 -340
- package/src/storymap/content-state.ts +180 -0
- package/src/storymap/font-css.ts +72 -0
- package/src/storymap/from-slideshow.ts +785 -0
- package/src/storymap/iiif-shared.ts +228 -0
- package/src/storymap/iiif.ts +1742 -95
- package/src/storymap/to-iiif.ts +1008 -0
- package/src/storymap/validate.ts +80 -7
- package/src/types.ts +591 -29
- package/src/ui/LayersControl.ts +302 -0
- package/src/ui/MenuBar.ts +325 -61
- package/src/ui/Message.ts +44 -2
- package/src/ui/Swipable.ts +170 -85
- package/dist/assets/demo-D6cTmzn6.js +0 -1
- package/dist/assets/harness-BPFlzutp.js +0 -1
- package/dist/assets/index-DDsPBPZA.js +0 -1
- package/dist/assets/main-Y-MYUSJ4.js +0 -17
- package/src/animation/morpheus.d.ts +0 -41
- package/src/scss/VCO.StoryMap.Dark.scss +0 -138
- package/src/scss/Variables.Dark.scss +0 -56
- package/src/scss/media/types/VCO.Media.Instagram.scss +0 -7
- package/src/scss/media/types/VCO.Media.Profile.scss +0 -5
- package/src/ui/Draggable.ts +0 -374
package/src/core/mixins.ts
CHANGED
|
@@ -8,17 +8,42 @@
|
|
|
8
8
|
/** Constructor shape accepted by the mixin functions. */
|
|
9
9
|
export type Constructor<T = object> = new (...args: any[]) => T;
|
|
10
10
|
|
|
11
|
+
/** What a listener receives: the payload, plus the framework's own fields.
|
|
12
|
+
*
|
|
13
|
+
* Kept as an intersection because `fire` merges them into one object — that
|
|
14
|
+
* is what a handler gets. As a side effect it also fixes the `type`
|
|
15
|
+
* clobbering at the type level: intersecting `type: "loaded"` with
|
|
16
|
+
* `type?: string` yields `"loaded"`.
|
|
17
|
+
*/
|
|
18
|
+
export type FiredEvent<M, K extends keyof M & string> = M[K] & { type: K; target: unknown };
|
|
19
|
+
|
|
11
20
|
/** Eventing members provided by the Evented mixin. */
|
|
12
|
-
export interface EventedInstance {
|
|
13
|
-
on
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
21
|
+
export interface EventedInstance<M = Record<string, unknown>> {
|
|
22
|
+
on<K extends keyof M & string>(
|
|
23
|
+
type: K,
|
|
24
|
+
fn: (e: FiredEvent<M, K>) => void,
|
|
25
|
+
context?: unknown,
|
|
26
|
+
): this;
|
|
27
|
+
off<K extends keyof M & string>(
|
|
28
|
+
type: K,
|
|
29
|
+
fn: (e: FiredEvent<M, K>) => void,
|
|
30
|
+
context?: unknown,
|
|
31
|
+
): this;
|
|
32
|
+
fire<K extends keyof M & string>(type: K, data?: M[K]): this;
|
|
33
|
+
hasEventListeners<K extends keyof M & string>(type: K): boolean;
|
|
17
34
|
}
|
|
18
35
|
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Instance contract for DomMixed consumers.
|
|
38
|
+
*
|
|
39
|
+
* `_el` is deliberately `Record<string, unknown>`: each class declares its
|
|
40
|
+
* own element shape, and several of them hold members that are legitimately
|
|
41
|
+
* null before the component builds them (a slide's call-to-action, a
|
|
42
|
+
* slider's live region). Requiring `Record<string, HTMLElement>` here would
|
|
43
|
+
* force every one of those back into an `{} as HTMLElement` placeholder.
|
|
44
|
+
*/
|
|
45
|
+
export interface DomMixedInstance<M = Record<string, unknown>> extends EventedInstance<M> {
|
|
46
|
+
_el: Record<string, unknown>;
|
|
22
47
|
data?: unknown;
|
|
23
48
|
}
|
|
24
49
|
|
|
@@ -28,7 +53,7 @@ export interface DomMixedInstance extends EventedInstance {
|
|
|
28
53
|
================================================== */
|
|
29
54
|
|
|
30
55
|
/** Adds eventing (on/off/fire/hasEventListeners) to a class. */
|
|
31
|
-
export function Evented<T extends Constructor>(Base: T) {
|
|
56
|
+
export function Evented<M, T extends Constructor>(Base: T) {
|
|
32
57
|
return class extends Base {
|
|
33
58
|
declare "_vco_events"?: Record<string, { action: unknown; context: unknown }[]>;
|
|
34
59
|
|
|
@@ -62,31 +87,25 @@ export function Evented<T extends Constructor>(Base: T) {
|
|
|
62
87
|
string,
|
|
63
88
|
{ action: unknown; context: unknown }[]
|
|
64
89
|
>;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return this;
|
|
72
|
-
}
|
|
90
|
+
events[type] = events[type].filter(
|
|
91
|
+
(listener) =>
|
|
92
|
+
!(listener.action === fn && (!context || listener.context === context)),
|
|
93
|
+
);
|
|
94
|
+
if (events[type].length === 0) {
|
|
95
|
+
delete events[type];
|
|
73
96
|
}
|
|
74
97
|
return this;
|
|
75
98
|
}
|
|
76
99
|
|
|
77
|
-
fire(
|
|
78
|
-
/*String*/ type: string,
|
|
79
|
-
/*(optional) Object*/ data?: unknown,
|
|
80
|
-
target?: unknown,
|
|
81
|
-
): this {
|
|
100
|
+
fire(/*String*/ type: string, /*(optional) Object*/ data?: unknown): this {
|
|
82
101
|
if (!this.hasEventListeners(type)) {
|
|
83
102
|
return this;
|
|
84
103
|
}
|
|
85
104
|
|
|
86
105
|
const event = {
|
|
87
|
-
type: type,
|
|
88
|
-
target: target || this,
|
|
89
106
|
...(data as Record<string, unknown> | undefined),
|
|
107
|
+
type,
|
|
108
|
+
target: this,
|
|
90
109
|
};
|
|
91
110
|
|
|
92
111
|
const listeners = (
|
|
@@ -103,7 +122,7 @@ export function Evented<T extends Constructor>(Base: T) {
|
|
|
103
122
|
constructor(...args: any[]) {
|
|
104
123
|
super(...args);
|
|
105
124
|
}
|
|
106
|
-
};
|
|
125
|
+
} as Constructor<EventedInstance<M>> & T;
|
|
107
126
|
}
|
|
108
127
|
|
|
109
128
|
/* DomMixed
|
|
@@ -113,29 +132,41 @@ export function Evented<T extends Constructor>(Base: T) {
|
|
|
113
132
|
|
|
114
133
|
/** Adds DOM container conveniences (addTo/removeFrom/setPosition/show/hide
|
|
115
134
|
* and the onAdd/onRemove/onLoaded lifecycle events) to a class. */
|
|
116
|
-
export function DomMixed<
|
|
135
|
+
export function DomMixed<
|
|
136
|
+
M extends { loaded: unknown; added: unknown; removed: unknown },
|
|
137
|
+
T extends Constructor<DomMixedInstance<M>>,
|
|
138
|
+
>(Base: T) {
|
|
117
139
|
return class extends Base {
|
|
140
|
+
/**
|
|
141
|
+
* The host element. Every DomMixed consumer keeps its root element
|
|
142
|
+
* here, so this narrows the `Record<string, unknown>` element map to
|
|
143
|
+
* something with a style and children.
|
|
144
|
+
*/
|
|
145
|
+
container(): HTMLElement {
|
|
146
|
+
return this._el.container as HTMLElement;
|
|
147
|
+
}
|
|
148
|
+
|
|
118
149
|
/* Adding, Hiding, Showing etc
|
|
119
150
|
================================================== */
|
|
120
151
|
show(animate?: unknown): void {
|
|
121
152
|
if (!animate) {
|
|
122
|
-
this.
|
|
153
|
+
this.container().style.display = "block";
|
|
123
154
|
}
|
|
124
155
|
// animated show is not implemented
|
|
125
156
|
}
|
|
126
157
|
|
|
127
158
|
hide(): void {
|
|
128
|
-
this.
|
|
159
|
+
this.container().style.display = "none";
|
|
129
160
|
}
|
|
130
161
|
|
|
131
162
|
addTo(container: HTMLElement): this {
|
|
132
|
-
container.appendChild(this.
|
|
163
|
+
container.appendChild(this.container());
|
|
133
164
|
this.onAdd();
|
|
134
165
|
return this;
|
|
135
166
|
}
|
|
136
167
|
|
|
137
168
|
removeFrom(container: HTMLElement): this {
|
|
138
|
-
container.removeChild(this.
|
|
169
|
+
container.removeChild(this.container());
|
|
139
170
|
this.onRemove();
|
|
140
171
|
return this;
|
|
141
172
|
}
|
|
@@ -143,7 +174,7 @@ export function DomMixed<T extends Constructor<DomMixedInstance>>(Base: T) {
|
|
|
143
174
|
/* Set the Position
|
|
144
175
|
================================================== */
|
|
145
176
|
setPosition(pos: Record<string, number>, el?: HTMLElement): this {
|
|
146
|
-
const target = el || this.
|
|
177
|
+
const target = el || this.container();
|
|
147
178
|
for (const name of Object.keys(pos)) {
|
|
148
179
|
(target.style as unknown as Record<string, string>)[name] = pos[name] + "px";
|
|
149
180
|
}
|
|
@@ -151,17 +182,17 @@ export function DomMixed<T extends Constructor<DomMixedInstance>>(Base: T) {
|
|
|
151
182
|
}
|
|
152
183
|
|
|
153
184
|
/* Lifecycle events
|
|
154
|
-
|
|
185
|
+
================================================== */
|
|
155
186
|
onLoaded(): void {
|
|
156
|
-
this.fire("loaded", this.data);
|
|
187
|
+
this.fire("loaded", this.data as M["loaded"]);
|
|
157
188
|
}
|
|
158
189
|
|
|
159
190
|
onAdd(): void {
|
|
160
|
-
this.fire("added", this.data);
|
|
191
|
+
this.fire("added", this.data as M["added"]);
|
|
161
192
|
}
|
|
162
193
|
|
|
163
194
|
onRemove(): void {
|
|
164
|
-
this.fire("removed", this.data);
|
|
195
|
+
this.fire("removed", this.data as M["removed"]);
|
|
165
196
|
}
|
|
166
197
|
|
|
167
198
|
constructor(...args: any[]) {
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A minimal registry of the viewers alive on this page.
|
|
3
|
+
*
|
|
4
|
+
* This is deliberately *not* a viewer singleton: nothing here owns or replaces
|
|
5
|
+
* a viewer, and the viewer itself holds all of its own state. It exists only
|
|
6
|
+
* so a viewer can answer the one question it cannot answer alone — "given a
|
|
7
|
+
* keypress or a focus change on the document, is this viewer the one that
|
|
8
|
+
* should react?" Two page-wide inputs (the arrow keys and `document.activeElement`)
|
|
9
|
+
* can only be attributed to a single viewer by comparing against the others.
|
|
10
|
+
*
|
|
11
|
+
* Entries are removed in `dispose()`, which is what keeps the registry from
|
|
12
|
+
* outliving the page content it describes.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** What a viewer has to expose to take part in page-wide arbitration. */
|
|
16
|
+
export interface Participant {
|
|
17
|
+
/** The viewer's root element, or null before layout. */
|
|
18
|
+
readonly element: HTMLElement | null;
|
|
19
|
+
/** Higher means more recently interacted. */
|
|
20
|
+
readonly interaction: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Monotonic interaction clock. Shared, but it carries no state of its own. */
|
|
24
|
+
let interactionClock = 0;
|
|
25
|
+
|
|
26
|
+
const participants = new Set<Participant>();
|
|
27
|
+
|
|
28
|
+
/** Stamp an interaction. Returns the new value, for the caller to store. */
|
|
29
|
+
export function markInteraction(): number {
|
|
30
|
+
interactionClock += 1;
|
|
31
|
+
return interactionClock;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** The interaction value currently held by the most recent participant. */
|
|
35
|
+
function latestInteraction(): number {
|
|
36
|
+
let latest = -1;
|
|
37
|
+
for (const participant of participants) {
|
|
38
|
+
if (participant.interaction > latest) {
|
|
39
|
+
latest = participant.interaction;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return latest;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Add a viewer. Call from the same place that registers its listeners. */
|
|
46
|
+
export function registerParticipant(participant: Participant): void {
|
|
47
|
+
participants.add(participant);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Remove a viewer. Call from `dispose()`. */
|
|
51
|
+
export function unregisterParticipant(participant: Participant): void {
|
|
52
|
+
participants.delete(participant);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** The registered viewer whose element contains `node`, if any. */
|
|
56
|
+
export function participantFor(node: Node | null): Participant | null {
|
|
57
|
+
if (!node) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
for (const participant of participants) {
|
|
61
|
+
if (participant.element && participant.element.contains(node)) {
|
|
62
|
+
return participant;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The viewer that should react to a page-wide event.
|
|
70
|
+
*
|
|
71
|
+
* Focus wins over recency: if the visitor has focused one viewer, arrow keys
|
|
72
|
+
* belong to it even if they last clicked a different one. With nothing focused
|
|
73
|
+
* — the common case, since clicking a `<div>` does not move focus — the most
|
|
74
|
+
* recently interacted viewer takes it, so the viewer the visitor just used is
|
|
75
|
+
* the one that responds.
|
|
76
|
+
*
|
|
77
|
+
* @param viewer - The viewer asking whether it should react.
|
|
78
|
+
* @returns True if this viewer owns the event.
|
|
79
|
+
*/
|
|
80
|
+
export function ownsPageEvent(viewer: Participant): boolean {
|
|
81
|
+
const active = typeof document === "undefined" ? null : document.activeElement;
|
|
82
|
+
// body (or null) means the visitor has focused nothing viewer-specific
|
|
83
|
+
const focused = participantFor(active);
|
|
84
|
+
if (focused) {
|
|
85
|
+
return focused === viewer;
|
|
86
|
+
}
|
|
87
|
+
// no viewer holds focus, so the most recently interacted one responds
|
|
88
|
+
return viewer.interaction === latestInteraction();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** The viewers currently registered. Test helper. */
|
|
92
|
+
export function registeredParticipants(): readonly Participant[] {
|
|
93
|
+
return [...participants];
|
|
94
|
+
}
|
package/src/dom/DomEvent.ts
CHANGED
|
@@ -16,6 +16,21 @@ export type LegacyEvent = Event & {
|
|
|
16
16
|
pageY?: number;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* The wrapper is remembered on the target so `removeListener` can find it
|
|
21
|
+
* again. Keyed by a per-registration counter rather than only by the stamped
|
|
22
|
+
* function: registering the same function twice for the same event used to
|
|
23
|
+
* overwrite the key, leaving the first listener permanently unremovable.
|
|
24
|
+
*/
|
|
25
|
+
const registrationCounts = new WeakMap<object, number>();
|
|
26
|
+
|
|
27
|
+
function handlerKey(obj: DomEventTarget, type: string, fn: (e: Event) => void): string {
|
|
28
|
+
const target = obj as object;
|
|
29
|
+
const next = (registrationCounts.get(target) ?? 0) + 1;
|
|
30
|
+
registrationCounts.set(target, next);
|
|
31
|
+
return "_vco_" + type + stamp(fn) + "_" + next;
|
|
32
|
+
}
|
|
33
|
+
|
|
19
34
|
const DomEvent = {
|
|
20
35
|
addListener: function (
|
|
21
36
|
obj: DomEventTarget,
|
|
@@ -28,7 +43,7 @@ const DomEvent = {
|
|
|
28
43
|
};
|
|
29
44
|
|
|
30
45
|
obj.addEventListener(type, handler, false);
|
|
31
|
-
(obj as unknown as Record<string, unknown>)[
|
|
46
|
+
(obj as unknown as Record<string, unknown>)[handlerKey(obj, type, fn)] = handler;
|
|
32
47
|
},
|
|
33
48
|
|
|
34
49
|
removeListener: function (
|
|
@@ -37,15 +52,19 @@ const DomEvent = {
|
|
|
37
52
|
fn: (e: Event) => void,
|
|
38
53
|
context?: unknown,
|
|
39
54
|
): void {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
55
|
+
// The most recent registration for this (type, fn) pair is the one the
|
|
56
|
+
// caller means; walk the counter back to find it.
|
|
57
|
+
const target = obj as unknown as Record<string, unknown>;
|
|
58
|
+
for (let n = registrationCounts.get(obj as object) ?? 0; n > 0; n--) {
|
|
59
|
+
const key = "_vco_" + type + stamp(fn) + "_" + n;
|
|
60
|
+
const handler = target[key];
|
|
61
|
+
if (!handler) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
obj.removeEventListener(type, handler as EventListener, false);
|
|
65
|
+
target[key] = null;
|
|
44
66
|
return;
|
|
45
67
|
}
|
|
46
|
-
|
|
47
|
-
obj.removeEventListener(type, handler as EventListener, false);
|
|
48
|
-
(obj as unknown as Record<string, unknown>)[key] = null;
|
|
49
68
|
},
|
|
50
69
|
|
|
51
70
|
preventDefault: function (e: Event): void {
|
package/src/globals.d.ts
CHANGED
|
@@ -11,6 +11,14 @@ declare global {
|
|
|
11
11
|
const SC: {
|
|
12
12
|
Widget: (el: HTMLElement) => { pause(): void };
|
|
13
13
|
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The library version, substituted from package.json by the Vite lib build
|
|
17
|
+
* (see the `define` in vite.config.ts). Hard-coded here only so the
|
|
18
|
+
* source type-checks; a dev-server run without the define falls back to
|
|
19
|
+
* "unknown" at runtime via the typeof guard in StoryMap.
|
|
20
|
+
*/
|
|
21
|
+
const __STORYMAP_VERSION__: string;
|
|
14
22
|
}
|
|
15
23
|
|
|
16
24
|
export {};
|
package/src/language/Language.ts
CHANGED
|
@@ -1,3 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI strings for the active locale.
|
|
3
|
+
*
|
|
4
|
+
* English is the fallback for every missing key (see `getLanguage`), so
|
|
5
|
+
* `messages` and `buttons` are guaranteed to be fully populated once a
|
|
6
|
+
* language has been set — they are typed as required here rather than as
|
|
7
|
+
* `Record<string, string> | undefined` so call sites do not need a null
|
|
8
|
+
* check on every one of the ~30 `Language.messages.*` reads.
|
|
9
|
+
*
|
|
10
|
+
* The locale JSON files themselves are *not* complete: only `en.json` defines
|
|
11
|
+
* every key, and 28 of the 29 bundled locales are missing 8-10 of them
|
|
12
|
+
* (the per-service consent strings and the fullscreen button labels). The
|
|
13
|
+
* runtime falls back to English per key, so this is a translation gap rather
|
|
14
|
+
* than a defect — `npm run check:locales` reports it.
|
|
15
|
+
*/
|
|
16
|
+
export interface LanguageEntry {
|
|
17
|
+
/** Display name of the language, e.g. "Deutsch". */
|
|
18
|
+
name?: string;
|
|
19
|
+
/** BCP 47 code, e.g. "de". */
|
|
20
|
+
lang?: string;
|
|
21
|
+
/** Writing direction; drives the `vco-rtl` layout. */
|
|
22
|
+
direction?: "ltr" | "rtl";
|
|
23
|
+
messages: Record<string, string>;
|
|
24
|
+
buttons: Record<string, string>;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// The locales are imported statically rather than through `import.meta.glob`
|
|
29
|
+
// on purpose. The viewer reads `Language.messages.*` while it is being
|
|
30
|
+
// constructed — the consent dialog, the RTL class, the swipe hint icon and
|
|
31
|
+
// every button label are all decided synchronously inside `new StoryMap()` —
|
|
32
|
+
// so a locale that has not finished fetching yet would silently render in
|
|
33
|
+
// English. The saving from splitting them is ~6 kB gzip, which is not worth
|
|
34
|
+
// making the language load order-dependent.
|
|
35
|
+
//
|
|
36
|
+
// English remains the fallback for every key a translation is missing (see
|
|
37
|
+
// `getLanguage`), and `npm run check:locales` reports those gaps.
|
|
1
38
|
import be from "./locale/be.json";
|
|
2
39
|
import bg from "./locale/bg.json";
|
|
3
40
|
import cs from "./locale/cs.json";
|
|
@@ -28,14 +65,6 @@ import ur from "./locale/ur.json";
|
|
|
28
65
|
import zhCn from "./locale/zh-cn.json";
|
|
29
66
|
import zhTw from "./locale/zh-tw.json";
|
|
30
67
|
|
|
31
|
-
interface LanguageEntry {
|
|
32
|
-
buttons?: Record<string, string>;
|
|
33
|
-
messages?: Record<string, string>;
|
|
34
|
-
[key: string]: unknown;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Static locale map: the bundler-agnostic form of what `import.meta.glob`
|
|
38
|
-
// with `{ eager: true }` desugars to (works in vite dev and rollup builds).
|
|
39
68
|
const localeModules: Record<string, { default?: unknown }> = {
|
|
40
69
|
"./locale/be.json": { default: be },
|
|
41
70
|
"./locale/bg.json": { default: bg },
|
|
@@ -68,40 +97,192 @@ const localeModules: Record<string, { default?: unknown }> = {
|
|
|
68
97
|
"./locale/zh-tw.json": { default: zhTw },
|
|
69
98
|
};
|
|
70
99
|
|
|
100
|
+
/** The locale every other language falls back to, per key. */
|
|
71
101
|
const EN: Record<string, unknown> =
|
|
72
102
|
(localeModules["./locale/en.json"]?.default as Record<string, unknown> | undefined) || {};
|
|
73
103
|
|
|
74
|
-
|
|
104
|
+
/** The strings the viewer reads before (or without) a `setLanguage` call. */
|
|
105
|
+
const FALLBACK: LanguageEntry = {
|
|
106
|
+
name: "English",
|
|
107
|
+
lang: "en",
|
|
108
|
+
direction: "ltr",
|
|
109
|
+
messages: (EN.messages as Record<string, string>) ?? {},
|
|
110
|
+
buttons: (EN.buttons as Record<string, string>) ?? {},
|
|
111
|
+
};
|
|
75
112
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
113
|
+
let Language: LanguageEntry = FALLBACK;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The locale code last passed to `setLanguage`, defaulting to the fallback.
|
|
117
|
+
*
|
|
118
|
+
* Deliberately not derived from `Language.lang`: every bundled locale's `lang`
|
|
119
|
+
* happens to equal its file name today, but a locale like `pt-BR` would make
|
|
120
|
+
* the claim comparison below judge two different identifiers for one locale.
|
|
121
|
+
* Tracking what the caller passed keeps every comparison on one vocabulary.
|
|
122
|
+
*/
|
|
123
|
+
let activeLanguageCode = "en";
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Which live viewer owns the page-wide locale.
|
|
127
|
+
*
|
|
128
|
+
* `Language` above is a single module-level binding, and every label read in
|
|
129
|
+
* the viewer goes through it (MenuBar, Message, StorySlider, Consent, Media,
|
|
130
|
+
* ...). That is deliberate — the strings are read synchronously while a viewer
|
|
131
|
+
* is constructed — but it means two viewers on one page cannot show different
|
|
132
|
+
* languages: whichever called `setLanguage` last would win, and the other
|
|
133
|
+
* would silently keep repainting its chrome in the wrong language.
|
|
134
|
+
*
|
|
135
|
+
* Rather than thread a resolved entry down the options chain, the viewer
|
|
136
|
+
* claims the locale it needs and we fail loudly on a conflict. The claim is
|
|
137
|
+
* refcounted, so tearing down one of two viewers set in the same language
|
|
138
|
+
* does not release the page.
|
|
139
|
+
*/
|
|
140
|
+
const languageHolders = new Map<symbol, string>();
|
|
141
|
+
|
|
142
|
+
/** Why a claim was rejected, for the thrown error. */
|
|
143
|
+
function languageConflict(claimed: string, requested: string): Error {
|
|
144
|
+
const err = new Error(
|
|
145
|
+
`StoryMapJS: two viewers on this page asked for different languages ` +
|
|
146
|
+
`("${claimed}" and "${requested}"), but the UI strings are a single ` +
|
|
147
|
+
`page-wide setting — the last one set would win and the other viewer ` +
|
|
148
|
+
`would keep rendering its chrome in the wrong language. Pass the same ` +
|
|
149
|
+
`language to every viewer on the page, or call refreshLanguage() on ` +
|
|
150
|
+
`the surviving viewer. See docs/DEVELOPMENT.md, ` +
|
|
151
|
+
`"Multiple instances on one page".`,
|
|
80
152
|
);
|
|
153
|
+
// the data may carry its own `language`, and a URL-loaded document claims
|
|
154
|
+
// asynchronously, where the constructor cannot throw — the name lets the
|
|
155
|
+
// async load path report the real cause instead of "could not load data"
|
|
156
|
+
err.name = "StoryMapLanguageConflict";
|
|
157
|
+
return err;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** True for the error {@link claimLanguage} throws on a conflicting locale. */
|
|
161
|
+
function isLanguageConflict(err: unknown): boolean {
|
|
162
|
+
return err instanceof Error && err.name === "StoryMapLanguageConflict";
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Claim the page-wide locale for a viewer.
|
|
167
|
+
*
|
|
168
|
+
* @param code - The locale code the viewer is about to render.
|
|
169
|
+
* @param holder - Per-viewer identity; pass the same one to `releaseLanguage`.
|
|
170
|
+
* @throws If a live holder already claimed a different locale.
|
|
171
|
+
*/
|
|
172
|
+
function claimLanguage(code: string, holder: symbol): void {
|
|
173
|
+
for (const [existingHolder, existingCode] of languageHolders) {
|
|
174
|
+
if (existingHolder !== holder && existingCode !== code) {
|
|
175
|
+
throw languageConflict(existingCode, code);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
languageHolders.set(holder, code);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Release a viewer's claim. The page-wide locale is only released once the
|
|
183
|
+
* last holder is gone, so a disposed viewer does not free the locale a
|
|
184
|
+
* sibling is still rendering in.
|
|
185
|
+
*
|
|
186
|
+
* @param holder - The identity passed to `claimLanguage`.
|
|
187
|
+
*/
|
|
188
|
+
function releaseLanguage(holder: symbol): void {
|
|
189
|
+
languageHolders.delete(holder);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** The locale currently claimed by a live viewer, or null if there is none. */
|
|
193
|
+
function claimedLanguage(): string | null {
|
|
194
|
+
const codes = new Set(languageHolders.values());
|
|
195
|
+
return codes.size > 0 ? [...codes][0] : null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function getLanguage(code: string): Record<string, unknown> {
|
|
199
|
+
const lang: Record<string, unknown> = {};
|
|
200
|
+
// start from a deep copy of the English defaults, then layer this locale
|
|
201
|
+
// on top: a key the translation is missing keeps its English value
|
|
81
202
|
for (const k in EN) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
203
|
+
lang[k] = structuredClone(EN[k]);
|
|
204
|
+
}
|
|
205
|
+
const entry = (localeModules[`./locale/${code}.json`]?.default ?? {}) as Record<
|
|
206
|
+
string,
|
|
207
|
+
unknown
|
|
208
|
+
>;
|
|
209
|
+
applyLanguage(lang, entry);
|
|
210
|
+
return lang;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** Merge `entry` over `target`, per key, never mutating the English defaults. */
|
|
214
|
+
function applyLanguage(target: Record<string, unknown>, entry: Record<string, unknown>): void {
|
|
215
|
+
for (const k in entry) {
|
|
216
|
+
if (!entry[k]) {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if (typeof EN[k] === "object" && EN[k] !== null && typeof entry[k] === "object") {
|
|
220
|
+
// fresh object: never mutate the shared English default,
|
|
221
|
+
// otherwise one setLanguage() call would poison every later
|
|
222
|
+
// lookup (and every other language falling back to English)
|
|
223
|
+
target[k] = Object.assign({}, EN[k] as object, entry[k] as object);
|
|
89
224
|
} else {
|
|
90
|
-
|
|
225
|
+
target[k] = structuredClone(entry[k]);
|
|
91
226
|
}
|
|
92
227
|
}
|
|
93
|
-
return lang;
|
|
94
228
|
}
|
|
95
229
|
|
|
96
230
|
/**
|
|
97
|
-
* Switch the active UI language.
|
|
231
|
+
* Switch the active UI language. Synchronous: the viewer resolves its labels
|
|
232
|
+
* while it is being constructed.
|
|
98
233
|
*
|
|
99
234
|
* @param code - A locale code for which a locale file exists (e.g. `"en"`).
|
|
100
235
|
* @returns The language entry that is now active.
|
|
101
236
|
*/
|
|
102
237
|
function setLanguage(code: string): LanguageEntry {
|
|
103
|
-
|
|
238
|
+
// recorded before the merge, and unconditionally: a rejected *claim* never
|
|
239
|
+
// reaches here, so a throw cannot leave the page locale half-switched
|
|
240
|
+
activeLanguageCode = code;
|
|
241
|
+
const merged = getLanguage(code);
|
|
242
|
+
Language = {
|
|
243
|
+
...(merged as Omit<LanguageEntry, "messages" | "buttons">),
|
|
244
|
+
messages: (merged.messages as Record<string, string>) ?? FALLBACK.messages,
|
|
245
|
+
buttons: (merged.buttons as Record<string, string>) ?? FALLBACK.buttons,
|
|
246
|
+
};
|
|
247
|
+
// The page declares the language the viewer actually renders, so
|
|
248
|
+
// assistive tech pronounces chrome correctly. One effective locale per
|
|
249
|
+
// page (a second viewer claiming another throws), so this cannot fight
|
|
250
|
+
// a sibling viewer.
|
|
251
|
+
if (typeof document !== "undefined") {
|
|
252
|
+
document.documentElement.setAttribute("lang", code);
|
|
253
|
+
}
|
|
104
254
|
return Language;
|
|
105
255
|
}
|
|
106
256
|
|
|
107
|
-
|
|
257
|
+
/**
|
|
258
|
+
* The locale code the page is currently set to.
|
|
259
|
+
*
|
|
260
|
+
* A viewer that was not given a `language` adopts this instead of claiming the
|
|
261
|
+
* hardcoded `"en"` default, so a host that called `setLanguage("de")` and then
|
|
262
|
+
* constructed a viewer gets German rather than a conflict with a sibling.
|
|
263
|
+
*/
|
|
264
|
+
function currentLanguageCode(): string {
|
|
265
|
+
return activeLanguageCode;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** The active locale's BCP 47 code, for `Intl` formatting. */
|
|
269
|
+
function currentLocale(): string {
|
|
270
|
+
return typeof Language.lang === "string" && Language.lang !== "" ? Language.lang : "en";
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** True when the active language is written right-to-left. */
|
|
274
|
+
function isRtl(): boolean {
|
|
275
|
+
return Language.direction === "rtl";
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export {
|
|
279
|
+
setLanguage,
|
|
280
|
+
Language,
|
|
281
|
+
currentLocale,
|
|
282
|
+
isRtl,
|
|
283
|
+
currentLanguageCode,
|
|
284
|
+
claimLanguage,
|
|
285
|
+
releaseLanguage,
|
|
286
|
+
claimedLanguage,
|
|
287
|
+
isLanguageConflict,
|
|
288
|
+
};
|