@projektemacher/storymapjs 0.10.6 → 0.10.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG +358 -16
- package/README.md +43 -9
- package/dist/assets/demo-DBpeF31K.js +1 -0
- package/dist/assets/harness-Cr0rYpvt.js +1 -0
- package/dist/assets/harness-multi-CYHgI0a9.js +1 -0
- package/dist/assets/harness-support-Do7sIp2j.js +1 -0
- package/dist/assets/index-wHPqGrBS.js +1 -0
- package/dist/assets/main-DXalctuR.js +17 -0
- package/dist/context.json +12 -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 +101 -21
- 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 +2 -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 +1604 -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/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/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 +197 -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/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/StorymapData.html +71 -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 +105 -0
- package/dist/docs/api/interfaces/StorymapManifestBackground.html +81 -0
- package/dist/docs/api/interfaces/StorymapManifestCanvas.html +140 -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 +532 -0
- package/dist/docs/api/interfaces/StorymapOverlayLayer.html +126 -0
- package/dist/docs/api/interfaces/StorymapSlide.html +132 -0
- package/dist/docs/api/interfaces/StorymapSlideBackground.html +72 -0
- package/dist/docs/api/interfaces/StorymapSlideLocation.html +117 -0
- package/dist/docs/api/interfaces/StorymapSlideMarker.html +104 -0
- package/dist/docs/api/interfaces/StorymapSlideMedia.html +110 -0
- package/dist/docs/api/interfaces/StorymapSlideNarration.html +65 -0
- package/dist/docs/api/interfaces/StorymapSlideText.html +72 -0
- package/dist/docs/api/interfaces/StorymapTilejson.html +105 -0
- package/dist/docs/api/media/es.json +31 -0
- package/dist/docs/api/media/migration-from-knightlab.md +359 -0
- package/dist/docs/api/modules.html +50 -0
- package/dist/docs/api/types/ContentState.html +70 -0
- package/dist/docs/api/types/ImagereadyKind.html +34 -0
- package/dist/docs/api/types/MediaTypeMatch.html +78 -0
- package/dist/docs/api/types/TileSourceFactory.html +53 -0
- package/dist/docs/authoring.html +293 -0
- package/dist/docs/iiif.html +617 -62
- package/dist/docs/migration.html +314 -12
- package/dist/docs/readme.html +40 -9
- package/dist/embed/index.html +130 -5
- 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/map-area-overlays.json +68 -0
- package/dist/examples/no-map.json +44 -0
- package/dist/examples-iiif/annotated-image.json +188 -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/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/map-area-overlays.json +289 -0
- package/dist/examples-iiif/marktwain.json +255 -58
- 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/harness-multi.html +17 -0
- package/dist/harness.html +3 -2
- package/dist/index.html +33 -10
- package/dist/js/storymap.d.ts +1558 -114
- package/dist/js/storymap.js +10113 -6490
- package/dist/js/storymap.js.map +1 -1
- package/dist/navplace-properties.json +40 -0
- package/docs/migration-from-knightlab.md +359 -0
- package/docs/storymap-as-iiif-manifest.md +934 -0
- package/package.json +16 -10
- package/schema/storymap.schema.json +431 -78
- package/src/animation/easings.ts +25 -0
- package/src/animation/tween.ts +186 -0
- package/src/core/Browser.ts +20 -0
- package/src/core/Load.ts +232 -0
- package/src/core/Util.ts +416 -0
- package/src/core/mixins.ts +188 -0
- package/src/core/viewers.ts +94 -0
- package/src/dom/Dom.ts +31 -0
- package/src/dom/DomEvent.ts +80 -0
- package/src/globals.d.ts +24 -0
- package/src/language/Language.ts +281 -0
- package/src/language/locale/.expected-gaps.json +86 -0
- package/src/language/locale/be.json +31 -0
- package/src/language/locale/bg.json +31 -0
- package/src/language/locale/cs.json +31 -0
- package/src/language/locale/de.json +31 -0
- package/src/language/locale/el.json +31 -0
- package/src/language/locale/en.json +32 -0
- package/src/language/locale/es.json +31 -0
- package/src/language/locale/et.json +22 -0
- package/src/language/locale/fr.json +31 -0
- package/src/language/locale/he.json +31 -0
- package/src/language/locale/hu.json +31 -0
- package/src/language/locale/is.json +22 -0
- package/src/language/locale/it.json +31 -0
- package/src/language/locale/jp.json +31 -0
- package/src/language/locale/ko.json +31 -0
- package/src/language/locale/nl.json +31 -0
- package/src/language/locale/nn.json +22 -0
- package/src/language/locale/no.json +31 -0
- package/src/language/locale/pl.json +31 -0
- package/src/language/locale/pt.json +31 -0
- package/src/language/locale/ru.json +31 -0
- package/src/language/locale/sk.json +31 -0
- package/src/language/locale/sr.json +21 -0
- package/src/language/locale/sv.json +31 -0
- package/src/language/locale/tr.json +31 -0
- package/src/language/locale/uk.json +31 -0
- package/src/language/locale/ur.json +22 -0
- package/src/language/locale/zh-cn.json +31 -0
- package/src/language/locale/zh-tw.json +31 -0
- package/src/main.ts +143 -0
- package/src/map/Map.ts +794 -0
- package/src/map/MapMarker.ts +172 -0
- package/src/map/georeference.ts +325 -0
- package/src/map/openlayers/Map.OpenLayers.ts +2492 -0
- package/src/map/openlayers/MapMarker.OpenLayers.ts +400 -0
- package/src/map/openlayers/zoomifyTiles.ts +25 -0
- package/src/map/types.ts +17 -0
- package/src/media/EmbedUtil.ts +452 -0
- package/src/media/Media.ts +597 -0
- package/src/media/MediaType.ts +163 -0
- package/src/media/embedId.ts +104 -0
- package/src/media/types/Audio.ts +14 -0
- package/src/media/types/Blockquote.ts +39 -0
- package/src/media/types/DailyMotion.ts +53 -0
- package/src/media/types/DocumentCloud.ts +12 -0
- package/src/media/types/Facebook.ts +40 -0
- package/src/media/types/Flickr.ts +115 -0
- package/src/media/types/GoogleDoc.ts +58 -0
- package/src/media/types/HtmlMedia.ts +167 -0
- package/src/media/types/IFrame.ts +50 -0
- package/src/media/types/Image.ts +115 -0
- package/src/media/types/Juxtapose.ts +41 -0
- package/src/media/types/SoundCloud.ts +99 -0
- package/src/media/types/Text.ts +178 -0
- package/src/media/types/Twitter.ts +109 -0
- package/src/media/types/Video.ts +14 -0
- package/src/media/types/Vimeo.ts +65 -0
- package/src/media/types/Website.ts +46 -0
- package/src/media/types/Wikipedia.ts +134 -0
- package/src/media/types/YouTube.ts +224 -0
- package/src/scss/Typography.scss +235 -0
- package/src/scss/VCO.StoryMap.Dark.scss +150 -0
- package/src/scss/VCO.StoryMap.scss +195 -0
- package/src/scss/Variables.Dark.scss +57 -0
- package/src/scss/Variables.scss +48 -0
- package/src/scss/core/Mixins.scss +54 -0
- package/src/scss/core/Reset.scss +206 -0
- package/src/scss/fonts/_font.base.scss +113 -0
- package/src/scss/fonts/font.abril-droidsans.scss +75 -0
- package/src/scss/fonts/font.amatic-andika.scss +76 -0
- package/src/scss/fonts/font.bitter-raleway.scss +92 -0
- package/src/scss/fonts/font.cairo.scss +79 -0
- package/src/scss/fonts/font.clicker-garamond.scss +97 -0
- package/src/scss/fonts/font.dancing-ledger.scss +75 -0
- package/src/scss/fonts/font.default.scss +9 -0
- package/src/scss/fonts/font.fjalla-average.scss +80 -0
- package/src/scss/fonts/font.georgia-helvetica.scss +58 -0
- package/src/scss/fonts/font.knightlab.scss +111 -0
- package/src/scss/fonts/font.lustria-lato.scss +80 -0
- package/src/scss/fonts/font.medula-lato.scss +73 -0
- package/src/scss/fonts/font.oldstandard.scss +94 -0
- package/src/scss/fonts/font.opensans-gentiumbook.scss +85 -0
- package/src/scss/fonts/font.playfair-faunaone.scss +88 -0
- package/src/scss/fonts/font.playfair.scss +89 -0
- package/src/scss/fonts/font.pt.scss +96 -0
- package/src/scss/fonts/font.roboto-megrim.scss +73 -0
- package/src/scss/fonts/font.rufina-sintony.scss +73 -0
- package/src/scss/fonts/font.ubuntu.scss +82 -0
- package/src/scss/fonts/font.unicaone-vollkorn.scss +90 -0
- package/src/scss/icons/Icons.scss +239 -0
- package/src/scss/map/VCO.ImageMarker.scss +23 -0
- package/src/scss/map/VCO.Map.scss +21 -0
- package/src/scss/map/VCO.MapMarker.scss +242 -0
- package/src/scss/map/openlayers/VCO.Map.OpenLayers.scss +126 -0
- package/src/scss/media/VCO.Media.scss +219 -0
- package/src/scss/media/types/VCO.Media.Blockquote.scss +76 -0
- package/src/scss/media/types/VCO.Media.IFrame.scss +11 -0
- package/src/scss/media/types/VCO.Media.Image.scss +13 -0
- package/src/scss/media/types/VCO.Media.Text.scss +98 -0
- package/src/scss/media/types/VCO.Media.Twitter.scss +87 -0
- package/src/scss/media/types/VCO.Media.Wikipedia.scss +65 -0
- package/src/scss/site/site.scss +748 -0
- package/src/scss/slider/VCO.Slide.scss +457 -0
- package/src/scss/slider/VCO.SlideNav.scss +332 -0
- package/src/scss/slider/VCO.StorySlider.scss +66 -0
- package/src/scss/snapmap/VCO.SnapMap.scss +103 -0
- package/src/scss/ui/VCO.Consent.scss +121 -0
- package/src/scss/ui/VCO.MenuBar.Button.scss +107 -0
- package/src/scss/ui/VCO.MenuBar.scss +20 -0
- package/src/scss/ui/VCO.Message.scss +101 -0
- package/src/site/site.ts +88 -0
- package/src/slider/Slide.ts +554 -0
- package/src/slider/SlideNav.ts +246 -0
- package/src/slider/StorySlider.ts +833 -0
- package/src/storymap/Consent.ts +471 -0
- package/src/storymap/StoryMap.ts +2118 -0
- package/src/storymap/content-state.ts +185 -0
- package/src/storymap/iiif.ts +1844 -0
- package/src/storymap/to-iiif.ts +921 -0
- package/src/storymap/validate.ts +257 -0
- package/src/types.ts +494 -0
- package/src/ui/MenuBar.ts +376 -0
- package/src/ui/Message.ts +127 -0
- package/src/ui/Swipable.ts +455 -0
- package/dist/assets/demo-CVQ7kFek.js +0 -1
- package/dist/assets/harness-C-VZV-ou.js +0 -1
- package/dist/assets/index-DDsPBPZA.js +0 -1
- package/dist/assets/main-DwbXrrYn.js +0 -17
package/src/core/Util.ts
ADDED
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
// const debug = true;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Format an ISO-8601-ish timestamp (as found in `date.created_time`, originally
|
|
5
|
+
* from Instagram) as a short, locale-aware date, e.g. "Mar 3, 2013".
|
|
6
|
+
*
|
|
7
|
+
* Falls back to the raw input when it does not parse, so an unusual value
|
|
8
|
+
* shows as-is rather than "Invalid Date".
|
|
9
|
+
*/
|
|
10
|
+
export function convertUnixTime(str: string, locale?: string): string {
|
|
11
|
+
if (!str) {
|
|
12
|
+
return str;
|
|
13
|
+
}
|
|
14
|
+
// "2013-12-09 01:56:28" is not valid ISO-8601 (space instead of "T"), so
|
|
15
|
+
// normalise it before parsing.
|
|
16
|
+
const parsed = new Date(/^\d{4}-\d{2}-\d{2} /.test(str) ? str.replace(" ", "T") : str);
|
|
17
|
+
if (Number.isNaN(parsed.getTime())) {
|
|
18
|
+
return str;
|
|
19
|
+
}
|
|
20
|
+
return parsed.toLocaleDateString(locale ?? "en-US", {
|
|
21
|
+
year: "numeric",
|
|
22
|
+
month: "short",
|
|
23
|
+
day: "numeric",
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Copy the own enumerable properties of `source` onto `target`, limited to
|
|
29
|
+
* `keys` (or all of the source's keys when omitted). Shared body for the two
|
|
30
|
+
* public merge helpers below.
|
|
31
|
+
*/
|
|
32
|
+
function copyOwn(
|
|
33
|
+
target: Record<string, unknown>,
|
|
34
|
+
source: Record<string, unknown> | null | undefined,
|
|
35
|
+
keys?: Iterable<string>,
|
|
36
|
+
): void {
|
|
37
|
+
// `for...in` over a null/undefined source was a silent no-op, and several
|
|
38
|
+
// call sites pass optional values straight through — keep that behaviour.
|
|
39
|
+
if (source == null) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const names = keys ?? Object.keys(source);
|
|
43
|
+
for (const name of names) {
|
|
44
|
+
if (Object.prototype.hasOwnProperty.call(source, name)) {
|
|
45
|
+
target[name] = source[name];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Shallow-assign every own property of `data_to_merge` onto `data_main`.
|
|
52
|
+
*
|
|
53
|
+
* Despite the name this is *not* a deep merge, and it must not become one:
|
|
54
|
+
* every call site merges a partial options object over a defaults object, and
|
|
55
|
+
* a recursive merge would silently change how nested `map_options` and
|
|
56
|
+
* `overlays` values are combined.
|
|
57
|
+
*/
|
|
58
|
+
export function mergeData<T extends object>(data_main: T, data_to_merge?: object | null): T {
|
|
59
|
+
copyOwn(
|
|
60
|
+
data_main as Record<string, unknown>,
|
|
61
|
+
data_to_merge as Record<string, unknown> | null | undefined,
|
|
62
|
+
);
|
|
63
|
+
return data_main;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Like `mergeData`, but only copies keys that already exist in `data_main`.
|
|
68
|
+
* This is what lets storymap *data* override a known option without being able
|
|
69
|
+
* to introduce new ones.
|
|
70
|
+
*/
|
|
71
|
+
export function updateData<T extends object>(data_main: T, data_to_merge?: object | null): T {
|
|
72
|
+
copyOwn(
|
|
73
|
+
data_main as Record<string, unknown>,
|
|
74
|
+
data_to_merge as Record<string, unknown> | null | undefined,
|
|
75
|
+
Object.keys(data_main),
|
|
76
|
+
);
|
|
77
|
+
return data_main;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
let _lastStampId = 0;
|
|
81
|
+
const _stampKey = "_vco_id";
|
|
82
|
+
|
|
83
|
+
/** Stamp an object (or function) with a unique id and return it. */
|
|
84
|
+
export function stamp(obj: object): number {
|
|
85
|
+
const target = obj as Record<string, unknown>;
|
|
86
|
+
target[_stampKey] = target[_stampKey] || ++_lastStampId;
|
|
87
|
+
return target[_stampKey] as number;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Index of the entry whose `data[prop]` equals `id`, or -1 when there is no
|
|
92
|
+
* match. Returning -1 matters: a "not found" result of 0 is indistinguishable
|
|
93
|
+
* from "the first slide", so a bad id silently jumped the story to the start
|
|
94
|
+
* (contrast StoryMap.goTo, which range-checks).
|
|
95
|
+
*/
|
|
96
|
+
export function findArrayNumberByUniqueID(
|
|
97
|
+
id: unknown,
|
|
98
|
+
array: { data: Record<string, unknown> }[],
|
|
99
|
+
prop: string,
|
|
100
|
+
): number {
|
|
101
|
+
for (let i = 0; i < array.length; i++) {
|
|
102
|
+
if (array[i].data[prop] === id) {
|
|
103
|
+
return i;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return -1;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Clear a timer that may be null/undefined and reset the variable.
|
|
111
|
+
*
|
|
112
|
+
* `clearTimeout(null)` is a harmless no-op at runtime but not assignable to
|
|
113
|
+
* the overloads, and forgetting to null the handle afterwards is what lets a
|
|
114
|
+
* cancelled timer be cleared twice (or, worse, not cleared at all).
|
|
115
|
+
*/
|
|
116
|
+
export function clearTimer(timer: ReturnType<typeof setTimeout> | null | undefined): void {
|
|
117
|
+
if (timer !== null && timer !== undefined) {
|
|
118
|
+
clearTimeout(timer);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function unique_ID(size: number, prefix?: string): string {
|
|
123
|
+
function getRandomNumber(range: number): number {
|
|
124
|
+
return Math.floor(Math.random() * range);
|
|
125
|
+
}
|
|
126
|
+
function getRandomChar(): string {
|
|
127
|
+
const chars = "abcdefghijklmnopqurstuvwxyz";
|
|
128
|
+
return chars.charAt(getRandomNumber(chars.length));
|
|
129
|
+
}
|
|
130
|
+
function randomID(size: number): string {
|
|
131
|
+
let str = "";
|
|
132
|
+
for (let i = 0; i < size; i++) {
|
|
133
|
+
str += getRandomChar();
|
|
134
|
+
}
|
|
135
|
+
return str;
|
|
136
|
+
}
|
|
137
|
+
if (prefix) {
|
|
138
|
+
return prefix + "-" + randomID(size);
|
|
139
|
+
} else {
|
|
140
|
+
return "vco-" + randomID(size);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function hexToRgb(hex: string): { r: number; g: number; b: number } | null {
|
|
145
|
+
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
|
|
146
|
+
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
|
147
|
+
hex = hex.replace(shorthandRegex, function (m: string, r: string, g: string, b: string) {
|
|
148
|
+
return r + r + g + g + b + b;
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
152
|
+
return result
|
|
153
|
+
? {
|
|
154
|
+
r: parseInt(result[1], 16),
|
|
155
|
+
g: parseInt(result[2], 16),
|
|
156
|
+
b: parseInt(result[3], 16),
|
|
157
|
+
}
|
|
158
|
+
: null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// CSS named colors (Colors Level 4) for parseCssColor below.
|
|
162
|
+
const NAMED_COLORS: Record<string, [number, number, number]> = {
|
|
163
|
+
aliceblue: [240, 248, 255],
|
|
164
|
+
antiquewhite: [250, 235, 215],
|
|
165
|
+
aqua: [0, 255, 255],
|
|
166
|
+
aquamarine: [127, 255, 212],
|
|
167
|
+
azure: [240, 255, 255],
|
|
168
|
+
beige: [245, 245, 220],
|
|
169
|
+
bisque: [255, 228, 196],
|
|
170
|
+
black: [0, 0, 0],
|
|
171
|
+
blanchedalmond: [255, 235, 205],
|
|
172
|
+
blue: [0, 0, 255],
|
|
173
|
+
blueviolet: [138, 43, 226],
|
|
174
|
+
brown: [165, 42, 42],
|
|
175
|
+
burlywood: [222, 184, 135],
|
|
176
|
+
cadetblue: [95, 158, 160],
|
|
177
|
+
chartreuse: [127, 255, 0],
|
|
178
|
+
chocolate: [210, 105, 30],
|
|
179
|
+
coral: [255, 127, 80],
|
|
180
|
+
cornflowerblue: [100, 149, 237],
|
|
181
|
+
cornsilk: [255, 248, 220],
|
|
182
|
+
crimson: [220, 20, 60],
|
|
183
|
+
cyan: [0, 255, 255],
|
|
184
|
+
darkblue: [0, 0, 139],
|
|
185
|
+
darkcyan: [0, 139, 139],
|
|
186
|
+
darkgoldenrod: [184, 134, 11],
|
|
187
|
+
darkgray: [169, 169, 169],
|
|
188
|
+
darkgreen: [0, 100, 0],
|
|
189
|
+
darkgrey: [169, 169, 169],
|
|
190
|
+
darkkhaki: [189, 183, 107],
|
|
191
|
+
darkmagenta: [139, 0, 139],
|
|
192
|
+
darkolivegreen: [85, 107, 47],
|
|
193
|
+
darkorange: [255, 140, 0],
|
|
194
|
+
darkorchid: [153, 50, 204],
|
|
195
|
+
darkred: [139, 0, 0],
|
|
196
|
+
darksalmon: [233, 150, 122],
|
|
197
|
+
darkseagreen: [143, 188, 143],
|
|
198
|
+
darkslateblue: [72, 61, 139],
|
|
199
|
+
darkslategray: [47, 79, 79],
|
|
200
|
+
darkslategrey: [47, 79, 79],
|
|
201
|
+
darkturquoise: [0, 206, 209],
|
|
202
|
+
darkviolet: [148, 0, 211],
|
|
203
|
+
deeppink: [255, 20, 147],
|
|
204
|
+
deepskyblue: [0, 191, 255],
|
|
205
|
+
dimgray: [105, 105, 105],
|
|
206
|
+
dimgrey: [105, 105, 105],
|
|
207
|
+
dodgerblue: [30, 144, 255],
|
|
208
|
+
firebrick: [178, 34, 34],
|
|
209
|
+
floralwhite: [255, 250, 240],
|
|
210
|
+
forestgreen: [34, 139, 34],
|
|
211
|
+
fuchsia: [255, 0, 255],
|
|
212
|
+
gainsboro: [220, 220, 220],
|
|
213
|
+
ghostwhite: [248, 248, 255],
|
|
214
|
+
gold: [255, 215, 0],
|
|
215
|
+
goldenrod: [218, 165, 32],
|
|
216
|
+
gray: [128, 128, 128],
|
|
217
|
+
green: [0, 128, 0],
|
|
218
|
+
greenyellow: [173, 255, 47],
|
|
219
|
+
grey: [128, 128, 128],
|
|
220
|
+
honeydew: [240, 255, 240],
|
|
221
|
+
hotpink: [255, 105, 180],
|
|
222
|
+
indianred: [205, 92, 92],
|
|
223
|
+
indigo: [75, 0, 130],
|
|
224
|
+
ivory: [255, 255, 240],
|
|
225
|
+
khaki: [240, 230, 140],
|
|
226
|
+
lavender: [230, 230, 250],
|
|
227
|
+
lavenderblush: [255, 240, 245],
|
|
228
|
+
lawngreen: [124, 252, 0],
|
|
229
|
+
lemonchiffon: [255, 250, 205],
|
|
230
|
+
lightblue: [173, 216, 230],
|
|
231
|
+
lightcoral: [240, 128, 128],
|
|
232
|
+
lightcyan: [224, 255, 255],
|
|
233
|
+
lightgoldenrodyellow: [250, 250, 210],
|
|
234
|
+
lightgray: [211, 211, 211],
|
|
235
|
+
lightgreen: [144, 238, 144],
|
|
236
|
+
lightgrey: [211, 211, 211],
|
|
237
|
+
lightpink: [255, 182, 193],
|
|
238
|
+
lightsalmon: [255, 160, 122],
|
|
239
|
+
lightseagreen: [32, 178, 170],
|
|
240
|
+
lightskyblue: [135, 206, 250],
|
|
241
|
+
lightslategray: [119, 136, 153],
|
|
242
|
+
lightslategrey: [119, 136, 153],
|
|
243
|
+
lightsteelblue: [176, 196, 222],
|
|
244
|
+
lightyellow: [255, 255, 224],
|
|
245
|
+
lime: [0, 255, 0],
|
|
246
|
+
limegreen: [50, 205, 50],
|
|
247
|
+
linen: [250, 240, 230],
|
|
248
|
+
magenta: [255, 0, 255],
|
|
249
|
+
maroon: [128, 0, 0],
|
|
250
|
+
mediumaquamarine: [102, 205, 170],
|
|
251
|
+
mediumblue: [0, 0, 205],
|
|
252
|
+
mediumorchid: [186, 85, 211],
|
|
253
|
+
mediumpurple: [147, 112, 219],
|
|
254
|
+
mediumseagreen: [60, 179, 113],
|
|
255
|
+
mediumslateblue: [123, 104, 238],
|
|
256
|
+
mediumspringgreen: [0, 250, 154],
|
|
257
|
+
mediumturquoise: [72, 209, 204],
|
|
258
|
+
mediumvioletred: [199, 21, 133],
|
|
259
|
+
midnightblue: [25, 25, 112],
|
|
260
|
+
mintcream: [245, 255, 250],
|
|
261
|
+
mistyrose: [255, 228, 225],
|
|
262
|
+
moccasin: [255, 228, 181],
|
|
263
|
+
navajowhite: [255, 222, 173],
|
|
264
|
+
navy: [0, 0, 128],
|
|
265
|
+
oldlace: [253, 245, 230],
|
|
266
|
+
olive: [128, 128, 0],
|
|
267
|
+
olivedrab: [107, 142, 35],
|
|
268
|
+
orange: [255, 165, 0],
|
|
269
|
+
orangered: [255, 69, 0],
|
|
270
|
+
orchid: [218, 112, 214],
|
|
271
|
+
palegoldenrod: [238, 232, 170],
|
|
272
|
+
palegreen: [152, 251, 152],
|
|
273
|
+
paleturquoise: [175, 238, 238],
|
|
274
|
+
palevioletred: [219, 112, 147],
|
|
275
|
+
papayawhip: [255, 239, 213],
|
|
276
|
+
peachpuff: [255, 218, 185],
|
|
277
|
+
peru: [205, 133, 63],
|
|
278
|
+
pink: [255, 192, 203],
|
|
279
|
+
plum: [221, 160, 221],
|
|
280
|
+
powderblue: [176, 224, 230],
|
|
281
|
+
purple: [128, 0, 128],
|
|
282
|
+
rebeccapurple: [102, 51, 153],
|
|
283
|
+
red: [255, 0, 0],
|
|
284
|
+
rosybrown: [188, 143, 143],
|
|
285
|
+
royalblue: [65, 105, 225],
|
|
286
|
+
saddlebrown: [139, 69, 19],
|
|
287
|
+
salmon: [250, 128, 114],
|
|
288
|
+
sandybrown: [244, 164, 96],
|
|
289
|
+
seagreen: [46, 139, 87],
|
|
290
|
+
seashell: [255, 245, 238],
|
|
291
|
+
sienna: [160, 82, 45],
|
|
292
|
+
silver: [192, 192, 192],
|
|
293
|
+
skyblue: [135, 206, 235],
|
|
294
|
+
slateblue: [106, 90, 205],
|
|
295
|
+
slategray: [112, 128, 144],
|
|
296
|
+
slategrey: [112, 128, 144],
|
|
297
|
+
snow: [255, 250, 250],
|
|
298
|
+
springgreen: [0, 255, 127],
|
|
299
|
+
steelblue: [70, 130, 180],
|
|
300
|
+
tan: [210, 180, 140],
|
|
301
|
+
teal: [0, 128, 128],
|
|
302
|
+
thistle: [216, 191, 216],
|
|
303
|
+
tomato: [255, 99, 71],
|
|
304
|
+
turquoise: [64, 224, 208],
|
|
305
|
+
violet: [238, 130, 238],
|
|
306
|
+
wheat: [245, 222, 179],
|
|
307
|
+
white: [255, 255, 255],
|
|
308
|
+
whitesmoke: [245, 245, 245],
|
|
309
|
+
yellow: [255, 255, 0],
|
|
310
|
+
yellowgreen: [154, 205, 50],
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
function parseRgbComponent(part: string, max: number): number | null {
|
|
314
|
+
const percent = part.endsWith("%");
|
|
315
|
+
const value = parseFloat(part);
|
|
316
|
+
if (!isFinite(value)) {
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
const scaled = percent ? (value / 100) * max : value;
|
|
320
|
+
return Math.min(max, Math.max(0, Math.round(scaled)));
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Parse any CSS color (hex, rgb()/rgba(), named colors) into {r, g, b}.
|
|
325
|
+
* Unlike hexToRgb this never throws on valid CSS input; returns null only
|
|
326
|
+
* for unparseable values so callers can fall back to a default.
|
|
327
|
+
*/
|
|
328
|
+
export function parseCssColor(value: string): { r: number; g: number; b: number } | null {
|
|
329
|
+
const input = value.trim().toLowerCase();
|
|
330
|
+
const hex = hexToRgb(input);
|
|
331
|
+
if (hex) {
|
|
332
|
+
return hex;
|
|
333
|
+
}
|
|
334
|
+
const rgb = /^rgba?\(\s*([^,)]+)\s*,\s*([^,)]+)\s*,\s*([^,)]+)\s*(?:,\s*[^)]+\s*)?\)$/.exec(
|
|
335
|
+
input,
|
|
336
|
+
);
|
|
337
|
+
if (rgb) {
|
|
338
|
+
const r = parseRgbComponent(rgb[1], 255);
|
|
339
|
+
const g = parseRgbComponent(rgb[2], 255);
|
|
340
|
+
const b = parseRgbComponent(rgb[3], 255);
|
|
341
|
+
return r === null || g === null || b === null ? null : { r, g, b };
|
|
342
|
+
}
|
|
343
|
+
const named = NAMED_COLORS[input];
|
|
344
|
+
return named ? { r: named[0], g: named[1], b: named[2] } : null;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Glide duration for a slide jump, scaled with the distance so out-of-order
|
|
349
|
+
* navigation glides instead of flicking. Shared by the slider and the map
|
|
350
|
+
* so both animations stay in sync, and exposed for transition events.
|
|
351
|
+
*/
|
|
352
|
+
export function slideTransitionDuration(from: number, to: number): number {
|
|
353
|
+
const steps = Math.abs(to - from);
|
|
354
|
+
return Math.max(600, Math.min(1000 + steps * 120, 2000));
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* True when the user prefers reduced motion
|
|
359
|
+
* (`prefers-reduced-motion: reduce`) — slide/map glides collapse to
|
|
360
|
+
* instant changes and autoplay stays off.
|
|
361
|
+
*/
|
|
362
|
+
export function prefersReducedMotion(): boolean {
|
|
363
|
+
return (
|
|
364
|
+
typeof window !== "undefined" &&
|
|
365
|
+
typeof window.matchMedia === "function" &&
|
|
366
|
+
window.matchMedia("(prefers-reduced-motion: reduce)").matches
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export function htmlify(str: string): string {
|
|
371
|
+
//if (str.match(/<\s*p[^>]*>([^<]*)<\s*\/\s*p\s*>/)) {
|
|
372
|
+
if (str.match(/<p>[\s\S]*?<\/p>/)) {
|
|
373
|
+
return str;
|
|
374
|
+
} else {
|
|
375
|
+
return "<p>" + str + "</p>";
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
export const ratio = {
|
|
380
|
+
/**
|
|
381
|
+
* The 16:9 height for a given width, or the 16:9 width for a given
|
|
382
|
+
* height. Returns 0 when neither is a usable number.
|
|
383
|
+
*
|
|
384
|
+
* The old guards were `!== null && !== ""`, which an `undefined` passes
|
|
385
|
+
* through — so a caller that omitted `w` computed `Math.round(NaN)` and
|
|
386
|
+
* wrote `height: "NaNpx"`. A `typeof === "number"` check is what the
|
|
387
|
+
* arithmetic actually needs.
|
|
388
|
+
*/
|
|
389
|
+
r16_9: function (size: { w?: number; h?: number }): number {
|
|
390
|
+
if (typeof size.w === "number" && isFinite(size.w)) {
|
|
391
|
+
return Math.round((size.w / 16) * 9);
|
|
392
|
+
}
|
|
393
|
+
if (typeof size.h === "number" && isFinite(size.h)) {
|
|
394
|
+
return Math.round((size.h / 9) * 16);
|
|
395
|
+
}
|
|
396
|
+
return 0;
|
|
397
|
+
},
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
export function getObjectAttributeByIndex(
|
|
401
|
+
obj: Record<string, unknown> | undefined,
|
|
402
|
+
index: number,
|
|
403
|
+
): unknown {
|
|
404
|
+
if (typeof obj != "undefined") {
|
|
405
|
+
let i = 0;
|
|
406
|
+
for (const attr in obj) {
|
|
407
|
+
if (index === i) {
|
|
408
|
+
return obj[attr];
|
|
409
|
+
}
|
|
410
|
+
i++;
|
|
411
|
+
}
|
|
412
|
+
return "";
|
|
413
|
+
} else {
|
|
414
|
+
return "";
|
|
415
|
+
}
|
|
416
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// Mixin helpers following the TypeScript handbook mixin pattern:
|
|
2
|
+
// https://www.typescriptlang.org/docs/handbook/mixins.html
|
|
3
|
+
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-explicit-any -- the handbook mixin
|
|
5
|
+
pattern requires mixin constructors to take a single any[] rest parameter
|
|
6
|
+
(see TS2545). */
|
|
7
|
+
|
|
8
|
+
/** Constructor shape accepted by the mixin functions. */
|
|
9
|
+
export type Constructor<T = object> = new (...args: any[]) => T;
|
|
10
|
+
|
|
11
|
+
/** Eventing members provided by the Evented mixin. */
|
|
12
|
+
export interface EventedInstance {
|
|
13
|
+
on: (type: string, fn: unknown, context?: unknown) => unknown;
|
|
14
|
+
off: (type: string, fn: unknown, context?: unknown) => unknown;
|
|
15
|
+
fire: (type: string, data?: unknown, target?: unknown) => unknown;
|
|
16
|
+
hasEventListeners: (type: string) => boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Instance contract for DomMixed consumers.
|
|
21
|
+
*
|
|
22
|
+
* `_el` is deliberately `Record<string, unknown>`: each class declares its
|
|
23
|
+
* own element shape, and several of them hold members that are legitimately
|
|
24
|
+
* null before the component builds them (a slide's call-to-action, a
|
|
25
|
+
* slider's live region). Requiring `Record<string, HTMLElement>` here would
|
|
26
|
+
* force every one of those back into an `{} as HTMLElement` placeholder.
|
|
27
|
+
*/
|
|
28
|
+
export interface DomMixedInstance extends EventedInstance {
|
|
29
|
+
_el: Record<string, unknown>;
|
|
30
|
+
data?: unknown;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* Evented
|
|
34
|
+
adds custom events functionality to a class (semantics of the former
|
|
35
|
+
core/Events class)
|
|
36
|
+
================================================== */
|
|
37
|
+
|
|
38
|
+
/** Adds eventing (on/off/fire/hasEventListeners) to a class. */
|
|
39
|
+
export function Evented<T extends Constructor>(Base: T) {
|
|
40
|
+
return class extends Base {
|
|
41
|
+
declare "_vco_events"?: Record<string, { action: unknown; context: unknown }[]>;
|
|
42
|
+
|
|
43
|
+
on(
|
|
44
|
+
/*String*/ type: string,
|
|
45
|
+
/*Function*/ fn: unknown,
|
|
46
|
+
/*(optional) Object*/ context?: unknown,
|
|
47
|
+
): this {
|
|
48
|
+
const events = (this._vco_events = this._vco_events || {});
|
|
49
|
+
events[type] = events[type] || [];
|
|
50
|
+
events[type].push({
|
|
51
|
+
action: fn,
|
|
52
|
+
context: context || this,
|
|
53
|
+
});
|
|
54
|
+
return this;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
hasEventListeners(/*String*/ type: string) /*-> Boolean*/ {
|
|
58
|
+
return !!this._vco_events?.[type]?.length;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
off(
|
|
62
|
+
/*String*/ type: string,
|
|
63
|
+
/*Function*/ fn: unknown,
|
|
64
|
+
/*(optional) Object*/ context?: unknown,
|
|
65
|
+
): this {
|
|
66
|
+
if (!this.hasEventListeners(type)) {
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
const events = this._vco_events as Record<
|
|
70
|
+
string,
|
|
71
|
+
{ action: unknown; context: unknown }[]
|
|
72
|
+
>;
|
|
73
|
+
for (let i = 0, len = events[type].length; i < len; i++) {
|
|
74
|
+
if (
|
|
75
|
+
events[type][i].action === fn &&
|
|
76
|
+
(!context || events[type][i].context === context)
|
|
77
|
+
) {
|
|
78
|
+
events[type].splice(i, 1);
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
fire(
|
|
86
|
+
/*String*/ type: string,
|
|
87
|
+
/*(optional) Object*/ data?: unknown,
|
|
88
|
+
target?: unknown,
|
|
89
|
+
): this {
|
|
90
|
+
if (!this.hasEventListeners(type)) {
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const event = {
|
|
95
|
+
type: type,
|
|
96
|
+
target: target || this,
|
|
97
|
+
...(data as Record<string, unknown> | undefined),
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const listeners = (
|
|
101
|
+
this._vco_events as Record<string, { action: unknown; context: unknown }[]>
|
|
102
|
+
)[type].slice();
|
|
103
|
+
|
|
104
|
+
for (const listener of listeners) {
|
|
105
|
+
(listener.action as (e: unknown) => void).call(listener.context || this, event);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return this;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
constructor(...args: any[]) {
|
|
112
|
+
super(...args);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* DomMixed
|
|
118
|
+
DOM container conveniences, replacing the former DomMixins runtime
|
|
119
|
+
mixin (addTo/removeFrom call the onAdd/onRemove lifecycle hooks)
|
|
120
|
+
================================================== */
|
|
121
|
+
|
|
122
|
+
/** Adds DOM container conveniences (addTo/removeFrom/setPosition/show/hide
|
|
123
|
+
* and the onAdd/onRemove/onLoaded lifecycle events) to a class. */
|
|
124
|
+
export function DomMixed<T extends Constructor<DomMixedInstance>>(Base: T) {
|
|
125
|
+
return class extends Base {
|
|
126
|
+
/**
|
|
127
|
+
* The host element. Every DomMixed consumer keeps its root element
|
|
128
|
+
* here, so this narrows the `Record<string, unknown>` element map to
|
|
129
|
+
* something with a style and children.
|
|
130
|
+
*/
|
|
131
|
+
container(): HTMLElement {
|
|
132
|
+
return this._el.container as HTMLElement;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* Adding, Hiding, Showing etc
|
|
136
|
+
================================================== */
|
|
137
|
+
show(animate?: unknown): void {
|
|
138
|
+
if (!animate) {
|
|
139
|
+
this.container().style.display = "block";
|
|
140
|
+
}
|
|
141
|
+
// animated show is not implemented
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
hide(): void {
|
|
145
|
+
this.container().style.display = "none";
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
addTo(container: HTMLElement): this {
|
|
149
|
+
container.appendChild(this.container());
|
|
150
|
+
this.onAdd();
|
|
151
|
+
return this;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
removeFrom(container: HTMLElement): this {
|
|
155
|
+
container.removeChild(this.container());
|
|
156
|
+
this.onRemove();
|
|
157
|
+
return this;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* Set the Position
|
|
161
|
+
================================================== */
|
|
162
|
+
setPosition(pos: Record<string, number>, el?: HTMLElement): this {
|
|
163
|
+
const target = el || this.container();
|
|
164
|
+
for (const name of Object.keys(pos)) {
|
|
165
|
+
(target.style as unknown as Record<string, string>)[name] = pos[name] + "px";
|
|
166
|
+
}
|
|
167
|
+
return this;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* Lifecycle events
|
|
171
|
+
================================================== */
|
|
172
|
+
onLoaded(): void {
|
|
173
|
+
this.fire("loaded", this.data);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
onAdd(): void {
|
|
177
|
+
this.fire("added", this.data);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
onRemove(): void {
|
|
181
|
+
this.fire("removed", this.data);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
constructor(...args: any[]) {
|
|
185
|
+
super(...args);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
}
|
|
@@ -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
|
+
}
|