@expressivecss/expressive 0.15.0 → 0.16.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 +1502 -1
- package/README.md +9 -8
- package/dist/css/expressive.css +19247 -11923
- 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-2CS6TITK.mjs +219 -0
- package/dist/js/chunks/chunk-2CS6TITK.mjs.map +7 -0
- package/dist/js/chunks/chunk-2RLBDFH4.mjs +108 -0
- package/dist/js/chunks/chunk-2RLBDFH4.mjs.map +7 -0
- package/dist/js/chunks/chunk-3L3QIYLC.mjs +85 -0
- package/dist/js/chunks/chunk-3L3QIYLC.mjs.map +7 -0
- package/dist/js/chunks/chunk-4EWGD4V2.mjs +75 -0
- package/dist/js/chunks/chunk-4EWGD4V2.mjs.map +7 -0
- package/dist/js/chunks/chunk-4IKVPCSU.mjs +7 -0
- package/dist/js/chunks/chunk-4IKVPCSU.mjs.map +7 -0
- package/dist/js/chunks/chunk-4PIXLDNJ.mjs +127 -0
- package/dist/js/chunks/chunk-4PIXLDNJ.mjs.map +7 -0
- package/dist/js/chunks/{chunk-KVJAVDBC.mjs → chunk-4QUCNFSD.mjs} +64 -113
- package/dist/js/chunks/chunk-4QUCNFSD.mjs.map +7 -0
- package/dist/js/chunks/{chunk-UETTGDLI.mjs → chunk-4TRZ2AER.mjs} +35 -41
- package/dist/js/chunks/chunk-4TRZ2AER.mjs.map +7 -0
- package/dist/js/chunks/{chunk-C6CHEWYP.mjs → chunk-5KIHWJI2.mjs} +40 -26
- package/dist/js/chunks/chunk-5KIHWJI2.mjs.map +7 -0
- package/dist/js/chunks/{chunk-L27Q6ZMI.mjs → chunk-67ZPPKXS.mjs} +20 -33
- package/dist/js/chunks/chunk-67ZPPKXS.mjs.map +7 -0
- package/dist/js/chunks/{chunk-XAEAEHIX.mjs → chunk-6FSEUFVW.mjs} +39 -26
- package/dist/js/chunks/chunk-6FSEUFVW.mjs.map +7 -0
- package/dist/js/chunks/chunk-752ADW4M.mjs +225 -0
- package/dist/js/chunks/chunk-752ADW4M.mjs.map +7 -0
- package/dist/js/chunks/{chunk-CK2XCICY.mjs → chunk-75E5EDJF.mjs} +3 -11
- package/dist/js/chunks/chunk-75E5EDJF.mjs.map +7 -0
- package/dist/js/chunks/{chunk-KHXZ2A4K.mjs → chunk-7NLUI3RR.mjs} +139 -66
- package/dist/js/chunks/chunk-7NLUI3RR.mjs.map +7 -0
- package/dist/js/chunks/chunk-7W7TV6NY.mjs +108 -0
- package/dist/js/chunks/chunk-7W7TV6NY.mjs.map +7 -0
- package/dist/js/chunks/chunk-7YQBHTK3.mjs +225 -0
- package/dist/js/chunks/chunk-7YQBHTK3.mjs.map +7 -0
- package/dist/js/chunks/chunk-7YZ5CN3V.mjs +33 -0
- package/dist/js/chunks/chunk-7YZ5CN3V.mjs.map +7 -0
- package/dist/js/chunks/chunk-AI73GJKG.mjs +28 -0
- package/dist/js/chunks/chunk-AI73GJKG.mjs.map +7 -0
- package/dist/js/chunks/{chunk-LQWUDNHZ.mjs → chunk-ANKFWNWT.mjs} +21 -45
- package/dist/js/chunks/chunk-ANKFWNWT.mjs.map +7 -0
- package/dist/js/chunks/{chunk-5CEAOLUA.mjs → chunk-B7DQFHA5.mjs} +30 -47
- package/dist/js/chunks/chunk-B7DQFHA5.mjs.map +7 -0
- package/dist/js/chunks/chunk-BIGU5RCJ.mjs +153 -0
- package/dist/js/chunks/chunk-BIGU5RCJ.mjs.map +7 -0
- package/dist/js/chunks/{chunk-VGNYF6FB.mjs → chunk-BPF3I2MN.mjs} +109 -24
- package/dist/js/chunks/chunk-BPF3I2MN.mjs.map +7 -0
- package/dist/js/chunks/chunk-CMGXGYUC.mjs +74 -0
- package/dist/js/chunks/chunk-CMGXGYUC.mjs.map +7 -0
- package/dist/js/chunks/{chunk-NUHMOAOY.mjs → chunk-CSYWKEK3.mjs} +310 -196
- package/dist/js/chunks/chunk-CSYWKEK3.mjs.map +7 -0
- package/dist/js/chunks/chunk-CZSQHXEV.mjs +227 -0
- package/dist/js/chunks/chunk-CZSQHXEV.mjs.map +7 -0
- package/dist/js/chunks/chunk-DZYVU75J.mjs +121 -0
- package/dist/js/chunks/chunk-DZYVU75J.mjs.map +7 -0
- package/dist/js/chunks/{chunk-74MXKKLN.mjs → chunk-EC26RU2D.mjs} +11 -29
- package/dist/js/chunks/chunk-EC26RU2D.mjs.map +7 -0
- package/dist/js/chunks/{chunk-WDK4T63U.mjs → chunk-EVCVFEV3.mjs} +235 -146
- package/dist/js/chunks/chunk-EVCVFEV3.mjs.map +7 -0
- package/dist/js/chunks/chunk-FCNF4GRJ.mjs +445 -0
- package/dist/js/chunks/chunk-FCNF4GRJ.mjs.map +7 -0
- package/dist/js/chunks/chunk-GCWWEZKO.mjs +342 -0
- package/dist/js/chunks/chunk-GCWWEZKO.mjs.map +7 -0
- package/dist/js/chunks/chunk-GNRSYMVH.mjs +1 -0
- package/dist/js/chunks/chunk-GVZQH2H5.mjs +54 -0
- package/dist/js/chunks/chunk-GVZQH2H5.mjs.map +7 -0
- package/dist/js/chunks/chunk-GWZ76SR4.mjs +435 -0
- package/dist/js/chunks/chunk-GWZ76SR4.mjs.map +7 -0
- package/dist/js/chunks/{chunk-PDG64UHF.mjs → chunk-ILDRRG7T.mjs} +21 -23
- package/dist/js/chunks/chunk-ILDRRG7T.mjs.map +7 -0
- package/dist/js/chunks/chunk-INLZWHLY.mjs +80 -0
- package/dist/js/chunks/chunk-INLZWHLY.mjs.map +7 -0
- package/dist/js/chunks/chunk-JUKBBN6P.mjs +175 -0
- package/dist/js/chunks/chunk-JUKBBN6P.mjs.map +7 -0
- package/dist/js/chunks/chunk-KYIEG4U3.mjs +730 -0
- package/dist/js/chunks/chunk-KYIEG4U3.mjs.map +7 -0
- package/dist/js/chunks/{chunk-BGZLF6JZ.mjs → chunk-KZPSAXIU.mjs} +142 -32
- package/dist/js/chunks/chunk-KZPSAXIU.mjs.map +7 -0
- package/dist/js/chunks/chunk-LDXCC2L3.mjs +438 -0
- package/dist/js/chunks/chunk-LDXCC2L3.mjs.map +7 -0
- package/dist/js/chunks/chunk-NAC72P7R.mjs +137 -0
- package/dist/js/chunks/chunk-NAC72P7R.mjs.map +7 -0
- package/dist/js/chunks/chunk-NBJAUGPP.mjs +244 -0
- package/dist/js/chunks/chunk-NBJAUGPP.mjs.map +7 -0
- package/dist/js/chunks/chunk-NNHVANQA.mjs +113 -0
- package/dist/js/chunks/chunk-NNHVANQA.mjs.map +7 -0
- package/dist/js/chunks/chunk-NVQ5EHCU.mjs +376 -0
- package/dist/js/chunks/chunk-NVQ5EHCU.mjs.map +7 -0
- package/dist/js/chunks/{chunk-DXGRXYYL.mjs → chunk-OP43LLIC.mjs} +28 -45
- package/dist/js/chunks/chunk-OP43LLIC.mjs.map +7 -0
- package/dist/js/chunks/chunk-OUCHKSAW.mjs +63 -0
- package/dist/js/chunks/chunk-OUCHKSAW.mjs.map +7 -0
- package/dist/js/chunks/{chunk-TSZYSW7F.mjs → chunk-OYNUDOHR.mjs} +19 -47
- package/dist/js/chunks/chunk-OYNUDOHR.mjs.map +7 -0
- package/dist/js/chunks/{chunk-UAZSDUVP.mjs → chunk-P6DRQ6KS.mjs} +36 -30
- package/dist/js/chunks/chunk-P6DRQ6KS.mjs.map +7 -0
- package/dist/js/chunks/chunk-PA7NU5AK.mjs +99 -0
- package/dist/js/chunks/chunk-PA7NU5AK.mjs.map +7 -0
- package/dist/js/chunks/chunk-QACZ6TUP.mjs +224 -0
- package/dist/js/chunks/chunk-QACZ6TUP.mjs.map +7 -0
- package/dist/js/chunks/{chunk-GJL6GCIU.mjs → chunk-QXKWVHBD.mjs} +265 -161
- package/dist/js/chunks/chunk-QXKWVHBD.mjs.map +7 -0
- package/dist/js/chunks/{chunk-X4ISMKE2.mjs → chunk-ROH2HDB4.mjs} +7 -6
- package/dist/js/chunks/chunk-ROH2HDB4.mjs.map +7 -0
- package/dist/js/chunks/chunk-S23RJ3XY.mjs +86 -0
- package/dist/js/chunks/chunk-S23RJ3XY.mjs.map +7 -0
- package/dist/js/chunks/{chunk-SMY7GJSS.mjs → chunk-SPPHF7YZ.mjs} +36 -29
- package/dist/js/chunks/chunk-SPPHF7YZ.mjs.map +7 -0
- package/dist/js/chunks/chunk-T3BNSRP3.mjs +152 -0
- package/dist/js/chunks/chunk-T3BNSRP3.mjs.map +7 -0
- package/dist/js/chunks/chunk-TFABTUAZ.mjs +108 -0
- package/dist/js/chunks/chunk-TFABTUAZ.mjs.map +7 -0
- package/dist/js/chunks/chunk-U4B3VHFS.mjs +507 -0
- package/dist/js/chunks/chunk-U4B3VHFS.mjs.map +7 -0
- package/dist/js/chunks/chunk-UGJHCHXG.mjs +341 -0
- package/dist/js/chunks/chunk-UGJHCHXG.mjs.map +7 -0
- package/dist/js/chunks/chunk-VFV75DHF.mjs +70 -0
- package/dist/js/chunks/chunk-VFV75DHF.mjs.map +7 -0
- package/dist/js/chunks/{chunk-ZX6M7SWO.mjs → chunk-VGY4M57S.mjs} +266 -120
- package/dist/js/chunks/chunk-VGY4M57S.mjs.map +7 -0
- package/dist/js/chunks/chunk-VH4BMAZS.mjs +167 -0
- package/dist/js/chunks/chunk-VH4BMAZS.mjs.map +7 -0
- package/dist/js/chunks/chunk-VJVQIXHC.mjs +123 -0
- package/dist/js/chunks/chunk-VJVQIXHC.mjs.map +7 -0
- package/dist/js/chunks/{chunk-SFI2U4YW.mjs → chunk-VMY55K2X.mjs} +76 -109
- package/dist/js/chunks/chunk-VMY55K2X.mjs.map +7 -0
- package/dist/js/chunks/{chunk-KUFHW3DS.mjs → chunk-VR3L2WN5.mjs} +11 -17
- package/dist/js/chunks/chunk-VR3L2WN5.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-WU7XJ4RR.mjs +450 -0
- package/dist/js/chunks/chunk-WU7XJ4RR.mjs.map +7 -0
- package/dist/js/chunks/chunk-X7SDA2J5.mjs +116 -0
- package/dist/js/chunks/chunk-X7SDA2J5.mjs.map +7 -0
- package/dist/js/chunks/chunk-Y6H2X7ZC.mjs +209 -0
- package/dist/js/chunks/chunk-Y6H2X7ZC.mjs.map +7 -0
- package/dist/js/chunks/chunk-Y6TLRA3U.mjs +129 -0
- package/dist/js/chunks/chunk-Y6TLRA3U.mjs.map +7 -0
- package/dist/js/chunks/chunk-Z4GICXR2.mjs +190 -0
- package/dist/js/chunks/chunk-Z4GICXR2.mjs.map +7 -0
- package/dist/js/chunks/chunk-Z4OARDZ7.mjs +442 -0
- package/dist/js/chunks/chunk-Z4OARDZ7.mjs.map +7 -0
- package/dist/js/chunks/{chunk-FM5CZOUB.mjs → chunk-ZJNLAGY5.mjs} +19 -30
- package/dist/js/chunks/chunk-ZJNLAGY5.mjs.map +7 -0
- package/dist/js/chunks/chunk-ZKWUWBUB.mjs +81 -0
- package/dist/js/chunks/chunk-ZKWUWBUB.mjs.map +7 -0
- package/dist/js/chunks/chunk-ZM3XBHWV.mjs +746 -0
- package/dist/js/chunks/chunk-ZM3XBHWV.mjs.map +7 -0
- package/dist/js/chunks/chunk-ZO6ZLHFF.mjs +48 -0
- package/dist/js/chunks/chunk-ZO6ZLHFF.mjs.map +7 -0
- package/dist/js/chunks/chunk-ZVLOUDIJ.mjs +251 -0
- package/dist/js/chunks/chunk-ZVLOUDIJ.mjs.map +7 -0
- package/dist/js/expressive.cjs +10613 -4327
- package/dist/js/expressive.cjs.map +4 -4
- package/dist/js/expressive.js +10613 -4327
- 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 +182 -71
- 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 +10 -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 +4 -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 +6 -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 +11 -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 -66
- 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 +25 -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 +59 -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 +4 -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 +13 -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 +2 -1
- package/dist/js/internal/core/formControl.mjs +12 -0
- package/dist/js/internal/core/formControl.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 +11 -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 +173 -71
- package/dist/types/behaviors/bottomSheets.d.ts +19 -3
- package/dist/types/behaviors/copy.d.ts +18 -0
- package/dist/types/behaviors/dataTables.d.ts +129 -0
- package/dist/types/behaviors/dialogs.d.ts +27 -1
- package/dist/types/behaviors/forms.d.ts +68 -2
- package/dist/types/behaviors/imageCompare.d.ts +12 -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 +51 -0
- package/dist/types/components/appBar.d.ts +5 -6
- package/dist/types/components/autocomplete.d.ts +91 -17
- 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 +9 -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 +65 -19
- package/dist/types/components/colorPicker.d.ts +42 -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 +59 -0
- package/dist/types/components/datepicker.d.ts +56 -32
- package/dist/types/components/expandingCard.d.ts +4 -6
- package/dist/types/components/funnelChart.d.ts +38 -0
- package/dist/types/components/heatmapChart.d.ts +39 -8
- package/dist/types/components/hoverCard.d.ts +58 -0
- package/dist/types/components/index.d.ts +16 -1
- package/dist/types/components/inputMask.d.ts +30 -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 +172 -10
- package/dist/types/components/loadingOverlay.d.ts +42 -0
- package/dist/types/components/mapView.d.ts +26 -17
- package/dist/types/components/menu.d.ts +60 -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 +8 -4
- package/dist/types/components/pieChart.d.ts +32 -7
- 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 +6 -14
- 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 +43 -30
- package/dist/types/components/showMore.d.ts +51 -0
- package/dist/types/components/slider.d.ts +3 -15
- package/dist/types/components/snackbar.d.ts +61 -0
- package/dist/types/components/swipeActions.d.ts +81 -0
- package/dist/types/components/tabs.d.ts +89 -27
- package/dist/types/components/timepicker.d.ts +113 -21
- package/dist/types/components/tooltip.d.ts +56 -20
- 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 +43 -25
- package/dist/types/core/formControl.d.ts +21 -0
- package/dist/types/core/spring.d.ts +20 -0
- package/dist/types/core/utils.d.ts +85 -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 +32 -0
- package/package.json +10 -8
- 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 +422 -36
- package/src/sass/abstracts/_spring.scss +63 -0
- package/src/sass/abstracts/_variables.scss +39 -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 +9 -16
- package/src/sass/components/_alert.scss +102 -0
- package/src/sass/components/_aura.scss +8 -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 +41 -19
- package/src/sass/components/_bottom-sheet.scss +44 -16
- package/src/sass/components/_breadcrumb.scss +8 -1
- package/src/sass/components/_button-groups.scss +15 -25
- package/src/sass/components/_buttons.scss +156 -63
- package/src/sass/components/_calendar.scss +246 -0
- package/src/sass/components/_cards.scss +36 -44
- package/src/sass/components/_carousel.scss +27 -103
- package/src/sass/components/_cascader.scss +142 -0
- package/src/sass/components/_chips.scss +36 -46
- package/src/sass/components/_column-chart.scss +19 -12
- package/src/sass/components/_command-palette.scss +4 -7
- package/src/sass/components/_confetti.scss +0 -2
- package/src/sass/components/_countdown.scss +1 -1
- package/src/sass/components/_data-table.scss +162 -25
- package/src/sass/components/_datepicker.scss +54 -40
- package/src/sass/components/_description-list.scss +85 -0
- package/src/sass/components/_dialog.scss +42 -41
- 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 +20 -9
- package/src/sass/components/_fab-menu.scss +44 -32
- package/src/sass/components/_funnel-chart.scss +124 -0
- package/src/sass/components/_heatmap-chart.scss +111 -22
- package/src/sass/components/_icon-buttons.scss +7 -7
- 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 +16 -2
- 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 +33 -11
- package/src/sass/components/_marquee.scss +3 -2
- package/src/sass/components/_mega-menu.scss +137 -0
- package/src/sass/components/_menu.scss +143 -123
- package/src/sass/components/_menubar.scss +59 -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 +37 -9
- package/src/sass/components/_modal-display.scss +21 -0
- package/src/sass/components/_navbar.scss +34 -20
- package/src/sass/components/_navigation-bar.scss +15 -77
- package/src/sass/components/_navigation-rail.scss +151 -92
- package/src/sass/components/_org-chart.scss +192 -0
- package/src/sass/components/_page-footer.scss +1 -1
- package/src/sass/components/_pagination.scss +6 -13
- package/src/sass/components/_panes.scss +32 -26
- package/src/sass/components/_particles.scss +0 -2
- package/src/sass/components/_pie-chart.scss +91 -11
- package/src/sass/components/_popover.scss +18 -5
- package/src/sass/components/_progress.scss +152 -31
- 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 +38 -10
- package/src/sass/components/_radial-chart.scss +113 -5
- package/src/sass/components/_rich-text-editor.scss +2 -2
- package/src/sass/components/_sankey-chart.scss +114 -0
- package/src/sass/components/_scatter-chart.scss +153 -0
- package/src/sass/components/_scrim.scss +0 -2
- package/src/sass/components/_scrollspy.scss +0 -2
- package/src/sass/components/_search.scss +26 -22
- package/src/sass/components/_show-more.scss +8 -0
- package/src/sass/components/_side-sheet.scss +23 -37
- package/src/sass/components/_skeleton.scss +2 -4
- package/src/sass/components/_snackbar.scss +27 -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/_tabs.scss +51 -32
- package/src/sass/components/_timeline.scss +12 -12
- package/src/sass/components/_timepicker.scss +109 -78
- package/src/sass/components/_toolbar.scss +35 -43
- package/src/sass/components/_tooltip.scss +21 -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 +3 -16
- package/src/sass/components/_treemap-chart.scss +122 -0
- package/src/sass/components/forms/_checkboxes.scss +106 -24
- 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 +15 -9
- package/src/sass/components/forms/_fieldset.scss +7 -7
- package/src/sass/components/forms/_file-input.scss +6 -8
- package/src/sass/components/forms/_index.scss +3 -1
- package/src/sass/components/forms/_input-fields.scss +254 -90
- package/src/sass/components/forms/_radio-buttons.scss +33 -94
- package/src/sass/components/forms/_rating.scss +2 -32
- package/src/sass/components/forms/_select.scss +199 -20
- package/src/sass/components/forms/_slider.scss +91 -94
- package/src/sass/components/forms/_switches.scss +53 -164
- 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 +183 -26
- 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 +47 -76
- 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.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,435 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Component
|
|
3
|
+
} from "./chunk-CMGXGYUC.mjs";
|
|
4
|
+
import {
|
|
5
|
+
Utils
|
|
6
|
+
} from "./chunk-ZVLOUDIJ.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
|
+
function answerText(control) {
|
|
26
|
+
if (control instanceof HTMLSelectElement) return Array.from(control.selectedOptions, (option) => option.text).join(", ");
|
|
27
|
+
if (isChoice(control)) return control.checked ? labelText(control) : "";
|
|
28
|
+
return control.value.trim();
|
|
29
|
+
}
|
|
30
|
+
var savedState = (control) => {
|
|
31
|
+
if (control instanceof HTMLSelectElement) return Array.from(control.selectedOptions, (option) => option.value);
|
|
32
|
+
return isChoice(control) ? control.checked : control.value;
|
|
33
|
+
};
|
|
34
|
+
var validSaved = (saved) => Array.isArray(saved?.answers) ? saved : null;
|
|
35
|
+
function restoreState(control, saved) {
|
|
36
|
+
if (control instanceof HTMLSelectElement) return restoreSelect(control, saved);
|
|
37
|
+
if (isChoice(control)) control.checked = saved === true;
|
|
38
|
+
else if (typeof saved === "string") control.value = saved;
|
|
39
|
+
}
|
|
40
|
+
function restoreSelect(select, saved) {
|
|
41
|
+
if (!Array.isArray(saved)) return;
|
|
42
|
+
for (const option of select.options) option.selected = saved.includes(option.value);
|
|
43
|
+
}
|
|
44
|
+
function restoreControl(control, saved) {
|
|
45
|
+
const before = JSON.stringify(savedState(control));
|
|
46
|
+
restoreState(control, saved);
|
|
47
|
+
if (JSON.stringify(savedState(control)) !== before) control.dispatchEvent(new Event("change", { bubbles: true }));
|
|
48
|
+
}
|
|
49
|
+
function shortcut(e) {
|
|
50
|
+
if (typingIn(e.target) || !Utils.plainKey(e)) return -1;
|
|
51
|
+
const digit = "123456789".indexOf(e.key);
|
|
52
|
+
return digit >= 0 ? digit : letterIndex(e.key);
|
|
53
|
+
}
|
|
54
|
+
var TYPING = 'textarea, select, [contenteditable], input:not([type="radio"], [type="checkbox"], [type="button"], [type="submit"], [type="reset"])';
|
|
55
|
+
var typingIn = (target) => !!target.matches?.(TYPING);
|
|
56
|
+
var letterIndex = (key) => key.length === 1 ? LETTERS.indexOf(key.toLowerCase()) : -1;
|
|
57
|
+
var Questionnaire = class extends Component {
|
|
58
|
+
// HTMLElement, not HTMLFormElement: init() takes the element type from
|
|
59
|
+
// here, and has always accepted any HTMLElement.
|
|
60
|
+
constructor(el, options) {
|
|
61
|
+
const progressLabel = el.dataset.progressLabel;
|
|
62
|
+
super(el, { ...progressLabel ? { progressLabel } : {}, ...options });
|
|
63
|
+
this._active = null;
|
|
64
|
+
this._generated = [];
|
|
65
|
+
this._generatedIds = [];
|
|
66
|
+
/** Set while one submission's invalid events arrive, so only the first opens. */
|
|
67
|
+
this._reporting = false;
|
|
68
|
+
/** With data-summary, the review step, and whether it is shown. */
|
|
69
|
+
this._summary = null;
|
|
70
|
+
this._reviewing = false;
|
|
71
|
+
/** Shows the question at `index` without checking the current one. */
|
|
72
|
+
this.goTo = (index) => {
|
|
73
|
+
const item = this.items[index];
|
|
74
|
+
if (!item) return;
|
|
75
|
+
this._active = item;
|
|
76
|
+
this._reviewing = false;
|
|
77
|
+
this._render();
|
|
78
|
+
this._save();
|
|
79
|
+
const controls = this._controls(item).filter((control) => !control.disabled);
|
|
80
|
+
(controls.find((control) => control.checked) ?? controls[0])?.focus();
|
|
81
|
+
};
|
|
82
|
+
/** Checks the shown question and moves to the next one if it is answered. */
|
|
83
|
+
this.next = () => {
|
|
84
|
+
if (this._validate(this._active)) this._advance();
|
|
85
|
+
};
|
|
86
|
+
/** Moves to the previous question, or from the review step back to the last one. */
|
|
87
|
+
this.previous = () => this.goTo(this._reviewing ? this.items.length - 1 : this.index - 1);
|
|
88
|
+
/** Shows the review step of a questionnaire with data-summary. */
|
|
89
|
+
this.review = () => {
|
|
90
|
+
if (!this._summary) return;
|
|
91
|
+
this._fillSummary(this._summary);
|
|
92
|
+
this._reviewing = true;
|
|
93
|
+
this._render();
|
|
94
|
+
this._summary.focus();
|
|
95
|
+
};
|
|
96
|
+
/** Clears the answer to the shown question and moves to the next one. */
|
|
97
|
+
this.skip = () => {
|
|
98
|
+
if (!this._active) return;
|
|
99
|
+
for (const control of this._controls(this._active)) {
|
|
100
|
+
const choice = isChoice(control);
|
|
101
|
+
if (choice ? !control.checked : !control.value) continue;
|
|
102
|
+
if (choice) control.checked = false;
|
|
103
|
+
else control.value = "";
|
|
104
|
+
control.dispatchEvent(new Event("change", { bubbles: true }));
|
|
105
|
+
}
|
|
106
|
+
this._setInvalid(this._active, false);
|
|
107
|
+
this._advance();
|
|
108
|
+
};
|
|
109
|
+
/** With data-save, stores the answers and the shown question. */
|
|
110
|
+
this._save = () => {
|
|
111
|
+
const key = this._key;
|
|
112
|
+
if (!key) return;
|
|
113
|
+
const state = { index: this.index, answers: this._allControls().map(savedState) };
|
|
114
|
+
try {
|
|
115
|
+
localStorage.setItem(key, JSON.stringify(state));
|
|
116
|
+
} catch {
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
/** A submitted questionnaire has nothing left to resume. */
|
|
120
|
+
this._forget = () => {
|
|
121
|
+
try {
|
|
122
|
+
if (this._key) localStorage.removeItem(this._key);
|
|
123
|
+
} catch {
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
this._handleClick = (e) => {
|
|
127
|
+
const button = e.target.closest?.("button");
|
|
128
|
+
if (!button || !this._buttons().includes(button)) return;
|
|
129
|
+
if (NAVIGATION.includes(button.value)) {
|
|
130
|
+
e.preventDefault();
|
|
131
|
+
this[button.value]();
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
this._syncRequired();
|
|
135
|
+
};
|
|
136
|
+
// Enter in a field moves on instead of submitting the form early. With
|
|
137
|
+
// data-shortcuts, a letter or digit picks an answer.
|
|
138
|
+
this._handleKeydown = (e) => {
|
|
139
|
+
if (e.key !== "Enter") return this._handleShortcut(e);
|
|
140
|
+
if (e.defaultPrevented || Utils.isComposing(e)) return;
|
|
141
|
+
if (!(e.target instanceof HTMLInputElement) || this._end) return;
|
|
142
|
+
e.preventDefault();
|
|
143
|
+
this.next();
|
|
144
|
+
};
|
|
145
|
+
// A submission found an unanswered question, possibly a hidden one. Open the
|
|
146
|
+
// first instead of letting the browser report a control it cannot show.
|
|
147
|
+
// One submission fires its invalid events in a single task.
|
|
148
|
+
this._handleInvalid = (e) => {
|
|
149
|
+
const item = this.items.find((item2) => item2.contains(e.target));
|
|
150
|
+
if (!item) return;
|
|
151
|
+
e.preventDefault();
|
|
152
|
+
if (this._reporting) return;
|
|
153
|
+
this._reporting = true;
|
|
154
|
+
setTimeout(() => this._reporting = false);
|
|
155
|
+
this._active = item;
|
|
156
|
+
this._reviewing = false;
|
|
157
|
+
this._render();
|
|
158
|
+
this._validate(item);
|
|
159
|
+
};
|
|
160
|
+
// An answer clears the question's error.
|
|
161
|
+
this._handleInput = (e) => {
|
|
162
|
+
this._syncRequired();
|
|
163
|
+
this._save();
|
|
164
|
+
const item = e.target.closest?.("fieldset");
|
|
165
|
+
if (item instanceof HTMLFieldSetElement && item.classList.contains("invalid")) this._setInvalid(item, false);
|
|
166
|
+
};
|
|
167
|
+
this._progress = document.createElement("div");
|
|
168
|
+
this._progress.className = "questionnaire-progress";
|
|
169
|
+
this._progressText = document.createElement("span");
|
|
170
|
+
this._progressText.id = `questionnaire-progress-${Utils.guid()}`;
|
|
171
|
+
this._progressBar = document.createElement("progress");
|
|
172
|
+
this._progressBar.className = "progress";
|
|
173
|
+
this._progressBar.setAttribute("aria-labelledby", this._progressText.id);
|
|
174
|
+
this._progress.append(this._progressText, this._progressBar);
|
|
175
|
+
this.el.prepend(this._progress);
|
|
176
|
+
for (const item of this._fieldsets()) {
|
|
177
|
+
const ids = Array.from(item.querySelectorAll(":scope > p:not(.questionnaire-error)")).map((p) => this._ensureId(p, "questionnaire-description"));
|
|
178
|
+
if (ids.length && !item.hasAttribute("aria-describedby")) {
|
|
179
|
+
item.setAttribute("aria-describedby", ids.join(" "));
|
|
180
|
+
this._generatedIds.push(item);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
this._active = this.items[0] ?? null;
|
|
184
|
+
this._summary = this._createSummary();
|
|
185
|
+
this._restore();
|
|
186
|
+
this._syncRequired();
|
|
187
|
+
this._render();
|
|
188
|
+
this._observer = new MutationObserver(() => {
|
|
189
|
+
this._syncRequired();
|
|
190
|
+
this._render();
|
|
191
|
+
});
|
|
192
|
+
this._observer.observe(this.el, { attributes: true, subtree: true, attributeFilter: ["disabled"] });
|
|
193
|
+
const { signal } = this._events;
|
|
194
|
+
this.el.addEventListener("click", this._handleClick, { signal });
|
|
195
|
+
this.el.addEventListener("keydown", this._handleKeydown, { signal });
|
|
196
|
+
this.el.addEventListener("input", this._handleInput, { signal });
|
|
197
|
+
this.el.addEventListener("change", this._save, { signal });
|
|
198
|
+
this.el.addEventListener("submit", this._forget, { signal });
|
|
199
|
+
this.el.addEventListener("invalid", this._handleInvalid, { capture: true, signal });
|
|
200
|
+
}
|
|
201
|
+
static get defaults() {
|
|
202
|
+
return _defaults;
|
|
203
|
+
}
|
|
204
|
+
/** The questions that apply: every fieldset child that is not disabled. */
|
|
205
|
+
get items() {
|
|
206
|
+
return this._fieldsets().filter((item) => !item.disabled);
|
|
207
|
+
}
|
|
208
|
+
/** Position of the shown question in `items`. */
|
|
209
|
+
get index() {
|
|
210
|
+
return this.items.indexOf(this._active);
|
|
211
|
+
}
|
|
212
|
+
/** The next question, or after the last one the review step. */
|
|
213
|
+
_advance() {
|
|
214
|
+
if (this._summary && this.index === this.items.length - 1) this.review();
|
|
215
|
+
else this.goTo(this.index + 1);
|
|
216
|
+
}
|
|
217
|
+
destroy() {
|
|
218
|
+
this._observer.disconnect();
|
|
219
|
+
this._summary?.remove();
|
|
220
|
+
for (const item of this._fieldsets()) {
|
|
221
|
+
if (item.hasAttribute("data-required")) for (const control of this._controls(item)) control.setCustomValidity("");
|
|
222
|
+
item.hidden = false;
|
|
223
|
+
this._setInvalid(item, false);
|
|
224
|
+
}
|
|
225
|
+
for (const button of this._buttons()) button.hidden = false;
|
|
226
|
+
this._progress.remove();
|
|
227
|
+
for (const el of this._generated) el.remove();
|
|
228
|
+
for (const el of this._generatedIds) {
|
|
229
|
+
el.removeAttribute(el instanceof HTMLFieldSetElement ? "aria-describedby" : "id");
|
|
230
|
+
}
|
|
231
|
+
super.destroy();
|
|
232
|
+
}
|
|
233
|
+
_fieldsets() {
|
|
234
|
+
return Array.from(this.el.querySelectorAll(":scope > fieldset"));
|
|
235
|
+
}
|
|
236
|
+
/** The footer's navigation and submit buttons. */
|
|
237
|
+
_buttons() {
|
|
238
|
+
return Array.from(this.el.querySelectorAll(":scope > footer > button")).filter(
|
|
239
|
+
(button) => NAVIGATION.includes(button.value) || button.type === "submit"
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
_controls(item) {
|
|
243
|
+
return Array.from(item.elements).filter(
|
|
244
|
+
(el) => el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement || el instanceof HTMLInputElement && el.type !== "button" && el.type !== "submit"
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
_required(item) {
|
|
248
|
+
return item.hasAttribute("data-required") || this._controls(item).some((control) => control.required);
|
|
249
|
+
}
|
|
250
|
+
_ensureId(el, prefix) {
|
|
251
|
+
if (!el.id) {
|
|
252
|
+
el.id = `${prefix}-${Utils.guid()}`;
|
|
253
|
+
this._generatedIds.push(el);
|
|
254
|
+
}
|
|
255
|
+
return el.id;
|
|
256
|
+
}
|
|
257
|
+
_render() {
|
|
258
|
+
const items = this.items;
|
|
259
|
+
if (!items.includes(this._active)) this._active = this._after(items);
|
|
260
|
+
const index = items.indexOf(this._active);
|
|
261
|
+
for (const item of this._fieldsets()) item.hidden = this._reviewing || item !== this._active;
|
|
262
|
+
this._summary?.toggleAttribute("hidden", !this._reviewing);
|
|
263
|
+
for (const button of this._buttons()) button.hidden = !this._shows(button, index);
|
|
264
|
+
this._renderProgress(index, items.length);
|
|
265
|
+
}
|
|
266
|
+
/** The question after the shown one, which was switched off, or the last that applies. */
|
|
267
|
+
_after(items) {
|
|
268
|
+
const all = this._fieldsets();
|
|
269
|
+
const after = all.slice(all.indexOf(this._active) + 1).find((item) => !item.disabled);
|
|
270
|
+
return after ?? items[items.length - 1] ?? null;
|
|
271
|
+
}
|
|
272
|
+
/** Whether the shown step is the one that submits: the review step, or without one the last question. */
|
|
273
|
+
get _end() {
|
|
274
|
+
return this._summary ? this._reviewing : this.index === this.items.length - 1;
|
|
275
|
+
}
|
|
276
|
+
/** Whether a footer button applies to the shown step. */
|
|
277
|
+
_shows(button, index) {
|
|
278
|
+
const end = this._end;
|
|
279
|
+
const shown = {
|
|
280
|
+
previous: index > 0 || this._reviewing,
|
|
281
|
+
skip: !end && this._skippable(),
|
|
282
|
+
next: !end
|
|
283
|
+
};
|
|
284
|
+
return shown[button.value] ?? end;
|
|
285
|
+
}
|
|
286
|
+
/** Whether the shown question may be skipped: it applies and needs no answer. */
|
|
287
|
+
_skippable() {
|
|
288
|
+
return !!this._active && !this._required(this._active);
|
|
289
|
+
}
|
|
290
|
+
_renderProgress(index, total) {
|
|
291
|
+
this._progressText.textContent = this._reviewing ? this.options.summaryLabel : this.options.progressLabel.replace("{current}", String(index + 1)).replace("{total}", String(total));
|
|
292
|
+
this._progressBar.max = Math.max(total, 1);
|
|
293
|
+
this._progressBar.value = this._reviewing ? total : index + 1;
|
|
294
|
+
}
|
|
295
|
+
/** With data-summary, the review step: a list of the questions and their answers, before the footer. */
|
|
296
|
+
_createSummary() {
|
|
297
|
+
if (!this.el.hasAttribute("data-summary")) return null;
|
|
298
|
+
const summary = document.createElement("section");
|
|
299
|
+
summary.className = "questionnaire-summary";
|
|
300
|
+
summary.tabIndex = -1;
|
|
301
|
+
summary.setAttribute("aria-label", this.options.summaryLabel);
|
|
302
|
+
summary.hidden = true;
|
|
303
|
+
summary.addEventListener("click", (e) => {
|
|
304
|
+
const edit = e.target.closest("button[data-question]");
|
|
305
|
+
if (edit) this.goTo(Number(edit.dataset.question));
|
|
306
|
+
});
|
|
307
|
+
const footer = this.el.querySelector(":scope > footer");
|
|
308
|
+
if (footer) footer.before(summary);
|
|
309
|
+
else this.el.append(summary);
|
|
310
|
+
return summary;
|
|
311
|
+
}
|
|
312
|
+
/** Lists each question that applies with its answer and a button back to it. */
|
|
313
|
+
_fillSummary(summary) {
|
|
314
|
+
const list = document.createElement("dl");
|
|
315
|
+
list.append(...this.items.map((item, i) => {
|
|
316
|
+
const row = document.createElement("div");
|
|
317
|
+
const [term, answer, action] = [document.createElement("dt"), document.createElement("dd"), document.createElement("dd")];
|
|
318
|
+
term.id = `questionnaire-summary-${Utils.guid()}`;
|
|
319
|
+
term.textContent = item.querySelector(":scope > legend")?.textContent.trim() ?? "";
|
|
320
|
+
answer.textContent = this._controls(item).map(answerText).filter(Boolean).join(", ") || this.options.skippedLabel;
|
|
321
|
+
const edit = document.createElement("button");
|
|
322
|
+
Object.assign(edit, { type: "button", className: "text", textContent: this.options.editLabel });
|
|
323
|
+
edit.dataset.question = String(i);
|
|
324
|
+
edit.setAttribute("aria-describedby", term.id);
|
|
325
|
+
action.append(edit);
|
|
326
|
+
row.append(term, answer, action);
|
|
327
|
+
return row;
|
|
328
|
+
}));
|
|
329
|
+
summary.replaceChildren(list);
|
|
330
|
+
}
|
|
331
|
+
/** The storage key from data-save, or '' without it. */
|
|
332
|
+
get _key() {
|
|
333
|
+
const key = this.el.dataset.save;
|
|
334
|
+
return key ? `questionnaire:${key}` : "";
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Every answer control that can be saved, in order. A file cannot be put back,
|
|
338
|
+
* a password must not sit in storage, and a hidden input is the server's.
|
|
339
|
+
*/
|
|
340
|
+
_allControls() {
|
|
341
|
+
return this._fieldsets().flatMap((item) => this._controls(item)).filter((control) => !UNSAVED.includes(control.type));
|
|
342
|
+
}
|
|
343
|
+
/** Puts back saved answers and the question they reached, if the questions are the same. */
|
|
344
|
+
_restore() {
|
|
345
|
+
const saved = this._read();
|
|
346
|
+
const controls = this._allControls();
|
|
347
|
+
if (saved?.answers.length !== controls.length) return;
|
|
348
|
+
controls.forEach((control, i) => restoreControl(control, saved.answers[i]));
|
|
349
|
+
this._active = this.items[saved.index] ?? this._active;
|
|
350
|
+
}
|
|
351
|
+
/** The saved state, or null for none or a broken one. */
|
|
352
|
+
_read() {
|
|
353
|
+
try {
|
|
354
|
+
return validSaved(JSON.parse(localStorage.getItem(this._key) ?? "null"));
|
|
355
|
+
} catch {
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Puts "choose at least one" on the first enabled checkbox of each
|
|
361
|
+
* data-required group with none checked, so the browser's validation, and
|
|
362
|
+
* every way of submitting, sees it. A disabled checkbox is not sent, so it
|
|
363
|
+
* does not count.
|
|
364
|
+
*/
|
|
365
|
+
_syncRequired() {
|
|
366
|
+
for (const item of this._fieldsets()) {
|
|
367
|
+
if (!item.hasAttribute("data-required")) continue;
|
|
368
|
+
const boxes = this._controls(item).filter(
|
|
369
|
+
(control) => control instanceof HTMLInputElement && control.type === "checkbox"
|
|
370
|
+
);
|
|
371
|
+
const enabled = boxes.filter((box) => !box.disabled);
|
|
372
|
+
for (const box of boxes) box.setCustomValidity("");
|
|
373
|
+
if (enabled.length && !enabled.some((box) => box.checked)) {
|
|
374
|
+
const error = item.querySelector(":scope > .questionnaire-error:not([data-generated])");
|
|
375
|
+
enabled[0].setCustomValidity(error?.textContent.trim() || this.options.requiredMessage);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
/** The first control in the question that still needs an answer. */
|
|
380
|
+
_invalidControl(item) {
|
|
381
|
+
return this._controls(item).find((control) => control.willValidate && !control.validity.valid);
|
|
382
|
+
}
|
|
383
|
+
/** Shows the question's error and returns false when it needs an answer. */
|
|
384
|
+
_validate(item) {
|
|
385
|
+
this._syncRequired();
|
|
386
|
+
const invalid = item && this._invalidControl(item);
|
|
387
|
+
if (!invalid) return true;
|
|
388
|
+
let error = item.querySelector(":scope > .questionnaire-error");
|
|
389
|
+
if (!error) {
|
|
390
|
+
error = document.createElement("p");
|
|
391
|
+
error.className = "questionnaire-error";
|
|
392
|
+
error.dataset.generated = "";
|
|
393
|
+
error.textContent = invalid.validationMessage || this.options.requiredMessage;
|
|
394
|
+
item.append(error);
|
|
395
|
+
this._generated.push(error);
|
|
396
|
+
}
|
|
397
|
+
this._setInvalid(item, true);
|
|
398
|
+
invalid.focus();
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
_setInvalid(item, invalid) {
|
|
402
|
+
item.classList.toggle("invalid", invalid);
|
|
403
|
+
const error = item.querySelector(":scope > .questionnaire-error");
|
|
404
|
+
const described = (item.getAttribute("aria-describedby") ?? "").split(" ").filter((id) => id && id !== error?.id);
|
|
405
|
+
if (invalid && error) described.push(this._ensureId(error, "questionnaire-error"));
|
|
406
|
+
if (described.length) item.setAttribute("aria-describedby", described.join(" "));
|
|
407
|
+
else item.removeAttribute("aria-describedby");
|
|
408
|
+
for (const control of this._controls(item)) {
|
|
409
|
+
if (invalid) control.setAttribute("aria-invalid", "true");
|
|
410
|
+
else control.removeAttribute("aria-invalid");
|
|
411
|
+
}
|
|
412
|
+
if (!invalid && this._generated.includes(error)) {
|
|
413
|
+
error.remove();
|
|
414
|
+
this._generated.splice(this._generated.indexOf(error), 1);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
/** Whether a shortcut key can pick an answer now: data-shortcuts is set and a question shows. */
|
|
418
|
+
get _shortcuts() {
|
|
419
|
+
return this.el.hasAttribute("data-shortcuts") && !!this._active && !this._reviewing;
|
|
420
|
+
}
|
|
421
|
+
_handleShortcut(e) {
|
|
422
|
+
if (!this._shortcuts) return;
|
|
423
|
+
const choice = this._controls(this._active).filter(isChoice)[shortcut(e)];
|
|
424
|
+
if (!choice || choice.disabled) return;
|
|
425
|
+
e.preventDefault();
|
|
426
|
+
choice.click();
|
|
427
|
+
choice.focus();
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
Questionnaire.key = "Expressive_Questionnaire";
|
|
431
|
+
|
|
432
|
+
export {
|
|
433
|
+
Questionnaire
|
|
434
|
+
};
|
|
435
|
+
//# sourceMappingURL=chunk-GWZ76SR4.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/** 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 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() {\n for (const item of this._fieldsets()) {\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();\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
|
+
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Utils
|
|
3
|
-
} from "./chunk-M372EDXD.mjs";
|
|
4
1
|
import {
|
|
5
2
|
Component
|
|
6
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-CMGXGYUC.mjs";
|
|
4
|
+
import {
|
|
5
|
+
restoreAttribute
|
|
6
|
+
} from "./chunk-ZVLOUDIJ.mjs";
|
|
7
7
|
|
|
8
8
|
// src/ts/components/buttons.ts
|
|
9
9
|
var _defaults = {};
|
|
10
|
-
var FloatingActionButton = class
|
|
10
|
+
var FloatingActionButton = class extends Component {
|
|
11
11
|
constructor(el, options) {
|
|
12
|
-
super(el, options
|
|
12
|
+
super(el, options);
|
|
13
|
+
this._addedExpanded = false;
|
|
13
14
|
this.open = () => {
|
|
14
15
|
if (this.isOpen) return;
|
|
15
16
|
this.isOpen = true;
|
|
@@ -39,56 +40,53 @@ var FloatingActionButton = class _FloatingActionButton extends Component {
|
|
|
39
40
|
else if (this._list?.contains(control)) this.close();
|
|
40
41
|
};
|
|
41
42
|
this._handleAnchorKeydown = (e) => {
|
|
42
|
-
if (e.key ===
|
|
43
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
43
44
|
e.preventDefault();
|
|
44
45
|
this._toggle();
|
|
45
46
|
}
|
|
46
47
|
};
|
|
47
48
|
this._handleDocumentKeydown = (e) => {
|
|
48
|
-
if (e.key ===
|
|
49
|
+
if (e.key === "Escape" && !e.defaultPrevented) this.close();
|
|
49
50
|
};
|
|
50
51
|
this._handleDocumentClick = (e) => {
|
|
51
52
|
if (e.composedPath().includes(this.el)) return;
|
|
52
53
|
this.close();
|
|
53
54
|
};
|
|
54
|
-
this.el["Expressive_FloatingActionButton"] = this;
|
|
55
|
-
this.options = { ..._FloatingActionButton.defaults, ...options };
|
|
56
55
|
this.isOpen = false;
|
|
57
56
|
this._anchor = this.el.querySelector(":scope > a, :scope > button");
|
|
58
57
|
this._list = this.el.querySelector(":scope > ul, :scope > menu");
|
|
59
58
|
this._listWasInert = this._list?.inert ?? false;
|
|
60
59
|
this.el.classList.remove("active");
|
|
61
60
|
if (this._list) this._list.inert = true;
|
|
61
|
+
this._addedExpanded = !!this._anchor && !this._anchor.hasAttribute("aria-expanded");
|
|
62
62
|
this._anchor?.setAttribute("aria-expanded", "false");
|
|
63
63
|
if (this._anchor instanceof HTMLAnchorElement && !this._anchor.hasAttribute("href")) {
|
|
64
|
-
if (this._anchor.
|
|
65
|
-
|
|
64
|
+
if (!this._anchor.hasAttribute("tabindex") || this._anchor.tabIndex < 0) {
|
|
65
|
+
this._anchorTabIndex = this._anchor.getAttribute("tabindex");
|
|
66
|
+
this._anchor.tabIndex = 0;
|
|
67
|
+
}
|
|
68
|
+
this._anchor.addEventListener("keydown", this._handleAnchorKeydown, { signal: this._events.signal });
|
|
66
69
|
}
|
|
67
|
-
this.el.addEventListener("click", this._handleFABClick);
|
|
70
|
+
this.el.addEventListener("click", this._handleFABClick, { signal: this._events.signal });
|
|
68
71
|
}
|
|
69
72
|
static get defaults() {
|
|
70
73
|
return _defaults;
|
|
71
74
|
}
|
|
72
|
-
static init(els, options = {}) {
|
|
73
|
-
return super.init(els, options, _FloatingActionButton);
|
|
74
|
-
}
|
|
75
|
-
static getInstance(el) {
|
|
76
|
-
return el["Expressive_FloatingActionButton"];
|
|
77
|
-
}
|
|
78
75
|
destroy() {
|
|
79
76
|
this.close();
|
|
80
77
|
if (this._list) this._list.inert = this._listWasInert;
|
|
81
|
-
this.
|
|
82
|
-
this._anchor
|
|
83
|
-
|
|
78
|
+
if (this._addedExpanded) this._anchor.removeAttribute("aria-expanded");
|
|
79
|
+
if (this._anchorTabIndex !== void 0) restoreAttribute(this._anchor, "tabindex", this._anchorTabIndex);
|
|
80
|
+
super.destroy();
|
|
84
81
|
}
|
|
85
82
|
_toggle() {
|
|
86
83
|
if (this.isOpen) this.close();
|
|
87
84
|
else this.open();
|
|
88
85
|
}
|
|
89
86
|
};
|
|
87
|
+
FloatingActionButton.key = "Expressive_FloatingActionButton";
|
|
90
88
|
|
|
91
89
|
export {
|
|
92
90
|
FloatingActionButton
|
|
93
91
|
};
|
|
94
|
-
//# sourceMappingURL=chunk-
|
|
92
|
+
//# sourceMappingURL=chunk-ILDRRG7T.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/ts/components/buttons.ts"],
|
|
4
|
+
"sourcesContent": ["import { restoreAttribute } from '../core/utils';\nimport { Component, BaseOptions } from \"../core/component\";\n\nexport type FloatingActionButtonOptions = BaseOptions;\n\nconst _defaults: FloatingActionButtonOptions = {};\n\nexport class FloatingActionButton extends Component<FloatingActionButtonOptions> {\n isOpen: boolean;\n private _anchor: HTMLElement | null;\n private _list: HTMLElement | null;\n private _listWasInert: boolean;\n private _addedExpanded = false;\n private _anchorTabIndex: string | null | undefined;\n\n constructor(el: HTMLElement, options: Partial<FloatingActionButtonOptions>) {\n super(el, options);\n this.isOpen = false;\n this._anchor = this.el.querySelector(':scope > a, :scope > button');\n this._list = this.el.querySelector(':scope > ul, :scope > menu');\n this._listWasInert = this._list?.inert ?? false;\n this.el.classList.remove('active');\n if (this._list) this._list.inert = true;\n this._addedExpanded = !!this._anchor && !this._anchor.hasAttribute('aria-expanded');\n this._anchor?.setAttribute('aria-expanded', 'false');\n if (this._anchor instanceof HTMLAnchorElement && !this._anchor.hasAttribute('href')) {\n // An <a> reports tabIndex 0 with or without href, but it only takes focus\n // without href once it has the attribute.\n if (!this._anchor.hasAttribute('tabindex') || this._anchor.tabIndex < 0) {\n this._anchorTabIndex = this._anchor.getAttribute('tabindex');\n this._anchor.tabIndex = 0;\n }\n this._anchor.addEventListener('keydown', this._handleAnchorKeydown, { signal: this._events.signal });\n }\n this.el.addEventListener('click', this._handleFABClick, { signal: this._events.signal });\n }\n\n static get defaults() {\n return _defaults;\n }\n\n static key = 'Expressive_FloatingActionButton';\n\n destroy() {\n this.close();\n if (this._list) this._list.inert = this._listWasInert;\n if (this._addedExpanded) this._anchor.removeAttribute('aria-expanded');\n if (this._anchorTabIndex !== undefined) restoreAttribute(this._anchor, 'tabindex', this._anchorTabIndex);\n super.destroy();\n }\n\n open = (): void => {\n if (this.isOpen) return;\n this.isOpen = true;\n if (this._list) this._list.inert = false;\n this.el.classList.add('active');\n this._anchor?.setAttribute('aria-expanded', 'true');\n document.addEventListener('click', this._handleDocumentClick);\n document.addEventListener('keydown', this._handleDocumentKeydown);\n };\n\n close = (): void => {\n if (!this.isOpen) return;\n const focused = (this.el.getRootNode() as Document | ShadowRoot).activeElement;\n if (focused && this._list?.contains(focused)) this._anchor?.focus();\n if (this._list) this._list.inert = true;\n this.isOpen = false;\n this.el.classList.remove('active');\n this._anchor?.setAttribute('aria-expanded', 'false');\n document.removeEventListener('click', this._handleDocumentClick);\n document.removeEventListener('keydown', this._handleDocumentKeydown);\n };\n\n private _handleFABClick = (e: MouseEvent) => {\n const target = e.target;\n if (!(target instanceof Element)) return;\n const control = target.closest('a, button');\n if (!control || control.matches(':disabled, [aria-disabled=\"true\"]')) return;\n if (control === this._anchor) this._toggle();\n else if (this._list?.contains(control)) this.close();\n };\n\n private _handleAnchorKeydown = (e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n this._toggle();\n }\n };\n\n private _handleDocumentKeydown = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && !e.defaultPrevented) this.close();\n };\n\n private _handleDocumentClick = (e: MouseEvent) => {\n if (e.composedPath().includes(this.el)) return;\n this.close();\n };\n\n private _toggle() {\n if (this.isOpen) this.close();\n else this.open();\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|