@expressivecss/expressive 0.15.0 → 0.17.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.md +1807 -1
- package/README.md +9 -8
- package/dist/css/expressive.css +19176 -11958
- package/dist/css/expressive.css.map +1 -1
- package/dist/css/expressive.min.css +1 -1
- package/dist/css/expressive.min.css.map +1 -1
- package/dist/fonts/LICENSE-noto-sans-arabic +93 -0
- package/dist/fonts/LICENSE-noto-sans-hebrew +93 -0
- package/dist/fonts/LICENSE-noto-sans-thai +93 -0
- package/dist/fonts/material-symbols-outlined.woff2 +0 -0
- package/dist/fonts/material-symbols-rounded.woff2 +0 -0
- package/dist/fonts/material-symbols-sharp.woff2 +0 -0
- package/dist/fonts/noto-sans-arabic-arabic-400.woff2 +0 -0
- package/dist/fonts/noto-sans-arabic-arabic-500.woff2 +0 -0
- package/dist/fonts/noto-sans-arabic-arabic-700.woff2 +0 -0
- package/dist/fonts/noto-sans-cyrillic-400.woff2 +0 -0
- package/dist/fonts/noto-sans-cyrillic-500.woff2 +0 -0
- package/dist/fonts/noto-sans-cyrillic-700.woff2 +0 -0
- package/dist/fonts/noto-sans-cyrillic-ext-400.woff2 +0 -0
- package/dist/fonts/noto-sans-cyrillic-ext-500.woff2 +0 -0
- package/dist/fonts/noto-sans-cyrillic-ext-700.woff2 +0 -0
- package/dist/fonts/noto-sans-devanagari-400.woff2 +0 -0
- package/dist/fonts/noto-sans-devanagari-500.woff2 +0 -0
- package/dist/fonts/noto-sans-devanagari-700.woff2 +0 -0
- package/dist/fonts/noto-sans-greek-400.woff2 +0 -0
- package/dist/fonts/noto-sans-greek-500.woff2 +0 -0
- package/dist/fonts/noto-sans-greek-700.woff2 +0 -0
- package/dist/fonts/noto-sans-greek-ext-400.woff2 +0 -0
- package/dist/fonts/noto-sans-greek-ext-500.woff2 +0 -0
- package/dist/fonts/noto-sans-greek-ext-700.woff2 +0 -0
- package/dist/fonts/noto-sans-hebrew-hebrew-400.woff2 +0 -0
- package/dist/fonts/noto-sans-hebrew-hebrew-500.woff2 +0 -0
- package/dist/fonts/noto-sans-hebrew-hebrew-700.woff2 +0 -0
- package/dist/fonts/noto-sans-latin-700.woff2 +0 -0
- package/dist/fonts/noto-sans-latin-ext-400.woff2 +0 -0
- package/dist/fonts/noto-sans-latin-ext-500.woff2 +0 -0
- package/dist/fonts/noto-sans-latin-ext-700.woff2 +0 -0
- package/dist/fonts/noto-sans-thai-thai-400.woff2 +0 -0
- package/dist/fonts/noto-sans-thai-thai-500.woff2 +0 -0
- package/dist/fonts/noto-sans-thai-thai-700.woff2 +0 -0
- package/dist/fonts/noto-sans-vietnamese-400.woff2 +0 -0
- package/dist/fonts/noto-sans-vietnamese-500.woff2 +0 -0
- package/dist/fonts/noto-sans-vietnamese-700.woff2 +0 -0
- package/dist/fonts/roboto-cyrillic-400.woff2 +0 -0
- package/dist/fonts/roboto-cyrillic-500.woff2 +0 -0
- package/dist/fonts/roboto-cyrillic-700.woff2 +0 -0
- package/dist/fonts/roboto-cyrillic-ext-400.woff2 +0 -0
- package/dist/fonts/roboto-cyrillic-ext-500.woff2 +0 -0
- package/dist/fonts/roboto-cyrillic-ext-700.woff2 +0 -0
- package/dist/fonts/roboto-greek-400.woff2 +0 -0
- package/dist/fonts/roboto-greek-500.woff2 +0 -0
- package/dist/fonts/roboto-greek-700.woff2 +0 -0
- package/dist/fonts/roboto-greek-ext-400.woff2 +0 -0
- package/dist/fonts/roboto-greek-ext-500.woff2 +0 -0
- package/dist/fonts/roboto-greek-ext-700.woff2 +0 -0
- package/dist/fonts/roboto-latin-700.woff2 +0 -0
- package/dist/fonts/roboto-latin-ext-400.woff2 +0 -0
- package/dist/fonts/roboto-latin-ext-500.woff2 +0 -0
- package/dist/fonts/roboto-latin-ext-700.woff2 +0 -0
- package/dist/fonts/roboto-vietnamese-400.woff2 +0 -0
- package/dist/fonts/roboto-vietnamese-500.woff2 +0 -0
- package/dist/fonts/roboto-vietnamese-700.woff2 +0 -0
- package/dist/js/chunks/chunk-26VUH75M.mjs +102 -0
- package/dist/js/chunks/chunk-26VUH75M.mjs.map +7 -0
- package/dist/js/chunks/chunk-2LFCOGC3.mjs +233 -0
- package/dist/js/chunks/chunk-2LFCOGC3.mjs.map +7 -0
- package/dist/js/chunks/{chunk-DXGRXYYL.mjs → chunk-36GELQGX.mjs} +29 -46
- package/dist/js/chunks/chunk-36GELQGX.mjs.map +7 -0
- package/dist/js/chunks/{chunk-74MXKKLN.mjs → chunk-3FKWIRHW.mjs} +15 -29
- package/dist/js/chunks/chunk-3FKWIRHW.mjs.map +7 -0
- package/dist/js/chunks/chunk-3KF65KGL.mjs +209 -0
- package/dist/js/chunks/chunk-3KF65KGL.mjs.map +7 -0
- package/dist/js/chunks/{chunk-KVJAVDBC.mjs → chunk-3KLZRQZI.mjs} +88 -116
- package/dist/js/chunks/chunk-3KLZRQZI.mjs.map +7 -0
- package/dist/js/chunks/{chunk-CK2XCICY.mjs → chunk-3XORNED5.mjs} +3 -11
- package/dist/js/chunks/chunk-3XORNED5.mjs.map +7 -0
- package/dist/js/chunks/chunk-4WBGAQN3.mjs +113 -0
- package/dist/js/chunks/chunk-4WBGAQN3.mjs.map +7 -0
- package/dist/js/chunks/{chunk-FM5CZOUB.mjs → chunk-5F4URJHL.mjs} +19 -30
- package/dist/js/chunks/chunk-5F4URJHL.mjs.map +7 -0
- package/dist/js/chunks/chunk-67UNY7RH.mjs +299 -0
- package/dist/js/chunks/chunk-67UNY7RH.mjs.map +7 -0
- package/dist/js/chunks/chunk-7CXNATJS.mjs +97 -0
- package/dist/js/chunks/chunk-7CXNATJS.mjs.map +7 -0
- package/dist/js/chunks/{chunk-UETTGDLI.mjs → chunk-7X44MKEQ.mjs} +43 -48
- package/dist/js/chunks/chunk-7X44MKEQ.mjs.map +7 -0
- package/dist/js/chunks/chunk-7ZAMOMGY.mjs +440 -0
- package/dist/js/chunks/chunk-7ZAMOMGY.mjs.map +7 -0
- package/dist/js/chunks/chunk-AEG6LOAJ.mjs +54 -0
- package/dist/js/chunks/chunk-AEG6LOAJ.mjs.map +7 -0
- package/dist/js/chunks/chunk-AQNFCJJ5.mjs +135 -0
- package/dist/js/chunks/chunk-AQNFCJJ5.mjs.map +7 -0
- package/dist/js/chunks/chunk-B55LWKBM.mjs +75 -0
- package/dist/js/chunks/chunk-B55LWKBM.mjs.map +7 -0
- package/dist/js/chunks/chunk-BB5VXYXT.mjs +28 -0
- package/dist/js/chunks/chunk-BB5VXYXT.mjs.map +7 -0
- package/dist/js/chunks/chunk-BDATLH3H.mjs +108 -0
- package/dist/js/chunks/chunk-BDATLH3H.mjs.map +7 -0
- package/dist/js/chunks/chunk-CWMQOT4O.mjs +232 -0
- package/dist/js/chunks/chunk-CWMQOT4O.mjs.map +7 -0
- package/dist/js/chunks/chunk-CY2CTOVM.mjs +81 -0
- package/dist/js/chunks/chunk-CY2CTOVM.mjs.map +7 -0
- package/dist/js/chunks/{chunk-NUHMOAOY.mjs → chunk-DWA5UYLJ.mjs} +363 -218
- package/dist/js/chunks/chunk-DWA5UYLJ.mjs.map +7 -0
- package/dist/js/chunks/chunk-EB2V4OKL.mjs +79 -0
- package/dist/js/chunks/chunk-EB2V4OKL.mjs.map +7 -0
- package/dist/js/chunks/chunk-EWO662ZC.mjs +188 -0
- package/dist/js/chunks/chunk-EWO662ZC.mjs.map +7 -0
- package/dist/js/chunks/{chunk-ZX6M7SWO.mjs → chunk-F7LAKFMX.mjs} +320 -141
- package/dist/js/chunks/chunk-F7LAKFMX.mjs.map +7 -0
- package/dist/js/chunks/{chunk-L27Q6ZMI.mjs → chunk-FNIIH2LU.mjs} +20 -33
- package/dist/js/chunks/chunk-FNIIH2LU.mjs.map +7 -0
- package/dist/js/chunks/chunk-GE3YMFS6.mjs +15 -0
- package/dist/js/chunks/chunk-GE3YMFS6.mjs.map +7 -0
- package/dist/js/chunks/chunk-GFWYMWYN.mjs +125 -0
- package/dist/js/chunks/chunk-GFWYMWYN.mjs.map +7 -0
- package/dist/js/chunks/chunk-GNRSYMVH.mjs +1 -0
- package/dist/js/chunks/chunk-H5ISU45X.mjs +87 -0
- package/dist/js/chunks/chunk-H5ISU45X.mjs.map +7 -0
- package/dist/js/chunks/{chunk-GJL6GCIU.mjs → chunk-H6YIKFAQ.mjs} +311 -186
- package/dist/js/chunks/chunk-H6YIKFAQ.mjs.map +7 -0
- package/dist/js/chunks/{chunk-BGZLF6JZ.mjs → chunk-HEH7E3KO.mjs} +155 -35
- package/dist/js/chunks/chunk-HEH7E3KO.mjs.map +7 -0
- package/dist/js/chunks/chunk-HQRLBTNM.mjs +152 -0
- package/dist/js/chunks/chunk-HQRLBTNM.mjs.map +7 -0
- package/dist/js/chunks/chunk-I2F7MLUU.mjs +137 -0
- package/dist/js/chunks/chunk-I2F7MLUU.mjs.map +7 -0
- package/dist/js/chunks/chunk-IQOTGGHX.mjs +797 -0
- package/dist/js/chunks/chunk-IQOTGGHX.mjs.map +7 -0
- package/dist/js/chunks/chunk-JH3YWKA6.mjs +225 -0
- package/dist/js/chunks/chunk-JH3YWKA6.mjs.map +7 -0
- package/dist/js/chunks/chunk-JOLJAYIJ.mjs +7 -0
- package/dist/js/chunks/chunk-JOLJAYIJ.mjs.map +7 -0
- package/dist/js/chunks/{chunk-VGNYF6FB.mjs → chunk-KOTGMCMI.mjs} +116 -24
- package/dist/js/chunks/chunk-KOTGMCMI.mjs.map +7 -0
- package/dist/js/chunks/{chunk-LQWUDNHZ.mjs → chunk-LC4O5LFS.mjs} +21 -45
- package/dist/js/chunks/chunk-LC4O5LFS.mjs.map +7 -0
- package/dist/js/chunks/chunk-LEF33SCP.mjs +127 -0
- package/dist/js/chunks/chunk-LEF33SCP.mjs.map +7 -0
- package/dist/js/chunks/{chunk-PDG64UHF.mjs → chunk-LFORZRPH.mjs} +21 -23
- package/dist/js/chunks/chunk-LFORZRPH.mjs.map +7 -0
- package/dist/js/chunks/chunk-LWLNV5EC.mjs +451 -0
- package/dist/js/chunks/chunk-LWLNV5EC.mjs.map +7 -0
- package/dist/js/chunks/chunk-LXRHUQAX.mjs +491 -0
- package/dist/js/chunks/chunk-LXRHUQAX.mjs.map +7 -0
- package/dist/js/chunks/{chunk-SFI2U4YW.mjs → chunk-MA2SZZFB.mjs} +82 -111
- package/dist/js/chunks/chunk-MA2SZZFB.mjs.map +7 -0
- package/dist/js/chunks/chunk-MDBZAMIV.mjs +121 -0
- package/dist/js/chunks/chunk-MDBZAMIV.mjs.map +7 -0
- package/dist/js/chunks/chunk-NODZ5VAD.mjs +75 -0
- package/dist/js/chunks/chunk-NODZ5VAD.mjs.map +7 -0
- package/dist/js/chunks/chunk-O2WJB6TH.mjs +365 -0
- package/dist/js/chunks/chunk-O2WJB6TH.mjs.map +7 -0
- package/dist/js/chunks/chunk-PCABY5BN.mjs +35 -0
- package/dist/js/chunks/chunk-PCABY5BN.mjs.map +7 -0
- package/dist/js/chunks/chunk-PWKYVMND.mjs +120 -0
- package/dist/js/chunks/chunk-PWKYVMND.mjs.map +7 -0
- package/dist/js/chunks/{chunk-SMY7GJSS.mjs → chunk-QHZZT7YO.mjs} +66 -38
- package/dist/js/chunks/chunk-QHZZT7YO.mjs.map +7 -0
- package/dist/js/chunks/chunk-QND56EW2.mjs +439 -0
- package/dist/js/chunks/chunk-QND56EW2.mjs.map +7 -0
- package/dist/js/chunks/chunk-QNODAANY.mjs +376 -0
- package/dist/js/chunks/chunk-QNODAANY.mjs.map +7 -0
- package/dist/js/chunks/{chunk-KHXZ2A4K.mjs → chunk-QRO5FV3I.mjs} +156 -73
- package/dist/js/chunks/chunk-QRO5FV3I.mjs.map +7 -0
- package/dist/js/chunks/chunk-R7A7JRC5.mjs +440 -0
- package/dist/js/chunks/chunk-R7A7JRC5.mjs.map +7 -0
- package/dist/js/chunks/chunk-RKG2CBFE.mjs +74 -0
- package/dist/js/chunks/chunk-RKG2CBFE.mjs.map +7 -0
- package/dist/js/chunks/{chunk-XAEAEHIX.mjs → chunk-RSNS5OYS.mjs} +38 -25
- package/dist/js/chunks/chunk-RSNS5OYS.mjs.map +7 -0
- package/dist/js/chunks/{chunk-X4ISMKE2.mjs → chunk-RUDYMEJ3.mjs} +7 -6
- package/dist/js/chunks/chunk-RUDYMEJ3.mjs.map +7 -0
- package/dist/js/chunks/chunk-STJR62SU.mjs +161 -0
- package/dist/js/chunks/chunk-STJR62SU.mjs.map +7 -0
- package/dist/js/chunks/chunk-SUSD4UTN.mjs +220 -0
- package/dist/js/chunks/chunk-SUSD4UTN.mjs.map +7 -0
- package/dist/js/chunks/{chunk-5CEAOLUA.mjs → chunk-SYBOA5HC.mjs} +26 -48
- package/dist/js/chunks/chunk-SYBOA5HC.mjs.map +7 -0
- package/dist/js/chunks/chunk-T4MOBP3J.mjs +108 -0
- package/dist/js/chunks/chunk-T4MOBP3J.mjs.map +7 -0
- package/dist/js/chunks/chunk-TM7HPGTV.mjs +342 -0
- package/dist/js/chunks/chunk-TM7HPGTV.mjs.map +7 -0
- package/dist/js/chunks/{chunk-C6CHEWYP.mjs → chunk-TMQDZSDC.mjs} +71 -35
- package/dist/js/chunks/chunk-TMQDZSDC.mjs.map +7 -0
- package/dist/js/chunks/chunk-TVSX5YA2.mjs +48 -0
- package/dist/js/chunks/chunk-TVSX5YA2.mjs.map +7 -0
- package/dist/js/chunks/chunk-UHO5CV6K.mjs +80 -0
- package/dist/js/chunks/chunk-UHO5CV6K.mjs.map +7 -0
- package/dist/js/chunks/chunk-UKCNELUN.mjs +223 -0
- package/dist/js/chunks/chunk-UKCNELUN.mjs.map +7 -0
- package/dist/js/chunks/chunk-UKQK5GWR.mjs +167 -0
- package/dist/js/chunks/chunk-UKQK5GWR.mjs.map +7 -0
- package/dist/js/chunks/{chunk-TSZYSW7F.mjs → chunk-UTSLYQ65.mjs} +21 -48
- package/dist/js/chunks/chunk-UTSLYQ65.mjs.map +7 -0
- package/dist/js/chunks/chunk-VS5OJBOD.mjs +108 -0
- package/dist/js/chunks/chunk-VS5OJBOD.mjs.map +7 -0
- package/dist/js/chunks/chunk-VZMROW5A.mjs +759 -0
- package/dist/js/chunks/chunk-VZMROW5A.mjs.map +7 -0
- package/dist/js/chunks/chunk-W6FAL3TI.mjs +38 -0
- package/dist/js/chunks/chunk-W6FAL3TI.mjs.map +7 -0
- package/dist/js/chunks/chunk-XB6Y7P5W.mjs +69 -0
- package/dist/js/chunks/chunk-XB6Y7P5W.mjs.map +7 -0
- package/dist/js/chunks/chunk-XDAMOMVD.mjs +226 -0
- package/dist/js/chunks/chunk-XDAMOMVD.mjs.map +7 -0
- package/dist/js/chunks/{chunk-WDK4T63U.mjs → chunk-XJPMW5SP.mjs} +247 -172
- package/dist/js/chunks/chunk-XJPMW5SP.mjs.map +7 -0
- package/dist/js/chunks/{chunk-KUFHW3DS.mjs → chunk-YKANQILZ.mjs} +16 -21
- package/dist/js/chunks/chunk-YKANQILZ.mjs.map +7 -0
- package/dist/js/chunks/chunk-YLZOJLDI.mjs +175 -0
- package/dist/js/chunks/chunk-YLZOJLDI.mjs.map +7 -0
- package/dist/js/chunks/chunk-ZK7YY322.mjs +514 -0
- package/dist/js/chunks/chunk-ZK7YY322.mjs.map +7 -0
- package/dist/js/expressive.cjs +10266 -3628
- package/dist/js/expressive.cjs.map +4 -4
- package/dist/js/expressive.js +10266 -3628
- package/dist/js/expressive.js.map +4 -4
- package/dist/js/expressive.min.js +23 -22
- package/dist/js/expressive.min.js.map +4 -4
- package/dist/js/expressive.mjs +181 -69
- package/dist/js/expressive.mjs.map +2 -2
- package/dist/js/internal/behaviors/bottomSheets.mjs +4 -3
- package/dist/js/internal/behaviors/copy.mjs +9 -0
- package/dist/js/internal/behaviors/copy.mjs.map +7 -0
- package/dist/js/internal/behaviors/dataTables.mjs +8 -0
- package/dist/js/internal/behaviors/dataTables.mjs.map +7 -0
- package/dist/js/internal/behaviors/dialogs.mjs +2 -2
- package/dist/js/internal/behaviors/forms.mjs +2 -2
- package/dist/js/internal/behaviors/imageCompare.mjs +8 -0
- package/dist/js/internal/behaviors/imageCompare.mjs.map +7 -0
- package/dist/js/internal/behaviors/lists.mjs +8 -0
- package/dist/js/internal/behaviors/lists.mjs.map +7 -0
- package/dist/js/internal/behaviors/paneResize.mjs +8 -0
- package/dist/js/internal/behaviors/paneResize.mjs.map +7 -0
- package/dist/js/internal/behaviors/sheetDrag.mjs +7 -2
- package/dist/js/internal/behaviors/sideSheets.mjs +4 -3
- package/dist/js/internal/behaviors/sortable.mjs +8 -0
- package/dist/js/internal/behaviors/sortable.mjs.map +7 -0
- package/dist/js/internal/behaviors/theme.mjs +8 -0
- package/dist/js/internal/behaviors/theme.mjs.map +7 -0
- package/dist/js/internal/behaviors/tour.mjs +8 -0
- package/dist/js/internal/behaviors/tour.mjs.map +7 -0
- package/dist/js/internal/behaviors/transferList.mjs +8 -0
- package/dist/js/internal/behaviors/transferList.mjs.map +7 -0
- package/dist/js/internal/components/appBar.mjs +3 -2
- package/dist/js/internal/components/autocomplete.mjs +5 -4
- package/dist/js/internal/components/backToTop.mjs +9 -0
- package/dist/js/internal/components/backToTop.mjs.map +7 -0
- package/dist/js/internal/components/barChart.mjs +5 -4
- package/dist/js/internal/components/buttonGroup.mjs +3 -2
- package/dist/js/internal/components/buttons.mjs +3 -3
- package/dist/js/internal/components/cards.mjs +3 -3
- package/dist/js/internal/components/carousel.mjs +3 -3
- package/dist/js/internal/components/cascader.mjs +10 -0
- package/dist/js/internal/components/cascader.mjs.map +7 -0
- package/dist/js/internal/components/characterCounter.mjs +3 -2
- package/dist/js/internal/components/chips.mjs +7 -5
- package/dist/js/internal/components/colorPicker.mjs +9 -0
- package/dist/js/internal/components/colorPicker.mjs.map +7 -0
- package/dist/js/internal/components/columnChart.mjs +4 -3
- package/dist/js/internal/components/commandPalette.mjs +3 -3
- package/dist/js/internal/components/confetti.mjs +3 -2
- package/dist/js/internal/components/currencyInput.mjs +9 -0
- package/dist/js/internal/components/currencyInput.mjs.map +7 -0
- package/dist/js/internal/components/datepicker.mjs +12 -8
- package/dist/js/internal/components/expandingCard.mjs +3 -3
- package/dist/js/internal/components/funnelChart.mjs +10 -0
- package/dist/js/internal/components/funnelChart.mjs.map +7 -0
- package/dist/js/internal/components/heatmapChart.mjs +4 -3
- package/dist/js/internal/components/hoverCard.mjs +9 -0
- package/dist/js/internal/components/hoverCard.mjs.map +7 -0
- package/dist/js/internal/components/index.mjs +131 -65
- package/dist/js/internal/components/inputMask.mjs +9 -0
- package/dist/js/internal/components/inputMask.mjs.map +7 -0
- package/dist/js/internal/components/keypad.mjs +3 -3
- package/dist/js/internal/components/lightbox.mjs +3 -3
- package/dist/js/internal/components/lineChart.mjs +41 -4
- package/dist/js/internal/components/loadingOverlay.mjs +9 -0
- package/dist/js/internal/components/loadingOverlay.mjs.map +7 -0
- package/dist/js/internal/components/mapView.mjs +3 -3
- package/dist/js/internal/components/menu.mjs +3 -3
- package/dist/js/internal/components/menubar.mjs +10 -0
- package/dist/js/internal/components/menubar.mjs.map +7 -0
- package/dist/js/internal/components/messageScroller.mjs +3 -3
- package/dist/js/internal/components/mixedChart.mjs +5 -4
- package/dist/js/internal/components/navigationRail.mjs +3 -2
- package/dist/js/internal/components/particles.mjs +3 -2
- package/dist/js/internal/components/pieChart.mjs +4 -3
- package/dist/js/internal/components/pullToRefresh.mjs +9 -0
- package/dist/js/internal/components/pullToRefresh.mjs.map +7 -0
- package/dist/js/internal/components/questionnaire.mjs +3 -3
- package/dist/js/internal/components/radarChart.mjs +4 -3
- package/dist/js/internal/components/radialChart.mjs +4 -3
- package/dist/js/internal/components/registry.mjs +60 -41
- package/dist/js/internal/components/richTextEditor.mjs +3 -3
- package/dist/js/internal/components/sankeyChart.mjs +10 -0
- package/dist/js/internal/components/sankeyChart.mjs.map +7 -0
- package/dist/js/internal/components/scatterChart.mjs +10 -0
- package/dist/js/internal/components/scatterChart.mjs.map +7 -0
- package/dist/js/internal/components/scrollspy.mjs +3 -2
- package/dist/js/internal/components/select.mjs +5 -4
- package/dist/js/internal/components/showMore.mjs +9 -0
- package/dist/js/internal/components/showMore.mjs.map +7 -0
- package/dist/js/internal/components/slider.mjs +3 -3
- package/dist/js/internal/components/snackbar.mjs +2 -2
- package/dist/js/internal/components/swipeActions.mjs +9 -0
- package/dist/js/internal/components/swipeActions.mjs.map +7 -0
- package/dist/js/internal/components/tabs.mjs +3 -4
- package/dist/js/internal/components/timepicker.mjs +5 -4
- package/dist/js/internal/components/tooltip.mjs +3 -3
- package/dist/js/internal/components/treeSelect.mjs +14 -0
- package/dist/js/internal/components/treeSelect.mjs.map +7 -0
- package/dist/js/internal/components/treemapChart.mjs +10 -0
- package/dist/js/internal/components/treemapChart.mjs.map +7 -0
- package/dist/js/internal/core/component.mjs +6 -3
- package/dist/js/internal/core/formControl.mjs +12 -0
- package/dist/js/internal/core/formControl.mjs.map +7 -0
- package/dist/js/internal/core/imageURL.mjs +7 -0
- package/dist/js/internal/core/imageURL.mjs.map +7 -0
- package/dist/js/internal/core/spring.mjs +11 -0
- package/dist/js/internal/core/spring.mjs.map +7 -0
- package/dist/js/internal/core/utils.mjs +21 -3
- package/dist/js/internal/plugins/dockedDisplayPlugin.mjs +2 -2
- package/dist/js/internal/plugins/modalDisplayPlugin.mjs +13 -0
- package/dist/js/internal/plugins/modalDisplayPlugin.mjs.map +7 -0
- package/dist/js/modular.mjs +172 -69
- package/dist/types/behaviors/bottomSheets.d.ts +23 -5
- package/dist/types/behaviors/copy.d.ts +18 -0
- package/dist/types/behaviors/dataTables.d.ts +125 -0
- package/dist/types/behaviors/dialogs.d.ts +27 -1
- package/dist/types/behaviors/forms.d.ts +70 -4
- package/dist/types/behaviors/imageCompare.d.ts +13 -0
- package/dist/types/behaviors/lists.d.ts +12 -0
- package/dist/types/behaviors/paneResize.d.ts +29 -0
- package/dist/types/behaviors/sheetDrag.d.ts +18 -0
- package/dist/types/behaviors/sideSheets.d.ts +1 -1
- package/dist/types/behaviors/sortable.d.ts +28 -0
- package/dist/types/behaviors/theme.d.ts +22 -0
- package/dist/types/behaviors/tour.d.ts +36 -0
- package/dist/types/behaviors/transferList.d.ts +53 -0
- package/dist/types/components/appBar.d.ts +5 -6
- package/dist/types/components/autocomplete.d.ts +105 -20
- package/dist/types/components/backToTop.d.ts +36 -0
- package/dist/types/components/barChart.d.ts +3 -6
- package/dist/types/components/buttonGroup.d.ts +2 -4
- package/dist/types/components/buttons.d.ts +5 -5
- package/dist/types/components/cards.d.ts +3 -16
- package/dist/types/components/carousel.d.ts +16 -15
- package/dist/types/components/cascader.d.ts +130 -0
- package/dist/types/components/characterCounter.d.ts +2 -15
- package/dist/types/components/chips.d.ts +80 -19
- package/dist/types/components/colorPicker.d.ts +56 -0
- package/dist/types/components/columnChart.d.ts +23 -10
- package/dist/types/components/commandPalette.d.ts +11 -16
- package/dist/types/components/confetti.d.ts +2 -4
- package/dist/types/components/currencyInput.d.ts +60 -0
- package/dist/types/components/datepicker.d.ts +107 -56
- package/dist/types/components/expandingCard.d.ts +4 -6
- package/dist/types/components/funnelChart.d.ts +35 -0
- package/dist/types/components/heatmapChart.d.ts +42 -8
- package/dist/types/components/hoverCard.d.ts +59 -0
- package/dist/types/components/index.d.ts +16 -1
- package/dist/types/components/inputMask.d.ts +28 -0
- package/dist/types/components/keypad.d.ts +38 -6
- package/dist/types/components/lightbox.d.ts +14 -20
- package/dist/types/components/lineChart.d.ts +212 -12
- package/dist/types/components/loadingOverlay.d.ts +42 -0
- package/dist/types/components/mapView.d.ts +138 -27
- package/dist/types/components/menu.d.ts +74 -22
- package/dist/types/components/menubar.d.ts +37 -0
- package/dist/types/components/messageScroller.d.ts +2 -14
- package/dist/types/components/mixedChart.d.ts +15 -6
- package/dist/types/components/navigationRail.d.ts +16 -5
- package/dist/types/components/particles.d.ts +22 -5
- package/dist/types/components/pieChart.d.ts +33 -9
- package/dist/types/components/pullToRefresh.d.ts +80 -0
- package/dist/types/components/questionnaire.d.ts +58 -16
- package/dist/types/components/radarChart.d.ts +10 -6
- package/dist/types/components/radialChart.d.ts +58 -7
- package/dist/types/components/registry.d.ts +73 -3
- package/dist/types/components/richTextEditor.d.ts +45 -22
- package/dist/types/components/sankeyChart.d.ts +72 -0
- package/dist/types/components/scatterChart.d.ts +102 -0
- package/dist/types/components/scrollspy.d.ts +3 -5
- package/dist/types/components/select.d.ts +44 -33
- package/dist/types/components/showMore.d.ts +53 -0
- package/dist/types/components/slider.d.ts +2 -15
- package/dist/types/components/snackbar.d.ts +68 -1
- package/dist/types/components/swipeActions.d.ts +81 -0
- package/dist/types/components/tabs.d.ts +92 -30
- package/dist/types/components/timepicker.d.ts +128 -27
- package/dist/types/components/tooltip.d.ts +57 -21
- package/dist/types/components/treeSelect.d.ts +106 -0
- package/dist/types/components/treemapChart.d.ts +56 -0
- package/dist/types/core/component.d.ts +49 -25
- package/dist/types/core/formControl.d.ts +21 -0
- package/dist/types/core/imageURL.d.ts +2 -0
- package/dist/types/core/spring.d.ts +20 -0
- package/dist/types/core/utils.d.ts +123 -72
- package/dist/types/modular.d.ts +33 -1
- package/dist/types/plugins/dockedDisplayPlugin.d.ts +10 -8
- package/dist/types/plugins/modalDisplayPlugin.d.ts +39 -0
- package/package.json +17 -13
- package/src/sass/README.md +27 -18
- package/src/sass/abstracts/_elevation.scss +13 -7
- package/src/sass/abstracts/_index.scss +1 -0
- package/src/sass/abstracts/_mixins.scss +864 -78
- package/src/sass/abstracts/_spring.scss +63 -0
- package/src/sass/abstracts/_variables.scss +64 -21
- package/src/sass/base/_fonts.scss +61 -48
- package/src/sass/base/_global.scss +104 -24
- package/src/sass/base/_index.scss +2 -0
- package/src/sass/base/_normalize.scss +59 -114
- package/src/sass/base/_print.scss +21 -0
- package/src/sass/base/_prose.scss +68 -0
- package/src/sass/base/_typography.scss +9 -5
- package/src/sass/components/_accordion.scss +10 -19
- package/src/sass/components/_alert.scss +102 -0
- package/src/sass/components/_aura.scss +9 -3
- package/src/sass/components/_avatar.scss +3 -3
- package/src/sass/components/_back-to-top.scss +38 -0
- package/src/sass/components/_badges.scss +6 -5
- package/src/sass/components/_bar-chart.scss +31 -90
- package/src/sass/components/_bottom-sheet.scss +51 -16
- package/src/sass/components/_breadcrumb.scss +8 -7
- package/src/sass/components/_button-groups.scss +30 -63
- package/src/sass/components/_buttons.scss +137 -94
- package/src/sass/components/_calendar.scss +244 -0
- package/src/sass/components/_cards.scss +36 -44
- package/src/sass/components/_carousel.scss +37 -113
- package/src/sass/components/_cascader.scss +131 -0
- package/src/sass/components/_chips.scss +36 -46
- package/src/sass/components/_column-chart.scss +15 -26
- package/src/sass/components/_command-palette.scss +4 -7
- package/src/sass/components/_confetti.scss +1 -4
- package/src/sass/components/_countdown.scss +1 -1
- package/src/sass/components/_data-table.scss +172 -25
- package/src/sass/components/_datepicker.scss +54 -40
- package/src/sass/components/_description-list.scss +85 -0
- package/src/sass/components/_dialog.scss +48 -55
- package/src/sass/components/_docked-display.scss +1 -3
- package/src/sass/components/_drag-handle.scss +16 -20
- package/src/sass/components/_expanding-card.scss +21 -14
- package/src/sass/components/_fab-menu.scss +43 -39
- package/src/sass/components/_funnel-chart.scss +63 -0
- package/src/sass/components/_heatmap-chart.scss +114 -29
- package/src/sass/components/_icon-buttons.scss +8 -11
- package/src/sass/components/_icons-material-design.scss +2 -2
- package/src/sass/components/_image-compare.scss +108 -0
- package/src/sass/components/_index.scss +20 -0
- package/src/sass/components/_keypad.scss +39 -19
- package/src/sass/components/_kpi.scss +6 -11
- package/src/sass/components/_lightbox.scss +24 -13
- package/src/sass/components/_line-chart.scss +9 -63
- package/src/sass/components/_list.scss +59 -14
- package/src/sass/components/_loading-indicator.scss +1 -0
- package/src/sass/components/_loading-overlay.scss +105 -0
- package/src/sass/components/_map.scss +37 -11
- package/src/sass/components/_marquee.scss +4 -3
- package/src/sass/components/_mega-menu.scss +128 -0
- package/src/sass/components/_menu.scss +146 -127
- package/src/sass/components/_menubar.scss +47 -0
- package/src/sass/components/_message-scroller.scss +2 -2
- package/src/sass/components/_message.scss +3 -3
- package/src/sass/components/_mixed-chart.scss +27 -35
- package/src/sass/components/_modal-display.scss +21 -0
- package/src/sass/components/_navbar.scss +45 -36
- package/src/sass/components/_navigation-bar.scss +12 -77
- package/src/sass/components/_navigation-rail.scss +161 -92
- package/src/sass/components/_org-chart.scss +192 -0
- package/src/sass/components/_page-footer.scss +2 -4
- package/src/sass/components/_pagination.scss +9 -27
- package/src/sass/components/_panes.scss +35 -42
- package/src/sass/components/_particles.scss +1 -4
- package/src/sass/components/_pie-chart.scss +86 -68
- package/src/sass/components/_popover.scss +18 -5
- package/src/sass/components/_progress.scss +183 -44
- package/src/sass/components/_pull-to-refresh.scss +90 -0
- package/src/sass/components/_questionnaire.scss +74 -3
- package/src/sass/components/_radar-chart.scss +40 -42
- package/src/sass/components/_radial-chart.scss +108 -46
- package/src/sass/components/_rich-text-editor.scss +2 -2
- package/src/sass/components/_sankey-chart.scss +91 -0
- package/src/sass/components/_scatter-chart.scss +144 -0
- package/src/sass/components/_scrim.scss +0 -2
- package/src/sass/components/_scrollspy.scss +0 -2
- package/src/sass/components/_search.scss +27 -26
- package/src/sass/components/_show-more.scss +8 -0
- package/src/sass/components/_side-sheet.scss +32 -51
- package/src/sass/components/_skeleton.scss +26 -19
- package/src/sass/components/_snackbar.scss +25 -21
- package/src/sass/components/_split-button.scss +5 -5
- package/src/sass/components/_stat.scss +3 -8
- package/src/sass/components/_stepper.scss +1 -1
- package/src/sass/components/_swipe-actions.scss +71 -0
- package/src/sass/components/_table_of_contents.scss +1 -3
- package/src/sass/components/_tabs.scss +49 -46
- package/src/sass/components/_timeline.scss +12 -12
- package/src/sass/components/_timepicker.scss +111 -79
- package/src/sass/components/_toolbar.scss +36 -47
- package/src/sass/components/_tooltip.scss +25 -12
- package/src/sass/components/_tour.scss +89 -0
- package/src/sass/components/_transfer-list.scss +73 -0
- package/src/sass/components/_transitions.scss +4 -4
- package/src/sass/components/_tree.scss +7 -32
- package/src/sass/components/_treemap-chart.scss +98 -0
- package/src/sass/components/forms/_checkboxes.scss +107 -44
- package/src/sass/components/forms/_color-picker.scss +135 -0
- package/src/sass/components/forms/_color-swatches.scss +85 -0
- package/src/sass/components/forms/_drop-zone.scss +16 -13
- package/src/sass/components/forms/_fieldset.scss +4 -7
- package/src/sass/components/forms/_file-input.scss +12 -8
- package/src/sass/components/forms/_index.scss +3 -1
- package/src/sass/components/forms/_input-fields.scss +271 -90
- package/src/sass/components/forms/_radio-buttons.scss +34 -117
- package/src/sass/components/forms/_rating.scss +2 -32
- package/src/sass/components/forms/_select.scss +198 -20
- package/src/sass/components/forms/_slider.scss +92 -98
- package/src/sass/components/forms/_switches.scss +62 -180
- package/src/sass/custom.scss +10 -1
- package/src/sass/expressive.scss +3 -63
- package/src/sass/tokens/_contrast.scss +94 -0
- package/src/sass/tokens/_elevation.scss +16 -0
- package/src/sass/tokens/_index.scss +5 -0
- package/src/sass/tokens/_motion.scss +109 -0
- package/src/sass/tokens/_reference.scss +72 -141
- package/src/sass/tokens/_shape.scss +38 -0
- package/src/sass/tokens/_stacking.scss +27 -0
- package/src/sass/tokens/_state.scss +0 -2
- package/src/sass/tokens/_theme.scss +10 -1
- package/src/sass/tokens/_vibrant.scss +2 -5
- package/src/sass/utilities/_defer-render.scss +17 -0
- package/src/sass/utilities/_helpers.scss +184 -27
- package/src/sass/utilities/_index.scss +1 -0
- package/src/sass/utilities/_scroll-area.scss +0 -2
- package/src/sass/utilities/_spacing.scss +52 -34
- package/src/sass/utilities/_typescale.scss +8 -1
- package/src/sass/utilities/_visibility.scss +46 -77
- package/src/sass/utilities/_z-depth.scss +7 -4
- package/dist/js/chunks/chunk-33QVDDGR.mjs +0 -270
- package/dist/js/chunks/chunk-33QVDDGR.mjs.map +0 -7
- package/dist/js/chunks/chunk-45FER6RI.mjs +0 -59
- package/dist/js/chunks/chunk-45FER6RI.mjs.map +0 -7
- package/dist/js/chunks/chunk-5CEAOLUA.mjs.map +0 -7
- package/dist/js/chunks/chunk-6VATUZC6.mjs +0 -295
- package/dist/js/chunks/chunk-6VATUZC6.mjs.map +0 -7
- package/dist/js/chunks/chunk-74MXKKLN.mjs.map +0 -7
- package/dist/js/chunks/chunk-AIURVCG6.mjs +0 -55
- package/dist/js/chunks/chunk-AIURVCG6.mjs.map +0 -7
- package/dist/js/chunks/chunk-BGZLF6JZ.mjs.map +0 -7
- package/dist/js/chunks/chunk-C6CHEWYP.mjs.map +0 -7
- package/dist/js/chunks/chunk-CK2XCICY.mjs.map +0 -7
- package/dist/js/chunks/chunk-CXXM2L4F.mjs +0 -344
- package/dist/js/chunks/chunk-CXXM2L4F.mjs.map +0 -7
- package/dist/js/chunks/chunk-DXGRXYYL.mjs.map +0 -7
- package/dist/js/chunks/chunk-FM5CZOUB.mjs.map +0 -7
- package/dist/js/chunks/chunk-GJL6GCIU.mjs.map +0 -7
- package/dist/js/chunks/chunk-K3HZMFMD.mjs +0 -135
- package/dist/js/chunks/chunk-K3HZMFMD.mjs.map +0 -7
- package/dist/js/chunks/chunk-KHXZ2A4K.mjs.map +0 -7
- package/dist/js/chunks/chunk-KQACNQ22.mjs +0 -7
- package/dist/js/chunks/chunk-KQACNQ22.mjs.map +0 -7
- package/dist/js/chunks/chunk-KUFHW3DS.mjs.map +0 -7
- package/dist/js/chunks/chunk-KVJAVDBC.mjs.map +0 -7
- package/dist/js/chunks/chunk-L27Q6ZMI.mjs.map +0 -7
- package/dist/js/chunks/chunk-LQWUDNHZ.mjs.map +0 -7
- package/dist/js/chunks/chunk-M372EDXD.mjs +0 -322
- package/dist/js/chunks/chunk-M372EDXD.mjs.map +0 -7
- package/dist/js/chunks/chunk-M3MURWMB.mjs +0 -82
- package/dist/js/chunks/chunk-M3MURWMB.mjs.map +0 -7
- package/dist/js/chunks/chunk-NUHMOAOY.mjs.map +0 -7
- package/dist/js/chunks/chunk-OWG3LMUL.mjs +0 -169
- package/dist/js/chunks/chunk-OWG3LMUL.mjs.map +0 -7
- package/dist/js/chunks/chunk-PD6HYHAE.mjs +0 -48
- package/dist/js/chunks/chunk-PD6HYHAE.mjs.map +0 -7
- package/dist/js/chunks/chunk-PDG64UHF.mjs.map +0 -7
- package/dist/js/chunks/chunk-PO3AXVR3.mjs +0 -546
- package/dist/js/chunks/chunk-PO3AXVR3.mjs.map +0 -7
- package/dist/js/chunks/chunk-QYGK36OG.mjs +0 -181
- package/dist/js/chunks/chunk-QYGK36OG.mjs.map +0 -7
- package/dist/js/chunks/chunk-SFI2U4YW.mjs.map +0 -7
- package/dist/js/chunks/chunk-SMY7GJSS.mjs.map +0 -7
- package/dist/js/chunks/chunk-TCCA2HDG.mjs +0 -414
- package/dist/js/chunks/chunk-TCCA2HDG.mjs.map +0 -7
- package/dist/js/chunks/chunk-TSZYSW7F.mjs.map +0 -7
- package/dist/js/chunks/chunk-UAZSDUVP.mjs +0 -90
- package/dist/js/chunks/chunk-UAZSDUVP.mjs.map +0 -7
- package/dist/js/chunks/chunk-UBRZZWRA.mjs +0 -127
- package/dist/js/chunks/chunk-UBRZZWRA.mjs.map +0 -7
- package/dist/js/chunks/chunk-UCOE7ZDL.mjs +0 -287
- package/dist/js/chunks/chunk-UCOE7ZDL.mjs.map +0 -7
- package/dist/js/chunks/chunk-UETTGDLI.mjs.map +0 -7
- package/dist/js/chunks/chunk-UNCRDLP6.mjs +0 -136
- package/dist/js/chunks/chunk-UNCRDLP6.mjs.map +0 -7
- package/dist/js/chunks/chunk-VGNYF6FB.mjs.map +0 -7
- package/dist/js/chunks/chunk-VGPGBNGL.mjs +0 -68
- package/dist/js/chunks/chunk-VGPGBNGL.mjs.map +0 -7
- package/dist/js/chunks/chunk-VKAUVTQY.mjs +0 -1
- package/dist/js/chunks/chunk-VM4FTS7L.mjs +0 -48
- package/dist/js/chunks/chunk-VM4FTS7L.mjs.map +0 -7
- package/dist/js/chunks/chunk-WDK4T63U.mjs.map +0 -7
- package/dist/js/chunks/chunk-WOCCTVUF.mjs +0 -185
- package/dist/js/chunks/chunk-WOCCTVUF.mjs.map +0 -7
- package/dist/js/chunks/chunk-WQYN5L4E.mjs +0 -107
- package/dist/js/chunks/chunk-WQYN5L4E.mjs.map +0 -7
- package/dist/js/chunks/chunk-X4ISMKE2.mjs.map +0 -7
- package/dist/js/chunks/chunk-XAEAEHIX.mjs.map +0 -7
- package/dist/js/chunks/chunk-ZX6M7SWO.mjs.map +0 -7
- /package/dist/js/chunks/{chunk-VKAUVTQY.mjs.map → chunk-GNRSYMVH.mjs.map} +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/ts/components/commandPalette.ts"],
|
|
4
|
+
"sourcesContent": ["import { Utils } from '../core/utils';\nimport { Component, BaseOptions } from '../core/component';\n\nexport interface CommandPaletteOptions extends BaseOptions {\n /**\n * Letter that toggles the palette together with Command on Apple platforms\n * or Ctrl elsewhere. A key event the page has already handled is left\n * alone. `null` turns the shortcut off. `data-shortcut` on the dialog sets\n * it; an empty `data-shortcut` turns it off.\n * @default 'k'\n */\n shortcut: string | null;\n /**\n * If true, the palette closes after a command runs.\n * @default true\n */\n closeOnRun: boolean;\n}\n\nconst _defaults: CommandPaletteOptions = {\n shortcut: 'k',\n closeOnRun: true\n};\n\n// On Apple platforms Ctrl+letter is text editing (Ctrl+K deletes to the end\n// of the line), so only Command opens the palette there.\nconst APPLE = typeof navigator !== 'undefined' && /Mac|iPhone|iPad|iPod/.test(navigator.platform);\n\n/** Whether the platform's shortcut modifier is held, and not the other one. */\nconst commandKey = (e: KeyboardEvent) => (APPLE ? e.metaKey && !e.ctrlKey : e.ctrlKey && !e.metaKey);\n\n/**\n * Whether a key event is `letter`. A non-Latin layout reports its own letter\n * in e.key, so that falls back to the physical key. A Latin layout matches on\n * the letter it types.\n */\nconst isLetter = (e: KeyboardEvent, letter: string) =>\n e.key.toLowerCase() === letter || (!/^[a-z]$/i.test(e.key) && /^[a-z]$/.test(letter) && e.code === `Key${letter.toUpperCase()}`);\n\n/** How the arrows move the active command. */\nconst MOVE_KEYS: Record<string, number> = { ArrowDown: 1, ArrowUp: -1 };\n\n/** Case- and accent-insensitive text for matching. */\nconst fold = (text: string) =>\n text.normalize('NFD').replace(/\\p{Diacritic}/gu, '').toLowerCase();\n\n/**\n * A command palette: a native modal <dialog class=\"command-palette\"> holding\n * a search input and a list of commands. Typing filters the list; the arrow\n * keys move through what is left and Enter runs it, while focus stays in the\n * input. The dialog owns modality, Escape and returning focus.\n *\n * The input is a combobox and the list a listbox of options, with the active\n * option reported through aria-activedescendant. A command is the link or\n * button inside an option; running it clicks that element, so a page wires\n * commands with ordinary hrefs and click handlers.\n */\nexport class CommandPalette extends Component<CommandPaletteOptions> {\n declare el: HTMLDialogElement;\n /** The search input. */\n input: HTMLInputElement;\n /** The list of commands. */\n list: HTMLElement;\n private _active: HTMLElement | null = null;\n private _generatedIds: HTMLElement[] = [];\n /** Wires and refilters commands the page adds or removes later. */\n private _observer: MutationObserver | null = null;\n\n // HTMLElement, not HTMLDialogElement: init() takes the element type from\n // here, and has always accepted any HTMLElement.\n constructor(el: HTMLElement, options: Partial<CommandPaletteOptions>) {\n const shortcut = el.dataset.shortcut;\n super(el, { ...(shortcut !== undefined ? { shortcut: shortcut || null } : {}), ...options });\n this.input = el.querySelector(':scope > input');\n this.list = el.querySelector(':scope > :is(ul, ol)');\n if (!this.input || !this.list) {\n console.error('CommandPalette needs an <input> and a <ul> as children of the dialog.');\n return;\n }\n this._setupAccessibility();\n this._filter();\n // A page adding commands while the user arrows through the list keeps\n // their place.\n this._observer = new MutationObserver(() => this._filter(true));\n // Also refilter when the page hides, shows, disables or enables a command.\n // Not aria-disabled: _filter writes that itself, which would loop.\n this._observer.observe(this.list, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['hidden', 'disabled']\n });\n const { signal } = this._events;\n this.input.addEventListener('input', this._handleInput, { signal });\n this.input.addEventListener('keydown', this._handleKeydown, { signal });\n this.input.addEventListener('keydown', this._handleEscape, { signal });\n this.list.addEventListener('click', this._handleListClick, { signal });\n this.list.addEventListener('pointermove', this._handlePointerMove, { signal });\n this.el.addEventListener('close', this._handleClose, { signal });\n document.addEventListener('keydown', this._handleShortcut, { signal });\n }\n\n static get defaults(): CommandPaletteOptions {\n return _defaults;\n }\n\n static key = 'Expressive_CommandPalette';\n\n /** If the palette is open. */\n get isOpen() {\n return this.el.open;\n }\n\n /** Opens the palette as a modal dialog with the search input focused. */\n open = () => {\n if (!this.el.open) this.el.showModal();\n this.input?.focus();\n };\n\n /** Closes the palette. The dialog returns focus to where it was. */\n close = () => {\n if (this.el.open) this.el.close();\n };\n\n destroy() {\n this._observer?.disconnect();\n if (this.input && this.list) {\n for (const name of ['role', 'aria-controls', 'aria-expanded', 'aria-autocomplete', 'aria-activedescendant']) {\n this.input.removeAttribute(name);\n }\n this.list.removeAttribute('role');\n for (const item of this._items()) {\n for (const name of ['role', 'aria-selected', 'aria-disabled', 'data-filtered']) item.removeAttribute(name);\n item.classList.remove('active');\n this._action(item)?.removeAttribute('tabindex');\n }\n for (const label of this._labels()) {\n label.removeAttribute('role');\n label.removeAttribute('data-filtered');\n }\n for (const el of this._generatedIds) el.removeAttribute('id');\n const empty = this._empty();\n if (empty) empty.hidden = false;\n }\n super.destroy();\n }\n\n private _items() {\n return Array.from(this.list.children).filter(\n (child): child is HTMLElement => child instanceof HTMLElement && !child.classList.contains('label')\n );\n }\n\n private _labels() {\n return Array.from(this.list.querySelectorAll<HTMLElement>(':scope > .label'));\n }\n\n private _empty() {\n return this.el.querySelector<HTMLElement>(':scope > .command-palette-empty');\n }\n\n private _action(item: HTMLElement) {\n return item.querySelector<HTMLElement>(':scope > :is(a[href], button)');\n }\n\n private _ensureId(el: HTMLElement, prefix: string) {\n if (!el.id) {\n el.id = `${prefix}-${Utils.guid()}`;\n this._generatedIds.push(el);\n }\n return el.id;\n }\n\n private _setupAccessibility() {\n this.list.setAttribute('role', 'listbox');\n this.input.setAttribute('role', 'combobox');\n this.input.setAttribute('aria-controls', this._ensureId(this.list, 'command-palette-list'));\n this.input.setAttribute('aria-expanded', 'true');\n this.input.setAttribute('aria-autocomplete', 'list');\n }\n\n /** Every command, including ones added since the last pass, is an option. */\n private _wireItems() {\n for (const item of this._items()) {\n if (item.getAttribute('role') === 'option') continue;\n item.setAttribute('role', 'option');\n this._ensureId(item, 'command-palette-option');\n // Focus stays in the input; the commands are reached with the arrows.\n this._action(item)?.setAttribute('tabindex', '-1');\n }\n // A listbox holds only options; a group heading is a visual divider.\n for (const label of this._labels()) label.setAttribute('role', 'none');\n }\n\n /** Commands on screen: neither hidden by the page nor filtered out. */\n private _shown() {\n return this._items().filter((item) => !item.hidden && !item.hasAttribute('data-filtered'));\n }\n\n /** Shown commands the arrows and Enter can reach: disabled ones are skipped. */\n private _visible() {\n return this._shown().filter((item) => item.getAttribute('aria-disabled') !== 'true');\n }\n\n /** A disabled link or button cannot run, so its option says so. */\n private _isDisabled(item: HTMLElement) {\n const action = this._action(item);\n return !!action && (action.matches(':disabled') || action.getAttribute('aria-disabled') === 'true');\n }\n\n private _setActive(item: HTMLElement | null) {\n if (this._active === item) return;\n this._active?.classList.remove('active');\n this._active?.removeAttribute('aria-selected');\n this._active = item;\n if (item) {\n item.classList.add('active');\n item.setAttribute('aria-selected', 'true');\n this.input.setAttribute('aria-activedescendant', item.id);\n item.scrollIntoView({ block: 'nearest' });\n } else {\n this.input.removeAttribute('aria-activedescendant');\n }\n }\n\n /**\n * Shows the commands matching the query. Filtering marks rows with\n * data-filtered rather than hidden, so a command the page hides stays\n * hidden. `keepActive` holds the active command while it is still\n * reachable, for list changes the user did not make.\n */\n private _filter(keepActive = false) {\n this._wireItems();\n const terms = fold(this.input.value).split(/\\s+/).filter(Boolean);\n for (const item of this._items()) {\n // data-keywords may sit on the row or on its link or button.\n const keywords = item.dataset.keywords ?? this._action(item)?.dataset.keywords ?? '';\n const text = fold(`${item.textContent} ${keywords}`);\n item.toggleAttribute('data-filtered', !terms.every((term) => text.includes(term)));\n if (this._isDisabled(item)) item.setAttribute('aria-disabled', 'true');\n else item.removeAttribute('aria-disabled');\n }\n // A heading stays only while one of the commands under it does.\n for (const label of this._labels()) {\n let next = label.nextElementSibling as HTMLElement | null;\n let any = false;\n while (next && !next.classList.contains('label')) {\n if (!next.hidden && !next.hasAttribute('data-filtered')) any = true;\n next = next.nextElementSibling as HTMLElement | null;\n }\n label.toggleAttribute('data-filtered', !any);\n }\n const visible = this._visible();\n const empty = this._empty();\n if (empty) empty.hidden = this._shown().length > 0;\n this._setActive(keepActive && visible.includes(this._active) ? this._active : visible[0] ?? null);\n }\n\n private _move(step: number) {\n const visible = this._visible();\n if (!visible.length) return;\n const index = visible.indexOf(this._active);\n this._setActive(visible[(index + step + visible.length) % visible.length]);\n }\n\n /** Runs a command by clicking its link or button; the click handler closes. */\n private _run(item: HTMLElement) {\n (this._action(item) ?? item).click();\n }\n\n _handleInput = () => this._filter();\n\n _handleKeydown = Utils.ignoringComposition((e: KeyboardEvent) => {\n const step = Utils.plainKey(e) ? MOVE_KEYS[e.key] : undefined;\n if (step) {\n e.preventDefault();\n this._move(step);\n } else if (e.key === 'Enter' && this._active) {\n e.preventDefault();\n this._run(this._active);\n }\n });\n\n /**\n * The first Escape clears a typed query and the next closes the palette.\n * Chromium and Firefox clear a search input on their own; WebKit closed at\n * once, and so did every engine for a text input. Escape that cancels an\n * IME composition is left to the IME.\n */\n _handleEscape = (e: KeyboardEvent) => {\n if (e.key !== 'Escape' || !this.input.value || Utils.isComposing(e)) return;\n e.preventDefault();\n this.input.value = '';\n this.input.dispatchEvent(new Event('input', { bubbles: true }));\n };\n\n _handleListClick = (e: MouseEvent) => {\n const item = (<Element>e.target).closest<HTMLElement>('[role=\"option\"]');\n if (!item || !this.list.contains(item) || item.getAttribute('aria-disabled') === 'true') return;\n const action = this._action(item);\n // A click on the row's padding runs its command; that click comes back\n // through here and closes the palette.\n if (action && !action.contains(<Node>e.target)) {\n action.click();\n return;\n }\n if (this.options.closeOnRun) this.close();\n };\n\n _handlePointerMove = (e: PointerEvent) => {\n const item = (<Element>e.target).closest<HTMLElement>('[role=\"option\"]');\n if (item && this.list.contains(item) && item.getAttribute('aria-disabled') !== 'true') this._setActive(item);\n };\n\n /**\n * Each opening starts from the full list. The close event is queued, so a\n * palette reopened straight away may already be open again; its new search\n * is left alone.\n */\n _handleClose = () => {\n if (this.el.open) return;\n this.input.value = '';\n this._filter();\n };\n\n _handleShortcut = (e: KeyboardEvent) => {\n const { shortcut } = this.options;\n if (!shortcut || e.defaultPrevented || e.altKey || e.shiftKey || !commandKey(e)) return;\n if (!isLetter(e, shortcut.toLowerCase())) return;\n e.preventDefault();\n // A held shortcut stays away from the browser but toggles only once.\n if (e.repeat) return;\n if (this.el.open) this.close();\n else this.open();\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Component
|
|
3
|
+
} from "./chunk-EB2V4OKL.mjs";
|
|
4
|
+
import {
|
|
5
|
+
Utils
|
|
6
|
+
} from "./chunk-67UNY7RH.mjs";
|
|
7
|
+
|
|
8
|
+
// src/ts/components/questionnaire.ts
|
|
9
|
+
var _defaults = {
|
|
10
|
+
progressLabel: "Question {current} of {total}",
|
|
11
|
+
requiredMessage: "Choose an answer to continue.",
|
|
12
|
+
summaryLabel: "Review your answers",
|
|
13
|
+
editLabel: "Edit",
|
|
14
|
+
skippedLabel: "Not answered"
|
|
15
|
+
};
|
|
16
|
+
var NAVIGATION = ["previous", "skip", "next"];
|
|
17
|
+
var UNSAVED = ["file", "password", "hidden"];
|
|
18
|
+
var LETTERS = "abcdefghijklmnopqrstuvwxyz";
|
|
19
|
+
var isChoice = (control) => control instanceof HTMLInputElement && (control.type === "radio" || control.type === "checkbox");
|
|
20
|
+
function labelText(control) {
|
|
21
|
+
const label = control.closest("label")?.cloneNode(true);
|
|
22
|
+
label?.querySelectorAll("input, small").forEach((el) => el.remove());
|
|
23
|
+
return label?.textContent.trim() || control.value;
|
|
24
|
+
}
|
|
25
|
+
var MASKED = {
|
|
26
|
+
hidden: () => "",
|
|
27
|
+
password: (control) => control.value ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : "",
|
|
28
|
+
file: (control) => Array.from(control.files ?? [], (file) => file.name).join(", ")
|
|
29
|
+
};
|
|
30
|
+
function answerText(control) {
|
|
31
|
+
if (control instanceof HTMLSelectElement) return Array.from(control.selectedOptions, (option) => option.text).join(", ");
|
|
32
|
+
if (isChoice(control)) return control.checked ? labelText(control) : "";
|
|
33
|
+
return MASKED[control.type]?.(control) ?? control.value.trim();
|
|
34
|
+
}
|
|
35
|
+
var savedState = (control) => {
|
|
36
|
+
if (control instanceof HTMLSelectElement) return Array.from(control.selectedOptions, (option) => option.value);
|
|
37
|
+
return isChoice(control) ? control.checked : control.value;
|
|
38
|
+
};
|
|
39
|
+
var validSaved = (saved) => Array.isArray(saved?.answers) ? saved : null;
|
|
40
|
+
function restoreState(control, saved) {
|
|
41
|
+
if (control instanceof HTMLSelectElement) return restoreSelect(control, saved);
|
|
42
|
+
if (isChoice(control)) control.checked = saved === true;
|
|
43
|
+
else if (typeof saved === "string") control.value = saved;
|
|
44
|
+
}
|
|
45
|
+
function restoreSelect(select, saved) {
|
|
46
|
+
if (!Array.isArray(saved)) return;
|
|
47
|
+
for (const option of select.options) option.selected = saved.includes(option.value);
|
|
48
|
+
}
|
|
49
|
+
function restoreControl(control, saved) {
|
|
50
|
+
const before = JSON.stringify(savedState(control));
|
|
51
|
+
restoreState(control, saved);
|
|
52
|
+
if (JSON.stringify(savedState(control)) !== before) control.dispatchEvent(new Event("change", { bubbles: true }));
|
|
53
|
+
}
|
|
54
|
+
function shortcut(e) {
|
|
55
|
+
if (typingIn(e.target) || !Utils.plainKey(e)) return -1;
|
|
56
|
+
const digit = "123456789".indexOf(e.key);
|
|
57
|
+
return digit >= 0 ? digit : letterIndex(e.key);
|
|
58
|
+
}
|
|
59
|
+
var TYPING = 'textarea, select, [contenteditable], input:not([type="radio"], [type="checkbox"], [type="button"], [type="submit"], [type="reset"])';
|
|
60
|
+
var typingIn = (target) => !!target.matches?.(TYPING);
|
|
61
|
+
var letterIndex = (key) => key.length === 1 ? LETTERS.indexOf(key.toLowerCase()) : -1;
|
|
62
|
+
var Questionnaire = class extends Component {
|
|
63
|
+
// HTMLElement, not HTMLFormElement: init() takes the element type from
|
|
64
|
+
// here, and has always accepted any HTMLElement.
|
|
65
|
+
constructor(el, options) {
|
|
66
|
+
const progressLabel = el.dataset.progressLabel;
|
|
67
|
+
super(el, { ...progressLabel ? { progressLabel } : {}, ...options });
|
|
68
|
+
this._active = null;
|
|
69
|
+
this._generated = [];
|
|
70
|
+
this._generatedIds = [];
|
|
71
|
+
/** Set while one submission's invalid events arrive, so only the first opens. */
|
|
72
|
+
this._reporting = false;
|
|
73
|
+
/** With data-summary, the review step, and whether it is shown. */
|
|
74
|
+
this._summary = null;
|
|
75
|
+
this._reviewing = false;
|
|
76
|
+
/** Shows the question at `index` without checking the current one. */
|
|
77
|
+
this.goTo = (index) => {
|
|
78
|
+
const item = this.items[index];
|
|
79
|
+
if (!item) return;
|
|
80
|
+
this._active = item;
|
|
81
|
+
this._reviewing = false;
|
|
82
|
+
this._render();
|
|
83
|
+
this._save();
|
|
84
|
+
const controls = this._controls(item).filter((control) => !control.disabled);
|
|
85
|
+
(controls.find((control) => control.checked) ?? controls[0])?.focus();
|
|
86
|
+
};
|
|
87
|
+
/** Checks the shown question and moves to the next one if it is answered. */
|
|
88
|
+
this.next = () => {
|
|
89
|
+
if (this._validate(this._active)) this._advance();
|
|
90
|
+
};
|
|
91
|
+
/** Moves to the previous question, or from the review step back to the last one. */
|
|
92
|
+
this.previous = () => this.goTo(this._reviewing ? this.items.length - 1 : this.index - 1);
|
|
93
|
+
/** Shows the review step of a questionnaire with data-summary. */
|
|
94
|
+
this.review = () => {
|
|
95
|
+
if (!this._summary) return;
|
|
96
|
+
this._fillSummary(this._summary);
|
|
97
|
+
this._reviewing = true;
|
|
98
|
+
this._render();
|
|
99
|
+
this._summary.focus();
|
|
100
|
+
};
|
|
101
|
+
/** Clears the answer to the shown question and moves to the next one. */
|
|
102
|
+
this.skip = () => {
|
|
103
|
+
if (!this._active) return;
|
|
104
|
+
for (const control of this._controls(this._active)) {
|
|
105
|
+
const choice = isChoice(control);
|
|
106
|
+
if (choice ? !control.checked : !control.value) continue;
|
|
107
|
+
if (choice) control.checked = false;
|
|
108
|
+
else control.value = "";
|
|
109
|
+
control.dispatchEvent(new Event("change", { bubbles: true }));
|
|
110
|
+
}
|
|
111
|
+
this._setInvalid(this._active, false);
|
|
112
|
+
this._advance();
|
|
113
|
+
};
|
|
114
|
+
/** With data-save, stores the answers and the shown question. */
|
|
115
|
+
this._save = () => {
|
|
116
|
+
const key = this._key;
|
|
117
|
+
if (!key) return;
|
|
118
|
+
const state = { index: this.index, answers: this._allControls().map(savedState) };
|
|
119
|
+
try {
|
|
120
|
+
localStorage.setItem(key, JSON.stringify(state));
|
|
121
|
+
} catch {
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
/** A submitted questionnaire has nothing left to resume. */
|
|
125
|
+
this._forget = () => {
|
|
126
|
+
try {
|
|
127
|
+
if (this._key) localStorage.removeItem(this._key);
|
|
128
|
+
} catch {
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
this._handleClick = (e) => {
|
|
132
|
+
const button = e.target.closest?.("button");
|
|
133
|
+
if (!button || !this._buttons().includes(button)) return;
|
|
134
|
+
if (NAVIGATION.includes(button.value)) {
|
|
135
|
+
e.preventDefault();
|
|
136
|
+
this[button.value]();
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
this._syncRequired();
|
|
140
|
+
};
|
|
141
|
+
// Enter in a field moves on instead of submitting the form early. With
|
|
142
|
+
// data-shortcuts, a letter or digit picks an answer.
|
|
143
|
+
this._handleKeydown = (e) => {
|
|
144
|
+
if (e.key !== "Enter") return this._handleShortcut(e);
|
|
145
|
+
if (e.defaultPrevented || Utils.isComposing(e)) return;
|
|
146
|
+
if (!(e.target instanceof HTMLInputElement) || this._end) return;
|
|
147
|
+
e.preventDefault();
|
|
148
|
+
this.next();
|
|
149
|
+
};
|
|
150
|
+
// A submission found an unanswered question, possibly a hidden one. Open the
|
|
151
|
+
// first instead of letting the browser report a control it cannot show.
|
|
152
|
+
// One submission fires its invalid events in a single task.
|
|
153
|
+
this._handleInvalid = (e) => {
|
|
154
|
+
const item = this.items.find((item2) => item2.contains(e.target));
|
|
155
|
+
if (!item) return;
|
|
156
|
+
e.preventDefault();
|
|
157
|
+
if (this._reporting) return;
|
|
158
|
+
this._reporting = true;
|
|
159
|
+
setTimeout(() => this._reporting = false);
|
|
160
|
+
this._active = item;
|
|
161
|
+
this._reviewing = false;
|
|
162
|
+
this._render();
|
|
163
|
+
this._validate(item);
|
|
164
|
+
};
|
|
165
|
+
// An answer clears the question's error.
|
|
166
|
+
this._handleInput = (e) => {
|
|
167
|
+
this._syncRequired(this._fieldsets().filter((item2) => item2.contains(e.target)));
|
|
168
|
+
this._save();
|
|
169
|
+
const item = e.target.closest?.("fieldset");
|
|
170
|
+
if (item instanceof HTMLFieldSetElement && item.classList.contains("invalid")) this._setInvalid(item, false);
|
|
171
|
+
};
|
|
172
|
+
this._progress = document.createElement("div");
|
|
173
|
+
this._progress.className = "questionnaire-progress";
|
|
174
|
+
this._progressText = document.createElement("span");
|
|
175
|
+
this._progressText.id = `questionnaire-progress-${Utils.guid()}`;
|
|
176
|
+
this._progressBar = document.createElement("progress");
|
|
177
|
+
this._progressBar.className = "progress";
|
|
178
|
+
this._progressBar.setAttribute("aria-labelledby", this._progressText.id);
|
|
179
|
+
this._progress.append(this._progressText, this._progressBar);
|
|
180
|
+
this.el.prepend(this._progress);
|
|
181
|
+
for (const item of this._fieldsets()) {
|
|
182
|
+
const ids = Array.from(item.querySelectorAll(":scope > p:not(.questionnaire-error)")).map((p) => this._ensureId(p, "questionnaire-description"));
|
|
183
|
+
if (ids.length && !item.hasAttribute("aria-describedby")) {
|
|
184
|
+
item.setAttribute("aria-describedby", ids.join(" "));
|
|
185
|
+
this._generatedIds.push(item);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
this._active = this.items[0] ?? null;
|
|
189
|
+
this._summary = this._createSummary();
|
|
190
|
+
this._restore();
|
|
191
|
+
this._syncRequired();
|
|
192
|
+
this._render();
|
|
193
|
+
this._observer = new MutationObserver(() => {
|
|
194
|
+
this._syncRequired();
|
|
195
|
+
this._render();
|
|
196
|
+
});
|
|
197
|
+
this._observer.observe(this.el, { attributes: true, subtree: true, attributeFilter: ["disabled"] });
|
|
198
|
+
const { signal } = this._events;
|
|
199
|
+
this.el.addEventListener("click", this._handleClick, { signal });
|
|
200
|
+
this.el.addEventListener("keydown", this._handleKeydown, { signal });
|
|
201
|
+
this.el.addEventListener("input", this._handleInput, { signal });
|
|
202
|
+
this.el.addEventListener("change", this._save, { signal });
|
|
203
|
+
this.el.addEventListener("submit", this._forget, { signal });
|
|
204
|
+
this.el.addEventListener("invalid", this._handleInvalid, { capture: true, signal });
|
|
205
|
+
}
|
|
206
|
+
static get defaults() {
|
|
207
|
+
return _defaults;
|
|
208
|
+
}
|
|
209
|
+
/** The questions that apply: every fieldset child that is not disabled. */
|
|
210
|
+
get items() {
|
|
211
|
+
return this._fieldsets().filter((item) => !item.disabled);
|
|
212
|
+
}
|
|
213
|
+
/** Position of the shown question in `items`. */
|
|
214
|
+
get index() {
|
|
215
|
+
return this.items.indexOf(this._active);
|
|
216
|
+
}
|
|
217
|
+
/** The next question, or after the last one the review step. */
|
|
218
|
+
_advance() {
|
|
219
|
+
if (this._summary && this.index === this.items.length - 1) this.review();
|
|
220
|
+
else this.goTo(this.index + 1);
|
|
221
|
+
}
|
|
222
|
+
destroy() {
|
|
223
|
+
this._observer.disconnect();
|
|
224
|
+
this._summary?.remove();
|
|
225
|
+
for (const item of this._fieldsets()) {
|
|
226
|
+
if (item.hasAttribute("data-required")) for (const control of this._controls(item)) control.setCustomValidity("");
|
|
227
|
+
item.hidden = false;
|
|
228
|
+
this._setInvalid(item, false);
|
|
229
|
+
}
|
|
230
|
+
for (const button of this._buttons()) button.hidden = false;
|
|
231
|
+
this._progress.remove();
|
|
232
|
+
for (const el of this._generated) el.remove();
|
|
233
|
+
for (const el of this._generatedIds) {
|
|
234
|
+
el.removeAttribute(el instanceof HTMLFieldSetElement ? "aria-describedby" : "id");
|
|
235
|
+
}
|
|
236
|
+
super.destroy();
|
|
237
|
+
}
|
|
238
|
+
_fieldsets() {
|
|
239
|
+
return Array.from(this.el.querySelectorAll(":scope > fieldset"));
|
|
240
|
+
}
|
|
241
|
+
/** The footer's navigation and submit buttons. */
|
|
242
|
+
_buttons() {
|
|
243
|
+
return Array.from(this.el.querySelectorAll(":scope > footer > button")).filter(
|
|
244
|
+
(button) => NAVIGATION.includes(button.value) || button.type === "submit"
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
_controls(item) {
|
|
248
|
+
return Array.from(item.elements).filter(
|
|
249
|
+
(el) => el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement || el instanceof HTMLInputElement && el.type !== "button" && el.type !== "submit"
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
_required(item) {
|
|
253
|
+
return item.hasAttribute("data-required") || this._controls(item).some((control) => control.required);
|
|
254
|
+
}
|
|
255
|
+
_ensureId(el, prefix) {
|
|
256
|
+
if (!el.id) {
|
|
257
|
+
el.id = `${prefix}-${Utils.guid()}`;
|
|
258
|
+
this._generatedIds.push(el);
|
|
259
|
+
}
|
|
260
|
+
return el.id;
|
|
261
|
+
}
|
|
262
|
+
_render() {
|
|
263
|
+
const items = this.items;
|
|
264
|
+
if (!items.includes(this._active)) this._active = this._after(items);
|
|
265
|
+
const index = items.indexOf(this._active);
|
|
266
|
+
for (const item of this._fieldsets()) item.hidden = this._reviewing || item !== this._active;
|
|
267
|
+
this._summary?.toggleAttribute("hidden", !this._reviewing);
|
|
268
|
+
for (const button of this._buttons()) button.hidden = !this._shows(button, index);
|
|
269
|
+
this._renderProgress(index, items.length);
|
|
270
|
+
}
|
|
271
|
+
/** The question after the shown one, which was switched off, or the last that applies. */
|
|
272
|
+
_after(items) {
|
|
273
|
+
const all = this._fieldsets();
|
|
274
|
+
const after = all.slice(all.indexOf(this._active) + 1).find((item) => !item.disabled);
|
|
275
|
+
return after ?? items[items.length - 1] ?? null;
|
|
276
|
+
}
|
|
277
|
+
/** Whether the shown step is the one that submits: the review step, or without one the last question. */
|
|
278
|
+
get _end() {
|
|
279
|
+
return this._summary ? this._reviewing : this.index === this.items.length - 1;
|
|
280
|
+
}
|
|
281
|
+
/** Whether a footer button applies to the shown step. */
|
|
282
|
+
_shows(button, index) {
|
|
283
|
+
const end = this._end;
|
|
284
|
+
const shown = {
|
|
285
|
+
previous: index > 0 || this._reviewing,
|
|
286
|
+
skip: !end && this._skippable(),
|
|
287
|
+
next: !end
|
|
288
|
+
};
|
|
289
|
+
return shown[button.value] ?? end;
|
|
290
|
+
}
|
|
291
|
+
/** Whether the shown question may be skipped: it applies and needs no answer. */
|
|
292
|
+
_skippable() {
|
|
293
|
+
return !!this._active && !this._required(this._active);
|
|
294
|
+
}
|
|
295
|
+
_renderProgress(index, total) {
|
|
296
|
+
this._progressText.textContent = this._reviewing ? this.options.summaryLabel : this.options.progressLabel.replace("{current}", String(index + 1)).replace("{total}", String(total));
|
|
297
|
+
this._progressBar.max = Math.max(total, 1);
|
|
298
|
+
this._progressBar.value = this._reviewing ? total : index + 1;
|
|
299
|
+
}
|
|
300
|
+
/** With data-summary, the review step: a list of the questions and their answers, before the footer. */
|
|
301
|
+
_createSummary() {
|
|
302
|
+
if (!this.el.hasAttribute("data-summary")) return null;
|
|
303
|
+
const summary = document.createElement("section");
|
|
304
|
+
summary.className = "questionnaire-summary";
|
|
305
|
+
summary.tabIndex = -1;
|
|
306
|
+
summary.setAttribute("aria-label", this.options.summaryLabel);
|
|
307
|
+
summary.hidden = true;
|
|
308
|
+
summary.addEventListener("click", (e) => {
|
|
309
|
+
const edit = e.target.closest("button[data-question]");
|
|
310
|
+
if (edit) this.goTo(Number(edit.dataset.question));
|
|
311
|
+
});
|
|
312
|
+
const footer = this.el.querySelector(":scope > footer");
|
|
313
|
+
if (footer) footer.before(summary);
|
|
314
|
+
else this.el.append(summary);
|
|
315
|
+
return summary;
|
|
316
|
+
}
|
|
317
|
+
/** Lists each question that applies with its answer and a button back to it. */
|
|
318
|
+
_fillSummary(summary) {
|
|
319
|
+
const list = document.createElement("dl");
|
|
320
|
+
list.append(...this.items.map((item, i) => {
|
|
321
|
+
const row = document.createElement("div");
|
|
322
|
+
const [term, answer, action] = [document.createElement("dt"), document.createElement("dd"), document.createElement("dd")];
|
|
323
|
+
term.id = `questionnaire-summary-${Utils.guid()}`;
|
|
324
|
+
term.textContent = item.querySelector(":scope > legend")?.textContent.trim() ?? "";
|
|
325
|
+
answer.textContent = this._controls(item).map(answerText).filter(Boolean).join(", ") || this.options.skippedLabel;
|
|
326
|
+
const edit = document.createElement("button");
|
|
327
|
+
Object.assign(edit, { type: "button", className: "text", textContent: this.options.editLabel });
|
|
328
|
+
edit.dataset.question = String(i);
|
|
329
|
+
edit.setAttribute("aria-describedby", term.id);
|
|
330
|
+
action.append(edit);
|
|
331
|
+
row.append(term, answer, action);
|
|
332
|
+
return row;
|
|
333
|
+
}));
|
|
334
|
+
summary.replaceChildren(list);
|
|
335
|
+
}
|
|
336
|
+
/** The storage key from data-save, or '' without it. */
|
|
337
|
+
get _key() {
|
|
338
|
+
const key = this.el.dataset.save;
|
|
339
|
+
return key ? `questionnaire:${key}` : "";
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Every answer control that can be saved, in order. A file cannot be put back,
|
|
343
|
+
* a password must not sit in storage, and a hidden input is the server's.
|
|
344
|
+
*/
|
|
345
|
+
_allControls() {
|
|
346
|
+
return this._fieldsets().flatMap((item) => this._controls(item)).filter((control) => !UNSAVED.includes(control.type));
|
|
347
|
+
}
|
|
348
|
+
/** Puts back saved answers and the question they reached, if the questions are the same. */
|
|
349
|
+
_restore() {
|
|
350
|
+
const saved = this._read();
|
|
351
|
+
const controls = this._allControls();
|
|
352
|
+
if (saved?.answers.length !== controls.length) return;
|
|
353
|
+
controls.forEach((control, i) => restoreControl(control, saved.answers[i]));
|
|
354
|
+
this._active = this.items[saved.index] ?? this._active;
|
|
355
|
+
}
|
|
356
|
+
/** The saved state, or null for none or a broken one. */
|
|
357
|
+
_read() {
|
|
358
|
+
try {
|
|
359
|
+
return validSaved(JSON.parse(localStorage.getItem(this._key) ?? "null"));
|
|
360
|
+
} catch {
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Puts "choose at least one" on the first enabled checkbox of each
|
|
366
|
+
* data-required group with none checked, so the browser's validation, and
|
|
367
|
+
* every way of submitting, sees it. A disabled checkbox is not sent, so it
|
|
368
|
+
* does not count.
|
|
369
|
+
*/
|
|
370
|
+
_syncRequired(items = this._fieldsets()) {
|
|
371
|
+
for (const item of items) {
|
|
372
|
+
if (!item.hasAttribute("data-required")) continue;
|
|
373
|
+
const boxes = this._controls(item).filter(
|
|
374
|
+
(control) => control instanceof HTMLInputElement && control.type === "checkbox"
|
|
375
|
+
);
|
|
376
|
+
const enabled = boxes.filter((box) => !box.disabled);
|
|
377
|
+
for (const box of boxes) box.setCustomValidity("");
|
|
378
|
+
if (enabled.length && !enabled.some((box) => box.checked)) {
|
|
379
|
+
const error = item.querySelector(":scope > .questionnaire-error:not([data-generated])");
|
|
380
|
+
enabled[0].setCustomValidity(error?.textContent.trim() || this.options.requiredMessage);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
/** The first control in the question that still needs an answer. */
|
|
385
|
+
_invalidControl(item) {
|
|
386
|
+
return this._controls(item).find((control) => control.willValidate && !control.validity.valid);
|
|
387
|
+
}
|
|
388
|
+
/** Shows the question's error and returns false when it needs an answer. */
|
|
389
|
+
_validate(item) {
|
|
390
|
+
this._syncRequired();
|
|
391
|
+
const invalid = item && this._invalidControl(item);
|
|
392
|
+
if (!invalid) return true;
|
|
393
|
+
let error = item.querySelector(":scope > .questionnaire-error");
|
|
394
|
+
if (!error) {
|
|
395
|
+
error = document.createElement("p");
|
|
396
|
+
error.className = "questionnaire-error";
|
|
397
|
+
error.dataset.generated = "";
|
|
398
|
+
error.textContent = invalid.validationMessage || this.options.requiredMessage;
|
|
399
|
+
item.append(error);
|
|
400
|
+
this._generated.push(error);
|
|
401
|
+
}
|
|
402
|
+
this._setInvalid(item, true);
|
|
403
|
+
invalid.focus();
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
_setInvalid(item, invalid) {
|
|
407
|
+
item.classList.toggle("invalid", invalid);
|
|
408
|
+
const error = item.querySelector(":scope > .questionnaire-error");
|
|
409
|
+
const described = (item.getAttribute("aria-describedby") ?? "").split(" ").filter((id) => id && id !== error?.id);
|
|
410
|
+
if (invalid && error) described.push(this._ensureId(error, "questionnaire-error"));
|
|
411
|
+
if (described.length) item.setAttribute("aria-describedby", described.join(" "));
|
|
412
|
+
else item.removeAttribute("aria-describedby");
|
|
413
|
+
for (const control of this._controls(item)) {
|
|
414
|
+
if (invalid) control.setAttribute("aria-invalid", "true");
|
|
415
|
+
else control.removeAttribute("aria-invalid");
|
|
416
|
+
}
|
|
417
|
+
if (!invalid && this._generated.includes(error)) {
|
|
418
|
+
error.remove();
|
|
419
|
+
this._generated.splice(this._generated.indexOf(error), 1);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
/** Whether a shortcut key can pick an answer now: data-shortcuts is set and a question shows. */
|
|
423
|
+
get _shortcuts() {
|
|
424
|
+
return this.el.hasAttribute("data-shortcuts") && !!this._active && !this._reviewing;
|
|
425
|
+
}
|
|
426
|
+
_handleShortcut(e) {
|
|
427
|
+
if (!this._shortcuts) return;
|
|
428
|
+
const choice = this._controls(this._active).filter(isChoice)[shortcut(e)];
|
|
429
|
+
if (!choice || choice.disabled) return;
|
|
430
|
+
e.preventDefault();
|
|
431
|
+
choice.click();
|
|
432
|
+
choice.focus();
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
Questionnaire.key = "Expressive_Questionnaire";
|
|
436
|
+
|
|
437
|
+
export {
|
|
438
|
+
Questionnaire
|
|
439
|
+
};
|
|
440
|
+
//# sourceMappingURL=chunk-7ZAMOMGY.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/ts/components/questionnaire.ts"],
|
|
4
|
+
"sourcesContent": ["import { Utils } from '../core/utils';\nimport { Component, BaseOptions } from '../core/component';\n\nexport interface QuestionnaireOptions extends BaseOptions {\n /**\n * Text above the progress bar. `{current}` and `{total}` are replaced with\n * the question number and the number of questions. `data-progress-label`\n * on the form sets it.\n * @default 'Question {current} of {total}'\n */\n progressLabel: string;\n /**\n * Error shown when a question has no `.questionnaire-error` of its own and\n * the browser gives no validation message, as for a `data-required` group\n * of checkboxes.\n * @default 'Choose an answer to continue.'\n */\n requiredMessage: string;\n /**\n * With `data-summary`, the heading of the review step and the text above\n * the progress bar there.\n * @default 'Review your answers'\n */\n summaryLabel: string;\n /** With `data-summary`, the text of each answer's edit button. @default 'Edit' */\n editLabel: string;\n /** With `data-summary`, the answer shown for a question left blank. @default 'Not answered' */\n skippedLabel: string;\n}\n\nconst _defaults: QuestionnaireOptions = {\n progressLabel: 'Question {current} of {total}',\n requiredMessage: 'Choose an answer to continue.',\n summaryLabel: 'Review your answers',\n editLabel: 'Edit',\n skippedLabel: 'Not answered'\n};\n\nconst NAVIGATION = ['previous', 'skip', 'next'];\nconst UNSAVED = ['file', 'password', 'hidden'];\nconst LETTERS = 'abcdefghijklmnopqrstuvwxyz';\n\ntype Control = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;\n/** A control's answer as saved: whether a choice is checked, a select's chosen values, or a field's value. */\ntype Saved = boolean | string | string[];\n\nconst isChoice = (control: Control): control is HTMLInputElement =>\n control instanceof HTMLInputElement && (control.type === 'radio' || control.type === 'checkbox');\n\n/** A choice's label text, without its input or the description in <small>. */\nfunction labelText(control: HTMLInputElement) {\n const label = control.closest('label')?.cloneNode(true) as HTMLElement | undefined;\n label?.querySelectorAll('input, small').forEach((el) => el.remove());\n return label?.textContent.trim() || control.value;\n}\n\n/**\n * Summary text for the inputs whose value must not be shown: a hidden input is\n * the server's, a password is masked at a fixed length, and a file shows its\n * names rather than the browser's fake path.\n */\nconst MASKED: Record<string, (control: HTMLInputElement | HTMLTextAreaElement) => string> = {\n hidden: () => '',\n password: (control) => (control.value ? '\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022' : ''),\n file: (control) => Array.from((control as HTMLInputElement).files ?? [], (file) => file.name).join(', ')\n};\n\n/** A control's answer as text for the summary. */\nfunction answerText(control: Control) {\n if (control instanceof HTMLSelectElement) return Array.from(control.selectedOptions, (option) => option.text).join(', ');\n if (isChoice(control)) return control.checked ? labelText(control) : '';\n return MASKED[control.type]?.(control) ?? control.value.trim();\n}\n\nconst savedState = (control: Control): Saved => {\n if (control instanceof HTMLSelectElement) return Array.from(control.selectedOptions, (option) => option.value);\n return isChoice(control) ? control.checked : control.value;\n};\n\n/** Saved state with a list of answers, or null. */\nconst validSaved = (saved: { answers?: unknown } | null) =>\n (Array.isArray(saved?.answers) ? saved : null) as { index: number; answers: Saved[] } | null;\n\n/** Puts a saved answer back, ignoring one of the wrong type, as a hand-edited store may hold. */\nfunction restoreState(control: Control, saved: Saved) {\n if (control instanceof HTMLSelectElement) return restoreSelect(control, saved);\n if (isChoice(control)) control.checked = saved === true;\n else if (typeof saved === 'string') control.value = saved;\n}\n\nfunction restoreSelect(select: HTMLSelectElement, saved: Saved) {\n if (!Array.isArray(saved)) return;\n for (const option of select.options) option.selected = saved.includes(option.value);\n}\n\n/**\n * Restores one control and fires `change` if its answer moved, so a page\n * that switches questions on from an answer sees the restored one.\n */\nfunction restoreControl(control: Control, saved: Saved) {\n const before = JSON.stringify(savedState(control));\n restoreState(control, saved);\n if (JSON.stringify(savedState(control)) !== before) control.dispatchEvent(new Event('change', { bubbles: true }));\n}\n\n/**\n * The answer a shortcut key picks, counted from 0: a digit 1 to 9 or a\n * letter. Keys typed into a text field, or with a modifier, pick nothing.\n */\nfunction shortcut(e: KeyboardEvent) {\n if (typingIn(e.target) || !Utils.plainKey(e)) return -1;\n const digit = '123456789'.indexOf(e.key);\n return digit >= 0 ? digit : letterIndex(e.key);\n}\n\nconst TYPING = 'textarea, select, [contenteditable], input:not([type=\"radio\"], [type=\"checkbox\"], [type=\"button\"], [type=\"submit\"], [type=\"reset\"])';\nconst typingIn = (target: EventTarget | null) => !!(target as Element).matches?.(TYPING);\n\nconst letterIndex = (key: string) => (key.length === 1 ? LETTERS.indexOf(key.toLowerCase()) : -1);\n\n/**\n * A multi-step questionnaire: a <form class=\"questionnaire\"> whose\n * <fieldset> children are the questions, shown one at a time, and a <footer>\n * of buttons. `value=\"previous\"`, `value=\"skip\"` and `value=\"next\"` mark the\n * navigation buttons; a submit button sends the form on the last question.\n *\n * A question is required when one of its controls is `required`, or when the\n * fieldset has `data-required` (at least one enabled checkbox, held as a\n * custom validity on the first one). Next and every way of submitting check\n * it with the browser's own validation; an optional question gets Skip, which\n * clears its answer. A disabled fieldset is left out, so a page can switch\n * questions on and off from earlier answers.\n *\n * Three attributes on the form add to that: `data-shortcuts` lets a letter or\n * digit pick an answer, `data-summary` adds a review step listing every\n * answer before the submit button, and `data-save=\"key\"` keeps the answers\n * and the shown question in localStorage under that key until the form is\n * submitted.\n *\n * Without JavaScript every question shows at once and the submit button sends\n * the form. The answers are ordinary form controls, so FormData reads them.\n */\nexport class Questionnaire extends Component<QuestionnaireOptions> {\n declare el: HTMLFormElement;\n private _active: HTMLFieldSetElement | null = null;\n private _progress: HTMLElement;\n private _progressText: HTMLElement;\n private _progressBar: HTMLProgressElement;\n private _generated: HTMLElement[] = [];\n private _generatedIds: HTMLElement[] = [];\n private _observer: MutationObserver;\n /** Set while one submission's invalid events arrive, so only the first opens. */\n private _reporting = false;\n /** With data-summary, the review step, and whether it is shown. */\n private _summary: HTMLElement | null = null;\n private _reviewing = false;\n\n // HTMLElement, not HTMLFormElement: init() takes the element type from\n // here, and has always accepted any HTMLElement.\n constructor(el: HTMLElement, options: Partial<QuestionnaireOptions>) {\n const progressLabel = el.dataset.progressLabel;\n super(el, { ...(progressLabel ? { progressLabel } : {}), ...options });\n\n this._progress = document.createElement('div');\n this._progress.className = 'questionnaire-progress';\n this._progressText = document.createElement('span');\n this._progressText.id = `questionnaire-progress-${Utils.guid()}`;\n this._progressBar = document.createElement('progress');\n this._progressBar.className = 'progress';\n this._progressBar.setAttribute('aria-labelledby', this._progressText.id);\n this._progress.append(this._progressText, this._progressBar);\n this.el.prepend(this._progress);\n\n for (const item of this._fieldsets()) {\n const ids = Array.from(item.querySelectorAll<HTMLElement>(':scope > p:not(.questionnaire-error)'))\n .map((p) => this._ensureId(p, 'questionnaire-description'));\n if (ids.length && !item.hasAttribute('aria-describedby')) {\n item.setAttribute('aria-describedby', ids.join(' '));\n this._generatedIds.push(item);\n }\n }\n\n this._active = this.items[0] ?? null;\n this._summary = this._createSummary();\n this._restore();\n this._syncRequired();\n this._render();\n // A page enabling or disabling a question from an earlier answer changes\n // the count and the buttons.\n this._observer = new MutationObserver(() => {\n this._syncRequired();\n this._render();\n });\n this._observer.observe(this.el, { attributes: true, subtree: true, attributeFilter: ['disabled'] });\n const { signal } = this._events;\n this.el.addEventListener('click', this._handleClick, { signal });\n this.el.addEventListener('keydown', this._handleKeydown, { signal });\n this.el.addEventListener('input', this._handleInput, { signal });\n this.el.addEventListener('change', this._save, { signal });\n this.el.addEventListener('submit', this._forget, { signal });\n // invalid does not bubble.\n this.el.addEventListener('invalid', this._handleInvalid, { capture: true, signal });\n }\n\n static get defaults(): QuestionnaireOptions {\n return _defaults;\n }\n\n static key = 'Expressive_Questionnaire';\n\n /** The questions that apply: every fieldset child that is not disabled. */\n get items(): HTMLFieldSetElement[] {\n return this._fieldsets().filter((item) => !item.disabled);\n }\n\n /** Position of the shown question in `items`. */\n get index(): number {\n return this.items.indexOf(this._active);\n }\n\n /** Shows the question at `index` without checking the current one. */\n goTo = (index: number) => {\n const item = this.items[index];\n if (!item) return;\n this._active = item;\n this._reviewing = false;\n this._render();\n this._save();\n const controls = this._controls(item).filter((control) => !control.disabled);\n (controls.find((control) => (control as HTMLInputElement).checked) ?? controls[0])?.focus();\n };\n\n /** Checks the shown question and moves to the next one if it is answered. */\n next = () => {\n if (this._validate(this._active)) this._advance();\n };\n\n /** Moves to the previous question, or from the review step back to the last one. */\n previous = () => this.goTo(this._reviewing ? this.items.length - 1 : this.index - 1);\n\n /** Shows the review step of a questionnaire with data-summary. */\n review = () => {\n if (!this._summary) return;\n this._fillSummary(this._summary);\n this._reviewing = true;\n this._render();\n this._summary.focus();\n };\n\n /** The next question, or after the last one the review step. */\n private _advance() {\n if (this._summary && this.index === this.items.length - 1) this.review();\n else this.goTo(this.index + 1);\n }\n\n /** Clears the answer to the shown question and moves to the next one. */\n skip = () => {\n if (!this._active) return;\n for (const control of this._controls(this._active)) {\n const choice = isChoice(control);\n if (choice ? !control.checked : !control.value) continue;\n if (choice) control.checked = false;\n else control.value = '';\n control.dispatchEvent(new Event('change', { bubbles: true }));\n }\n // A skipped question has no answer left to be wrong about. Clearing fires\n // only `change`, not the `input` that clears an error, so clear it here.\n this._setInvalid(this._active, false);\n this._advance();\n };\n\n destroy() {\n this._observer.disconnect();\n this._summary?.remove();\n for (const item of this._fieldsets()) {\n if (item.hasAttribute('data-required')) for (const control of this._controls(item)) control.setCustomValidity('');\n item.hidden = false;\n this._setInvalid(item, false);\n }\n for (const button of this._buttons()) button.hidden = false;\n this._progress.remove();\n for (const el of this._generated) el.remove();\n for (const el of this._generatedIds) {\n el.removeAttribute(el instanceof HTMLFieldSetElement ? 'aria-describedby' : 'id');\n }\n super.destroy();\n }\n\n private _fieldsets() {\n return Array.from(this.el.querySelectorAll<HTMLFieldSetElement>(':scope > fieldset'));\n }\n\n /** The footer's navigation and submit buttons. */\n private _buttons() {\n return Array.from(this.el.querySelectorAll<HTMLButtonElement>(':scope > footer > button')).filter(\n (button) => NAVIGATION.includes(button.value) || button.type === 'submit'\n );\n }\n\n private _controls(item: HTMLFieldSetElement) {\n return Array.from(item.elements).filter(\n (el): el is Control =>\n el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement ||\n (el instanceof HTMLInputElement && el.type !== 'button' && el.type !== 'submit')\n );\n }\n\n private _required(item: HTMLFieldSetElement) {\n return item.hasAttribute('data-required') || this._controls(item).some((control) => control.required);\n }\n\n private _ensureId(el: HTMLElement, prefix: string) {\n if (!el.id) {\n el.id = `${prefix}-${Utils.guid()}`;\n this._generatedIds.push(el);\n }\n return el.id;\n }\n\n private _render() {\n const items = this.items;\n // The shown question was switched off: carry on from the next one.\n if (!items.includes(this._active)) this._active = this._after(items);\n const index = items.indexOf(this._active);\n for (const item of this._fieldsets()) item.hidden = this._reviewing || item !== this._active;\n this._summary?.toggleAttribute('hidden', !this._reviewing);\n for (const button of this._buttons()) button.hidden = !this._shows(button, index);\n this._renderProgress(index, items.length);\n }\n\n /** The question after the shown one, which was switched off, or the last that applies. */\n private _after(items: HTMLFieldSetElement[]) {\n const all = this._fieldsets();\n const after = all.slice(all.indexOf(this._active) + 1).find((item) => !item.disabled);\n return after ?? items[items.length - 1] ?? null;\n }\n\n /** Whether the shown step is the one that submits: the review step, or without one the last question. */\n private get _end() {\n return this._summary ? this._reviewing : this.index === this.items.length - 1;\n }\n\n /** Whether a footer button applies to the shown step. */\n private _shows(button: HTMLButtonElement, index: number) {\n const end = this._end;\n const shown: Record<string, boolean> = {\n previous: index > 0 || this._reviewing,\n skip: !end && this._skippable(),\n next: !end\n };\n return shown[button.value] ?? end;\n }\n\n /** Whether the shown question may be skipped: it applies and needs no answer. */\n private _skippable() {\n return !!this._active && !this._required(this._active);\n }\n\n private _renderProgress(index: number, total: number) {\n this._progressText.textContent = this._reviewing\n ? this.options.summaryLabel\n : this.options.progressLabel.replace('{current}', String(index + 1)).replace('{total}', String(total));\n this._progressBar.max = Math.max(total, 1);\n this._progressBar.value = this._reviewing ? total : index + 1;\n }\n\n /** With data-summary, the review step: a list of the questions and their answers, before the footer. */\n private _createSummary() {\n if (!this.el.hasAttribute('data-summary')) return null;\n const summary = document.createElement('section');\n summary.className = 'questionnaire-summary';\n summary.tabIndex = -1;\n summary.setAttribute('aria-label', this.options.summaryLabel);\n summary.hidden = true;\n summary.addEventListener('click', (e) => {\n const edit = (e.target as Element).closest<HTMLButtonElement>('button[data-question]');\n if (edit) this.goTo(Number(edit.dataset.question));\n });\n const footer = this.el.querySelector(':scope > footer');\n if (footer) footer.before(summary);\n else this.el.append(summary);\n return summary;\n }\n\n /** Lists each question that applies with its answer and a button back to it. */\n private _fillSummary(summary: HTMLElement) {\n const list = document.createElement('dl');\n list.append(...this.items.map((item, i) => {\n const row = document.createElement('div');\n const [term, answer, action] = [document.createElement('dt'), document.createElement('dd'), document.createElement('dd')];\n term.id = `questionnaire-summary-${Utils.guid()}`;\n term.textContent = item.querySelector(':scope > legend')?.textContent.trim() ?? '';\n answer.textContent = this._controls(item).map(answerText).filter(Boolean).join(', ') || this.options.skippedLabel;\n const edit = document.createElement('button');\n Object.assign(edit, { type: 'button', className: 'text', textContent: this.options.editLabel });\n edit.dataset.question = String(i);\n edit.setAttribute('aria-describedby', term.id);\n action.append(edit);\n row.append(term, answer, action);\n return row;\n }));\n summary.replaceChildren(list);\n }\n\n /** The storage key from data-save, or '' without it. */\n private get _key() {\n const key = this.el.dataset.save;\n return key ? `questionnaire:${key}` : '';\n }\n\n /**\n * Every answer control that can be saved, in order. A file cannot be put back,\n * a password must not sit in storage, and a hidden input is the server's.\n */\n private _allControls() {\n return this._fieldsets().flatMap((item) => this._controls(item)).filter((control) => !UNSAVED.includes(control.type));\n }\n\n /** With data-save, stores the answers and the shown question. */\n private _save = () => {\n const key = this._key;\n if (!key) return;\n const state = { index: this.index, answers: this._allControls().map(savedState) };\n try {\n localStorage.setItem(key, JSON.stringify(state));\n } catch {\n // Storage full or blocked: the questionnaire still works unsaved.\n }\n };\n\n /** Puts back saved answers and the question they reached, if the questions are the same. */\n private _restore() {\n const saved = this._read();\n const controls = this._allControls();\n if (saved?.answers.length !== controls.length) return;\n controls.forEach((control, i) => restoreControl(control, saved!.answers[i]));\n this._active = this.items[saved!.index] ?? this._active;\n }\n\n /** The saved state, or null for none or a broken one. */\n private _read(): { index: number; answers: Saved[] } | null {\n try {\n return validSaved(JSON.parse(localStorage.getItem(this._key) ?? 'null'));\n } catch {\n return null;\n }\n }\n\n /** A submitted questionnaire has nothing left to resume. */\n private _forget = () => {\n try {\n if (this._key) localStorage.removeItem(this._key);\n } catch {\n // Blocked storage has nothing saved.\n }\n };\n\n /**\n * Puts \"choose at least one\" on the first enabled checkbox of each\n * data-required group with none checked, so the browser's validation, and\n * every way of submitting, sees it. A disabled checkbox is not sent, so it\n * does not count.\n */\n private _syncRequired(items = this._fieldsets()) {\n for (const item of items) {\n if (!item.hasAttribute('data-required')) continue;\n const boxes = this._controls(item).filter(\n (control): control is HTMLInputElement => control instanceof HTMLInputElement && control.type === 'checkbox'\n );\n const enabled = boxes.filter((box) => !box.disabled);\n for (const box of boxes) box.setCustomValidity('');\n if (enabled.length && !enabled.some((box) => box.checked)) {\n const error = item.querySelector<HTMLElement>(':scope > .questionnaire-error:not([data-generated])');\n enabled[0].setCustomValidity(error?.textContent.trim() || this.options.requiredMessage);\n }\n }\n }\n\n /** The first control in the question that still needs an answer. */\n private _invalidControl(item: HTMLFieldSetElement): Control | undefined {\n return this._controls(item).find((control) => control.willValidate && !control.validity.valid);\n }\n\n /** Shows the question's error and returns false when it needs an answer. */\n private _validate(item: HTMLFieldSetElement | null) {\n this._syncRequired();\n const invalid = item && this._invalidControl(item);\n if (!invalid) return true;\n let error = item.querySelector<HTMLElement>(':scope > .questionnaire-error');\n if (!error) {\n error = document.createElement('p');\n error.className = 'questionnaire-error';\n error.dataset.generated = '';\n error.textContent = invalid.validationMessage || this.options.requiredMessage;\n item.append(error);\n this._generated.push(error);\n }\n this._setInvalid(item, true);\n invalid.focus();\n return false;\n }\n\n private _setInvalid(item: HTMLFieldSetElement, invalid: boolean) {\n item.classList.toggle('invalid', invalid);\n const error = item.querySelector<HTMLElement>(':scope > .questionnaire-error');\n const described = (item.getAttribute('aria-describedby') ?? '').split(' ').filter((id) => id && id !== error?.id);\n if (invalid && error) described.push(this._ensureId(error, 'questionnaire-error'));\n if (described.length) item.setAttribute('aria-describedby', described.join(' '));\n else item.removeAttribute('aria-describedby');\n for (const control of this._controls(item)) {\n if (invalid) control.setAttribute('aria-invalid', 'true');\n else control.removeAttribute('aria-invalid');\n }\n if (!invalid && this._generated.includes(error)) {\n error.remove();\n this._generated.splice(this._generated.indexOf(error), 1);\n }\n }\n\n private _handleClick = (e: MouseEvent) => {\n const button = (e.target as Element).closest?.('button');\n if (!button || !this._buttons().includes(button)) return;\n if (NAVIGATION.includes(button.value)) {\n // Also stops a navigation button written without type=\"button\" from\n // submitting the form.\n e.preventDefault();\n this[button.value as 'previous' | 'skip' | 'next']();\n return;\n }\n // Submit by click or Enter: catch answers a script set without an event.\n this._syncRequired();\n };\n\n // Enter in a field moves on instead of submitting the form early. With\n // data-shortcuts, a letter or digit picks an answer.\n private _handleKeydown = (e: KeyboardEvent) => {\n if (e.key !== 'Enter') return this._handleShortcut(e);\n if (e.defaultPrevented || Utils.isComposing(e)) return;\n if (!(e.target instanceof HTMLInputElement) || this._end) return;\n e.preventDefault();\n this.next();\n };\n\n /** Whether a shortcut key can pick an answer now: data-shortcuts is set and a question shows. */\n private get _shortcuts() {\n return this.el.hasAttribute('data-shortcuts') && !!this._active && !this._reviewing;\n }\n\n private _handleShortcut(e: KeyboardEvent) {\n if (!this._shortcuts) return;\n // Counted as the letters are, disabled choices included.\n const choice = this._controls(this._active!).filter(isChoice)[shortcut(e)] as HTMLInputElement | undefined;\n if (!choice || choice.disabled) return;\n e.preventDefault();\n choice.click();\n choice.focus();\n }\n\n // A submission found an unanswered question, possibly a hidden one. Open the\n // first instead of letting the browser report a control it cannot show.\n // One submission fires its invalid events in a single task.\n private _handleInvalid = (e: Event) => {\n const item = this.items.find((item) => item.contains(e.target as Node));\n if (!item) return;\n e.preventDefault();\n if (this._reporting) return;\n this._reporting = true;\n setTimeout(() => (this._reporting = false));\n this._active = item;\n this._reviewing = false;\n this._render();\n this._validate(item);\n };\n\n // An answer clears the question's error.\n private _handleInput = (e: Event) => {\n this._syncRequired(this._fieldsets().filter((item) => item.contains(e.target as Node)));\n this._save();\n const item = (e.target as Element).closest?.('fieldset');\n if (item instanceof HTMLFieldSetElement && item.classList.contains('invalid')) this._setInvalid(item, false);\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["item"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Utils
|
|
3
|
+
} from "./chunk-67UNY7RH.mjs";
|
|
4
|
+
|
|
5
|
+
// src/ts/behaviors/theme.ts
|
|
6
|
+
var themes = ["light", "dark", "auto"];
|
|
7
|
+
var storageKey = "theme";
|
|
8
|
+
var _Theme = class _Theme {
|
|
9
|
+
static Init() {
|
|
10
|
+
if (_Theme._initialized || typeof document === "undefined") return;
|
|
11
|
+
_Theme._initialized = true;
|
|
12
|
+
document.addEventListener("click", _Theme._onClick);
|
|
13
|
+
Utils.onDocumentReady(() => _Theme.sync());
|
|
14
|
+
}
|
|
15
|
+
/** The current theme: the root's `theme` attribute, or `auto` without one. */
|
|
16
|
+
static get() {
|
|
17
|
+
const value = document.documentElement.getAttribute("theme");
|
|
18
|
+
return themes.includes(value) ? value : "auto";
|
|
19
|
+
}
|
|
20
|
+
/** Applies and saves a theme, then marks the controls. Unknown values are ignored. */
|
|
21
|
+
static set(theme) {
|
|
22
|
+
if (!themes.includes(theme)) return;
|
|
23
|
+
document.documentElement.setAttribute("theme", theme);
|
|
24
|
+
try {
|
|
25
|
+
localStorage.setItem(storageKey, theme);
|
|
26
|
+
} catch {
|
|
27
|
+
}
|
|
28
|
+
_Theme.sync();
|
|
29
|
+
}
|
|
30
|
+
/** Marks every theme control in `root` as current or not. Call it after rendering new controls. */
|
|
31
|
+
static sync(root = document) {
|
|
32
|
+
const current = _Theme.get();
|
|
33
|
+
root.querySelectorAll("[data-theme-set]").forEach((control) => {
|
|
34
|
+
const state = String(control.getAttribute("data-theme-set") === current);
|
|
35
|
+
const role = control.getAttribute("role");
|
|
36
|
+
const checked = role === "menuitemradio" || role === "radio";
|
|
37
|
+
control.setAttribute(checked ? "aria-checked" : "aria-pressed", state);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
static _onClick(e) {
|
|
41
|
+
const control = Utils.closestInPath(e, "[data-theme-set]");
|
|
42
|
+
if (!control || control.matches(':disabled, [aria-disabled="true"]')) return;
|
|
43
|
+
_Theme.set(control.getAttribute("data-theme-set"));
|
|
44
|
+
const root = control.getRootNode();
|
|
45
|
+
if (root !== document) _Theme.sync(root);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
_Theme._initialized = false;
|
|
49
|
+
var Theme = _Theme;
|
|
50
|
+
|
|
51
|
+
export {
|
|
52
|
+
Theme
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=chunk-AEG6LOAJ.mjs.map
|