@expressivecss/expressive 0.16.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 +306 -1
- package/README.md +1 -1
- package/dist/css/expressive.css +540 -646
- 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/js/chunks/{chunk-PA7NU5AK.mjs → chunk-26VUH75M.mjs} +6 -3
- package/dist/js/chunks/chunk-26VUH75M.mjs.map +7 -0
- package/dist/js/chunks/{chunk-NBJAUGPP.mjs → chunk-2LFCOGC3.mjs} +12 -23
- package/dist/js/chunks/chunk-2LFCOGC3.mjs.map +7 -0
- package/dist/js/chunks/{chunk-OP43LLIC.mjs → chunk-36GELQGX.mjs} +4 -4
- package/dist/js/chunks/{chunk-OP43LLIC.mjs.map → chunk-36GELQGX.mjs.map} +2 -2
- package/dist/js/chunks/{chunk-EC26RU2D.mjs → chunk-3FKWIRHW.mjs} +6 -2
- package/dist/js/chunks/chunk-3FKWIRHW.mjs.map +7 -0
- package/dist/js/chunks/{chunk-Y6H2X7ZC.mjs → chunk-3KF65KGL.mjs} +3 -3
- package/dist/js/chunks/{chunk-4QUCNFSD.mjs → chunk-3KLZRQZI.mjs} +31 -10
- package/dist/js/chunks/chunk-3KLZRQZI.mjs.map +7 -0
- package/dist/js/chunks/{chunk-75E5EDJF.mjs → chunk-3XORNED5.mjs} +2 -2
- package/dist/js/chunks/{chunk-NNHVANQA.mjs → chunk-4WBGAQN3.mjs} +3 -3
- package/dist/js/chunks/{chunk-ZJNLAGY5.mjs → chunk-5F4URJHL.mjs} +2 -2
- package/dist/js/chunks/{chunk-ZVLOUDIJ.mjs → chunk-67UNY7RH.mjs} +50 -2
- package/dist/js/chunks/chunk-67UNY7RH.mjs.map +7 -0
- package/dist/js/chunks/{chunk-P6DRQ6KS.mjs → chunk-7CXNATJS.mjs} +6 -5
- package/dist/js/chunks/chunk-7CXNATJS.mjs.map +7 -0
- package/dist/js/chunks/{chunk-4TRZ2AER.mjs → chunk-7X44MKEQ.mjs} +15 -14
- package/dist/js/chunks/chunk-7X44MKEQ.mjs.map +7 -0
- package/dist/js/chunks/{chunk-GWZ76SR4.mjs → chunk-7ZAMOMGY.mjs} +12 -7
- package/dist/js/chunks/chunk-7ZAMOMGY.mjs.map +7 -0
- package/dist/js/chunks/{chunk-GVZQH2H5.mjs → chunk-AEG6LOAJ.mjs} +2 -2
- package/dist/js/chunks/{chunk-Y6TLRA3U.mjs → chunk-AQNFCJJ5.mjs} +27 -21
- package/dist/js/chunks/chunk-AQNFCJJ5.mjs.map +7 -0
- package/dist/js/chunks/{chunk-OUCHKSAW.mjs → chunk-B55LWKBM.mjs} +16 -4
- package/dist/js/chunks/chunk-B55LWKBM.mjs.map +7 -0
- package/dist/js/chunks/{chunk-AI73GJKG.mjs → chunk-BB5VXYXT.mjs} +2 -2
- package/dist/js/chunks/{chunk-2RLBDFH4.mjs → chunk-BDATLH3H.mjs} +4 -4
- package/dist/js/chunks/{chunk-2CS6TITK.mjs → chunk-CWMQOT4O.mjs} +23 -10
- package/dist/js/chunks/chunk-CWMQOT4O.mjs.map +7 -0
- package/dist/js/chunks/{chunk-ZKWUWBUB.mjs → chunk-CY2CTOVM.mjs} +2 -2
- package/dist/js/chunks/{chunk-CSYWKEK3.mjs → chunk-DWA5UYLJ.mjs} +58 -27
- package/dist/js/chunks/chunk-DWA5UYLJ.mjs.map +7 -0
- package/dist/js/chunks/{chunk-CMGXGYUC.mjs → chunk-EB2V4OKL.mjs} +14 -9
- package/dist/js/chunks/chunk-EB2V4OKL.mjs.map +7 -0
- package/dist/js/chunks/{chunk-Z4GICXR2.mjs → chunk-EWO662ZC.mjs} +5 -7
- package/dist/js/chunks/chunk-EWO662ZC.mjs.map +7 -0
- package/dist/js/chunks/{chunk-VGY4M57S.mjs → chunk-F7LAKFMX.mjs} +67 -34
- package/dist/js/chunks/chunk-F7LAKFMX.mjs.map +7 -0
- package/dist/js/chunks/{chunk-67ZPPKXS.mjs → chunk-FNIIH2LU.mjs} +3 -3
- package/dist/js/chunks/chunk-GE3YMFS6.mjs +15 -0
- package/dist/js/chunks/chunk-GE3YMFS6.mjs.map +7 -0
- package/dist/js/chunks/{chunk-DZYVU75J.mjs → chunk-GFWYMWYN.mjs} +18 -14
- package/dist/js/chunks/chunk-GFWYMWYN.mjs.map +7 -0
- package/dist/js/chunks/{chunk-3L3QIYLC.mjs → chunk-H5ISU45X.mjs} +8 -6
- package/dist/js/chunks/chunk-H5ISU45X.mjs.map +7 -0
- package/dist/js/chunks/{chunk-QXKWVHBD.mjs → chunk-H6YIKFAQ.mjs} +67 -46
- package/dist/js/chunks/chunk-H6YIKFAQ.mjs.map +7 -0
- package/dist/js/chunks/{chunk-KZPSAXIU.mjs → chunk-HEH7E3KO.mjs} +22 -12
- package/dist/js/chunks/chunk-HEH7E3KO.mjs.map +7 -0
- package/dist/js/chunks/{chunk-T3BNSRP3.mjs → chunk-HQRLBTNM.mjs} +3 -3
- package/dist/js/chunks/{chunk-NAC72P7R.mjs → chunk-I2F7MLUU.mjs} +2 -2
- package/dist/js/chunks/{chunk-ZM3XBHWV.mjs → chunk-IQOTGGHX.mjs} +86 -35
- package/dist/js/chunks/chunk-IQOTGGHX.mjs.map +7 -0
- package/dist/js/chunks/{chunk-QACZ6TUP.mjs → chunk-JH3YWKA6.mjs} +5 -4
- package/dist/js/chunks/chunk-JH3YWKA6.mjs.map +7 -0
- package/dist/js/chunks/chunk-JOLJAYIJ.mjs +7 -0
- package/dist/js/chunks/{chunk-4IKVPCSU.mjs.map → chunk-JOLJAYIJ.mjs.map} +1 -1
- package/dist/js/chunks/{chunk-BPF3I2MN.mjs → chunk-KOTGMCMI.mjs} +9 -2
- package/dist/js/chunks/chunk-KOTGMCMI.mjs.map +7 -0
- package/dist/js/chunks/{chunk-ANKFWNWT.mjs → chunk-LC4O5LFS.mjs} +3 -3
- package/dist/js/chunks/{chunk-4PIXLDNJ.mjs → chunk-LEF33SCP.mjs} +2 -2
- package/dist/js/chunks/{chunk-ILDRRG7T.mjs → chunk-LFORZRPH.mjs} +3 -3
- package/dist/js/chunks/{chunk-Z4OARDZ7.mjs → chunk-LWLNV5EC.mjs} +26 -17
- package/dist/js/chunks/chunk-LWLNV5EC.mjs.map +7 -0
- package/dist/js/chunks/{chunk-WU7XJ4RR.mjs → chunk-LXRHUQAX.mjs} +66 -25
- package/dist/js/chunks/chunk-LXRHUQAX.mjs.map +7 -0
- package/dist/js/chunks/{chunk-VMY55K2X.mjs → chunk-MA2SZZFB.mjs} +11 -7
- package/dist/js/chunks/chunk-MA2SZZFB.mjs.map +7 -0
- package/dist/js/chunks/{chunk-VJVQIXHC.mjs → chunk-MDBZAMIV.mjs} +8 -10
- package/dist/js/chunks/chunk-MDBZAMIV.mjs.map +7 -0
- package/dist/js/chunks/{chunk-4EWGD4V2.mjs → chunk-NODZ5VAD.mjs} +2 -2
- package/dist/js/chunks/{chunk-UGJHCHXG.mjs → chunk-O2WJB6TH.mjs} +79 -55
- package/dist/js/chunks/chunk-O2WJB6TH.mjs.map +7 -0
- package/dist/js/chunks/{chunk-7YZ5CN3V.mjs → chunk-PCABY5BN.mjs} +5 -3
- package/dist/js/chunks/chunk-PCABY5BN.mjs.map +7 -0
- package/dist/js/chunks/{chunk-X7SDA2J5.mjs → chunk-PWKYVMND.mjs} +9 -5
- package/dist/js/chunks/{chunk-X7SDA2J5.mjs.map → chunk-PWKYVMND.mjs.map} +2 -2
- package/dist/js/chunks/{chunk-SPPHF7YZ.mjs → chunk-QHZZT7YO.mjs} +35 -14
- package/dist/js/chunks/chunk-QHZZT7YO.mjs.map +7 -0
- package/dist/js/chunks/{chunk-LDXCC2L3.mjs → chunk-QND56EW2.mjs} +5 -4
- package/dist/js/chunks/chunk-QND56EW2.mjs.map +7 -0
- package/dist/js/chunks/{chunk-NVQ5EHCU.mjs → chunk-QNODAANY.mjs} +4 -4
- package/dist/js/chunks/{chunk-7NLUI3RR.mjs → chunk-QRO5FV3I.mjs} +23 -13
- package/dist/js/chunks/chunk-QRO5FV3I.mjs.map +7 -0
- package/dist/js/chunks/{chunk-FCNF4GRJ.mjs → chunk-R7A7JRC5.mjs} +6 -11
- package/dist/js/chunks/chunk-R7A7JRC5.mjs.map +7 -0
- package/dist/js/chunks/{chunk-S23RJ3XY.mjs → chunk-RKG2CBFE.mjs} +4 -16
- package/dist/js/chunks/chunk-RKG2CBFE.mjs.map +7 -0
- package/dist/js/chunks/{chunk-6FSEUFVW.mjs → chunk-RSNS5OYS.mjs} +6 -6
- package/dist/js/chunks/chunk-RSNS5OYS.mjs.map +7 -0
- package/dist/js/chunks/{chunk-ROH2HDB4.mjs → chunk-RUDYMEJ3.mjs} +2 -2
- package/dist/js/chunks/{chunk-BIGU5RCJ.mjs → chunk-STJR62SU.mjs} +13 -5
- package/dist/js/chunks/chunk-STJR62SU.mjs.map +7 -0
- package/dist/js/chunks/{chunk-752ADW4M.mjs → chunk-SUSD4UTN.mjs} +27 -32
- package/dist/js/chunks/chunk-SUSD4UTN.mjs.map +7 -0
- package/dist/js/chunks/{chunk-B7DQFHA5.mjs → chunk-SYBOA5HC.mjs} +7 -12
- package/dist/js/chunks/chunk-SYBOA5HC.mjs.map +7 -0
- package/dist/js/chunks/{chunk-TFABTUAZ.mjs → chunk-T4MOBP3J.mjs} +2 -2
- package/dist/js/chunks/{chunk-GCWWEZKO.mjs → chunk-TM7HPGTV.mjs} +3 -3
- package/dist/js/chunks/{chunk-5KIHWJI2.mjs → chunk-TMQDZSDC.mjs} +34 -12
- package/dist/js/chunks/chunk-TMQDZSDC.mjs.map +7 -0
- package/dist/js/chunks/{chunk-ZO6ZLHFF.mjs → chunk-TVSX5YA2.mjs} +3 -3
- package/dist/js/chunks/{chunk-INLZWHLY.mjs → chunk-UHO5CV6K.mjs} +2 -2
- package/dist/js/chunks/{chunk-INLZWHLY.mjs.map → chunk-UHO5CV6K.mjs.map} +2 -2
- package/dist/js/chunks/{chunk-7YQBHTK3.mjs → chunk-UKCNELUN.mjs} +6 -8
- package/dist/js/chunks/chunk-UKCNELUN.mjs.map +7 -0
- package/dist/js/chunks/{chunk-VH4BMAZS.mjs → chunk-UKQK5GWR.mjs} +13 -13
- package/dist/js/chunks/chunk-UKQK5GWR.mjs.map +7 -0
- package/dist/js/chunks/{chunk-OYNUDOHR.mjs → chunk-UTSLYQ65.mjs} +7 -6
- package/dist/js/chunks/{chunk-OYNUDOHR.mjs.map → chunk-UTSLYQ65.mjs.map} +2 -2
- package/dist/js/chunks/{chunk-7W7TV6NY.mjs → chunk-VS5OJBOD.mjs} +2 -2
- package/dist/js/chunks/{chunk-7W7TV6NY.mjs.map → chunk-VS5OJBOD.mjs.map} +2 -2
- package/dist/js/chunks/{chunk-KYIEG4U3.mjs → chunk-VZMROW5A.mjs} +43 -14
- package/dist/js/chunks/chunk-VZMROW5A.mjs.map +7 -0
- package/dist/js/chunks/{chunk-VFV75DHF.mjs → chunk-XB6Y7P5W.mjs} +11 -12
- package/dist/js/chunks/chunk-XB6Y7P5W.mjs.map +7 -0
- package/dist/js/chunks/{chunk-CZSQHXEV.mjs → chunk-XDAMOMVD.mjs} +20 -21
- package/dist/js/chunks/chunk-XDAMOMVD.mjs.map +7 -0
- package/dist/js/chunks/{chunk-EVCVFEV3.mjs → chunk-XJPMW5SP.mjs} +21 -35
- package/dist/js/chunks/chunk-XJPMW5SP.mjs.map +7 -0
- package/dist/js/chunks/{chunk-VR3L2WN5.mjs → chunk-YKANQILZ.mjs} +7 -6
- package/dist/js/chunks/chunk-YKANQILZ.mjs.map +7 -0
- package/dist/js/chunks/{chunk-JUKBBN6P.mjs → chunk-YLZOJLDI.mjs} +2 -2
- package/dist/js/chunks/{chunk-U4B3VHFS.mjs → chunk-ZK7YY322.mjs} +28 -21
- package/dist/js/chunks/chunk-ZK7YY322.mjs.map +7 -0
- package/dist/js/expressive.cjs +2739 -2387
- package/dist/js/expressive.cjs.map +4 -4
- package/dist/js/expressive.js +2739 -2387
- package/dist/js/expressive.js.map +4 -4
- package/dist/js/expressive.min.js +7 -7
- package/dist/js/expressive.min.js.map +4 -4
- package/dist/js/expressive.mjs +76 -75
- package/dist/js/expressive.mjs.map +1 -1
- package/dist/js/internal/behaviors/bottomSheets.mjs +3 -3
- package/dist/js/internal/behaviors/copy.mjs +3 -3
- package/dist/js/internal/behaviors/dataTables.mjs +2 -4
- 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 +2 -2
- package/dist/js/internal/behaviors/lists.mjs +2 -2
- package/dist/js/internal/behaviors/paneResize.mjs +2 -2
- package/dist/js/internal/behaviors/sheetDrag.mjs +2 -2
- package/dist/js/internal/behaviors/sideSheets.mjs +3 -3
- package/dist/js/internal/behaviors/sortable.mjs +2 -2
- package/dist/js/internal/behaviors/theme.mjs +2 -2
- package/dist/js/internal/behaviors/tour.mjs +2 -2
- package/dist/js/internal/behaviors/transferList.mjs +2 -2
- package/dist/js/internal/components/appBar.mjs +3 -3
- package/dist/js/internal/components/autocomplete.mjs +5 -4
- package/dist/js/internal/components/backToTop.mjs +3 -3
- package/dist/js/internal/components/barChart.mjs +5 -5
- package/dist/js/internal/components/buttonGroup.mjs +3 -3
- 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 +4 -4
- package/dist/js/internal/components/characterCounter.mjs +3 -3
- package/dist/js/internal/components/chips.mjs +7 -6
- package/dist/js/internal/components/colorPicker.mjs +3 -3
- package/dist/js/internal/components/columnChart.mjs +4 -4
- package/dist/js/internal/components/commandPalette.mjs +3 -3
- package/dist/js/internal/components/confetti.mjs +3 -3
- package/dist/js/internal/components/currencyInput.mjs +3 -3
- package/dist/js/internal/components/datepicker.mjs +8 -7
- package/dist/js/internal/components/expandingCard.mjs +3 -3
- package/dist/js/internal/components/funnelChart.mjs +4 -4
- package/dist/js/internal/components/heatmapChart.mjs +4 -4
- package/dist/js/internal/components/hoverCard.mjs +3 -3
- package/dist/js/internal/components/index.mjs +60 -59
- package/dist/js/internal/components/inputMask.mjs +3 -3
- 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 +23 -7
- package/dist/js/internal/components/loadingOverlay.mjs +3 -3
- 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 +4 -4
- package/dist/js/internal/components/messageScroller.mjs +3 -3
- package/dist/js/internal/components/mixedChart.mjs +5 -5
- package/dist/js/internal/components/navigationRail.mjs +3 -3
- package/dist/js/internal/components/particles.mjs +3 -3
- package/dist/js/internal/components/pieChart.mjs +4 -4
- package/dist/js/internal/components/pullToRefresh.mjs +3 -3
- package/dist/js/internal/components/questionnaire.mjs +3 -3
- package/dist/js/internal/components/radarChart.mjs +4 -4
- package/dist/js/internal/components/radialChart.mjs +4 -4
- package/dist/js/internal/components/registry.mjs +59 -58
- package/dist/js/internal/components/richTextEditor.mjs +3 -3
- package/dist/js/internal/components/sankeyChart.mjs +4 -4
- package/dist/js/internal/components/scatterChart.mjs +4 -4
- package/dist/js/internal/components/scrollspy.mjs +3 -3
- package/dist/js/internal/components/select.mjs +5 -4
- package/dist/js/internal/components/showMore.mjs +3 -3
- 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 +3 -3
- package/dist/js/internal/components/tabs.mjs +3 -3
- package/dist/js/internal/components/timepicker.mjs +5 -5
- package/dist/js/internal/components/tooltip.mjs +3 -3
- package/dist/js/internal/components/treeSelect.mjs +6 -5
- package/dist/js/internal/components/treemapChart.mjs +4 -4
- package/dist/js/internal/core/component.mjs +6 -4
- package/dist/js/internal/core/formControl.mjs +2 -2
- package/dist/js/internal/core/imageURL.mjs +7 -0
- package/dist/js/internal/core/imageURL.mjs.map +7 -0
- package/dist/js/internal/core/utils.mjs +11 -1
- package/dist/js/internal/plugins/dockedDisplayPlugin.mjs +2 -2
- package/dist/js/internal/plugins/modalDisplayPlugin.mjs +3 -3
- package/dist/js/modular.mjs +76 -75
- package/dist/types/behaviors/bottomSheets.d.ts +5 -3
- package/dist/types/behaviors/dataTables.d.ts +2 -6
- package/dist/types/behaviors/forms.d.ts +7 -7
- package/dist/types/behaviors/imageCompare.d.ts +2 -1
- package/dist/types/behaviors/transferList.d.ts +2 -0
- package/dist/types/components/autocomplete.d.ts +14 -3
- package/dist/types/components/carousel.d.ts +7 -0
- package/dist/types/components/chips.d.ts +15 -0
- package/dist/types/components/colorPicker.d.ts +14 -0
- package/dist/types/components/currencyInput.d.ts +5 -4
- package/dist/types/components/datepicker.d.ts +54 -27
- package/dist/types/components/funnelChart.d.ts +1 -4
- package/dist/types/components/heatmapChart.d.ts +3 -0
- package/dist/types/components/hoverCard.d.ts +1 -0
- package/dist/types/components/inputMask.d.ts +0 -2
- package/dist/types/components/lineChart.d.ts +43 -5
- package/dist/types/components/mapView.d.ts +113 -11
- package/dist/types/components/menu.d.ts +14 -0
- package/dist/types/components/particles.d.ts +14 -1
- package/dist/types/components/pieChart.d.ts +1 -2
- package/dist/types/components/richTextEditor.d.ts +40 -9
- package/dist/types/components/select.d.ts +1 -3
- package/dist/types/components/showMore.d.ts +2 -0
- package/dist/types/components/slider.d.ts +0 -1
- package/dist/types/components/snackbar.d.ts +7 -1
- package/dist/types/components/tabs.d.ts +3 -3
- package/dist/types/components/timepicker.d.ts +15 -6
- package/dist/types/components/tooltip.d.ts +1 -1
- package/dist/types/components/treemapChart.d.ts +2 -2
- package/dist/types/core/component.d.ts +9 -3
- package/dist/types/core/imageURL.d.ts +2 -0
- package/dist/types/core/utils.d.ts +39 -1
- package/dist/types/modular.d.ts +1 -1
- package/dist/types/plugins/modalDisplayPlugin.d.ts +8 -1
- package/package.json +8 -6
- package/src/sass/abstracts/_mixins.scss +459 -59
- package/src/sass/abstracts/_variables.scss +25 -0
- package/src/sass/components/_accordion.scss +1 -3
- package/src/sass/components/_aura.scss +1 -0
- package/src/sass/components/_back-to-top.scss +3 -3
- package/src/sass/components/_bar-chart.scss +2 -83
- package/src/sass/components/_bottom-sheet.scss +7 -0
- package/src/sass/components/_breadcrumb.scss +1 -7
- package/src/sass/components/_button-groups.scss +15 -38
- package/src/sass/components/_buttons.scss +24 -74
- package/src/sass/components/_calendar.scss +1 -3
- package/src/sass/components/_carousel.scss +10 -10
- package/src/sass/components/_cascader.scss +3 -14
- package/src/sass/components/_column-chart.scss +1 -19
- package/src/sass/components/_confetti.scss +3 -4
- package/src/sass/components/_data-table.scss +10 -0
- package/src/sass/components/_dialog.scss +10 -18
- package/src/sass/components/_expanding-card.scss +1 -5
- package/src/sass/components/_fab-menu.scss +4 -12
- package/src/sass/components/_funnel-chart.scss +1 -62
- package/src/sass/components/_heatmap-chart.scss +2 -6
- package/src/sass/components/_icon-buttons.scss +1 -4
- package/src/sass/components/_line-chart.scss +2 -70
- package/src/sass/components/_map.scss +4 -0
- package/src/sass/components/_marquee.scss +3 -3
- package/src/sass/components/_mega-menu.scss +8 -17
- package/src/sass/components/_menu.scss +10 -11
- package/src/sass/components/_menubar.scss +1 -13
- package/src/sass/components/_mixed-chart.scss +1 -37
- package/src/sass/components/_navbar.scss +11 -16
- package/src/sass/components/_navigation-bar.scss +2 -5
- package/src/sass/components/_navigation-rail.scss +25 -15
- package/src/sass/components/_page-footer.scss +1 -3
- package/src/sass/components/_pagination.scss +3 -14
- package/src/sass/components/_panes.scss +3 -16
- package/src/sass/components/_particles.scss +3 -4
- package/src/sass/components/_pie-chart.scss +8 -70
- package/src/sass/components/_progress.scss +31 -13
- package/src/sass/components/_radar-chart.scss +2 -32
- package/src/sass/components/_radial-chart.scss +2 -48
- package/src/sass/components/_sankey-chart.scss +5 -28
- package/src/sass/components/_scatter-chart.scss +2 -11
- package/src/sass/components/_search.scss +1 -4
- package/src/sass/components/_side-sheet.scss +9 -14
- package/src/sass/components/_skeleton.scss +24 -15
- package/src/sass/components/_snackbar.scss +11 -13
- package/src/sass/components/_table_of_contents.scss +1 -3
- package/src/sass/components/_tabs.scss +4 -20
- package/src/sass/components/_timepicker.scss +2 -1
- package/src/sass/components/_toolbar.scss +1 -4
- package/src/sass/components/_tooltip.scss +9 -5
- package/src/sass/components/_tree.scss +5 -17
- package/src/sass/components/_treemap-chart.scss +2 -26
- package/src/sass/components/forms/_checkboxes.scss +2 -21
- package/src/sass/components/forms/_drop-zone.scss +1 -4
- package/src/sass/components/forms/_fieldset.scss +1 -4
- package/src/sass/components/forms/_file-input.scss +6 -0
- package/src/sass/components/forms/_input-fields.scss +21 -4
- package/src/sass/components/forms/_radio-buttons.scss +2 -24
- package/src/sass/components/forms/_select.scss +6 -7
- package/src/sass/components/forms/_slider.scss +1 -4
- package/src/sass/components/forms/_switches.scss +14 -21
- package/src/sass/utilities/_helpers.scss +1 -1
- package/src/sass/utilities/_visibility.scss +1 -3
- package/dist/js/chunks/chunk-2CS6TITK.mjs.map +0 -7
- package/dist/js/chunks/chunk-3L3QIYLC.mjs.map +0 -7
- package/dist/js/chunks/chunk-4IKVPCSU.mjs +0 -7
- package/dist/js/chunks/chunk-4QUCNFSD.mjs.map +0 -7
- package/dist/js/chunks/chunk-4TRZ2AER.mjs.map +0 -7
- package/dist/js/chunks/chunk-5KIHWJI2.mjs.map +0 -7
- package/dist/js/chunks/chunk-6FSEUFVW.mjs.map +0 -7
- package/dist/js/chunks/chunk-752ADW4M.mjs.map +0 -7
- package/dist/js/chunks/chunk-7NLUI3RR.mjs.map +0 -7
- package/dist/js/chunks/chunk-7YQBHTK3.mjs.map +0 -7
- package/dist/js/chunks/chunk-7YZ5CN3V.mjs.map +0 -7
- package/dist/js/chunks/chunk-B7DQFHA5.mjs.map +0 -7
- package/dist/js/chunks/chunk-BIGU5RCJ.mjs.map +0 -7
- package/dist/js/chunks/chunk-BPF3I2MN.mjs.map +0 -7
- package/dist/js/chunks/chunk-CMGXGYUC.mjs.map +0 -7
- package/dist/js/chunks/chunk-CSYWKEK3.mjs.map +0 -7
- package/dist/js/chunks/chunk-CZSQHXEV.mjs.map +0 -7
- package/dist/js/chunks/chunk-DZYVU75J.mjs.map +0 -7
- package/dist/js/chunks/chunk-EC26RU2D.mjs.map +0 -7
- package/dist/js/chunks/chunk-EVCVFEV3.mjs.map +0 -7
- package/dist/js/chunks/chunk-FCNF4GRJ.mjs.map +0 -7
- package/dist/js/chunks/chunk-GWZ76SR4.mjs.map +0 -7
- package/dist/js/chunks/chunk-KYIEG4U3.mjs.map +0 -7
- package/dist/js/chunks/chunk-KZPSAXIU.mjs.map +0 -7
- package/dist/js/chunks/chunk-LDXCC2L3.mjs.map +0 -7
- package/dist/js/chunks/chunk-NBJAUGPP.mjs.map +0 -7
- package/dist/js/chunks/chunk-OUCHKSAW.mjs.map +0 -7
- package/dist/js/chunks/chunk-P6DRQ6KS.mjs.map +0 -7
- package/dist/js/chunks/chunk-PA7NU5AK.mjs.map +0 -7
- package/dist/js/chunks/chunk-QACZ6TUP.mjs.map +0 -7
- package/dist/js/chunks/chunk-QXKWVHBD.mjs.map +0 -7
- package/dist/js/chunks/chunk-S23RJ3XY.mjs.map +0 -7
- package/dist/js/chunks/chunk-SPPHF7YZ.mjs.map +0 -7
- package/dist/js/chunks/chunk-U4B3VHFS.mjs.map +0 -7
- package/dist/js/chunks/chunk-UGJHCHXG.mjs.map +0 -7
- package/dist/js/chunks/chunk-VFV75DHF.mjs.map +0 -7
- package/dist/js/chunks/chunk-VGY4M57S.mjs.map +0 -7
- package/dist/js/chunks/chunk-VH4BMAZS.mjs.map +0 -7
- package/dist/js/chunks/chunk-VJVQIXHC.mjs.map +0 -7
- package/dist/js/chunks/chunk-VMY55K2X.mjs.map +0 -7
- package/dist/js/chunks/chunk-VR3L2WN5.mjs.map +0 -7
- package/dist/js/chunks/chunk-WU7XJ4RR.mjs.map +0 -7
- package/dist/js/chunks/chunk-Y6TLRA3U.mjs.map +0 -7
- package/dist/js/chunks/chunk-Z4GICXR2.mjs.map +0 -7
- package/dist/js/chunks/chunk-Z4OARDZ7.mjs.map +0 -7
- package/dist/js/chunks/chunk-ZM3XBHWV.mjs.map +0 -7
- package/dist/js/chunks/chunk-ZVLOUDIJ.mjs.map +0 -7
- /package/dist/js/chunks/{chunk-Y6H2X7ZC.mjs.map → chunk-3KF65KGL.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-75E5EDJF.mjs.map → chunk-3XORNED5.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-NNHVANQA.mjs.map → chunk-4WBGAQN3.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-ZJNLAGY5.mjs.map → chunk-5F4URJHL.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-GVZQH2H5.mjs.map → chunk-AEG6LOAJ.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-AI73GJKG.mjs.map → chunk-BB5VXYXT.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-2RLBDFH4.mjs.map → chunk-BDATLH3H.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-ZKWUWBUB.mjs.map → chunk-CY2CTOVM.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-67ZPPKXS.mjs.map → chunk-FNIIH2LU.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-T3BNSRP3.mjs.map → chunk-HQRLBTNM.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-NAC72P7R.mjs.map → chunk-I2F7MLUU.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-ANKFWNWT.mjs.map → chunk-LC4O5LFS.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-4PIXLDNJ.mjs.map → chunk-LEF33SCP.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-ILDRRG7T.mjs.map → chunk-LFORZRPH.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-4EWGD4V2.mjs.map → chunk-NODZ5VAD.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-NVQ5EHCU.mjs.map → chunk-QNODAANY.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-ROH2HDB4.mjs.map → chunk-RUDYMEJ3.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-TFABTUAZ.mjs.map → chunk-T4MOBP3J.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-GCWWEZKO.mjs.map → chunk-TM7HPGTV.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-ZO6ZLHFF.mjs.map → chunk-TVSX5YA2.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-JUKBBN6P.mjs.map → chunk-YLZOJLDI.mjs.map} +0 -0
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/ts/components/autocomplete.ts"],
|
|
4
|
-
"sourcesContent": ["import { Utils } from '../core/utils';\nimport { Menu, MenuOptions } from './menu';\nimport { Component, BaseOptions } from '../core/component';\n\nexport interface AutocompleteData {\n /**\n * A primitive value that can be converted to string.\n * If \"text\" is not provided, it will also be used as \"option text\" as well\n */\n id: string | number;\n /**\n * This optional attribute is used as \"display value\" for the current entry.\n * When provided, it will also be taken into consideration by the standard search function.\n */\n text?: string;\n /**\n * This optional attribute is used to provide a valid image URL to the current option.\n */\n image?: string;\n /**\n * Optional attributes which describes the option.\n */\n description?: string;\n /**\n * Shows the entry dimmed and keeps every selection path from choosing or\n * removing it. The arrow keys skip it, and the result count leaves it out.\n * The `selected` option and `setMenuItems()` can still select it.\n */\n disabled?: boolean;\n /**\n * Lists the entry under this heading. Entries with the same group gather\n * where the group first appears in the results; entries without one stay\n * outside every group.\n */\n group?: string;\n}\n\nexport interface AutocompleteOptions extends BaseOptions {\n i18n: Partial<{\n loading: string;\n noResults: string;\n results: (count: number) => string;\n selected: (count: number) => string;\n create: (text: string) => string;\n }>;\n /**\n * Data object defining autocomplete options with\n * optional icon strings.\n */\n data: AutocompleteData[];\n /**\n * Flag which can be set if multiple values can be selected. The Result will be an Array.\n * @default false\n */\n isMultiSelect: boolean;\n /**\n * Callback for when autocompleted.\n */\n onAutocomplete: (entries: AutocompleteData[]) => void;\n /**\n * Minimum number of characters before autocomplete starts.\n * @default 1\n */\n minLength: number;\n /**\n * The height of the Menu which can be set via css-property.\n * @default '300px'\n */\n maxMenuHeight: string;\n /**\n * Function is called when the input text is altered and data can also be loaded asynchronously.\n * If the results are collected the items in the list can be updated via the function setMenuItems(collectedItems).\n * @param text Searched text.\n * @param autocomplete Current autocomplete instance.\n * @param signal Aborted when a newer search starts or the autocomplete is\n * destroyed. Pass it to `fetch()` so a slow, stale response never replaces\n * newer results.\n */\n onSearch: (text: string, autocomplete: Autocomplete, signal: AbortSignal) => void;\n /**\n * Milliseconds to wait after typing pauses before calling `onSearch`, so\n * remote data is fetched once per pause rather than once per key. A search\n * on focus never waits. `0` searches on every input.\n * @default 0\n */\n searchDelay: number;\n /**\n * Ends the list in an \"Add\" row when the typed text matches no suggestion\n * exactly. Choosing the row calls `onCreate` and fires `expressive:create`;\n * the selection does not change.\n * @default false\n */\n allowCreate: boolean;\n /**\n * Called when the person chooses the \"Add\" row.\n * @param text The typed text, trimmed.\n * @param autocomplete Current autocomplete instance.\n * @default null\n */\n onCreate: (text: string, autocomplete: Autocomplete) => void;\n /**\n * If true will render the key from each item directly as HTML.\n * User input MUST be properly sanitized first.\n * @default false\n */\n allowUnsafeHTML: boolean;\n /**\n * Pass options object to select menu initialization.\n * @default {}\n */\n menuOptions: Partial<MenuOptions>;\n /**\n * Predefined selected values\n */\n selected: number[] | string[];\n}\n\nconst _defaults: AutocompleteOptions = {\n i18n: {\n loading: 'Loading results.',\n noResults: 'No results.',\n results: count => `${count} ${count === 1 ? 'result' : 'results'} available.`,\n selected: count => `${count} ${count === 1 ? 'item' : 'items'} selected.`,\n create: text => `Add \"${text}\"`\n },\n data: [], // Autocomplete data set\n onAutocomplete: null, // Callback for when autocompleted\n menuOptions: {\n // Default menu options\n autoFocus: false,\n closeOnClick: false,\n coverTrigger: false\n },\n minLength: 1, // Min characters before autocomplete starts\n searchDelay: 0,\n allowCreate: false,\n onCreate: null,\n isMultiSelect: false,\n onSearch: (text: string, autocomplete: Autocomplete) => {\n const normSearch = text.toLocaleLowerCase();\n autocomplete.setMenuItems(\n autocomplete.options.data.filter((option) =>\n option.id.toString().toLocaleLowerCase().includes(normSearch)\n || option.text?.toLocaleLowerCase().includes(normSearch)\n )\n );\n },\n maxMenuHeight: '300px',\n allowUnsafeHTML: false,\n selected: []\n};\n\nexport class Autocomplete extends Component<AutocompleteOptions> {\n declare el: HTMLInputElement;\n /** If the autocomplete is open. */\n isOpen: boolean;\n /**\n * Whether the user left or dismissed the field since the last search, so\n * late results must not reopen it. A field nobody has focused yet counts.\n */\n private _left = true;\n /** Number of matching autocomplete options. */\n count: number;\n /** Index of the current selected option. */\n activeIndex: number;\n private oldVal: string;\n private $active: HTMLElement | null;\n private _openTimer: ReturnType<typeof setTimeout> | undefined;\n /** Aborts the running search when a newer one starts. */\n private _searchAbort: AbortController | undefined;\n /** The search waiting for typing to pause. */\n private _searchTimer: ReturnType<typeof setTimeout> | undefined;\n // Counts selections, so a callback that selects again silences the stale event.\n private _selection = 0;\n private _statusInfo: HTMLElement;\n private _announcer: HTMLElement;\n /** The last search returned no suggestions. A text change clears it until the next one returns. */\n private _noResults = false;\n\n /**\n * The active entry, for both the eye and the screen reader. The class alone\n * was invisible to assistive technology; aria-activedescendant on the input\n * is what reports the move.\n *\n * Deliberately does not touch aria-selected. Active and selected are two\n * different things - in a multi-select the checkboxes track real choices,\n * and folding the highlight into aria-selected would announce a committed\n * choice as unselected the moment the user arrowed past it.\n */\n private _setActive(item: HTMLElement | null) {\n this.$active?.classList.remove('active');\n this.$active = item;\n if (item) {\n item.classList.add('active');\n this.el.setAttribute('aria-activedescendant', item.id);\n } else {\n this.el.removeAttribute('aria-activedescendant');\n }\n }\n private _pointerDown: boolean;\n container: HTMLElement;\n /** Instance of the menu plugin for this autocomplete. */\n menu: Menu;\n static _keydown: boolean;\n selectedValues: AutocompleteData[];\n menuItems: AutocompleteData[];\n\n constructor(el: HTMLInputElement, options: Partial<AutocompleteOptions>) {\n super(el, options);\n\n this.isOpen = false;\n this.count = 0;\n this.activeIndex = -1;\n this.oldVal = '';\n this.selectedValues = this.options.selected.map((id) => this.options.data.find(entry => entry.id === id) ?? { id });\n this.menuItems = this.options.data || [];\n this.$active = null;\n this._pointerDown = false;\n this._setupMenu();\n this._setupEventHandlers();\n }\n\n static get defaults(): AutocompleteOptions {\n return _defaults;\n }\n\n static key = 'Expressive_Autocomplete';\n\n /**\n * The three-dot loading indicator, parsed once and cloned thereafter.\n *\n * It is shown on every input change, and it used to be assigned as an\n * innerHTML string each time - re-running the HTML parser over the same\n * fixed markup on every keystroke.\n */\n private static _loadingTemplate: HTMLElement = null;\n\n private static _loadingIndicator(): HTMLElement {\n if (!Autocomplete._loadingTemplate) {\n const template = document.createElement('template');\n template.innerHTML = `<div style=\"height:100%;width:50px;\"><svg version=\"1.1\" id=\"L4\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\" viewBox=\"0 0 100 100\" enable-background=\"new 0 0 0 0\" xml:space=\"preserve\">\n <circle fill=\"#888c\" stroke=\"none\" cx=\"6\" cy=\"50\" r=\"6\"><animate attributeName=\"opacity\" dur=\"1s\" values=\"0;1;0\" repeatCount=\"indefinite\" begin=\"0.1\"/></circle>\n <circle fill=\"#888c\" stroke=\"none\" cx=\"26\" cy=\"50\" r=\"6\"><animate attributeName=\"opacity\" dur=\"1s\" values=\"0;1;0\" repeatCount=\"indefinite\" begin=\"0.2\"/></circle>\n <circle fill=\"#888c\" stroke=\"none\" cx=\"46\" cy=\"50\" r=\"6\"><animate attributeName=\"opacity\" dur=\"1s\" values=\"0;1;0\" repeatCount=\"indefinite\" begin=\"0.3\"/></circle>\n </svg></div>`;\n Autocomplete._loadingTemplate = template.content.firstElementChild as HTMLElement;\n }\n return Autocomplete._loadingTemplate.cloneNode(true) as HTMLElement;\n }\n\n destroy() {\n // open() defers menu.open() to a timer. Without cancelling it, destroying\n // an autocomplete that was opened in the same tick let the callback run\n // against a menu whose element had already been removed.\n if (this._openTimer !== undefined) {\n clearTimeout(this._openTimer);\n this._openTimer = undefined;\n }\n this._cancelPendingSearch();\n this._searchAbort?.abort();\n this._events.abort();\n this.menu.destroy();\n this.isOpen = false;\n this._removeMenu();\n for (const name of ['role', 'aria-autocomplete', 'aria-controls', 'data-target', 'aria-haspopup', 'aria-expanded', 'aria-activedescendant']) {\n this.el.removeAttribute(name);\n }\n this._statusInfo.remove();\n this._announcer.remove();\n super.destroy();\n }\n\n _setupEventHandlers() {\n const { signal } = this._events;\n this.el.addEventListener('blur', this._handleInputBlur, { signal });\n this.el.addEventListener('input', this._handleInput, { signal });\n this.el.addEventListener('keyup', this._handleInputKeyup, { signal });\n this.el.addEventListener('focus', this._handleInputFocus, { signal });\n this.el.addEventListener('keydown', this._handleInputKeydown, { signal });\n this.el.addEventListener('click', this._handleInputClick, { signal });\n // One pair, not two. These used to be a mouse pair plus a touch pair behind\n // a `window.ontouchstart` feature detect; a pointer event covers both, and\n // the detect covered nothing the browser does not report itself.\n this.container.addEventListener('pointerdown', this._handleContainerPointerDown, { signal });\n this.container.addEventListener('pointerup', this._handleContainerPointerUp, { signal });\n this.container.addEventListener('pointercancel', this._handleContainerPointerUp, { signal });\n this.container.addEventListener('mousedown', this._handleInertRowPress, { capture: true, signal });\n this.container.addEventListener('click', this._handleInertRowPress, { capture: true, signal });\n }\n\n _setupMenu() {\n this.container = document.createElement('menu');\n this.container.style.maxHeight = this.options.maxMenuHeight;\n this.container.id = `autocomplete-options-${Utils.guid()}`;\n this.container.classList.add('autocomplete-content');\n this.container.ariaExpanded = 'true';\n // An autocomplete is the textbook combobox, and this one already\n // implements the keyboard contract the roles promise - Up and Down move\n // the active entry, Enter commits it - so it is allowed to claim them.\n // It had none: the suggestions were an unlabelled list of <li>, and the\n // highlight moved with a class no assistive technology could see.\n this.container.setAttribute('role', 'listbox');\n this.el.setAttribute('role', 'combobox');\n this.el.setAttribute('aria-autocomplete', 'list');\n this.el.setAttribute('aria-controls', this.container.id);\n this.el.setAttribute('data-target', this.container.id);\n\n this.menuItems.forEach((menuItem) => {\n const itemElement = this._createMenuItem(menuItem);\n this.container.append(itemElement);\n });\n\n // ! Issue in Component Menu: _placeMenu moves dom-position\n this.el.parentElement.appendChild(this.container);\n\n // Initialize menu\n const menuOptions = {\n ...Autocomplete.defaults.menuOptions,\n ...this.options.menuOptions\n };\n const userOnOpenStart = menuOptions.onOpenStart;\n const userOnCloseStart = menuOptions.onCloseStart;\n menuOptions.onOpenStart = (el) => {\n this.isOpen = true;\n if (typeof userOnOpenStart === 'function') userOnOpenStart.call(this.menu, el);\n };\n menuOptions.onCloseStart = (el) => {\n this.isOpen = false;\n if (typeof userOnCloseStart === 'function') userOnCloseStart.call(this.menu, el);\n };\n // The wrapper is installed unconditionally: selecting the clicked entry is\n // how the autocomplete works, not an optional extra. Only the forwarding to\n // a user-supplied handler is conditional, and it hands over exactly what\n // Menu would have (the clicked `li`, called on the Menu instance).\n const userOnItemClick = menuOptions.onItemClick;\n menuOptions.onItemClick = (li) => {\n if (!li) return;\n this._choose(li);\n if (typeof userOnItemClick === 'function') userOnItemClick.call(this.menu, li);\n };\n this.menu = Menu.init(this.el, menuOptions);\n this.el.setAttribute('aria-haspopup', 'listbox');\n\n // ! Workaround for Label: move label up again\n // TODO: Just use PopperJS in future!\n const label = this.el.parentElement.querySelector('label');\n if (label) this.el.after(label);\n\n // Menu's trigger handlers open the list without rendering it, and its\n // keydown cancels Space and Enter, which a text field needs.\n this.el.removeEventListener('click', this.menu._handleClick);\n this.el.removeEventListener('keydown', this.menu._handleTriggerKeydown);\n if (!this.options.isMultiSelect) this._refreshInputText();\n // Set Value if already set in HTML\n if (this.el.value) this.selectOption(this.el.value);\n // Add StatusInfo\n const div = document.createElement('div');\n div.classList.add('status-info');\n div.setAttribute('aria-hidden', 'true');\n div.setAttribute('style', 'position: absolute;right:0;top:0;');\n this.el.parentElement.appendChild(div);\n this._statusInfo = div;\n this._announcer = document.createElement('div');\n this._announcer.classList.add('autocomplete-status');\n this._announcer.setAttribute('role', 'status');\n this._announcer.setAttribute('aria-live', 'polite');\n this._announcer.setAttribute('aria-atomic', 'true');\n this.el.parentElement.appendChild(this._announcer);\n this._updateSelectedInfo();\n }\n\n _removeMenu() {\n this.container.ariaExpanded = 'false';\n this.container.parentNode.removeChild(this.container);\n }\n\n _handleInputBlur = () => {\n if (!this._pointerDown) {\n this._left = true;\n this._cancelPendingSearch();\n this.close();\n this._resetAutocomplete();\n }\n };\n\n _handleInputKeyup = () => {\n Autocomplete._keydown = false;\n };\n\n _handleInput = () => {\n this._left = false;\n this.count = 0;\n const actualValue = this.el.value.toLocaleLowerCase();\n // Check if the input isn't empty, and that focus arrived by keyboard -\n // which is what `:focus-visible` means, and used to be a global flag this\n // bundle maintained from four capture-phase document listeners. An open\n // menu is not re-rendered with the old results here: setMenuItems renders\n // the new ones. Below minLength, open() still runs to clear the list.\n if (this.oldVal !== actualValue) {\n // The old results can stay on screen until setMenuItems replaces them,\n // but none may stay active: Enter would select a result for the\n // previous query.\n this._resetCurrentElementPosition();\n // open() renders before the new search starts, so the old answer goes first.\n this._noResults = false;\n if (this.el.matches(':focus-visible')\n && (!this.menu.isOpen || actualValue.length < this.options.minLength)) this.open();\n }\n this._inputChangeDetection(actualValue, true);\n };\n\n _handleInputFocus = () => {\n this._left = false;\n this.count = 0;\n const actualValue = this.el.value.toLocaleLowerCase();\n this._inputChangeDetection(actualValue);\n };\n\n _inputChangeDetection = (value: string, typed?: boolean) => {\n // Editing or clearing a single selection's text deselects it.\n const deselected = !this.options.isMultiSelect && this.selectedValues.length > 0\n && this.el.value !== (this.selectedValues[0].text || String(this.selectedValues[0].id));\n if (deselected) this.selectedValues = [];\n // Value has changed!\n if (this.oldVal !== value) {\n this._noResults = false;\n this._setStatusLoading();\n this._queueSearch(typed);\n }\n if (deselected) this._triggerChanged();\n this.oldVal = value;\n };\n\n /** Searches now, or once typing pauses for `searchDelay`. Focus never waits. */\n private _queueSearch(typed?: boolean) {\n this._cancelPendingSearch();\n const delay = this.options.searchDelay;\n if (!typed || !(delay > 0 && delay < Infinity)) return this._search(this.el.value);\n // The running search is for text the field no longer holds.\n this._searchAbort?.abort();\n this._searchTimer = setTimeout(() => {\n this._searchTimer = undefined;\n this._search(this.el.value);\n }, delay);\n }\n\n private _cancelPendingSearch() {\n clearTimeout(this._searchTimer);\n this._searchTimer = undefined;\n }\n\n /** Starts a search and aborts the one before, whose response is now stale. */\n private _search(text: string) {\n this._searchAbort?.abort();\n this._searchAbort = new AbortController();\n this.options.onSearch(text, this, this._searchAbort.signal);\n }\n\n _handleInputKeydown = Utils.ignoringComposition((e: KeyboardEvent) => {\n Autocomplete._keydown = true;\n if (e.key === 'Escape' || e.key === 'Tab') {\n this._dismiss(e);\n return;\n }\n // Arrow keys and enter key usage\n const options = this._options();\n const numItems = options.length;\n // select element on Enter\n if (e.key === 'Enter' && this.activeIndex >= 0) {\n const liElement = options[this.activeIndex];\n if (liElement) {\n this._choose(liElement);\n e.preventDefault();\n }\n return;\n }\n // Capture up and down key\n if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {\n e.preventDefault();\n // A list that is already opening keeps its rendered results.\n if (!this.menu.isOpen && this._openTimer === undefined) {\n this.open();\n return;\n }\n if (e.key === 'ArrowUp' && this.activeIndex > 0) this.activeIndex--;\n if (e.key === 'ArrowDown' && this.activeIndex < numItems - 1)\n this.activeIndex++;\n this._setActive(null);\n if (this.activeIndex >= 0) {\n this._setActive(options[this.activeIndex]);\n // Focus selected\n options[this.activeIndex].scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'nearest'\n });\n }\n }\n });\n\n private _dismiss(e: KeyboardEvent) {\n if (e.key === 'Escape') {\n // Take the key only when it closes something, or a surrounding <dialog>\n // would cancel too. A dismissed list stays shut for late results.\n if (this.menu.isOpen || this._openTimer !== undefined) e.preventDefault();\n this._left = true;\n }\n this.close();\n this._resetCurrentElementPosition();\n }\n\n _handleInputClick = () => {\n this.open();\n };\n\n // The flag says \"a press is in flight inside the option list\", so that a blur\n // caused by that press does not close the list out from under it. Without the\n // cancel half, a cancelled gesture left the flag set and the next blur could\n // not close the list at all.\n _handleContainerPointerDown = (e: PointerEvent) => {\n if (!e.isPrimary) return;\n if (e.pointerType === 'mouse' && e.button !== 0) return;\n this._pointerDown = true;\n };\n\n _handleContainerPointerUp = () => {\n this._pointerDown = false;\n };\n\n // The no-results row and group headings are not options, and a disabled row\n // cannot be chosen. A press on any of them would move focus to the list,\n // which nothing hands back, and Menu would report the row as chosen.\n _handleInertRowPress = (e: MouseEvent) => {\n if (!(e.target instanceof Element) || !e.target.closest('.autocomplete-no-results, .autocomplete-group-label, [aria-disabled=\"true\"]')) return;\n e.preventDefault();\n e.stopPropagation();\n };\n\n /** The rows that can be chosen. The no-results row and disabled rows are not. */\n private _options() {\n return this.container.querySelectorAll<HTMLElement>('li[role=\"option\"]:not([aria-disabled=\"true\"])');\n }\n\n _resetCurrentElementPosition() {\n this.activeIndex = -1;\n this._setActive(null);\n }\n\n _resetAutocomplete() {\n this.container.replaceChildren();\n this._resetCurrentElementPosition();\n this.oldVal = null;\n this._pointerDown = false;\n }\n\n _highlightPartialText(input: string, label: string) {\n const start = label.toLocaleLowerCase().indexOf(input.toLocaleLowerCase());\n const end = start + input.length - 1;\n //custom filters may return results where the string does not match any part\n if (start == -1 || end == -1) {\n return [label, '', ''];\n }\n return [label.slice(0, start), label.slice(start, end + 1), label.slice(end + 1)];\n }\n\n _createMenuItem(entry: AutocompleteData) {\n const item = document.createElement('li');\n item.id = `autocomplete-option-${Utils.guid()}`;\n item.setAttribute('role', 'option');\n // role=option promises a selection state on every entry, not just the\n // chosen one - and it has to be the *real* one. A multi-select entry that\n // is already committed is selected whether or not it is the highlighted\n // row.\n const isSelected = this.selectedValues.some((sel) => sel.id === entry.id);\n item.setAttribute('aria-selected', isSelected ? 'true' : 'false');\n item.setAttribute('data-id', <string>entry.id);\n Autocomplete._markDisabled(item, entry);\n item.setAttribute(\n 'style',\n 'display:grid; grid-auto-flow: column; user-select: none; align-items: center;'\n );\n item.tabIndex = -1;\n // Checkbox\n if (this.options.isMultiSelect) {\n const selection = document.createElement('div');\n selection.classList.add('item-selection');\n selection.style.textAlign = 'center';\n const checkbox = document.createElement('input');\n checkbox.type = 'checkbox';\n checkbox.tabIndex = -1;\n checkbox.checked = isSelected;\n checkbox.disabled = entry.disabled === true;\n const spacer = document.createElement('span');\n spacer.style.paddingLeft = '21px';\n selection.append(checkbox, spacer);\n item.appendChild(selection);\n }\n // Image\n if (entry.image) {\n const img = document.createElement('img');\n img.classList.add('circle');\n img.src = entry.image;\n item.appendChild(img);\n }\n\n const div = this._createLabel(entry);\n\n const itemText = document.createElement('div');\n itemText.classList.add('item-text');\n itemText.setAttribute('style', 'padding:5px;overflow:hidden;');\n item.appendChild(itemText);\n itemText.appendChild(div);\n // Description\n if (\n typeof entry.description === 'string' ||\n (typeof entry.description === 'number' && !isNaN(entry.description))\n ) {\n const description = document.createElement('small');\n description.setAttribute(\n 'style',\n 'line-height:1.3;color:grey;white-space:nowrap;text-overflow:ellipsis;display:block;width:90%;overflow:hidden;'\n );\n description.innerText = entry.description;\n itemText.appendChild(description);\n }\n // Set Grid\n const getGridConfig = () => {\n if (this.options.isMultiSelect) {\n if (entry.image) return '40px min-content auto'; // cb-img-txt\n return '40px auto'; // cb-txt\n }\n if (entry.image) return 'min-content auto'; // img-txt\n return 'auto'; // txt\n };\n item.style.gridTemplateColumns = getGridConfig();\n return item;\n }\n\n /** Menu already ignores a click on an aria-disabled row. */\n private static _markDisabled(item: HTMLElement, entry: AutocompleteData) {\n if (entry.disabled === true) item.setAttribute('aria-disabled', 'true');\n }\n\n _createLabel(entry: AutocompleteData) {\n const inputText = this.el.value.toLocaleLowerCase();\n const label = (entry.text || entry.id).toString();\n const div = document.createElement('div');\n div.setAttribute('style', 'line-height:1.2;font-weight:500;');\n // Only a script-supplied text is HTML. An id can come from markup's\n // `selected`, which AutoInit treats as untrusted, so it stays text.\n if (this.options.allowUnsafeHTML && entry.text) this._highlightHTML(div, label, inputText);\n else this._highlightText(div, this._highlightPartialText(inputText, label));\n return div;\n }\n\n _highlightHTML(div: HTMLElement, label: string, inputText: string) {\n // Highlight inside a parsed text node. Splicing the span into the HTML\n // string put its quotes inside any attribute the match landed in, which\n // closed that attribute and let the rest of it become markup.\n div.innerHTML = label;\n const walker = document.createTreeWalker(div, NodeFilter.SHOW_TEXT);\n for (let node = walker.nextNode() as Text; node; node = walker.nextNode() as Text) {\n const [before, match] = this._highlightPartialText(inputText, node.data);\n if (!match) continue;\n const matched = node.splitText(before.length);\n matched.splitText(match.length);\n const highlight = document.createElement('span');\n highlight.classList.add('highlight');\n matched.replaceWith(highlight);\n highlight.append(matched);\n break;\n }\n }\n\n _highlightText(div: HTMLElement, parts: string[]) {\n div.appendChild(document.createTextNode(parts[0]));\n if (parts[1]) {\n const highlight = document.createElement('span');\n highlight.textContent = parts[1];\n highlight.classList.add('highlight');\n div.appendChild(highlight);\n div.appendChild(document.createTextNode(parts[2]));\n }\n }\n\n _renderMenu() {\n this._resetAutocomplete();\n if (this._noResults) this.container.append(this._createNoResultsRow());\n // Check if Data is empty\n if (this.menuItems.length === 0) {\n this.menuItems = this.selectedValues; // Show selected Items\n }\n const groups = new Map<string, HTMLElement>();\n this.menuItems.forEach((entry) => this._groupList(entry.group, groups).append(this._createMenuItem(entry)));\n const createText = this._createText();\n if (createText) this.container.append(this._createRow(createText));\n }\n\n /** The list a row goes in: the listbox, or its group's list, made where the group first appears. */\n private _groupList(name: string | undefined, groups: Map<string, HTMLElement>) {\n if (!name) return this.container;\n if (!groups.has(name)) groups.set(name, this._createGroup(name));\n return groups.get(name);\n }\n\n /**\n * A labelled group of options, as the APG grouped listbox nests it. The\n * heading is not an option, so the arrow keys and the count pass over it.\n * Its name is set as text: only an entry's own `text` may be HTML.\n */\n private _createGroup(name: string) {\n const heading = document.createElement('li');\n heading.id = `autocomplete-group-${Utils.guid()}`;\n heading.setAttribute('role', 'presentation');\n heading.classList.add('label', 'autocomplete-group-label');\n heading.textContent = name;\n const list = document.createElement('ul');\n list.setAttribute('role', 'group');\n list.setAttribute('aria-labelledby', heading.id);\n list.append(heading);\n const wrapper = document.createElement('li');\n wrapper.setAttribute('role', 'none');\n wrapper.append(list);\n this.container.append(wrapper);\n return list;\n }\n\n /** The typed text to offer as a new value, or '' when the option is off, the text is short or a suggestion matches it. */\n private _createText() {\n const text = this.el.value.trim();\n if (!this.options.allowCreate || text.length < this.options.minLength) return '';\n const typed = text.toLocaleLowerCase();\n return this.menuItems.some((entry) => (entry.text || String(entry.id)).toLocaleLowerCase() === typed) ? '' : text;\n }\n\n /** The \"Add\" row. Its label is what the person typed, so it is set as text, never as HTML. */\n private _createRow(text: string) {\n const item = document.createElement('li');\n item.id = `autocomplete-option-${Utils.guid()}`;\n item.setAttribute('role', 'option');\n item.setAttribute('aria-selected', 'false');\n // Not data-id, which an entry's id could equal. The text is kept on the\n // row because the field can change before newer results replace it.\n item.setAttribute('data-create', text);\n item.classList.add('autocomplete-create');\n item.setAttribute('style', 'display:grid; user-select: none; align-items: center;');\n item.tabIndex = -1;\n const label = document.createElement('div');\n label.classList.add('item-text');\n label.setAttribute('style', 'padding:5px;overflow:hidden;line-height:1.2;font-weight:500;');\n label.textContent = this.options.i18n.create(text);\n item.append(label);\n return item;\n }\n\n /**\n * Shows sighted users the `i18n.noResults` that the live region announces.\n * Screen readers already hear that, and a listbox may only own options, so\n * the row is hidden from them.\n */\n private _createNoResultsRow() {\n const row = document.createElement('li');\n row.classList.add('autocomplete-no-results');\n row.setAttribute('role', 'none');\n row.setAttribute('aria-hidden', 'true');\n row.textContent = this.options.i18n.noResults;\n return row;\n }\n\n _setStatusLoading() {\n const statusElement = this._statusInfo;\n if (statusElement) statusElement.replaceChildren(Autocomplete._loadingIndicator());\n this._announce(this.options.i18n.loading);\n }\n\n private _announce(message: string) {\n if (!this._announcer) return;\n const text = this.el.matches(':focus') && this.el.value.length >= this.options.minLength ? message : '';\n if (this._announcer.textContent !== text) this._announcer.textContent = text;\n }\n\n /** Announces the entries a person can choose. Disabled ones are shown, not counted. */\n private _resultsMessage() {\n const count = this.menuItems.filter((entry) => entry.disabled !== true).length;\n return count ? this.options.i18n.results(count) : this.options.i18n.noResults;\n }\n\n _updateSelectedInfo() {\n const statusElement = this._statusInfo;\n if (statusElement) {\n if (this.options.isMultiSelect)\n statusElement.textContent = this.selectedValues.length.toString();\n else statusElement.replaceChildren();\n }\n }\n\n _refreshInputText() {\n if (this.selectedValues.length === 1) {\n const entry = this.selectedValues[0];\n this.el.value = entry.text || <string>entry.id; // Write Text to Input\n }\n }\n\n _triggerChanged() {\n // Counted before the native change, whose listeners may select again.\n const values = this.selectedValues;\n const selection = ++this._selection;\n this.el.dispatchEvent(new Event('change', { bubbles: true, cancelable: true, composed: true }));\n if (selection !== this._selection) return;\n this._notify('autocomplete', this.options.onAutocomplete, { args: [values], detail: { values }, current: () => selection === this._selection });\n }\n\n /**\n * Show autocomplete.\n */\n open = () => {\n const inputText = this.el.value.toLocaleLowerCase();\n this._resetAutocomplete();\n if (inputText.length >= this.options.minLength) {\n this._renderMenu();\n this._announce(this._resultsMessage());\n }\n // Open menu\n if (!this.menu.isOpen) {\n // Cancel first: two open() calls before the callback fires would leave\n // the earlier timer untracked, and destroy() can only cancel the one it\n // knows about.\n if (this._openTimer !== undefined) clearTimeout(this._openTimer);\n this._openTimer = setTimeout(() => {\n this._openTimer = undefined;\n this.menu.open();\n }, 0); // TODO: why?\n } else this.menu.recalculateDimensions(); // Recalculate menu when its already open\n };\n\n /**\n * Hide autocomplete.\n */\n close = () => {\n if (this._announcer) this._announcer.textContent = '';\n if (this._openTimer !== undefined) {\n clearTimeout(this._openTimer);\n this._openTimer = undefined;\n }\n this.isOpen = false;\n this.menu.close();\n };\n\n /**\n * Updates the visible or selectable items shown in the menu.\n * @param menuItems Items to be available.\n * @param selected Selected item ids\n * @param open Option to conditionally open menu\n */\n setMenuItems(menuItems: AutocompleteData[], selected: number[] | string[] = null, open: boolean = true) {\n if (this.el['Expressive_Autocomplete'] !== this) return;\n // Results that arrive after the user left the field update the list\n // without opening it under an input nobody is using.\n open &&= !this._left;\n this._noResults = menuItems.length === 0;\n this.menuItems = menuItems;\n if (selected) {\n this.selectedValues = this.menuItems.filter(\n (item) => !(selected.indexOf(<never>item.id) === -1)\n );\n }\n // open() clears and renders the list itself.\n if (this.options.isMultiSelect) {\n if (!open) this._renderMenu();\n } else {\n this._refreshInputText();\n }\n if (open) this.open();\n this._updateSelectedInfo();\n this._announce(open ? this._resultsMessage() : '');\n if (selected) this._triggerChanged();\n }\n\n private _toggleOption(entry: AutocompleteData) {\n const selected = !this.selectedValues.some((selectedEntry) => selectedEntry.id === entry.id);\n if (selected) this.selectedValues.push(entry);\n else this.selectedValues = this.selectedValues.filter((selectedEntry) => selectedEntry.id !== entry.id);\n // Update the row in place. Re-rendering the list dropped the active row,\n // and its reset of oldVal made the refocus below run a new search.\n const row = Array.from(this.container.querySelectorAll('li[data-id]')).find((li) => li.getAttribute('data-id') === String(entry.id));\n if (row) {\n row.setAttribute('aria-selected', String(selected));\n row.querySelector('input').checked = selected;\n }\n this.el.focus();\n }\n\n private _selectSingle(entry: AutocompleteData) {\n // A click focuses the row, and removing it would drop focus to <body>.\n // A selection made from code leaves focus where it is.\n const refocus = Utils.focusIsIn(this.container);\n // A search still waiting would run on the chosen label and reopen the list.\n this._cancelPendingSearch();\n this.selectedValues = [entry];\n this._refreshInputText();\n this._resetAutocomplete();\n this.close();\n if (refocus) {\n // The field already shows the choice, so returning to it is not a new search.\n this.oldVal = this.el.value.toLocaleLowerCase();\n this.el.focus();\n }\n }\n\n /** Commits a row chosen by Enter or a click. */\n private _choose(li: Element) {\n if (li.hasAttribute('data-create')) this._create(li.getAttribute('data-create'));\n else this.selectOption(li.getAttribute('data-id'));\n }\n\n private _create(text: string) {\n const refocus = Utils.focusIsIn(this.container);\n // A search still waiting would reopen the list on the same text.\n this._cancelPendingSearch();\n // The field keeps the text, so returning to it is not a new search.\n this.oldVal = this.el.value.toLocaleLowerCase();\n this.close();\n if (refocus) this.el.focus();\n this._notify('create', this.options.onCreate, { args: [text, this], detail: { text } });\n }\n\n /**\n * Select a specific autocomplete option via id-property.\n * @param id The id of a data-entry.\n */\n selectOption(id: number | string) {\n // A disabled entry is never found, so it is neither chosen nor removed.\n const entry = this.menuItems.find((item) => item.id == id && item.disabled !== true);\n if (!entry) return;\n if (this.options.isMultiSelect) this._toggleOption(entry);\n else this._selectSingle(entry);\n this._updateSelectedInfo();\n if (this.options.isMultiSelect) this._announce(this.options.i18n.selected(this.selectedValues.length));\n this._triggerChanged();\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/ts/components/treemapChart.ts"],
|
|
4
|
-
"sourcesContent": ["import { LineChart, LineChartOptions, numberFormat } from './lineChart';\n\nexport type TreemapChartOptions = LineChartOptions;\n\n/** A rectangle: its inline start, top, width and height. */\ntype Box = [x: number, y: number, width: number, height: number];\n\n// ponytail: rows past six repeat the colors, so neighbours can match.\nconst COLORS = 6;\n/** The keys that move to the next row and to the one before, in any direction. */\nconst NEXT = ['ArrowRight', 'ArrowDown'];\nconst PREVIOUS = ['ArrowLeft', 'ArrowUp'];\n\nconst sum = (areas: number[]) => areas.reduce((total, area) => total + area, 0);\n\n/** The box with its axes swapped, so one strip routine lays out both ways. */\nconst flip = ([x, y, width, height]: Box): Box => [y, x, height, width];\n\n/** How far the least square of `areas` is from square, in a strip along a side `side` long. */\nfunction worst(areas: number[], side: number) {\n const [total, squared] = [sum(areas) ** 2, side ** 2];\n return Math.max(...areas.map((area) => Math.max((squared * area) / total, total / (squared * area))));\n}\n\n/**\n * Lays `areas` out as one strip down the inline start of `free`, or across\n * its top when it is taller than wide, in order, and returns their boxes and\n * the space left beside the strip.\n */\nfunction strip(areas: number[], free: Box): [Box[], Box] {\n if (free[2] < free[3]) {\n const [boxes, rest] = strip(areas, flip(free));\n return [boxes.map(flip), flip(rest)];\n }\n const [x, y, width, height] = free;\n const across = sum(areas) / height;\n let top = y;\n const boxes = areas.map((area): Box => {\n const box: Box = [x, top, across, area / across];\n top += area / across;\n return box;\n });\n return [boxes, [x + across, y, width - across, height]];\n}\n\n/**\n * The squarified treemap of Bruls, Huizing and van Wijk: `areas`, largest\n * first and adding up to the free box's area, each join the current strip\n * while that keeps its rectangles nearer square, and the strip is laid down\n * when it would not.\n */\nfunction squarify(areas: number[], free: Box): Box[] {\n const boxes: Box[] = [];\n let row: number[] = [];\n for (const area of areas) {\n const side = Math.min(free[2], free[3]);\n if (row.length && worst([...row, area], side) > worst(row, side)) {\n const [laid, rest] = strip(row, free);\n boxes.push(...laid);\n [free, row] = [rest, []];\n }\n row.push(area);\n }\n return [...boxes, ...strip(row, free)[0]];\n}\n\n/** Whether a point, as fractions of the plot, lies in a box. */\nconst inside = ([x, y, width, height]: Box, at: number, down: number) =>\n at >= x && at < x + width && down >= y && down < y + height;\n\n/**\n * The tooltip's top or bottom for a box: from its top in the plot's upper\n * half, and up from its bottom in the lower half, so it stays in the plot.\n */\nconst hang = (y: number, height: number) => (y + height / 2 > 0.5\n ? { top: 'auto', bottom: `${(1 - y - height) * 100}%` }\n : { top: `${y * 100}%`, bottom: 'auto' });\n\n/**\n * Treemap chart. It reads its <table> like LineChart, but draws each row of\n * the first value column as a rectangle whose area is its share of the\n * whole, filling the plot, the largest at the top inline-start corner. Rows\n * with no positive value draw nothing. Further columns show in the tooltip.\n *\n * Call `update()` after changing the table, or start it with `watch` or\n * `data-watch`.\n */\nexport class TreemapChart extends LineChart {\n // No initializers: LineChart's constructor draws before they would run.\n /** Each row's positive value, or 0 for a row with no rectangle. */\n private _values: number[];\n /** Each row's rectangle, or null. */\n private _boxes: (HTMLElement | null)[];\n /** Each drawn row's place as fractions of the plot. */\n private _places: Box[];\n /** Lays the rectangles out again when the plot changes shape. */\n private _sizes: ResizeObserver;\n\n protected get _type() {\n return 'treemap-chart';\n }\n\n /** Area carries the value, so there is no value axis. */\n protected get _axis() {\n return false;\n }\n\n protected get _points() {\n return false;\n }\n\n static key = 'Expressive_TreemapChart';\n\n /**\n * Highlights one row: outlines its rectangle and fills the tooltip, with\n * the row's share. A row with no rectangle passes to the next one with\n * one, as when focus asks for the first row. Pass -1 to hide them.\n */\n show(index: number) {\n const row = this._drawnFrom(index);\n if (!this._tooltip || row === this.activeIndex) return;\n this._boxes.forEach((box, i) => box?.classList.toggle('active', i === row));\n super.show(row);\n this._share(row);\n }\n\n /** The first row from `index` on with a rectangle, or -1. */\n private _drawnFrom(index: number) {\n return index < 0 ? index : this._boxes.findIndex((box, i) => i >= index && box);\n }\n\n /** Adds the row's share of the whole to its cell in the tooltip, as the pie chart writes it. */\n private _share(row: number) {\n if (row < 0) return;\n const share = this._values[row] / sum(this._values);\n // Whole percentages, with a tenth below 10% so a small part is not 0%.\n const percent = numberFormat(this.el, { style: 'percent', maximumFractionDigits: share < 0.1 ? 1 : 0 });\n this._tooltip.querySelector('span:nth-of-type(2)')!.textContent += ` (${percent.format(share)})`;\n }\n\n /**\n * Opens the tooltip from the middle of the row's rectangle toward the\n * middle of the plot.\n */\n protected _place(index: number) {\n const [x, y, width, height] = this._places[index];\n const middle = x + width / 2;\n const left = this._reversed ? 1 - middle : middle;\n Object.assign(this._tooltip.style, { left: `${left * 100}%`, ...hang(y, height) });\n this._tooltip.classList.toggle('end', left > 0.5);\n }\n\n /** The row whose rectangle is under the pointer, or -1. */\n protected _indexAt(e: PointerEvent) {\n const box = this._plot.getBoundingClientRect();\n const across = (e.clientX - box.left) / box.width;\n const [at, down] = [this._reversed ? 1 - across : across, (e.clientY - box.top) / box.height];\n return this._places.findIndex((place) => place && inside(place, at, down));\n }\n\n /**\n * The arrows step through the rows with a rectangle in table order, which\n * runs in no one direction on screen, so they do not swap in a\n * right-to-left page. Home and End go to the first and last of them.\n */\n protected _keyTarget(key: string): number | undefined {\n const drawn = this._boxes.flatMap((box, i) => (box ? [i] : []));\n const [at, last] = [drawn.indexOf(this.activeIndex), drawn.length - 1];\n const step = NEXT.includes(key) ? Math.min(at + 1, last)\n : PREVIOUS.includes(key) ? Math.max(at - 1, 0)\n : ({ Home: 0, End: last } as Record<string, number>)[key];\n return step === undefined ? super._keyTarget(key) : drawn[step];\n }\n\n destroy() {\n this._sizes?.disconnect();\n super.destroy();\n }\n\n /** Neither row labels nor a legend: each rectangle carries its name. */\n protected _guides(): Element[] {\n return [];\n }\n\n /** One rectangle per positive row, in table order, placed by _layout(). */\n protected _draw(): Element {\n this._values = this.series[0].values.map((value) => Math.max(0, value ?? 0));\n const container = document.createElement('div');\n container.className = 'treemap-chart-boxes';\n container.setAttribute('aria-hidden', 'true');\n let drawn = 0;\n this._boxes = this._values.map((value, i) => {\n if (!value) return null;\n const box = document.createElement('div');\n box.className = 'treemap-chart-box';\n box.dataset.series = String((drawn++ % COLORS) + 1);\n const [name, text] = [document.createElement('span'), document.createElement('span')];\n [name.textContent, text.textContent] = [this.labels[i], this.series[0].text[i]];\n box.append(name, text);\n container.append(box);\n return box;\n });\n // The squares depend on the plot's shape, so it goes in the page to be measured.\n this.el.append(this._plot);\n this._layout();\n this._sizes?.disconnect();\n this._sizes = new ResizeObserver(() => this._layout());\n this._sizes.observe(this._plot);\n return container;\n }\n\n /** Squarifies the positive rows, largest first, equal values in table order, and places their rectangles. */\n private _layout() {\n // A hidden plot has no size; lay it out as a square until it shows.\n const [width, height] = [this._plot.clientWidth || 1, this._plot.clientHeight || 1];\n const rows = this._values.map((_, i) => i).filter((i) => this._values[i]).sort((a, b) => this._values[b] - this._values[a]);\n const scale = (width * height) / sum(this._values);\n const laid = squarify(rows.map((i) => this._values[i] * scale), [0, 0, width, height]);\n this._places = [];\n rows.forEach((row, k) => {\n const [x, y, w, h] = laid[k];\n const place = (this._places[row] = [x / width, y / height, w / width, h / height]);\n Object.assign(this._boxes[row]!.style, {\n insetInlineStart: `${place[0] * 100}%`,\n top: `${place[1] * 100}%`,\n width: `${place[2] * 100}%`,\n height: `${place[3] * 100}%`\n });\n });\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["boxes"]
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/ts/components/inputMask.ts"],
|
|
4
|
-
"sourcesContent": ["import { Component, BaseOptions } from '../core/component';\n\nconst _defaults = Object.freeze({});\n\n/** A mask position: a slot that takes the characters `accepts` matches, or a literal the mask writes itself. */\ntype Token = { accepts: RegExp } | { literal: string };\n\n/** What each slot character in a mask accepts. */\nconst SLOTS: Record<string, RegExp> = { '0': /[0-9]/, a: /\\p{L}/u, '*': /[0-9\\p{L}]/u };\n\n/** Which way a one-character delete from a collapsed caret goes. */\nconst DELETES: Record<string, number> = { deleteContentBackward: -1, deleteContentForward: 1 };\n\n/** Splits a mask into tokens. A backslash makes the character after it a literal. */\nconst parse = (mask: string): Token[] =>\n (mask.match(/\\\\[^]|[^]/gu) ?? []).map((part) => (SLOTS[part] ? { accepts: SLOTS[part] } : { literal: part.slice(-1) }));\n\n/**\n * The token `ch` lands on from token `t`: the literal at `t` when `ch` is that\n * literal, otherwise the next slot. Only the literal at `t` counts, so a\n * digit is not taken for a literal further on, such as the 1 in `+1 (000)`.\n */\nfunction landing(tokens: Token[], t: number, ch: string) {\n if ((tokens[t] as { literal?: string })?.literal === ch) return t;\n const slot = tokens.findIndex((token, i) => i >= t && 'accepts' in token);\n return slot < 0 ? tokens.length : slot;\n}\n\n/** Feeds `ch` to the mask at token `t`, keeping it in `chars` if a slot takes it. Returns the next token. */\nfunction place(tokens: Token[], t: number, ch: string, chars: string[]) {\n const at = landing(tokens, t, ch);\n const token = tokens[at];\n if (!token) return t;\n if ('literal' in token) return at + 1;\n if (!token.accepts.test(ch)) return t;\n chars.push(ch);\n return at + 1;\n}\n\n/**\n * The slot characters in `value`, in order, and how many of them come before\n * `caret`. Characters are normalized first, so full-width digits from an IME\n * fill digit slots. A character that neither fits a slot nor matches the next\n * literal is dropped, and so is any past the last slot.\n */\nfunction read(tokens: Token[], value: string, caret: number) {\n const chars: string[] = [];\n let t = 0;\n let at = 0;\n let before = 0;\n for (const typed of value) {\n for (const ch of typed.normalize('NFKC')) t = place(tokens, t, ch, chars);\n at += typed.length;\n if (at <= caret) before = chars.length;\n }\n return { chars, before };\n}\n\n/**\n * Writes `chars` into the mask's slots, with the literals that come before\n * each filled slot and none after the last. Returns the text and the index\n * just after each slot character.\n */\nfunction write(tokens: Token[], chars: string[]) {\n let text = '';\n let pending = '';\n const ends: number[] = [];\n for (const token of tokens) {\n if (ends.length === chars.length) break;\n if ('literal' in token) pending += token.literal;\n else {\n text += pending + chars[ends.length];\n pending = '';\n ends.push(text.length);\n }\n }\n return { text, ends };\n}\n\n/**\n * Input mask. Formats a text field's value to the pattern in its `data-mask`\n * attribute as people type, paste or compose: `0` takes a digit, `a` a\n * letter, `*` either, and every other character is a literal the mask writes\n * itself. The form submits the value as the field shows it.\n */\nexport class InputMask extends Component<BaseOptions> {\n declare el: HTMLInputElement;\n static key = 'Expressive_InputMask';\n private _tokens: Token[];\n\n constructor(el: HTMLInputElement, options: Partial<BaseOptions>) {\n super(el, options);\n this._tokens = parse(el.dataset.mask ?? '');\n // A mask with no slot would format every value to nothing, erasing a\n // saved value, so the component leaves such a field alone.\n if (!this._tokens.some((token) => 'accepts' in token)) return;\n const signal = this._events.signal;\n // Capture, which runs before the field's own bubble listeners, so the\n // page's input listeners read the formatted value.\n el.addEventListener('input', this._onInput, { capture: true, signal });\n // An IME writes as it composes; the mask waits until it is done. Engines\n // fire the last input before or after compositionend, and formatting\n // twice changes nothing.\n el.addEventListener('compositionend', this._format, { signal });\n el.addEventListener('beforeinput', this._onBeforeInput, { signal });\n // The form resets its fields after the reset event, so the mask formats\n // the restored value a task later.\n el.ownerDocument.addEventListener('reset', this._onReset, { capture: true, signal });\n this._rewrite();\n }\n\n static get defaults(): BaseOptions {\n return _defaults;\n }\n\n private _onInput = (e: InputEvent) => {\n if (!e.isComposing) this._format();\n };\n\n /**\n * Backspace after a literal, or Delete before one, would remove the\n * literal, which the mask then writes back. It removes the slot character\n * across the literal instead.\n */\n private _onBeforeInput = (e: InputEvent) => {\n const step = DELETES[e.inputType];\n const index = step && this.el.selectionStart === this.el.selectionEnd ? this._acrossLiteral(step) : -1;\n if (index < 0) return;\n e.preventDefault();\n this._remove(index, e.inputType);\n };\n\n /** The index among the slot characters to delete when the character `step` from the caret is a literal, or -1. */\n private _acrossLiteral(step: number) {\n const { selectionStart: caret, value } = this.el;\n const here = read(this._tokens, value, caret);\n const index = here.before + Math.min(step, 0);\n // Stepping over a literal passes no slot character.\n return read(this._tokens, value, caret + step).before === here.before && index in here.chars ? index : -1;\n }\n\n /** Removes slot character `index`, puts the caret where it was, and reports the edit as typing would. */\n private _remove(index: number, inputType: string) {\n const { chars } = read(this._tokens, this.el.value, 0);\n chars.splice(index, 1);\n const { text, ends } = write(this._tokens, chars);\n this.el.value = text;\n const caret = ends[index - 1] ?? 0;\n this.el.setSelectionRange(caret, caret);\n this.el.dispatchEvent(new InputEvent('input', { bubbles: true, composed: true, inputType }));\n }\n\n private _onReset = (e: Event) => {\n if (e.target === this.el.form) setTimeout(this._afterReset);\n };\n\n private _afterReset = () => {\n if (!this._events.signal.aborted) this._rewrite();\n };\n\n private _format = () => {\n const caret = this._rewrite();\n if (caret !== null && this.el.ownerDocument.activeElement === this.el) this.el.setSelectionRange(caret, caret);\n };\n\n /** Rewrites the value to the mask. Returns where the caret goes, or null when the value already fit. */\n private _rewrite() {\n const el = this.el;\n const { chars, before } = read(this._tokens, el.value, el.selectionEnd ?? el.value.length);\n const { text, ends } = write(this._tokens, chars);\n if (text === el.value) return null;\n el.value = text;\n return ends[before - 1] ?? 0;\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/ts/components/lightbox.ts"],
|
|
4
|
-
"sourcesContent": ["import { Utils, controllerFor, restoreAttribute } from '../core/utils';\nimport { BaseOptions, Component } from '../core/component';\n\nexport interface LightboxOptions extends BaseOptions {\n /**\n * Transition in duration in milliseconds.\n * @default 275\n */\n inDuration: number;\n /**\n * Transition out duration in milliseconds.\n * @default 200\n */\n outDuration: number;\n /**\n * Callback function called before lightbox is opened.\n * @default null\n */\n onOpenStart: (el: Element) => void;\n /**\n * Callback function called after lightbox is opened.\n * @default null\n */\n onOpenEnd: (el: Element) => void;\n /**\n * Callback function called before lightbox is closed.\n * @default null\n */\n onCloseStart: (el: Element) => void;\n /**\n * Callback function called after lightbox is closed.\n * @default null\n */\n onCloseEnd: (el: Element) => void;\n}\n\nconst _defaults: LightboxOptions = {\n inDuration: 275,\n outDuration: 200,\n onOpenStart: null,\n onOpenEnd: null,\n onCloseStart: null,\n onCloseEnd: null\n};\n\nexport class Lightbox extends Component<LightboxOptions> {\n /** If the lightbox overlay is showing. */\n overlayActive: boolean;\n /** If the lightbox is no longer being animated. */\n doneAnimating: boolean;\n /** Caption, if specified. */\n caption: string;\n /** Original width of image. */\n originalWidth: number;\n /** Original height of image. */\n originalHeight: number;\n private originInlineStyles: string;\n private placeholder: HTMLElement;\n private newHeight: number;\n private newWidth: number;\n private windowWidth: number;\n private windowHeight: number;\n private attrWidth: string;\n private attrHeight: string;\n private _overlay: HTMLElement;\n private _photoCaption: HTMLElement;\n private _trigger: HTMLElement;\n private _tabindex: string | null;\n private _timers = new Map<ReturnType<typeof setTimeout>, () => void>();\n private _motion = window.matchMedia('(prefers-reduced-motion: reduce)');\n private _isOpen = false;\n private _destroyed = false;\n /** Removes the listeners that close an open lightbox. */\n private _windowEvents: AbortController | undefined;\n private _revision = 0;\n // Counts opens and closes only. _revision also moves when reduced motion\n // flushes a transition, which must still report its end.\n private _phase = 0;\n\n constructor(el: HTMLElement, options: Partial<LightboxOptions>) {\n super(el, options);\n\n this.overlayActive = false;\n this.doneAnimating = true;\n this.placeholder = document.createElement('div');\n this.placeholder.classList.add('material-placeholder');\n this.originalWidth = 0;\n this.originalHeight = 0;\n this.originInlineStyles = this.el.getAttribute('style');\n this.caption = this.el.getAttribute('data-caption') || '';\n this._tabindex = this.el.getAttribute('tabindex');\n this._trigger = this.el.closest('button') ?? this.el;\n this.el.tabIndex = this._trigger === this.el ? 0 : -1;\n // Wrap\n this.el.before(this.placeholder);\n this.placeholder.append(this.el);\n this._setupEventHandlers();\n }\n\n static get defaults(): LightboxOptions {\n return _defaults;\n }\n\n static key = 'Expressive_Lightbox';\n\n destroy() {\n if (this._destroyed) return;\n this._destroyed = true;\n const focused = (this.el.getRootNode() as Document | ShadowRoot).activeElement === this.el;\n this._cancel();\n this._reset();\n this.placeholder.replaceWith(this.el);\n if (focused) this._restoreFocus();\n restoreAttribute(this.el, 'tabindex', this._tabindex);\n super.destroy();\n }\n\n // Back to the trigger when focus fell to the body (or the shadow host), as\n // a click on the overlay, which cannot take focus, leaves it.\n private _restoreFocus() {\n const root = this.el.getRootNode() as Document | ShadowRoot;\n let active = document.activeElement;\n while (active?.shadowRoot?.activeElement) active = active.shadowRoot.activeElement;\n if ([document.body, (root as ShadowRoot).host].includes(active)) this._trigger.focus({ preventScroll: true });\n }\n\n private _reset() {\n this._windowEvents?.abort();\n // Removing a popover, or its attribute, takes it out of the top layer.\n this._overlay?.remove();\n this._photoCaption?.remove();\n this.el.removeAttribute('popover');\n if (this.attrWidth != null) this.el.setAttribute('width', this.attrWidth);\n if (this.attrHeight != null) this.el.setAttribute('height', this.attrHeight);\n this.el.classList.remove('active');\n this.placeholder.removeAttribute('style');\n restoreAttribute(this.el, 'style', this.originInlineStyles);\n this.overlayActive = false;\n this._isOpen = false;\n this.doneAnimating = true;\n }\n\n private _cancel() {\n for (const timer of this._timers.keys()) clearTimeout(timer);\n this._timers.clear();\n return ++this._revision;\n }\n\n private _schedule(callback: () => void, delay: number) {\n if (this._motion.matches) { callback(); return; }\n const timer = setTimeout(() => { this._timers.delete(timer); callback(); }, delay);\n this._timers.set(timer, callback);\n }\n\n private _handleMotionChange = () => {\n if (!this._motion.matches) return;\n const callbacks = [...this._timers.values()];\n const revision = this._cancel();\n for (const callback of callbacks) {\n if (revision !== this._revision) break;\n callback();\n }\n if (this.overlayActive) {\n for (const el of [this.el, this._overlay, this._photoCaption]) if (el) el.style.transition = 'none';\n }\n };\n\n private _setupEventHandlers() {\n const { signal } = this._events;\n this._motion.addEventListener('change', this._handleMotionChange, { signal });\n this._trigger.addEventListener('click', this._handleLightboxToggle, { signal });\n this.el.addEventListener('keydown', this._handleLightboxKeypress, { signal });\n }\n\n private _handleLightboxKeypress = (e: KeyboardEvent) => {\n if (this._trigger === this.el && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault();\n this._handleLightboxToggle();\n }\n };\n\n private _handleLightboxToggle = () => {\n // If already modal, return to original\n if (this._isOpen) this.close();\n else this.open();\n };\n\n private _handleWindowChange = () => {\n if (this.overlayActive) this.close();\n };\n\n private _handleWindowEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') this.close();\n };\n\n // The image zooms in place, not in a modal, so Tab would reach the page\n // behind the overlay. Tab closes it instead, then moves focus as usual.\n private _handleWindowTab = (e: KeyboardEvent) => {\n if (e.key === 'Tab') this.close();\n };\n\n /**\n * Shows `el` as a manual popover, so it is in the top layer: no ancestor\n * clips or covers it, and it stacks above what was shown before it.\n */\n private _showOnTop(el: HTMLElement) {\n el.setAttribute('popover', 'manual');\n el.showPopover();\n }\n\n /** The placeholder's document position, where the image rests. */\n private _restingPlace() {\n const box = this.placeholder.getBoundingClientRect();\n return { left: box.left + window.scrollX + 'px', top: box.top + window.scrollY + 'px' };\n }\n\n private _updateVars(): void {\n this.windowWidth = window.innerWidth;\n this.windowHeight = window.innerHeight;\n this.caption = this.el.getAttribute('data-caption') || '';\n }\n\n // Image\n private _animateImageIn(): void {\n const phase = this._phase;\n this.el.style.maxHeight = this.newHeight.toString() + 'px';\n this.el.style.maxWidth = this.newWidth.toString() + 'px';\n const duration = this._motion.matches ? 0 : this.options.inDuration;\n // from\n this.el.style.transition = 'none';\n this.el.style.height = this.originalHeight + 'px';\n this.el.style.width = this.originalWidth + 'px';\n this._schedule(() => {\n // easeOutQuad\n this.el.style.transition = `height ${duration}ms ease,\n width ${duration}ms ease,\n left ${duration}ms ease,\n top ${duration}ms ease\n `;\n // to\n this.el.style.height = this.newHeight + 'px';\n this.el.style.width = this.newWidth + 'px';\n this.el.style.left = window.scrollX + (this.windowWidth - this.newWidth) / 2 + 'px';\n this.el.style.top = window.scrollY + (this.windowHeight - this.newHeight) / 2 + 'px';\n }, 1);\n\n this._schedule(() => {\n this.doneAnimating = true;\n this._notify('opened', this.options.onOpenEnd, { current: () => phase === this._phase });\n }, duration);\n\n }\n private _animateImageOut(): void {\n const phase = this._phase;\n const duration = this._motion.matches ? 0 : this.options.outDuration;\n // easeOutQuad\n this.el.style.transition = `height ${duration}ms ease,\n width ${duration}ms ease,\n left ${duration}ms ease,\n top ${duration}ms ease\n `;\n // to\n this.el.style.height = this.originalHeight + 'px'; // was originalWidth\n this.el.style.width = this.originalWidth + 'px';\n Object.assign(this.el.style, this._restingPlace());\n this._schedule(() => {\n this._reset();\n // onCloseEnd callback\n this._notify('closed', this.options.onCloseEnd, { current: () => phase === this._phase });\n }, duration);\n }\n\n // Caption\n private _addCaption(): void {\n this._photoCaption = document.createElement('div');\n this._photoCaption.classList.add('lightbox-caption');\n this._photoCaption.innerText = this.caption;\n Utils.portalRoot(this.el).append(this._photoCaption);\n this._photoCaption.style.display = 'inline';\n this._showOnTop(this._photoCaption);\n this._fadeIn(this._photoCaption);\n }\n\n // Overlay\n private _addOverlay(): void {\n this._overlay = document.createElement('div');\n this._overlay.id = 'lightbox-overlay';\n this._overlay.addEventListener(\n 'click',\n (event) => {\n event.stopPropagation();\n this.close();\n },\n { once: true }\n );\n\n this.el.before(this._overlay);\n this._showOnTop(this._overlay);\n this._fadeIn(this._overlay);\n }\n\n private _fadeIn(el: HTMLElement): void {\n el.style.transition = 'none';\n el.style.opacity = '0';\n const duration = this._motion.matches ? 0 : this.options.inDuration;\n this._schedule(() => {\n el.style.transition = `opacity ${duration}ms ease`;\n el.style.opacity = '1';\n }, 1);\n }\n\n private _fadeOut(el: HTMLElement): void {\n const duration = this._motion.matches ? 0 : this.options.outDuration;\n el.style.transition = `opacity ${duration}ms ease`;\n el.style.opacity = '0';\n }\n\n /**\n * Open lightbox.\n */\n open = () => {\n if (this._destroyed || this._isOpen) return;\n this._phase++;\n const revision = this._cancel();\n if (this.overlayActive) this._reset();\n this._updateVars();\n // Both rects are read up front: measuring the placeholder after writing\n // its width forced a second layout for the height.\n const originRect = this.el.getBoundingClientRect();\n const placeholderRect = this.placeholder.getBoundingClientRect();\n // An image not yet loaded, or hidden, has no size to zoom from; the\n // ratios below would be 0 / 0.\n if (!originRect.width || !originRect.height) return;\n this._isOpen = true;\n this.originalWidth = originRect.width;\n this.originalHeight = originRect.height;\n // Set states\n this.doneAnimating = false;\n this.el.classList.add('active');\n this.overlayActive = true;\n // onOpenStart callback\n if (!this._notify('open', this.options.onOpenStart, { current: () => revision === this._revision })) return;\n // Set positioning for placeholder\n this.placeholder.style.width = placeholderRect.width + 'px';\n this.placeholder.style.height = placeholderRect.height + 'px';\n // In the top layer the image is positioned in the document, starting\n // where the placeholder holds its place.\n this.el.style.position = 'absolute';\n this.el.style.inset = 'auto';\n this.el.style.left = placeholderRect.left + window.scrollX + 'px';\n this.el.style.top = placeholderRect.top + window.scrollY + 'px';\n this.el.style.willChange = 'left, top, width, height';\n // Change from width or height attribute to css\n this.attrWidth = this.el.getAttribute('width');\n this.attrHeight = this.el.getAttribute('height');\n if (this.attrWidth) {\n this.el.style.width = this.attrWidth + 'px';\n this.el.removeAttribute('width');\n }\n if (this.attrHeight) {\n this.el.style.height = this.attrHeight + 'px'; // was width, from the height attribute\n this.el.removeAttribute('height');\n }\n // The overlay, the image and the caption go into the top layer in that\n // order, so each stacks above the one before.\n this._addOverlay();\n this._showOnTop(this.el);\n if (this.caption !== '') this._addCaption();\n // Resize Image\n const widthPercent = this.originalWidth / this.windowWidth;\n const heightPercent = this.originalHeight / this.windowHeight;\n if (widthPercent > heightPercent) {\n // Width first\n const ratio = this.originalHeight / this.originalWidth;\n this.newWidth = this.windowWidth * 0.9;\n this.newHeight = this.windowWidth * 0.9 * ratio;\n } else {\n // Height first\n const ratio = this.originalWidth / this.originalHeight;\n this.newWidth = this.windowHeight * 0.9 * ratio;\n this.newHeight = this.windowHeight * 0.9;\n }\n // Handle Exit triggers\n this._windowEvents?.abort();\n this._windowEvents = controllerFor(this.el);\n const { signal } = this._windowEvents;\n window.addEventListener('scroll', this._handleWindowChange, { passive: true, signal });\n window.addEventListener('resize', this._handleWindowChange, { passive: true, signal });\n window.addEventListener('keyup', this._handleWindowEscape, { signal });\n window.addEventListener('keydown', this._handleWindowTab, { signal });\n this._animateImageIn();\n };\n\n /**\n * Close lightbox.\n */\n close = () => {\n if (this._destroyed || !this._isOpen) return;\n this._phase++;\n const revision = this._cancel();\n this._isOpen = false;\n this.doneAnimating = false;\n // onCloseStart callback\n if (!this._notify('close', this.options.onCloseStart, { current: () => revision === this._revision })) return;\n // disable exit handlers\n this._windowEvents?.abort();\n this._restoreFocus();\n if (this._overlay) this._fadeOut(this._overlay);\n if (this._photoCaption) this._fadeOut(this._photoCaption);\n this._animateImageOut();\n };\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/ts/components/confetti.ts"],
|
|
4
|
-
"sourcesContent": ["import { Component, BaseOptions } from '../core/component';\n\nexport type ConfettiShape = 'square' | 'circle' | 'star';\n\nexport interface ConfettiOptions extends BaseOptions {\n /**\n * Pieces per burst.\n * @default 50\n */\n particleCount: number;\n /**\n * Launch direction in degrees. 90 is straight up, 0 is right.\n * @default 90\n */\n angle: number;\n /**\n * How far the pieces fan out from the angle, in degrees.\n * @default 45\n */\n spread: number;\n /**\n * Launch speed in pixels per frame.\n * @default 45\n */\n startVelocity: number;\n /**\n * Share of its speed a piece keeps each frame.\n * @default 0.9\n */\n decay: number;\n /**\n * Pull toward the bottom. 0 floats, 1 is normal.\n * @default 1\n */\n gravity: number;\n /**\n * Sideways push per frame. Negative drifts left.\n * @default 0\n */\n drift: number;\n /**\n * Frames a piece lives while it fades out.\n * @default 200\n */\n ticks: number;\n /**\n * Launch point as fractions of the canvas, 0 to 1. A missing side is\n * 0.5. A trigger element ignores it and launches from its own center.\n * @default { x: 0.5, y: 0.5 }\n */\n origin: { x?: number; y?: number };\n /**\n * CSS colors. Empty uses the theme's primary, secondary and tertiary\n * colors and their containers.\n * @default []\n */\n colors: string[];\n /**\n * @default ['square', 'circle']\n */\n shapes: ConfettiShape[];\n /**\n * Piece size multiplier.\n * @default 1\n */\n scalar: number;\n /**\n * On a canvas, wait for `fire()` instead of bursting once at init.\n * @default false\n */\n manualStart: boolean;\n}\n\nconst _defaults: ConfettiOptions = {\n particleCount: 50,\n angle: 90,\n spread: 45,\n startVelocity: 45,\n decay: 0.9,\n gravity: 1,\n drift: 0,\n ticks: 200,\n origin: { x: 0.5, y: 0.5 },\n colors: [],\n shapes: ['square', 'circle'],\n scalar: 1,\n manualStart: false\n};\n\nconst THEME_COLORS = ['primary', 'secondary', 'tertiary', 'primary-container', 'secondary-container', 'tertiary-container'];\n// Used when the page has no theme tokens.\nconst FALLBACK_COLORS = ['#26ccff', '#a25afd', '#ff5e7e', '#88ff5a', '#fcff42', '#ffa62d', '#ff36ff'];\nconst RAD = Math.PI / 180;\n\ninterface Piece {\n x: number;\n y: number;\n velocity: number;\n angle: number;\n wobble: number;\n wobbleSpeed: number;\n tilt: number;\n tick: number;\n color: string;\n shape: ConfettiShape;\n options: ConfettiOptions;\n}\n\ninterface Scene {\n ctx: CanvasRenderingContext2D;\n pieces: Piece[];\n frame: number;\n last: number;\n done: (() => void)[];\n overlay: boolean;\n}\n\nconst scenes = new Map<HTMLCanvasElement, Scene>();\nlet overlay: HTMLCanvasElement | null = null;\n\n/**\n * Confetti. Bursts of theme-colored pieces drawn on a canvas.\n *\n * - `Confetti.fire(options)` bursts over the whole viewport.\n * - Any other `.confetti` element bursts from its center when clicked.\n * - A `<canvas class=\"confetti\">` bursts inside its own box, once at init\n * unless `manualStart`, and again on each `fire()`.\n *\n * The viewport canvas is a manual popover, so it draws above an open modal\n * dialog, and it ignores the pointer. Nothing is drawn when the reader\n * prefers reduced motion.\n */\nexport class Confetti extends Component<ConfettiOptions> {\n private _onClick = () => { this.fire(); };\n\n constructor(el: HTMLElement, options: Partial<ConfettiOptions>) {\n super(el, options);\n if (!(el instanceof HTMLCanvasElement)) el.addEventListener('click', this._onClick, { signal: this._events.signal });\n else if (!this.options.manualStart) this.fire();\n }\n\n static get defaults(): ConfettiOptions {\n return _defaults;\n }\n\n static key = 'Expressive_Confetti';\n\n /**\n * Bursts over the whole viewport. Resolves when the last piece is gone.\n */\n static fire(options: Partial<ConfettiOptions> = {}): Promise<void> {\n return burst(viewportCanvas, document.body, { ...Confetti.defaults, ...options });\n }\n\n /**\n * Bursts on this canvas, or from this element's center over the viewport.\n * Resolves when the last piece is gone.\n */\n fire(options: Partial<ConfettiOptions> = {}): Promise<void> {\n const merged = { ...this.options, ...options };\n if (this.el instanceof HTMLCanvasElement) {\n const canvas = this.el;\n return burst(() => canvas, canvas.parentElement ?? document.body, merged);\n }\n const r = this.el.getBoundingClientRect();\n merged.origin = { x: (r.left + r.width / 2) / innerWidth, y: (r.top + r.height / 2) / innerHeight };\n return burst(viewportCanvas, this.el.parentElement ?? document.body, merged);\n }\n\n destroy() {\n if (this.el instanceof HTMLCanvasElement) stop(this.el);\n super.destroy();\n }\n}\n\n// `themed` is where the theme colors are read, so a scoped theme applies.\nfunction burst(getCanvas: () => HTMLCanvasElement, themed: Element, o: ConfettiOptions): Promise<void> {\n if (matchMedia('(prefers-reduced-motion: reduce)').matches) return Promise.resolve();\n const canvas = getCanvas();\n let scene = scenes.get(canvas);\n if (!scene) {\n const ctx = canvas.getContext('2d');\n if (!ctx) return Promise.resolve();\n scene = { ctx, pieces: [], frame: 0, last: 0, done: [], overlay: canvas === overlay };\n scenes.set(canvas, scene);\n }\n const { width, height } = fit(canvas);\n const colors = o.colors.length ? o.colors : themeColors(themed);\n const x = (o.origin.x ?? 0.5) * width;\n const y = (o.origin.y ?? 0.5) * height;\n for (let i = 0; i < o.particleCount; i++) {\n scene.pieces.push({\n x, y,\n velocity: o.startVelocity * (0.5 + Math.random()),\n angle: -o.angle * RAD + (0.5 - Math.random()) * o.spread * RAD,\n wobble: Math.random() * 10,\n wobbleSpeed: 0.05 + Math.random() * 0.05,\n tilt: (0.25 + Math.random() / 2) * Math.PI,\n tick: 0,\n color: colors[i % colors.length],\n shape: o.shapes[Math.floor(Math.random() * o.shapes.length)] ?? 'square',\n options: o\n });\n }\n const s = scene;\n if (!s.frame) s.frame = requestAnimationFrame((now) => { s.last = now; draw(canvas, s, now); });\n return new Promise((resolve) => s.done.push(resolve));\n}\n\nfunction draw(canvas: HTMLCanvasElement, scene: Scene, now: number) {\n // Frames are counted at 60 per second whatever the display rate.\n const step = Math.min((now - scene.last) / (1000 / 60), 4);\n scene.last = now;\n const { width, height } = fit(canvas);\n const { ctx } = scene;\n const dpr = canvas.width / (width || 1);\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n scene.pieces = scene.pieces.filter((p) => {\n const o = p.options;\n p.x += (Math.cos(p.angle) * p.velocity + o.drift) * step;\n p.y += (Math.sin(p.angle) * p.velocity + o.gravity * 3) * step;\n p.velocity *= o.decay ** step;\n p.wobble += p.wobbleSpeed * step;\n p.tilt += 0.1 * step;\n p.tick += step;\n if (p.tick >= o.ticks) return false;\n const size = 8 * o.scalar;\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.translate(p.x + 10 * o.scalar * Math.cos(p.wobble), p.y + 10 * o.scalar * Math.sin(p.wobble));\n ctx.rotate(p.tilt);\n ctx.scale(1, Math.cos(p.wobble));\n ctx.globalAlpha = 1 - p.tick / o.ticks;\n ctx.fillStyle = p.color;\n ctx.beginPath();\n if (p.shape === 'circle') ctx.arc(0, 0, size / 2, 0, 2 * Math.PI);\n else if (p.shape === 'star') star(ctx, size * 0.75);\n else ctx.rect(-size / 2, -size / 2, size, size);\n ctx.fill();\n return true;\n });\n if (scene.pieces.length) scene.frame = requestAnimationFrame((t) => draw(canvas, scene, t));\n else stop(canvas);\n}\n\nfunction stop(canvas: HTMLCanvasElement) {\n const scene = scenes.get(canvas);\n if (!scene) return;\n cancelAnimationFrame(scene.frame);\n scenes.delete(canvas);\n scene.ctx.setTransform(1, 0, 0, 1, 0, 0);\n scene.ctx.clearRect(0, 0, canvas.width, canvas.height);\n if (scene.overlay) {\n canvas.remove();\n overlay = null;\n }\n for (const resolve of scene.done) resolve();\n}\n\nfunction star(ctx: CanvasRenderingContext2D, r: number) {\n for (let i = 0; i < 10; i++) {\n const a = (i * Math.PI) / 5 - Math.PI / 2;\n const d = i % 2 ? r / 2 : r;\n ctx.lineTo(Math.cos(a) * d, Math.sin(a) * d);\n }\n ctx.closePath();\n}\n\n// Matches the canvas's pixel buffer to its box and the screen's pixel ratio.\nfunction fit(canvas: HTMLCanvasElement) {\n const width = canvas.clientWidth;\n const height = canvas.clientHeight;\n const w = Math.round(width * devicePixelRatio);\n const h = Math.round(height * devicePixelRatio);\n if (canvas.width !== w || canvas.height !== h) {\n canvas.width = w;\n canvas.height = h;\n }\n return { width, height };\n}\n\nfunction viewportCanvas(): HTMLCanvasElement {\n if (overlay?.isConnected) return overlay;\n overlay = document.createElement('canvas');\n overlay.className = 'confetti-overlay';\n overlay.setAttribute('aria-hidden', 'true');\n // Inline, so the overlay works even where the stylesheet does not reach.\n Object.assign(overlay.style, {\n position: 'fixed', inset: '0', width: '100%', height: '100%', margin: '0', padding: '0',\n // The fallback keeps the order where the sheet, and so the token, is absent.\n border: '0', background: 'transparent', pointerEvents: 'none', zIndex: 'var(--expressive-z-confetti, 10001)'\n });\n document.body.append(overlay);\n if (typeof overlay.showPopover === 'function') {\n overlay.popover = 'manual';\n overlay.showPopover();\n }\n return overlay;\n}\n\n// Resolves each theme color token through `color`, so light-dark() and\n// relative colors reach the canvas as plain colors.\nfunction themeColors(themed: Element): string[] {\n const probe = document.createElement('span');\n probe.hidden = true;\n themed.append(probe);\n const style = getComputedStyle(probe);\n const colors = THEME_COLORS.filter((role) => style.getPropertyValue(`--md-sys-color-${role}`).trim()).map((role) => {\n probe.style.color = `var(--md-sys-color-${role})`;\n return getComputedStyle(probe).color;\n });\n probe.remove();\n return colors.length ? colors : FALLBACK_COLORS;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/ts/components/chips.ts"],
|
|
4
|
-
"sourcesContent": ["import { Utils, restoreAttribute } from '../core/utils';\nimport { Autocomplete, AutocompleteOptions } from './autocomplete';\nimport { Component, BaseOptions } from '../core/component';\nimport { FormControl, formAssociated, wrapInControl, unwrapControl } from '../core/formControl';\n\nexport interface ChipData {\n /**\n * Unique identifier.\n */\n id: number | string;\n /**\n * Chip text. If not specified, \"id\" will be used.\n */\n text?: string;\n /**\n * Chip image (URL).\n */\n image?: string;\n}\n\n/** The form control a named field submits through, wrapping its input. */\nconst CONTROL = 'expressive-chips-control';\n\n/** The values in pasted text, split by commas, tabs or lines. */\nconst pastedValues = (e: ClipboardEvent) =>\n (e.clipboardData?.getData('text') ?? '').split(/[,\\t\\n]/).map((value) => value.trim()).filter(Boolean);\n\nexport interface ChipsI18nOptions {\n /** Prefix for the delete button's accessible name. */\n remove: string;\n /** What a required field says while it has no chips. */\n required: string;\n}\n\nexport interface ChipsOptions extends BaseOptions {\n /**\n * Set the chip data.\n * @default []\n */\n data: ChipData[];\n /**\n * Set first placeholder when there are no tags.\n * @default \"\"\n */\n placeholder: string;\n /**\n * Set second placeholder when adding additional tags.\n * @default \"\"\n */\n secondaryPlaceholder: string;\n /**\n * Set autocomplete options.\n * @default {}\n */\n autocompleteOptions: Partial<AutocompleteOptions>;\n /**\n * Toggles abililty to add custom value not in autocomplete list.\n * @default false\n */\n autocompleteOnly: boolean;\n /**\n * Set chips limit.\n * @default Infinity\n */\n limit: number;\n /**\n * Specifies class to be used in \"close\" button.\n * @default 'material-symbols'\n */\n closeIconClass: string;\n /**\n * Specifies option to render user input field\n * @default false;\n */\n allowUserInput: boolean;\n /**\n * Strings the component generates. `remove` prefixes the delete button's\n * accessible name, giving \"Remove Apple\". `required` is what a required\n * field says while it has no chips.\n * @default { remove: 'Remove', required: 'Add at least one item.' }\n */\n i18n: Partial<ChipsI18nOptions>;\n /**\n * Callback for chip add.\n * @default null\n */\n onChipAdd: (element: HTMLElement, chip: HTMLElement) => void;\n /**\n * Callback for chip select.\n * @default null\n */\n onChipSelect: (element: HTMLElement, chip: HTMLElement) => void;\n /**\n * Callback for chip delete.\n * @default null\n */\n onChipDelete: (element: HTMLElement, chip: HTMLElement) => void;\n}\n\nconst _defaults: ChipsOptions = {\n data: [],\n placeholder: '',\n secondaryPlaceholder: '',\n closeIconClass: 'material-symbols',\n autocompleteOptions: {},\n autocompleteOnly: false,\n limit: Infinity,\n allowUserInput: false,\n i18n: { remove: 'Remove', required: 'Add at least one item.' },\n onChipAdd: null,\n onChipSelect: null,\n onChipDelete: null\n};\n\nexport class Chips extends Component<ChipsOptions> {\n /** Array of the current chips data. */\n chipsData: ChipData[];\n /** If the chips has autocomplete enabled. */\n hasAutocomplete: boolean;\n /** Autocomplete instance, if any. */\n autocomplete: Autocomplete;\n _input: HTMLInputElement;\n _label: HTMLLabelElement;\n _chips: HTMLElement[];\n private _selectedChip: HTMLElement;\n /** The form name the text input had, which the chips submit instead. */\n private _name = '';\n /** The chips the field started with, which a form reset puts back. */\n private _initialData: ChipData[] = [];\n /** The input's own aria-required, or null, put back on destroy. */\n private _ariaRequired: string | null = null;\n /** The form control wrapping a named input, which the form reads instead of it. */\n private _control: FormControl | null = null;\n /** The named text input, whose form, disabled state and required the chips take over. */\n private _source: HTMLInputElement | null = null;\n private _required = false;\n\n /**\n * Selection is drawn by a class now, not by `:focus`, so it does not clear\n * itself when focus moves - every path that changes the selection has to go\n * through here or the class and the field drift apart.\n *\n * Deliberately no `aria-selected`: the chip is not an option in a listbox,\n * and putting the attribute on an element with no such role is the same\n * defect the semantics standard exists to remove.\n */\n private _setSelected(chip: HTMLElement | null) {\n this._selectedChip?.classList.remove('selected');\n this._selectedChip = chip;\n chip?.classList.add('selected');\n }\n\n constructor(el: HTMLElement, options: Partial<ChipsOptions>) {\n super(el, options);\n\n this.el.classList.add('chips');\n this.chipsData = [];\n this._chips = [];\n this._takeName();\n\n // Render initial chips\n if (this.options.data.length) {\n // A copy: adding or deleting a chip would otherwise edit the caller's\n // array, and a batch init would have every instance share one list.\n this.chipsData = [...this.options.data];\n this._renderChips();\n }\n\n // Render input element, setup event handlers\n if (this.options.allowUserInput) {\n this.el.classList.add('field');\n this._setupInput();\n this._setupEventHandlers();\n // move input to end, inside its control when it has one\n this.el.append(this._end);\n }\n // After _setupInput: the label points at the input's id, which is only\n // assigned there. Running this first threw on any .chips with a <label>.\n this._setupLabel();\n this._sync();\n // After autocomplete, which can turn the input's value into a chip.\n this._initialData = [...this.chipsData];\n }\n\n static get defaults() {\n return _defaults;\n }\n\n static key = 'Expressive_Chips';\n\n getData() {\n return this.chipsData;\n }\n\n destroy() {\n if (this.autocomplete && Autocomplete.getInstance(this._input) === this.autocomplete) {\n this.autocomplete.destroy();\n }\n this._events.abort();\n this._chips.forEach((c) => c.remove());\n this._chips = [];\n this._giveNameBack();\n super.destroy();\n }\n\n _setupEventHandlers() {\n const { signal } = this._events;\n this.el.addEventListener('click', this._handleChipClick, { signal });\n this.el.addEventListener('keydown', Chips._handleChipsKeydown, { signal });\n this.el.addEventListener('focusin', this._handleFocusIn, { signal });\n this.el.addEventListener('focusout', this._handleFocusOut, { signal });\n this._input.addEventListener('focus', this._handleInputFocus, { signal });\n this._input.addEventListener('blur', this._handleInputBlur, { signal });\n this._input.addEventListener('keydown', this._handleInputKeydown, { signal });\n this._input.addEventListener('paste', this._handleInputPaste, { signal });\n }\n\n /**\n * A text input with a `name` would submit whatever is half typed. The chips\n * submit under that name instead, one value per chip, as a multiple select\n * does, so the input gives its name up until destroy().\n */\n private _takeName() {\n const input = this._editorInput();\n this._name = input?.getAttribute('name') ?? '';\n // ponytail: without form-associated custom elements (jsdom) the input keeps its name and submits its text.\n if (this._name && formAssociated()) this._wrap(input);\n }\n\n /**\n * Wraps the input in the form control, which takes its name and required.\n * `display: contents` lays the input out as a child of the field still.\n */\n private _wrap(input: HTMLInputElement) {\n this._source = input;\n this._takeRequired(input);\n // The control follows the input's disabled state and form; a read-only input is not validated, so its required no longer counts.\n this._control = wrapInControl(CONTROL, input, () => this._validate());\n this._control.onFormReset = () => this._resetChips();\n this._validate();\n }\n\n /**\n * The editor's text field, or null. A static .chips of filter checkboxes,\n * which AutoInit also starts, keeps its own native form values.\n */\n private _editorInput() {\n return this.options.allowUserInput ? this.el.querySelector<HTMLInputElement>('input:is(:not([type]), [type=\"text\"])') : null;\n }\n\n /** Where the text field ends: chips go before it, and it goes last. */\n private get _end() {\n return this._control ?? this._input;\n }\n\n /** After the chips change: give the form one value per chip and update a required field's validity. */\n private _sync() {\n if (!this._control) return;\n const data = new FormData();\n this.chipsData.forEach((chip) => data.append(this._name, String(chip.id)));\n this._control.internals.setFormValue(data);\n this._validate();\n }\n\n /**\n * The chips are what is required, not the text, so `required` moves to the\n * control, and aria-required keeps telling assistive technology.\n */\n private _takeRequired(input: HTMLInputElement) {\n this._required = input.required;\n if (!this._required) return;\n this._ariaRequired = input.getAttribute('aria-required');\n input.required = false;\n input.setAttribute('aria-required', 'true');\n }\n\n /**\n * A required field is valid once it has a chip, whatever is half typed. The\n * control holds this validity, apart from any error the page sets on the\n * input, and anchors it at the input, which a submit then focuses.\n */\n private _validate() {\n const internals = this._control.internals;\n if (this._required && !this._source.readOnly && !this.chipsData.length) {\n internals.setValidity({ valueMissing: true }, this._requiredMessage, this._anchor);\n } else internals.setValidity({});\n }\n\n /** The input, unless page script moved it out of the control, where it cannot anchor the message. */\n private get _anchor() {\n return this._control.contains(this._source) ? this._source : undefined;\n }\n\n /** A validity flag needs a message, so an empty i18n.required falls back to the default. */\n private get _requiredMessage() {\n return this.options.i18n.required || _defaults.i18n.required;\n }\n\n private _resetChips() {\n this._setSelected(null);\n this._chips.forEach((chip) => chip.remove());\n this.chipsData = [...this._initialData];\n this._chips = this.chipsData.map((chip) => this._renderChip(chip));\n this._control.before(...this._chips);\n this._setPlaceholder();\n this._sync();\n }\n\n /** Unwraps the input, with whatever else went in the control, and gives it its name and required back. */\n private _giveNameBack() {\n if (!this._control) return;\n unwrapControl(this._control, this._source);\n this._control = null;\n if (!this._required) return;\n this._source.required = true;\n restoreAttribute(this._source, 'aria-required', this._ariaRequired);\n }\n\n /** Whether only an autocomplete suggestion can become a chip. */\n private get _suggestionsOnly() {\n return this.hasAutocomplete && this.options.autocompleteOnly;\n }\n\n /** Pasted text that lists several values, split by commas, tabs or lines, adds a chip for each. */\n _handleInputPaste = (e: ClipboardEvent) => {\n const values = pastedValues(e);\n if (values.length < 2 || this._suggestionsOnly) return;\n e.preventDefault();\n // An add callback can destroy or replace the instance; the rest of the paste is its.\n values.every((id) => (this.addChip({ id }), Chips.getInstance(this.el) === this));\n };\n\n _handleChipClick = (e: MouseEvent) => {\n const _chip = (<HTMLElement>e.target).closest('.chip');\n // closest, not classList: the close button now wraps an icon span, so a\n // click on the glyph reports the span as the target.\n const clickedClose = !!(<HTMLElement>e.target).closest('.close');\n if (_chip) {\n // Index into the chip list, not into the container's children: the\n // container also holds the label and the input, so counting children\n // gave an index that did not line up with chipsData.\n const index = this._chips.indexOf(_chip as HTMLElement);\n if (index < 0) return;\n if (clickedClose) {\n this._deleteChip(index, 'input');\n } else {\n this.selectChip(index);\n }\n // Default handle click to focus on input\n } else {\n this._input.focus();\n }\n };\n\n /** The arrow that points back towards the first chip, which in RTL is Right. */\n private static _backKey(el: Element) {\n return getComputedStyle(el).direction === 'rtl' ? 'ArrowRight' : 'ArrowLeft';\n }\n\n static _handleChipsKeydown(e: KeyboardEvent) {\n const chips = (<HTMLElement>e.target).closest('.chips');\n\n // Don't handle keydown inputs on input and textarea\n const tag = (<HTMLElement>e.target).tagName;\n if (tag === 'INPUT' || tag === 'TEXTAREA' || !chips) return;\n\n const currChips: Chips = chips['Expressive_Chips'];\n if (!currChips) return; // .chips markup without an instance behind it\n\n if (e.key === 'Backspace' || e.key === 'Delete') {\n const index = currChips._chips.indexOf((e.target as HTMLElement).closest('.chip'));\n if (index < 0) return;\n e.preventDefault();\n currChips._deleteChip(index, 'previous');\n } else if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {\n // Move from the chip that has focus, the same one Backspace deletes.\n const current = (e.target as HTMLElement).closest<HTMLElement>('.chip') ?? currChips._selectedChip;\n const index = currChips._chips.indexOf(current);\n if (index < 0) return;\n if (e.key === Chips._backKey(chips)) {\n if (index > 0) currChips.selectChip(index - 1);\n } else {\n const selectIndex = index + 1;\n if (selectIndex >= currChips.chipsData.length) {\n // Walking off the end returns to the input, so nothing is selected\n // any more - without this the last chip kept the class.\n currChips._setSelected(null);\n currChips._input.focus();\n }\n else currChips.selectChip(selectIndex);\n }\n }\n }\n\n // Selection follows focus: a chip is selected while focus is inside it, and\n // none is once focus moves to the input or out of the field.\n _handleFocusIn = (e: FocusEvent) => {\n const chip = (e.target as HTMLElement).closest<HTMLElement>('.chip');\n this._setSelected(chip && this._chips.includes(chip) ? chip : null);\n };\n\n _handleFocusOut = (e: FocusEvent) => {\n if (!this.el.contains(e.relatedTarget as Node | null)) this._setSelected(null);\n };\n\n _handleInputFocus = () => {\n this.el.classList.add('focus');\n };\n\n _handleInputBlur = () => {\n this.el.classList.remove('focus');\n };\n\n _handleInputKeydown = (e: KeyboardEvent) => {\n // Enter that confirms an IME composition is not a request to add a chip.\n if (Utils.isComposing(e)) return;\n if (e.key === 'Enter') {\n // Override enter if autocompleting.\n if (this.hasAutocomplete && this.autocomplete?.isOpen &&\n this.autocomplete.container.querySelector('[role=\"option\"]')) {\n return;\n }\n e.preventDefault();\n if (!this.hasAutocomplete || !this.options.autocompleteOnly) {\n this.addChip({ id: this._input.value });\n }\n this._input.value = '';\n // The list answered the text Enter just used up.\n this.autocomplete?.close();\n } else if (\n this._input.value === '' &&\n this.chipsData.length &&\n ['Backspace', Chips._backKey(this.el)].includes(e.key)\n ) {\n e.preventDefault();\n this.selectChip(this.chipsData.length - 1);\n }\n };\n\n _renderChip(chip: ChipData): HTMLElement {\n if (!chip.id && chip.id !== 0) return;\n const label = chip.text || <string>chip.id;\n // <span>, not <div>: a chip is inline, and the container itself is not a\n // control. It used to be a <div tabindex=\"0\"> with no role - focusable,\n // and announcing nothing.\n const renderedChip = document.createElement('span');\n renderedChip.classList.add('chip');\n renderedChip.innerText = label;\n // attach image if needed\n if (chip.image) {\n const img = document.createElement('img');\n img.setAttribute('src', chip.image);\n renderedChip.insertBefore(img, renderedChip.firstChild);\n }\n if (this.options.allowUserInput) {\n // The delete affordance is the control, so it is the <button> and it\n // carries the name. `type` is explicit because a bare button inside a\n // form submits it.\n const closeButton = document.createElement('button');\n closeButton.type = 'button';\n closeButton.classList.add('close');\n closeButton.setAttribute('aria-label', `${this.options.i18n.remove} ${label}`);\n // The ligature is text and is read out, so the glyph is hidden and the\n // button's own label is what gets announced.\n const closeIcon = document.createElement('span');\n closeIcon.classList.add(this.options.closeIconClass);\n closeIcon.setAttribute('aria-hidden', 'true');\n closeIcon.innerText = 'close';\n closeButton.appendChild(closeIcon);\n renderedChip.appendChild(closeButton);\n }\n return renderedChip;\n }\n\n _renderChips() {\n this._chips = []; //.remove();\n for (let i = 0; i < this.chipsData.length; i++) {\n const chipElem = this._renderChip(this.chipsData[i]);\n this.el.appendChild(chipElem);\n this._chips.push(chipElem);\n }\n }\n\n _setupAutocomplete() {\n this.options.autocompleteOptions.onAutocomplete = (items) => {\n if (Chips.getInstance(this.el) !== this) return;\n if (items.length > 0) {\n this.addChip({\n id: items[0].id,\n text: items[0].text,\n image: items[0].image\n });\n this._input.value = '';\n this._input.focus();\n }\n };\n // A new object, so a second Chips given the same options does not wrap this wrapper.\n const pageOnCreate = this.options.autocompleteOptions.onCreate;\n this.autocomplete = Autocomplete.init(this._input, {\n ...this.options.autocompleteOptions,\n onCreate: (text, autocomplete) => {\n this._addTyped(text);\n if (typeof pageOnCreate === 'function') pageOnCreate.call(autocomplete, text, autocomplete);\n }\n });\n }\n\n /** The \"Add\" row is a deliberate choice, so it adds a chip even in an autocompleteOnly field. */\n private _addTyped(text: string) {\n if (Chips.getInstance(this.el) !== this) return;\n this.addChip({ id: text });\n this._input.value = '';\n this._input.focus();\n }\n\n _setupInput() {\n this._input = this.el.querySelector('input');\n if (!this._input) {\n this._input = document.createElement('input');\n this.el.append(this._input);\n }\n this._input.classList.add('input');\n this.hasAutocomplete = Object.keys(this.options.autocompleteOptions).length > 0;\n // Setup autocomplete if needed\n if (this.hasAutocomplete) this._setupAutocomplete();\n this._setPlaceholder();\n // Set input id\n if (!this._input.getAttribute('id')) this._input.setAttribute('id', Utils.guid());\n }\n\n _setupLabel() {\n this._label = this.el.querySelector('label');\n // No input to point at when allowUserInput is off.\n if (this._label && this._input) this._label.setAttribute('for', this._input.getAttribute('id'));\n }\n\n _setPlaceholder() {\n if (!this._input) return;\n if (!this.chipsData.length && this.options.placeholder) {\n this._input.placeholder = this.options.placeholder;\n } else if (this.chipsData.length && this.options.secondaryPlaceholder) {\n this._input.placeholder = this.options.secondaryPlaceholder;\n }\n }\n\n _isValidAndNotExist(chip: ChipData) {\n const isValid = !!chip.id || chip.id === 0;\n const doesNotExist = !this.chipsData.some((item) => item.id == chip.id);\n return isValid && doesNotExist;\n }\n\n /**\n * Add chip to input.\n * @param chip Chip data object\n */\n addChip(chip: ChipData) {\n if (!this._isValidAndNotExist(chip) || this.chipsData.length >= this.options.limit) return;\n const renderedChip = this._renderChip(chip);\n this._chips.push(renderedChip);\n this.chipsData.push(chip);\n if (this._end) this._end.before(renderedChip);\n else this.el.append(renderedChip);\n this._setPlaceholder();\n this._sync();\n this._notify('chip-add', this.options.onChipAdd, { args: [this.el, renderedChip], detail: { chip: renderedChip }, current: () => this._chips.includes(renderedChip) });\n }\n\n /**\n * Delete nth chip.\n * @param chipIndex Index of chip\n */\n deleteChip(chipIndex: number) {\n const root = this.el.getRootNode() as Document | ShadowRoot;\n this._deleteChip(chipIndex, this._chips[chipIndex]?.contains(root.activeElement) ? 'input' : null);\n }\n\n private _deleteChip(chipIndex: number, focus: 'input' | 'previous' | null) {\n const chip = this._chips[chipIndex];\n if (!chip) return;\n if (this._selectedChip === chip) this._setSelected(null);\n chip.remove();\n this._chips.splice(chipIndex, 1);\n this.chipsData.splice(chipIndex, 1);\n this._setPlaceholder();\n this._sync();\n const focusPath: { root: Document | ShadowRoot; element: Element | null }[] = [];\n let root = this.el.getRootNode() as Document | ShadowRoot;\n while (root) {\n focusPath.push({ root, element: root.activeElement });\n root = 'host' in root ? root.host.getRootNode() as Document | ShadowRoot : null;\n }\n this._notify('chip-delete', this.options.onChipDelete, { args: [this.el, chip], detail: { chip }, current: () => !this._chips.includes(chip) });\n if (!focus || focusPath.some(({ root, element }) => root.activeElement !== element) || this.el['Expressive_Chips'] !== this) return;\n if (focus === 'previous' && this._chips.length) this.selectChip(Math.max(chipIndex - 1, 0));\n else {\n this._setSelected(null);\n this._input?.focus();\n }\n }\n\n /**\n * Select nth chip.\n * @param chipIndex Index of chip\n */\n selectChip(chipIndex: number) {\n const chip = this._chips[chipIndex];\n if (!chip) return;\n this._setSelected(chip);\n // The chip is not a control any more, so focus goes to the one thing in it\n // that is - the delete button.\n (chip.querySelector('.close') as HTMLElement | null)?.focus();\n this._notify('chip-select', this.options.onChipSelect, { args: [this.el, chip], detail: { chip }, current: () => this._selectedChip === chip });\n }\n\n static Init() {\n // Handle removal of static chips - markup written by hand, which no Chips\n // instance tracks even when one sits on the container (AutoInit gives every\n // .chips one, usually without allowUserInput and so without a click\n // handler). A chip the instance rendered belongs to _handleChipClick:\n // removing the node here as well left chipsData holding an entry whose\n // element was gone.\n Utils.onDocumentReady(() => {\n const chips = document.querySelectorAll('.chips');\n chips.forEach((el) => {\n el.addEventListener('click', (e) => {\n // closest: the close button wraps an icon span, so a click on the\n // glyph reports the span.\n if (!(<HTMLElement>e.target).closest('.close')) return;\n const chip = (<HTMLElement>e.target).closest<HTMLElement>('.chip');\n if (chip && !(el['Expressive_Chips'] as Chips | undefined)?._chips.includes(chip)) chip.remove();\n });\n });\n });\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;AAqBA,IAAM,UAAU;AAGhB,IAAM,eAAe,CAAC,OACnB,EAAE,eAAe,QAAQ,MAAM,KAAK,IAAI,MAAM,SAAS,EAAE,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAAE,OAAO,OAAO;AA0EvG,IAAM,YAA0B;AAAA,EAC9B,MAAM,CAAC;AAAA,EACP,aAAa;AAAA,EACb,sBAAsB;AAAA,EACtB,gBAAgB;AAAA,EAChB,qBAAqB,CAAC;AAAA,EACtB,kBAAkB;AAAA,EAClB,OAAO;AAAA,EACP,gBAAgB;AAAA,EAChB,MAAM,EAAE,QAAQ,UAAU,UAAU,yBAAyB;AAAA,EAC7D,WAAW;AAAA,EACX,cAAc;AAAA,EACd,cAAc;AAChB;AAEO,IAAM,SAAN,MAAM,eAAc,UAAwB;AAAA,EAsCjD,YAAY,IAAiB,SAAgC;AAC3D,UAAM,IAAI,OAAO;AA3BnB;AAAA,SAAQ,QAAQ;AAEhB;AAAA,SAAQ,eAA2B,CAAC;AAEpC;AAAA,SAAQ,gBAA+B;AAEvC;AAAA,SAAQ,WAA+B;AAEvC;AAAA,SAAQ,UAAmC;AAC3C,SAAQ,YAAY;AA6LpB;AAAA,6BAAoB,CAAC,MAAsB;AACzC,YAAM,SAAS,aAAa,CAAC;AAC7B,UAAI,OAAO,SAAS,KAAK,KAAK,iBAAkB;AAChD,QAAE,eAAe;AAEjB,aAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,GAAG,CAAC,GAAG,OAAM,YAAY,KAAK,EAAE,MAAM,KAAK;AAAA,IAClF;AAEA,4BAAmB,CAAC,MAAkB;AACpC,YAAM,QAAsB,EAAE,OAAQ,QAAQ,OAAO;AAGrD,YAAM,eAAe,CAAC,CAAe,EAAE,OAAQ,QAAQ,QAAQ;AAC/D,UAAI,OAAO;AAIT,cAAM,QAAQ,KAAK,OAAO,QAAQ,KAAoB;AACtD,YAAI,QAAQ,EAAG;AACf,YAAI,cAAc;AAChB,eAAK,YAAY,OAAO,OAAO;AAAA,QACjC,OAAO;AACL,eAAK,WAAW,KAAK;AAAA,QACvB;AAAA,MAEF,OAAO;AACL,aAAK,OAAO,MAAM;AAAA,MACpB;AAAA,IACF;AA4CA;AAAA;AAAA,0BAAiB,CAAC,MAAkB;AAClC,YAAM,OAAQ,EAAE,OAAuB,QAAqB,OAAO;AACnE,WAAK,aAAa,QAAQ,KAAK,OAAO,SAAS,IAAI,IAAI,OAAO,IAAI;AAAA,IACpE;AAEA,2BAAkB,CAAC,MAAkB;AACnC,UAAI,CAAC,KAAK,GAAG,SAAS,EAAE,aAA4B,EAAG,MAAK,aAAa,IAAI;AAAA,IAC/E;AAEA,6BAAoB,MAAM;AACxB,WAAK,GAAG,UAAU,IAAI,OAAO;AAAA,IAC/B;AAEA,4BAAmB,MAAM;AACvB,WAAK,GAAG,UAAU,OAAO,OAAO;AAAA,IAClC;AAEA,+BAAsB,CAAC,MAAqB;AAE1C,UAAI,MAAM,YAAY,CAAC,EAAG;AAC1B,UAAI,EAAE,QAAQ,SAAS;AAErB,YAAI,KAAK,mBAAmB,KAAK,cAAc,UAC7C,KAAK,aAAa,UAAU,cAAc,iBAAiB,GAAG;AAC9D;AAAA,QACF;AACA,UAAE,eAAe;AACjB,YAAI,CAAC,KAAK,mBAAmB,CAAC,KAAK,QAAQ,kBAAkB;AAC3D,eAAK,QAAQ,EAAE,IAAI,KAAK,OAAO,MAAM,CAAC;AAAA,QACxC;AACA,aAAK,OAAO,QAAQ;AAEpB,aAAK,cAAc,MAAM;AAAA,MAC3B,WACE,KAAK,OAAO,UAAU,MACtB,KAAK,UAAU,UACf,CAAC,aAAa,OAAM,SAAS,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,GACrD;AACA,UAAE,eAAe;AACjB,aAAK,WAAW,KAAK,UAAU,SAAS,CAAC;AAAA,MAC3C;AAAA,IACF;AA1RE,SAAK,GAAG,UAAU,IAAI,OAAO;AAC7B,SAAK,YAAY,CAAC;AAClB,SAAK,SAAS,CAAC;AACf,SAAK,UAAU;AAGf,QAAI,KAAK,QAAQ,KAAK,QAAQ;AAG5B,WAAK,YAAY,CAAC,GAAG,KAAK,QAAQ,IAAI;AACtC,WAAK,aAAa;AAAA,IACpB;AAGA,QAAI,KAAK,QAAQ,gBAAgB;AAC/B,WAAK,GAAG,UAAU,IAAI,OAAO;AAC7B,WAAK,YAAY;AACjB,WAAK,oBAAoB;AAEzB,WAAK,GAAG,OAAO,KAAK,IAAI;AAAA,IAC1B;AAGA,SAAK,YAAY;AACjB,SAAK,MAAM;AAEX,SAAK,eAAe,CAAC,GAAG,KAAK,SAAS;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EApCQ,aAAa,MAA0B;AAC7C,SAAK,eAAe,UAAU,OAAO,UAAU;AAC/C,SAAK,gBAAgB;AACrB,UAAM,UAAU,IAAI,UAAU;AAAA,EAChC;AAAA,EAkCA,WAAW,WAAW;AACpB,WAAO;AAAA,EACT;AAAA,EAIA,UAAU;AACR,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,UAAU;AACR,QAAI,KAAK,gBAAgB,aAAa,YAAY,KAAK,MAAM,MAAM,KAAK,cAAc;AACpF,WAAK,aAAa,QAAQ;AAAA,IAC5B;AACA,SAAK,QAAQ,MAAM;AACnB,SAAK,OAAO,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;AACrC,SAAK,SAAS,CAAC;AACf,SAAK,cAAc;AACnB,UAAM,QAAQ;AAAA,EAChB;AAAA,EAEA,sBAAsB;AACpB,UAAM,EAAE,OAAO,IAAI,KAAK;AACxB,SAAK,GAAG,iBAAiB,SAAS,KAAK,kBAAkB,EAAE,OAAO,CAAC;AACnE,SAAK,GAAG,iBAAiB,WAAW,OAAM,qBAAqB,EAAE,OAAO,CAAC;AACzE,SAAK,GAAG,iBAAiB,WAAW,KAAK,gBAAgB,EAAE,OAAO,CAAC;AACnE,SAAK,GAAG,iBAAiB,YAAY,KAAK,iBAAiB,EAAE,OAAO,CAAC;AACrE,SAAK,OAAO,iBAAiB,SAAS,KAAK,mBAAmB,EAAE,OAAO,CAAC;AACxE,SAAK,OAAO,iBAAiB,QAAQ,KAAK,kBAAkB,EAAE,OAAO,CAAC;AACtE,SAAK,OAAO,iBAAiB,WAAW,KAAK,qBAAqB,EAAE,OAAO,CAAC;AAC5E,SAAK,OAAO,iBAAiB,SAAS,KAAK,mBAAmB,EAAE,OAAO,CAAC;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,YAAY;AAClB,UAAM,QAAQ,KAAK,aAAa;AAChC,SAAK,QAAQ,OAAO,aAAa,MAAM,KAAK;AAE5C,QAAI,KAAK,SAAS,eAAe,EAAG,MAAK,MAAM,KAAK;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,MAAM,OAAyB;AACrC,SAAK,UAAU;AACf,SAAK,cAAc,KAAK;AAExB,SAAK,WAAW,cAAc,SAAS,OAAO,MAAM,KAAK,UAAU,CAAC;AACpE,SAAK,SAAS,cAAc,MAAM,KAAK,YAAY;AACnD,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,eAAe;AACrB,WAAO,KAAK,QAAQ,iBAAiB,KAAK,GAAG,cAAgC,uCAAuC,IAAI;AAAA,EAC1H;AAAA;AAAA,EAGA,IAAY,OAAO;AACjB,WAAO,KAAK,YAAY,KAAK;AAAA,EAC/B;AAAA;AAAA,EAGQ,QAAQ;AACd,QAAI,CAAC,KAAK,SAAU;AACpB,UAAM,OAAO,IAAI,SAAS;AAC1B,SAAK,UAAU,QAAQ,CAAC,SAAS,KAAK,OAAO,KAAK,OAAO,OAAO,KAAK,EAAE,CAAC,CAAC;AACzE,SAAK,SAAS,UAAU,aAAa,IAAI;AACzC,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,cAAc,OAAyB;AAC7C,SAAK,YAAY,MAAM;AACvB,QAAI,CAAC,KAAK,UAAW;AACrB,SAAK,gBAAgB,MAAM,aAAa,eAAe;AACvD,UAAM,WAAW;AACjB,UAAM,aAAa,iBAAiB,MAAM;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,YAAY;AAClB,UAAM,YAAY,KAAK,SAAS;AAChC,QAAI,KAAK,aAAa,CAAC,KAAK,QAAQ,YAAY,CAAC,KAAK,UAAU,QAAQ;AACtE,gBAAU,YAAY,EAAE,cAAc,KAAK,GAAG,KAAK,kBAAkB,KAAK,OAAO;AAAA,IACnF,MAAO,WAAU,YAAY,CAAC,CAAC;AAAA,EACjC;AAAA;AAAA,EAGA,IAAY,UAAU;AACpB,WAAO,KAAK,SAAS,SAAS,KAAK,OAAO,IAAI,KAAK,UAAU;AAAA,EAC/D;AAAA;AAAA,EAGA,IAAY,mBAAmB;AAC7B,WAAO,KAAK,QAAQ,KAAK,YAAY,UAAU,KAAK;AAAA,EACtD;AAAA,EAEQ,cAAc;AACpB,SAAK,aAAa,IAAI;AACtB,SAAK,OAAO,QAAQ,CAAC,SAAS,KAAK,OAAO,CAAC;AAC3C,SAAK,YAAY,CAAC,GAAG,KAAK,YAAY;AACtC,SAAK,SAAS,KAAK,UAAU,IAAI,CAAC,SAAS,KAAK,YAAY,IAAI,CAAC;AACjE,SAAK,SAAS,OAAO,GAAG,KAAK,MAAM;AACnC,SAAK,gBAAgB;AACrB,SAAK,MAAM;AAAA,EACb;AAAA;AAAA,EAGQ,gBAAgB;AACtB,QAAI,CAAC,KAAK,SAAU;AACpB,kBAAc,KAAK,UAAU,KAAK,OAAO;AACzC,SAAK,WAAW;AAChB,QAAI,CAAC,KAAK,UAAW;AACrB,SAAK,QAAQ,WAAW;AACxB,qBAAiB,KAAK,SAAS,iBAAiB,KAAK,aAAa;AAAA,EACpE;AAAA;AAAA,EAGA,IAAY,mBAAmB;AAC7B,WAAO,KAAK,mBAAmB,KAAK,QAAQ;AAAA,EAC9C;AAAA;AAAA,EAkCA,OAAe,SAAS,IAAa;AACnC,WAAO,iBAAiB,EAAE,EAAE,cAAc,QAAQ,eAAe;AAAA,EACnE;AAAA,EAEA,OAAO,oBAAoB,GAAkB;AAC3C,UAAM,QAAsB,EAAE,OAAQ,QAAQ,QAAQ;AAGtD,UAAM,MAAoB,EAAE,OAAQ;AACpC,QAAI,QAAQ,WAAW,QAAQ,cAAc,CAAC,MAAO;AAErD,UAAM,YAAmB,MAAM,kBAAkB;AACjD,QAAI,CAAC,UAAW;AAEhB,QAAI,EAAE,QAAQ,eAAe,EAAE,QAAQ,UAAU;AAC/C,YAAM,QAAQ,UAAU,OAAO,QAAS,EAAE,OAAuB,QAAQ,OAAO,CAAC;AACjF,UAAI,QAAQ,EAAG;AACf,QAAE,eAAe;AACjB,gBAAU,YAAY,OAAO,UAAU;AAAA,IACzC,WAAW,EAAE,QAAQ,eAAe,EAAE,QAAQ,cAAc;AAE1D,YAAM,UAAW,EAAE,OAAuB,QAAqB,OAAO,KAAK,UAAU;AACrF,YAAM,QAAQ,UAAU,OAAO,QAAQ,OAAO;AAC9C,UAAI,QAAQ,EAAG;AACf,UAAI,EAAE,QAAQ,OAAM,SAAS,KAAK,GAAG;AACnC,YAAI,QAAQ,EAAG,WAAU,WAAW,QAAQ,CAAC;AAAA,MAC/C,OAAO;AACL,cAAM,cAAc,QAAQ;AAC5B,YAAI,eAAe,UAAU,UAAU,QAAQ;AAG7C,oBAAU,aAAa,IAAI;AAC3B,oBAAU,OAAO,MAAM;AAAA,QACzB,MACK,WAAU,WAAW,WAAW;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAAA,EA+CA,YAAY,MAA6B;AACvC,QAAI,CAAC,KAAK,MAAM,KAAK,OAAO,EAAG;AAC/B,UAAM,QAAQ,KAAK,QAAgB,KAAK;AAIxC,UAAM,eAAe,SAAS,cAAc,MAAM;AAClD,iBAAa,UAAU,IAAI,MAAM;AACjC,iBAAa,YAAY;AAEzB,QAAI,KAAK,OAAO;AACd,YAAM,MAAM,SAAS,cAAc,KAAK;AACxC,UAAI,aAAa,OAAO,KAAK,KAAK;AAClC,mBAAa,aAAa,KAAK,aAAa,UAAU;AAAA,IACxD;AACA,QAAI,KAAK,QAAQ,gBAAgB;AAI/B,YAAM,cAAc,SAAS,cAAc,QAAQ;AACnD,kBAAY,OAAO;AACnB,kBAAY,UAAU,IAAI,OAAO;AACjC,kBAAY,aAAa,cAAc,GAAG,KAAK,QAAQ,KAAK,MAAM,IAAI,KAAK,EAAE;AAG7E,YAAM,YAAY,SAAS,cAAc,MAAM;AAC/C,gBAAU,UAAU,IAAI,KAAK,QAAQ,cAAc;AACnD,gBAAU,aAAa,eAAe,MAAM;AAC5C,gBAAU,YAAY;AACtB,kBAAY,YAAY,SAAS;AACjC,mBAAa,YAAY,WAAW;AAAA,IACtC;AACA,WAAO;AAAA,EACT;AAAA,EAEA,eAAe;AACb,SAAK,SAAS,CAAC;AACf,aAAS,IAAI,GAAG,IAAI,KAAK,UAAU,QAAQ,KAAK;AAC9C,YAAM,WAAW,KAAK,YAAY,KAAK,UAAU,CAAC,CAAC;AACnD,WAAK,GAAG,YAAY,QAAQ;AAC5B,WAAK,OAAO,KAAK,QAAQ;AAAA,IAC3B;AAAA,EACF;AAAA,EAEA,qBAAqB;AACnB,SAAK,QAAQ,oBAAoB,iBAAiB,CAAC,UAAU;AAC3D,UAAI,OAAM,YAAY,KAAK,EAAE,MAAM,KAAM;AACzC,UAAI,MAAM,SAAS,GAAG;AACpB,aAAK,QAAQ;AAAA,UACX,IAAI,MAAM,CAAC,EAAE;AAAA,UACb,MAAM,MAAM,CAAC,EAAE;AAAA,UACf,OAAO,MAAM,CAAC,EAAE;AAAA,QAClB,CAAC;AACD,aAAK,OAAO,QAAQ;AACpB,aAAK,OAAO,MAAM;AAAA,MACpB;AAAA,IACF;AAEA,UAAM,eAAe,KAAK,QAAQ,oBAAoB;AACtD,SAAK,eAAe,aAAa,KAAK,KAAK,QAAQ;AAAA,MACjD,GAAG,KAAK,QAAQ;AAAA,MAChB,UAAU,CAAC,MAAM,iBAAiB;AAChC,aAAK,UAAU,IAAI;AACnB,YAAI,OAAO,iBAAiB,WAAY,cAAa,KAAK,cAAc,MAAM,YAAY;AAAA,MAC5F;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA,EAGQ,UAAU,MAAc;AAC9B,QAAI,OAAM,YAAY,KAAK,EAAE,MAAM,KAAM;AACzC,SAAK,QAAQ,EAAE,IAAI,KAAK,CAAC;AACzB,SAAK,OAAO,QAAQ;AACpB,SAAK,OAAO,MAAM;AAAA,EACpB;AAAA,EAEA,cAAc;AACZ,SAAK,SAAS,KAAK,GAAG,cAAc,OAAO;AAC3C,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,SAAS,SAAS,cAAc,OAAO;AAC5C,WAAK,GAAG,OAAO,KAAK,MAAM;AAAA,IAC5B;AACA,SAAK,OAAO,UAAU,IAAI,OAAO;AACjC,SAAK,kBAAkB,OAAO,KAAK,KAAK,QAAQ,mBAAmB,EAAE,SAAS;AAE9E,QAAI,KAAK,gBAAiB,MAAK,mBAAmB;AAClD,SAAK,gBAAgB;AAErB,QAAI,CAAC,KAAK,OAAO,aAAa,IAAI,EAAG,MAAK,OAAO,aAAa,MAAM,MAAM,KAAK,CAAC;AAAA,EAClF;AAAA,EAEA,cAAc;AACZ,SAAK,SAAS,KAAK,GAAG,cAAc,OAAO;AAE3C,QAAI,KAAK,UAAU,KAAK,OAAQ,MAAK,OAAO,aAAa,OAAO,KAAK,OAAO,aAAa,IAAI,CAAC;AAAA,EAChG;AAAA,EAEA,kBAAkB;AAChB,QAAI,CAAC,KAAK,OAAQ;AAClB,QAAI,CAAC,KAAK,UAAU,UAAU,KAAK,QAAQ,aAAa;AACtD,WAAK,OAAO,cAAc,KAAK,QAAQ;AAAA,IACzC,WAAW,KAAK,UAAU,UAAU,KAAK,QAAQ,sBAAsB;AACrE,WAAK,OAAO,cAAc,KAAK,QAAQ;AAAA,IACzC;AAAA,EACF;AAAA,EAEA,oBAAoB,MAAgB;AAClC,UAAM,UAAU,CAAC,CAAC,KAAK,MAAM,KAAK,OAAO;AACzC,UAAM,eAAe,CAAC,KAAK,UAAU,KAAK,CAAC,SAAS,KAAK,MAAM,KAAK,EAAE;AACtE,WAAO,WAAW;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAQ,MAAgB;AACtB,QAAI,CAAC,KAAK,oBAAoB,IAAI,KAAK,KAAK,UAAU,UAAU,KAAK,QAAQ,MAAO;AACpF,UAAM,eAAe,KAAK,YAAY,IAAI;AAC1C,SAAK,OAAO,KAAK,YAAY;AAC7B,SAAK,UAAU,KAAK,IAAI;AACxB,QAAI,KAAK,KAAM,MAAK,KAAK,OAAO,YAAY;AAAA,QACvC,MAAK,GAAG,OAAO,YAAY;AAChC,SAAK,gBAAgB;AACrB,SAAK,MAAM;AACX,SAAK,QAAQ,YAAY,KAAK,QAAQ,WAAW,EAAE,MAAM,CAAC,KAAK,IAAI,YAAY,GAAG,QAAQ,EAAE,MAAM,aAAa,GAAG,SAAS,MAAM,KAAK,OAAO,SAAS,YAAY,EAAE,CAAC;AAAA,EACvK;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,WAAmB;AAC5B,UAAM,OAAO,KAAK,GAAG,YAAY;AACjC,SAAK,YAAY,WAAW,KAAK,OAAO,SAAS,GAAG,SAAS,KAAK,aAAa,IAAI,UAAU,IAAI;AAAA,EACnG;AAAA,EAEQ,YAAY,WAAmB,OAAoC;AACzE,UAAM,OAAO,KAAK,OAAO,SAAS;AAClC,QAAI,CAAC,KAAM;AACX,QAAI,KAAK,kBAAkB,KAAM,MAAK,aAAa,IAAI;AACvD,SAAK,OAAO;AACZ,SAAK,OAAO,OAAO,WAAW,CAAC;AAC/B,SAAK,UAAU,OAAO,WAAW,CAAC;AAClC,SAAK,gBAAgB;AACrB,SAAK,MAAM;AACX,UAAM,YAAwE,CAAC;AAC/E,QAAI,OAAO,KAAK,GAAG,YAAY;AAC/B,WAAO,MAAM;AACX,gBAAU,KAAK,EAAE,MAAM,SAAS,KAAK,cAAc,CAAC;AACpD,aAAO,UAAU,OAAO,KAAK,KAAK,YAAY,IAA6B;AAAA,IAC7E;AACA,SAAK,QAAQ,eAAe,KAAK,QAAQ,cAAc,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI,GAAG,QAAQ,EAAE,KAAK,GAAG,SAAS,MAAM,CAAC,KAAK,OAAO,SAAS,IAAI,EAAE,CAAC;AAC9I,QAAI,CAAC,SAAS,UAAU,KAAK,CAAC,EAAE,MAAAA,OAAM,QAAQ,MAAMA,MAAK,kBAAkB,OAAO,KAAK,KAAK,GAAG,kBAAkB,MAAM,KAAM;AAC7H,QAAI,UAAU,cAAc,KAAK,OAAO,OAAQ,MAAK,WAAW,KAAK,IAAI,YAAY,GAAG,CAAC,CAAC;AAAA,SACrF;AACH,WAAK,aAAa,IAAI;AACtB,WAAK,QAAQ,MAAM;AAAA,IACrB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,WAAmB;AAC5B,UAAM,OAAO,KAAK,OAAO,SAAS;AAClC,QAAI,CAAC,KAAM;AACX,SAAK,aAAa,IAAI;AAGtB,IAAC,KAAK,cAAc,QAAQ,GAA0B,MAAM;AAC5D,SAAK,QAAQ,eAAe,KAAK,QAAQ,cAAc,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI,GAAG,QAAQ,EAAE,KAAK,GAAG,SAAS,MAAM,KAAK,kBAAkB,KAAK,CAAC;AAAA,EAChJ;AAAA,EAEA,OAAO,OAAO;AAOZ,UAAM,gBAAgB,MAAM;AAC1B,YAAM,QAAQ,SAAS,iBAAiB,QAAQ;AAChD,YAAM,QAAQ,CAAC,OAAO;AACpB,WAAG,iBAAiB,SAAS,CAAC,MAAM;AAGlC,cAAI,CAAe,EAAE,OAAQ,QAAQ,QAAQ,EAAG;AAChD,gBAAM,OAAqB,EAAE,OAAQ,QAAqB,OAAO;AACjE,cAAI,QAAQ,CAAE,GAAG,kBAAkB,GAAyB,OAAO,SAAS,IAAI,EAAG,MAAK,OAAO;AAAA,QACjG,CAAC;AAAA,MACH,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;AAxgBa,OA0EJ,MAAM;AA1ER,IAAM,QAAN;",
|
|
6
|
-
"names": ["root"]
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/ts/components/currencyInput.ts"],
|
|
4
|
-
"sourcesContent": ["import { Component, BaseOptions } from '../core/component';\nimport { Utils } from '../core/utils';\n\nexport interface CurrencyInputOptions extends BaseOptions {\n /** `invalid` is the validity message for text that holds no amount. */\n i18n: Partial<{ invalid: string }>;\n}\n\nconst _defaults: CurrencyInputOptions = Object.freeze({ i18n: Object.freeze({ invalid: 'Enter an amount.' }) });\n\n/** Latin digits in the order `_native` holds them, to map a locale's own digits back. */\nconst LATIN = '9876543210';\n\n/**\n * Splits digits and separators into whole and fraction digits. The last `.`\n * or `,` is the decimal mark when no more than `digits` digits follow it, so\n * `1.234,5` and `1,234.50` both split at the end; any other separator groups.\n */\nfunction split(clean: string, digits: number): [string, string] {\n const mark = Math.max(clean.lastIndexOf('.'), clean.lastIndexOf(','));\n const fraction = clean.slice(mark + 1);\n return mark >= 0 && fraction.length <= digits ? [clean.slice(0, mark), fraction] : [clean, ''];\n}\n\n/**\n * Reads text in Latin digits as an amount, or null when it holds no digit.\n * Signs, spaces and letters are ignored, and a `-` or `\u2212` before the first\n * digit makes the amount negative. A separator after the last digit is\n * dropped, since it belongs to a symbol such as `kr.`.\n */\nfunction parse(text: string, digits: number): number | null {\n const clean = text.replace(/[^\\d.,]/g, '').replace(/[.,]+$/, '');\n if (!/\\d/.test(clean)) return null;\n const [whole, fraction] = split(clean, digits);\n const sign = /^\\D*[-\u2212]/.test(text) ? -1 : 1;\n return sign * Number(`${whole.replace(/[.,]/g, '')}.${fraction}`);\n}\n\n/**\n * Currency input. Shows a text field's amount in the page's locale and the\n * currency its `data-currency` attribute names once the field loses focus,\n * shows the plain number while it has focus, and puts the plain number in the\n * form data.\n */\nexport class CurrencyInput extends Component<CurrencyInputOptions> {\n declare el: HTMLInputElement;\n static key = 'Expressive_CurrencyInput';\n private _display: Intl.NumberFormat;\n /** Writes an amount for editing: the locale's digits and mark, no grouping or sign. */\n private _edit: Intl.NumberFormat;\n /** Writes an amount as the form submits it: Latin digits, a `.` mark, no grouping. */\n private _plain: Intl.NumberFormat;\n private _digits: number;\n /** The locale's digits for 9876543210, and its decimal mark. */\n private _native: string;\n private _decimal: string;\n\n constructor(el: HTMLInputElement, options: Partial<CurrencyInputOptions>) {\n super(el, options);\n const locale = Utils.locale(el);\n try {\n this._display = new Intl.NumberFormat(locale, { style: 'currency', currency: el.dataset.currency });\n } catch {\n // A malformed code leaves the field a plain text input.\n return;\n }\n this._digits = this._display.resolvedOptions().maximumFractionDigits;\n this._edit = new Intl.NumberFormat(locale, { useGrouping: false, maximumFractionDigits: this._digits });\n this._plain = new Intl.NumberFormat('en', { useGrouping: false, maximumFractionDigits: this._digits });\n this._native = new Intl.NumberFormat(locale, { useGrouping: false }).format(9876543210);\n this._decimal = new Intl.NumberFormat(locale).formatToParts(0.5).find((part) => part.type === 'decimal').value;\n const signal = this._events.signal;\n // Capture, so a page's change listener on the field reads the formatted\n // text. Blur covers a visit that changed nothing, which fires no change.\n el.addEventListener('change', this._onChange, { capture: true, signal });\n el.addEventListener('blur', this._format, { signal });\n el.addEventListener('focus', this._onFocus, { signal });\n el.addEventListener('input', this._validate, { signal });\n // Neither formdata nor reset leaves a shadow root, so a field in one\n // listens there. Otherwise the document, so the listener follows the\n // field into another form.\n const root = el.getRootNode() as Document | ShadowRoot;\n const scope = 'host' in root ? root : el.ownerDocument;\n scope.addEventListener('formdata', this._onFormData, { capture: true, signal });\n // The form resets its fields after the reset event, so the field formats\n // the restored value a task later.\n scope.addEventListener('reset', this._onReset, { capture: true, signal });\n this._start();\n }\n\n static get defaults(): CurrencyInputOptions {\n return _defaults;\n }\n\n /** The amount the field holds, rounded as it shows, or null when it is empty or holds no digit. */\n get value(): number | null {\n return this._round(this._read(this.el.value));\n }\n\n /** Reads text in the locale's digits, or full-width ones from an IME, as an amount. */\n private _read(text: string) {\n const latin = Array.from(text.normalize('NFKC'), (ch) => (ch === this._decimal ? '.' : (LATIN[this._native.indexOf(ch)] ?? ch)));\n return parse(latin.join(''), this._digits);\n }\n\n private _round(amount: number | null) {\n return amount === null ? null : Number(this._plain.format(amount));\n }\n\n /**\n * Formats the starting value without events. It reads as a plain number\n * first, the form the field submits, so a saved `1.234` stays 1.234.\n */\n private _start() {\n const text = this.el.value;\n const number = Number(text);\n this._show(this._round(text.trim() && Number.isFinite(number) ? number : this._read(text)));\n }\n\n private _format = () => {\n this._show(this.value);\n };\n\n /**\n * Enter fires change while the field keeps focus. Formatting then would\n * put the next keystroke after the currency sign, so the field waits for\n * blur.\n */\n private _onChange = () => {\n if (!this.el.matches(':focus')) this._format();\n };\n\n /** Shows `amount` in the locale and currency, leaving text that reads as no amount as it is. */\n private _show(amount: number | null) {\n if (amount !== null) this.el.value = this._display.format(amount);\n this._validate();\n }\n\n /** Shows the amount as a plain number to edit, with the caret at the end. */\n private _onFocus = () => {\n const amount = this.value;\n if (amount === null) return;\n const text = this._edit.format(amount);\n this.el.value = text;\n this.el.setSelectionRange(text.length, text.length);\n };\n\n /** Marks text that holds no amount invalid, and clears the mark once it holds one or is empty. */\n private _validate = () => {\n const { el } = this;\n const invalid = el.value.trim() !== '' && this.value === null;\n el.setCustomValidity(invalid ? this.options.i18n.invalid : '');\n };\n\n private _onReset = (e: Event) => {\n if (e.target === this.el.form) setTimeout(this._afterReset);\n };\n\n private _afterReset = () => {\n if (!this._events.signal.aborted) this._start();\n };\n\n /** Puts the plain number in the form data in place of the formatted text. */\n private _onFormData = (e: FormDataEvent) => {\n if (!this._submitsTo(e.target)) return;\n // ponytail: set() collapses fields that share this name into one entry; a\n // per-field swap if a form ever repeats a currency field's name.\n e.formData.set(this.el.name, String(this.value ?? this.el.value));\n };\n\n /** Whether the field has an entry in `form`'s data. */\n private _submitsTo(form: EventTarget) {\n const { el } = this;\n return form === el.form && el.name !== '' && !el.matches(':disabled');\n }\n\n /** Stops formatting and clears the validity message, leaving the text as it is. */\n destroy(): void {\n super.destroy();\n this.el.setCustomValidity('');\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;AAQA,IAAM,YAAkC,OAAO,OAAO,EAAE,MAAM,OAAO,OAAO,EAAE,SAAS,mBAAmB,CAAC,EAAE,CAAC;AAG9G,IAAM,QAAQ;AAOd,SAAS,MAAM,OAAe,QAAkC;AAC9D,QAAM,OAAO,KAAK,IAAI,MAAM,YAAY,GAAG,GAAG,MAAM,YAAY,GAAG,CAAC;AACpE,QAAM,WAAW,MAAM,MAAM,OAAO,CAAC;AACrC,SAAO,QAAQ,KAAK,SAAS,UAAU,SAAS,CAAC,MAAM,MAAM,GAAG,IAAI,GAAG,QAAQ,IAAI,CAAC,OAAO,EAAE;AAC/F;AAQA,SAAS,MAAM,MAAc,QAA+B;AAC1D,QAAM,QAAQ,KAAK,QAAQ,YAAY,EAAE,EAAE,QAAQ,UAAU,EAAE;AAC/D,MAAI,CAAC,KAAK,KAAK,KAAK,EAAG,QAAO;AAC9B,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,OAAO,MAAM;AAC7C,QAAM,OAAO,WAAW,KAAK,IAAI,IAAI,KAAK;AAC1C,SAAO,OAAO,OAAO,GAAG,MAAM,QAAQ,SAAS,EAAE,CAAC,IAAI,QAAQ,EAAE;AAClE;AAQO,IAAM,gBAAN,cAA4B,UAAgC;AAAA,EAajE,YAAY,IAAsB,SAAwC;AACxE,UAAM,IAAI,OAAO;AA6DnB,SAAQ,UAAU,MAAM;AACtB,WAAK,MAAM,KAAK,KAAK;AAAA,IACvB;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAQ,YAAY,MAAM;AACxB,UAAI,CAAC,KAAK,GAAG,QAAQ,QAAQ,EAAG,MAAK,QAAQ;AAAA,IAC/C;AASA;AAAA,SAAQ,WAAW,MAAM;AACvB,YAAM,SAAS,KAAK;AACpB,UAAI,WAAW,KAAM;AACrB,YAAM,OAAO,KAAK,MAAM,OAAO,MAAM;AACrC,WAAK,GAAG,QAAQ;AAChB,WAAK,GAAG,kBAAkB,KAAK,QAAQ,KAAK,MAAM;AAAA,IACpD;AAGA;AAAA,SAAQ,YAAY,MAAM;AACxB,YAAM,EAAE,GAAG,IAAI;AACf,YAAM,UAAU,GAAG,MAAM,KAAK,MAAM,MAAM,KAAK,UAAU;AACzD,SAAG,kBAAkB,UAAU,KAAK,QAAQ,KAAK,UAAU,EAAE;AAAA,IAC/D;AAEA,SAAQ,WAAW,CAAC,MAAa;AAC/B,UAAI,EAAE,WAAW,KAAK,GAAG,KAAM,YAAW,KAAK,WAAW;AAAA,IAC5D;AAEA,SAAQ,cAAc,MAAM;AAC1B,UAAI,CAAC,KAAK,QAAQ,OAAO,QAAS,MAAK,OAAO;AAAA,IAChD;AAGA;AAAA,SAAQ,cAAc,CAAC,MAAqB;AAC1C,UAAI,CAAC,KAAK,WAAW,EAAE,MAAM,EAAG;AAGhC,QAAE,SAAS,IAAI,KAAK,GAAG,MAAM,OAAO,KAAK,SAAS,KAAK,GAAG,KAAK,CAAC;AAAA,IAClE;AA7GE,UAAM,SAAS,MAAM,OAAO,EAAE;AAC9B,QAAI;AACF,WAAK,WAAW,IAAI,KAAK,aAAa,QAAQ,EAAE,OAAO,YAAY,UAAU,GAAG,QAAQ,SAAS,CAAC;AAAA,IACpG,QAAQ;AAEN;AAAA,IACF;AACA,SAAK,UAAU,KAAK,SAAS,gBAAgB,EAAE;AAC/C,SAAK,QAAQ,IAAI,KAAK,aAAa,QAAQ,EAAE,aAAa,OAAO,uBAAuB,KAAK,QAAQ,CAAC;AACtG,SAAK,SAAS,IAAI,KAAK,aAAa,MAAM,EAAE,aAAa,OAAO,uBAAuB,KAAK,QAAQ,CAAC;AACrG,SAAK,UAAU,IAAI,KAAK,aAAa,QAAQ,EAAE,aAAa,MAAM,CAAC,EAAE,OAAO,UAAU;AACtF,SAAK,WAAW,IAAI,KAAK,aAAa,MAAM,EAAE,cAAc,GAAG,EAAE,KAAK,CAAC,SAAS,KAAK,SAAS,SAAS,EAAE;AACzG,UAAM,SAAS,KAAK,QAAQ;AAG5B,OAAG,iBAAiB,UAAU,KAAK,WAAW,EAAE,SAAS,MAAM,OAAO,CAAC;AACvE,OAAG,iBAAiB,QAAQ,KAAK,SAAS,EAAE,OAAO,CAAC;AACpD,OAAG,iBAAiB,SAAS,KAAK,UAAU,EAAE,OAAO,CAAC;AACtD,OAAG,iBAAiB,SAAS,KAAK,WAAW,EAAE,OAAO,CAAC;AAIvD,UAAM,OAAO,GAAG,YAAY;AAC5B,UAAM,QAAQ,UAAU,OAAO,OAAO,GAAG;AACzC,UAAM,iBAAiB,YAAY,KAAK,aAAa,EAAE,SAAS,MAAM,OAAO,CAAC;AAG9E,UAAM,iBAAiB,SAAS,KAAK,UAAU,EAAE,SAAS,MAAM,OAAO,CAAC;AACxE,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,WAAW,WAAiC;AAC1C,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,IAAI,QAAuB;AACzB,WAAO,KAAK,OAAO,KAAK,MAAM,KAAK,GAAG,KAAK,CAAC;AAAA,EAC9C;AAAA;AAAA,EAGQ,MAAM,MAAc;AAC1B,UAAM,QAAQ,MAAM,KAAK,KAAK,UAAU,MAAM,GAAG,CAAC,OAAQ,OAAO,KAAK,WAAW,MAAO,MAAM,KAAK,QAAQ,QAAQ,EAAE,CAAC,KAAK,EAAI;AAC/H,WAAO,MAAM,MAAM,KAAK,EAAE,GAAG,KAAK,OAAO;AAAA,EAC3C;AAAA,EAEQ,OAAO,QAAuB;AACpC,WAAO,WAAW,OAAO,OAAO,OAAO,KAAK,OAAO,OAAO,MAAM,CAAC;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,SAAS;AACf,UAAM,OAAO,KAAK,GAAG;AACrB,UAAM,SAAS,OAAO,IAAI;AAC1B,SAAK,MAAM,KAAK,OAAO,KAAK,KAAK,KAAK,OAAO,SAAS,MAAM,IAAI,SAAS,KAAK,MAAM,IAAI,CAAC,CAAC;AAAA,EAC5F;AAAA;AAAA,EAgBQ,MAAM,QAAuB;AACnC,QAAI,WAAW,KAAM,MAAK,GAAG,QAAQ,KAAK,SAAS,OAAO,MAAM;AAChE,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA,EAmCQ,WAAW,MAAmB;AACpC,UAAM,EAAE,GAAG,IAAI;AACf,WAAO,SAAS,GAAG,QAAQ,GAAG,SAAS,MAAM,CAAC,GAAG,QAAQ,WAAW;AAAA,EACtE;AAAA;AAAA,EAGA,UAAgB;AACd,UAAM,QAAQ;AACd,SAAK,GAAG,kBAAkB,EAAE;AAAA,EAC9B;AACF;AAzIa,cAEJ,MAAM;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/ts/components/navigationRail.ts"],
|
|
4
|
-
"sourcesContent": ["import { Component, BaseOptions } from '../core/component';\n\nexport interface NavigationRailOptions extends BaseOptions {\n /**\n * Called before the rail expands.\n */\n onOpenStart: (el: HTMLElement) => void;\n /**\n * Called after the rail expands.\n */\n onOpenEnd: (el: HTMLElement) => void;\n /**\n * Called before the rail collapses.\n */\n onCloseStart: (el: HTMLElement) => void;\n /**\n * Called after the rail collapses.\n */\n onCloseEnd: (el: HTMLElement) => void;\n}\n\nconst _defaults: NavigationRailOptions = {\n onOpenStart: null,\n onOpenEnd: null,\n onCloseStart: null,\n onCloseEnd: null\n};\n\nconst COMPACT = '(width < 600px)';\n// Delay before a hovered destination opens its panel, and before the panel\n// closes once the pointer leaves; it covers the trip across the rail's padding.\nconst HOVER_DELAY = 200;\n\n/** The focused element, followed down through open shadow roots. */\nfunction deepActiveElement(root: Document | ShadowRoot): Element | null {\n let active = root.activeElement;\n while (active?.shadowRoot?.activeElement) active = active.shadowRoot.activeElement;\n return active;\n}\n\n/**\n * Navigation rail. Layout is CSS (collapsed / .expanded). This class\n * toggles that class from the menu button, closes a compact overlay on\n * Escape or a scrim tap, and keeps aria-expanded in sync. A destination's\n * .navigation-rail-panel is a native popover; this class also opens it on\n * mouse hover.\n */\nexport class NavigationRail extends Component<NavigationRailOptions> {\n isExpanded: boolean;\n private _toggle: HTMLButtonElement | null;\n private _mql: MediaQueryList;\n private _hoverPanel: HTMLElement | null = null;\n private _hoverTimer: ReturnType<typeof setTimeout> | undefined;\n\n constructor(el: HTMLElement, options: Partial<NavigationRailOptions>) {\n super(el, options);\n\n this._toggle = this._findToggle();\n this._mql = window.matchMedia(COMPACT);\n this.isExpanded = this.el.classList.contains('expanded');\n this._sync();\n const { signal } = this._events;\n this.el.addEventListener('click', this._onClick, { signal });\n this.el.addEventListener('pointerover', this._onPointerOver, { signal });\n this.el.addEventListener('pointerleave', this._onPointerLeave, { signal });\n document.addEventListener('keydown', this._onKeyDown, { signal });\n }\n\n static get defaults(): NavigationRailOptions {\n return _defaults;\n }\n\n static key = 'Expressive_NavigationRail';\n\n destroy() {\n clearTimeout(this._hoverTimer);\n super.destroy();\n }\n\n /**\n * Expands the rail. On compact windows the overlay (scrim) is CSS.\n */\n expand = () => {\n if (this.isExpanded) return;\n if (!this._notify('open', this.options.onOpenStart, { current: () => !this.isExpanded })) return;\n this.isExpanded = true;\n this.el.classList.add('expanded');\n this._sync();\n this._notify('opened', this.options.onOpenEnd, { current: () => this.isExpanded });\n };\n\n /**\n * Collapses the rail.\n */\n collapse = () => {\n if (!this.isExpanded) return;\n if (!this._notify('close', this.options.onCloseStart, { current: () => this.isExpanded })) return;\n this.isExpanded = false;\n this.el.classList.remove('expanded');\n this._sync();\n this._notify('closed', this.options.onCloseEnd, { current: () => !this.isExpanded });\n };\n\n /**\n * Toggles expanded / collapsed.\n */\n toggle = () => {\n if (this.isExpanded) this.collapse();\n else this.expand();\n };\n\n private _findToggle(): HTMLButtonElement | null {\n const first = this.el.querySelector(':scope > button:not(.button, [popovertarget])');\n return first instanceof HTMLButtonElement ? first : null;\n }\n\n private _isCompact() {\n return this._mql.matches;\n }\n\n private _isModal() {\n return this.el.classList.contains('modal') || this._isCompact();\n }\n\n private _sync() {\n this.el.setAttribute('aria-expanded', this.isExpanded ? 'true' : 'false');\n this._toggle?.setAttribute('aria-expanded', this.isExpanded ? 'true' : 'false');\n }\n\n /** The side panel of the enabled destination around `target`, if any. */\n private _panelAt(target: EventTarget | null): HTMLElement | null {\n const trigger = target instanceof Element ? target.closest('button[popovertarget]:enabled') : null;\n const panel = (trigger as HTMLButtonElement | null)?.popoverTargetElement;\n return panel?.classList.contains('navigation-rail-panel') ? (panel as HTMLElement) : null;\n }\n\n // Looks the panel up again because the trigger can be disabled during the delay.\n private _hoverOpen(target: Element) {\n const panel = this._panelAt(target);\n if (!panel || panel.matches(':popover-open')) return;\n // `source` makes the trigger the panel's anchor and invoker, as a click would.\n (panel.showPopover as (options?: { source?: Element | null }) => void).call(panel, {\n source: target.closest('button[popovertarget]')\n });\n this._hoverPanel = panel;\n }\n\n // Closes the hover-opened panel after the delay, unless the pointer is still inside it.\n private _hoverClose(target: Element | null = null) {\n const panel = this._hoverPanel;\n if (!panel || panel.contains(target)) return;\n this._hoverTimer = setTimeout(() => {\n // Keyboard focus inside the panel keeps it open, as a click would.\n const root = this.el.getRootNode() as Document | ShadowRoot;\n if (panel.matches(':popover-open') && !panel.contains(root.activeElement)) panel.hidePopover();\n if (this._hoverPanel === panel) this._hoverPanel = null;\n }, HOVER_DELAY);\n }\n\n private _onPointerOver = (e: PointerEvent) => {\n if (e.pointerType !== 'mouse') return;\n clearTimeout(this._hoverTimer);\n const target = e.target as Element;\n const panel = this._panelAt(target);\n if (!panel) this._hoverClose(target);\n // Hovering the open panel's own trigger leaves it as it is.\n else if (panel !== this._hoverPanel) {\n this._hoverTimer = setTimeout(() => this._hoverOpen(target), HOVER_DELAY);\n }\n };\n\n // The panel is a descendant, so moving onto it does not leave the rail.\n private _onPointerLeave = (e: PointerEvent) => {\n if (e.pointerType !== 'mouse') return;\n clearTimeout(this._hoverTimer);\n this._hoverClose();\n };\n\n // Clicking a hover-opened panel's trigger keeps it open instead of toggling\n // it shut; either way the panel no longer follows the pointer.\n private _pinPanel(e: MouseEvent): boolean {\n const panel = this._panelAt(e.target);\n if (!panel) return false;\n clearTimeout(this._hoverTimer);\n if (panel === this._hoverPanel && panel.matches(':popover-open')) e.preventDefault();\n this._hoverPanel = null;\n return true;\n }\n\n private _onClick = (e: MouseEvent) => {\n const target = e.target;\n if (!(target instanceof Node) || this._pinPanel(e)) return;\n if (this._toggle?.contains(target)) {\n this.toggle();\n e.preventDefault();\n return;\n }\n if (this._isScrimClick(e) && this.isExpanded && this._isModal()) {\n this.collapse();\n }\n };\n\n // Escape closes an open side panel before the rail, and reports whether a\n // panel took the key. A hover-opened panel has no focus to return to, so\n // focus inside it goes back to its trigger.\n private _escapePanel(e: KeyboardEvent): boolean {\n // A pending hover would reopen a panel Escape just dismissed.\n clearTimeout(this._hoverTimer);\n this._hoverPanel = null;\n const panel = Array.from(this.el.querySelectorAll<HTMLElement>('.navigation-rail-panel')).find(\n (el) => el.matches(':popover-open')\n );\n if (!panel) return false;\n // A popover open inside the panel is on top; the browser closes it first.\n if (panel.querySelector(':popover-open')) return true;\n const root = this.el.getRootNode() as Document | ShadowRoot;\n const hadFocus = panel.contains(root.activeElement);\n panel.hidePopover();\n if (hadFocus) (panel.previousElementSibling as HTMLElement | null)?.focus();\n e.preventDefault();\n return true;\n }\n\n // The scrim is the rail's own ::before, so a click on blank space inside the\n // rail targets the rail just as a scrim click does. Only a click beside the\n // rail's box landed on the scrim; a modal rail spans the full height.\n private _isScrimClick(e: MouseEvent) {\n if (e.target !== this.el) return false;\n const { left, right } = this.el.getBoundingClientRect();\n return e.clientX < left || e.clientX > right;\n }\n\n private _onKeyDown = (e: KeyboardEvent) => {\n if (e.key !== 'Escape' || e.defaultPrevented || this._escapePanel(e)) return;\n if (this.isExpanded && this._isModal()) {\n const root = this.el.getRootNode() as Document | ShadowRoot;\n const restoreFocus = this.el.contains(root.activeElement);\n const focused = deepActiveElement(root);\n this.collapse();\n if (!this.isExpanded && restoreFocus && deepActiveElement(root) === focused) {\n this._toggle?.focus();\n }\n }\n };\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/ts/behaviors/forms.ts"],
|
|
4
|
-
"sourcesContent": ["import { Utils } from '../core/utils';\n\nconst FILE_RULES = '.drop-zone input[type=\"file\"]:is([data-validate-types], [data-max-size], [data-max-files])';\n\ninterface FileFailure {\n rejected: File[];\n reason: 'type' | 'size' | 'count';\n message: string;\n}\n\nfunction fileLimit(input: HTMLInputElement, attribute: string) {\n const value = (input.getAttribute(attribute) || '').trim();\n if (!/^\\d+$/.test(value)) return 0;\n const limit = Number(value);\n return Number.isSafeInteger(limit) ? limit : 0;\n}\n\nfunction fileSpecifier(value: string) {\n if (value.endsWith('/*')) return /^(image|audio|video)\\/\\*$/.test(value);\n return /^\\.[^\\s/\\\\]+$/.test(value) ||\n /^[!#$%&'*+.^_`|~0-9a-z-]+\\/[!#$%&'*+.^_`|~0-9a-z-]+$/.test(value);\n}\n\nfunction fileMatches(file: File, specifier: string) {\n if (specifier.startsWith('.')) return file.name.toLowerCase().endsWith(specifier);\n if (specifier.endsWith('/*')) return file.type.toLowerCase().startsWith(specifier.slice(0, -1));\n return file.type.toLowerCase() === specifier;\n}\n\nexport class Forms {\n /**\n * Validates a `.validate` field: marks it `invalid` and `aria-invalid`\n * when it fails its constraints or `data-length`, and clears both when it\n * passes. An empty optional field never fails. The field is described by\n * its `[data-error]` supporting text, so the error the CSS shows there is\n * read with it.\n * Marked drop-zone file inputs also validate type/size rules and synchronize their\n * native custom validity and zone-level error text, without emitting events.\n * @param textfield\n */\n static validateField(textfield: HTMLInputElement) {\n if (!textfield) {\n console.error('No text field element found');\n return;\n }\n if (Forms._validatedFile(textfield)) {\n Forms._validateFiles(textfield);\n return;\n }\n if (!textfield.classList.contains('validate')) return;\n Forms._markInvalid(textfield, Forms._fails(textfield));\n Forms._describeByError(textfield);\n }\n\n private static _markInvalid(field: HTMLInputElement, invalid: boolean) {\n field.classList.toggle('invalid', invalid);\n if (invalid) field.setAttribute('aria-invalid', 'true');\n else field.removeAttribute('aria-invalid');\n }\n\n /** Whether a field fails its constraints or is longer than `data-length`. */\n private static _fails(field: HTMLInputElement) {\n return !Forms._blankOptional(field) && (!field.validity.valid || field.value.length > parseInt(field.getAttribute('data-length')));\n }\n\n /** An empty field that is not required, and holds no half-typed number or date, never fails. */\n private static _blankOptional(field: HTMLInputElement) {\n return field.value.length === 0 && !field.validity.badInput && !field.required;\n }\n\n /** Adds the field's `[data-error]` supporting text to its aria-describedby. */\n private static _describeByError(field: HTMLInputElement) {\n const error = field.parentElement?.querySelector(':scope > [data-error]');\n if (error) Forms._addDescription(field, Forms._idOf(error));\n }\n\n private static _idOf(el: Element) {\n if (!el.id) el.id = `field-error-${Utils.guid()}`;\n return el.id;\n }\n\n /** Adds an id to a field's aria-describedby once, after the page's own. */\n private static _addDescription(field: HTMLInputElement, id: string) {\n const ids = (field.getAttribute('aria-describedby') ?? '').split(/\\s+/).filter(Boolean);\n if (!ids.includes(id)) field.setAttribute('aria-describedby', [...ids, id].join(' '));\n }\n\n /**\n * Resizes the given TextArea after updating the\n * value content dynamically.\n * @param e EventTarget\n */\n static textareaAutoResize(e: EventTarget) {\n const textarea = e as HTMLTextAreaElement;\n if (!textarea) return;\n\n // Measure the textarea against itself: collapse it to its natural height,\n // then read the content height back. `.expressive-textarea` is\n // `overflow-y: hidden`, so scrollHeight is the full content height and\n // offsetHeight - clientHeight is exactly the borders (no scrollbar to\n // account for) - which border-box sizing needs added back.\n //\n // This replaces a mirror div that the value was copied into via\n // `innerHTML = innerHTML.replace(...)` - a full serialize and reparse of\n // the text on every keystroke, plus getComputedStyle and seven style\n // writes, run twice per keystroke because it was bound to keydown and\n // keyup both.\n if (!textarea.hasAttribute('original-height')) Forms._measureTextarea(textarea);\n // Not measured yet when it was hidden.\n const originalHeight = parseInt(textarea.getAttribute('original-height'));\n if (isNaN(originalHeight)) return;\n\n textarea.style.height = 'auto';\n // Three reads after a single write: one layout flush for the whole resize.\n const borders = textarea.offsetHeight - textarea.clientHeight;\n const contentHeight = textarea.scrollHeight + borders;\n textarea.style.height = Math.max(originalHeight, contentHeight) + 'px';\n }\n\n // A hidden textarea (closed dialog, inactive tab) measures 0. Storing that\n // would pin it collapsed, so it waits for a focus or input to measure.\n private static _measureTextarea(textarea: HTMLTextAreaElement) {\n const height = textarea.getBoundingClientRect().height;\n if (height) textarea.setAttribute('original-height', height.toString());\n }\n\n private static _initialized = false;\n private static _fileErrors = new WeakMap<HTMLInputElement, string>();\n private static _fileSelections = new WeakMap<HTMLInputElement, { files: File[]; constraints: string }>();\n private static _fileResetForms = new WeakSet<HTMLFormElement>();\n\n private static _validatedFile(input: HTMLInputElement) {\n return input.matches(FILE_RULES) || Forms._fileErrors.has(input);\n }\n\n private static _rejectedTypes(input: HTMLInputElement) {\n const accepted = input.accept.split(',').map((value) => value.trim().toLowerCase()).filter(fileSpecifier);\n if (!accepted.length) return [];\n return Array.from(input.files ?? []).filter((file) => !accepted.some((specifier) => fileMatches(file, specifier)));\n }\n\n private static _validateFiles(input: HTMLInputElement) {\n if (input.matches(':disabled')) return;\n Forms._bindFileReset(input);\n const failure = Forms._checkFiles(input);\n Forms._showFileError(input, failure?.message ?? input.validationMessage);\n return failure;\n }\n\n private static _checkFiles(input: HTMLInputElement) {\n Forms._clearFileError(input);\n if (!input.matches(FILE_RULES)) {\n Forms._fileErrors.delete(input);\n return;\n }\n Forms._fileErrors.set(input, '');\n const failure = Forms._fileFailure(input);\n if (failure) Forms._setFileError(input, failure.message);\n return failure;\n }\n\n private static _fileFailure(input: HTMLInputElement) {\n return Forms._typeFailure(input) ?? Forms._sizeFailure(input) ?? Forms._countFailure(input);\n }\n\n private static _typeFailure(input: HTMLInputElement): FileFailure | undefined {\n if (!input.hasAttribute('data-validate-types')) return;\n const rejected = Forms._rejectedTypes(input);\n if (rejected.length) return { rejected, reason: 'type', message: Forms._fileTypeMessage(input) };\n }\n\n private static _sizeFailure(input: HTMLInputElement): FileFailure | undefined {\n const limit = fileLimit(input, 'data-max-size');\n if (!limit) return;\n const rejected = Array.from(input.files ?? []).filter((file) => file.size > limit);\n if (!rejected.length) return;\n return { rejected, reason: 'size', message: Forms._fileSizeMessage(input, limit) };\n }\n\n private static _fileSizeMessage(input: HTMLInputElement, limit: number) {\n return Forms._fileError(input)?.getAttribute('data-error-size')?.trim() || `Maximum file size: ${limit} bytes.`;\n }\n\n private static _countFailure(input: HTMLInputElement): FileFailure | undefined {\n const limit = fileLimit(input, 'data-max-files');\n if (!limit) return;\n const rejected = Array.from(input.files ?? []);\n if (rejected.length > limit) return { rejected, reason: 'count', message: Forms._fileCountMessage(input, limit) };\n }\n\n private static _fileCountMessage(input: HTMLInputElement, limit: number) {\n return Forms._fileError(input)?.getAttribute('data-error-count')?.trim() || `Maximum file count: ${limit}.`;\n }\n\n private static _clearFileError(input: HTMLInputElement) {\n const owned = Forms._fileErrors.get(input);\n if (owned && owned === input.validationMessage) input.setCustomValidity('');\n }\n\n private static _setFileError(input: HTMLInputElement, message: string) {\n if (input.validity.customError) return;\n input.setCustomValidity(message);\n Forms._fileErrors.set(input, message);\n }\n\n private static _fileTypeMessage(input: HTMLInputElement) {\n const error = Forms._fileError(input);\n return error?.getAttribute('data-error')?.trim() || `Choose files matching: ${input.accept}.`;\n }\n\n private static _fileError(input: HTMLInputElement) {\n return Array.from(input.closest('.drop-zone')?.children ?? [])\n .find((child) => child.hasAttribute('data-error')) as HTMLElement | undefined;\n }\n\n private static _showFileError(input: HTMLInputElement, message: string) {\n Forms._markInvalid(input, !input.validity.valid);\n const error = Forms._fileError(input);\n if (!error) return;\n Forms._addDescription(input, Forms._idOf(error));\n error.textContent = message;\n error.hidden = !message;\n }\n\n private static _onFileInput = (event: Event) => {\n const input = Utils.closestInPath(event, '.drop-zone input[type=\"file\"]') as HTMLInputElement;\n if (!input) return;\n if (input.matches(':disabled')) return;\n Forms._updateDropZone(input);\n };\n\n private static _updateDropZone(input: HTMLInputElement) {\n Forms._bindFileReset(input);\n const zone = input.closest('.drop-zone');\n const files = Array.from(input.files ?? []);\n const failure = Forms._validateDropZone(input);\n Forms.listDropZoneFiles(zone, input);\n Forms._reportFileRejection(input, files, failure);\n }\n\n private static _validateDropZone(input: HTMLInputElement) {\n if (Forms._validatedFile(input)) return Forms._validateFiles(input);\n Forms.validateField(input);\n }\n\n private static _reportFileRejection(input: HTMLInputElement, files: File[], failure?: FileFailure) {\n if (!input.matches(FILE_RULES)) {\n Forms._fileSelections.delete(input);\n return;\n }\n if (!Forms._newFileSelection(input, files)) return;\n if (!failure) return;\n Utils.emit(input.closest('.drop-zone'), 'reject', { input, files: files.slice(), rejected: failure.rejected.slice(), reason: failure.reason });\n }\n\n private static _newFileSelection(input: HTMLInputElement, files: File[]) {\n const constraints = JSON.stringify([input.hasAttribute('data-validate-types'), input.accept, fileLimit(input, 'data-max-size'), fileLimit(input, 'data-max-files')]);\n const previous = Forms._fileSelections.get(input);\n Forms._fileSelections.set(input, { files, constraints });\n return !previous || previous.constraints !== constraints || previous.files.length !== files.length ||\n !previous.files.every((file, index) => file === files[index]);\n }\n\n private static _bindFileReset(input: HTMLInputElement) {\n if (!(input.getRootNode() as ShadowRoot).host) return;\n const form = input.form;\n if (!form || Forms._fileResetForms.has(form)) return;\n Forms._fileResetForms.add(form);\n form.addEventListener('reset', Forms.resetFormExtras);\n }\n\n private static _resetFileInput(input: HTMLInputElement) {\n if (input.files?.length) return;\n Forms._fileSelections.delete(input);\n Forms._resetFileList(input);\n Forms._resetFileValidity(input);\n }\n\n private static _resetFileList(input: HTMLInputElement) {\n const zone = input.closest('.drop-zone');\n if (!zone) return;\n Forms.listDropZoneFiles(zone, input);\n zone.classList.remove('dragover');\n }\n\n private static _resetFileValidity(input: HTMLInputElement) {\n if (input.matches(':disabled')) return;\n if (!Forms._validatedFile(input)) return;\n Forms._clearFileError(input);\n Forms._fileErrors.delete(input);\n Forms._showFileError(input, input.validationMessage);\n }\n\n private static _resetDropZones(form: HTMLFormElement) {\n Array.from(form.elements).filter((field): field is HTMLInputElement =>\n field instanceof HTMLInputElement && field.type === 'file').forEach(Forms._resetFileInput);\n }\n\n /**\n * Safe to call more than once: the root entry calls it on import, and a page\n * that also loads the modular entry may call it again.\n */\n static Init() {\n if (Forms._initialized) return;\n Forms._initialized = true;\n Utils.onDocumentReady(() => {\n document.addEventListener('input', Forms._onFileInput);\n document.addEventListener('change', (e: Event) => {\n const target = Utils.eventTarget(e);\n if (!(target instanceof HTMLInputElement)) return;\n if (target.matches('.drop-zone input[type=\"file\"]')) {\n Forms._onFileInput(e);\n return;\n }\n // The sibling-label loop that used to live here compared\n // `tagName == 'label'` (tagName is uppercase) so it never matched,\n // and no rule in the Sass styles `label.active` anyway - the\n // floating label is driven by CSS, not by a class from here.\n Forms.validateField(target);\n });\n\n document.addEventListener('click', Forms.togglePassword);\n document.addEventListener('click', Forms.stepNumber);\n // Capture, so the password is hidden again before any submit handler\n // reads the form or the browser offers to save it.\n document.addEventListener('submit', Forms.resetFormExtras, true);\n document.addEventListener('submit', Forms.summarizeErrors, true);\n document.addEventListener('click', Forms.focusSummaryField);\n document.addEventListener('reset', Forms.resetFormExtras, true);\n for (const type of ['dragenter', 'dragover', 'dragleave', 'drop']) {\n document.addEventListener(type, Forms.markDropZone);\n }\n\n document.querySelectorAll('.expressive-textarea').forEach((textArea: HTMLTextAreaElement) => {\n Forms.InitTextarea(textArea);\n });\n\n // File Input Path\n document\n .querySelectorAll('.file-field input[type=\"file\"]')\n .forEach((fileInput: HTMLInputElement) => {\n Forms.InitFileInputPath(fileInput);\n });\n });\n }\n\n /**\n * A .password-toggle button shows or hides the password in its field. The\n * button's own name stays put (\"Show password\"); aria-pressed carries the\n * state, so there is no generated text to translate.\n */\n static togglePassword(e: MouseEvent) {\n const button = Utils.closestInPath(e, '.password-toggle');\n const input = button?.closest('.field')?.querySelector<HTMLInputElement>(\n 'input[type=\"password\"], input[data-password]'\n );\n if (!input) return;\n const show = input.type === 'password';\n // Marked so the input is still found once it has become type=\"text\".\n input.toggleAttribute('data-password', show);\n input.type = show ? 'text' : 'password';\n button.setAttribute('aria-pressed', String(show));\n }\n\n /**\n * A [data-step=\"up\"] or [data-step=\"down\"] button in a .field steps the\n * field's number input as the arrow keys would, within min, max and step,\n * and fires input and change. A disabled, read-only or step=\"any\" input\n * is left alone; stepUp() would throw on step=\"any\".\n */\n static stepNumber(e: MouseEvent) {\n const button = Utils.closestInPath(e, '.field > [data-step]:not(:disabled)') as HTMLElement | null;\n const input = button?.parentElement!.querySelector<HTMLInputElement>(\n ':scope > input[type=\"number\"]:not(:disabled, [readonly], [step=\"any\"])'\n );\n if (!input) return;\n input[button!.dataset.step === 'down' ? 'stepDown' : 'stepUp']();\n input.dispatchEvent(new Event('input', { bubbles: true, composed: true }));\n input.dispatchEvent(new Event('change', { bubbles: true }));\n }\n\n /**\n * A revealed password goes back to type=\"password\" when its form is\n * submitted or reset, so it is never sent or autofilled as plain text and\n * a reset field does not stay revealed. A reset form also drops the file\n * lists it would otherwise leave showing: reset fires no change event.\n * File cleanup waits for native reset and respects later cancellation.\n */\n static resetFormExtras(e: Event) {\n const form = e.target;\n if (!(form instanceof HTMLFormElement)) return;\n form.querySelectorAll<HTMLInputElement>('input[data-password]').forEach((input) => {\n input.removeAttribute('data-password');\n input.type = 'password';\n input.closest('.field')?.querySelector('.password-toggle')?.setAttribute('aria-pressed', 'false');\n });\n if (e.type === 'reset') {\n // Native events can run microtasks between listeners, before a later cancellation.\n setTimeout(() => {\n if (!e.defaultPrevented) Forms._resetDropZones(form);\n }, 0);\n }\n }\n\n /**\n * Error summary. A `novalidate` form holding a `.error-summary` is checked\n * when it is submitted. While any field is invalid the submit stops, as it\n * would natively, and the summary's list gets one link per invalid field,\n * \"Label: browser message\", before the summary is shown and focused. A\n * valid submit hides it again. A submitter with `formnovalidate` skips the\n * check.\n */\n static summarizeErrors(e: SubmitEvent) {\n const form = e.target;\n if (!(form instanceof HTMLFormElement)) return;\n const summary = form.querySelector<HTMLElement>('.error-summary');\n const list = summary?.querySelector('ul, ol');\n if (!list || e.submitter?.hasAttribute('formnovalidate')) return;\n // checkValidity fires `invalid` on each field, which FormSelect needs to\n // mark its generated field.\n if (form.checkValidity()) {\n summary.hidden = true;\n list.replaceChildren();\n return;\n }\n e.preventDefault();\n // Stop here, in the capture phase, so the page's own submit handlers do\n // not run for a form the browser would not have submitted.\n e.stopPropagation();\n const seen = new Set<string>();\n const items = [...form.elements].flatMap((field: HTMLInputElement) => {\n if (!field.willValidate || field.validity.valid) return [];\n // One entry per radio group.\n if (field.type === 'radio') {\n if (seen.has(field.name)) return [];\n seen.add(field.name);\n }\n if (!field.id) field.id = `field-${Utils.guid()}`;\n const group = field.type === 'radio' ? field.closest('fieldset')?.querySelector('legend') : null;\n // An enhanced select's label names the generated input, so fall back to\n // the label in the same .field.\n const named = group ?? field.labels?.[0] ?? field.closest('.field')?.querySelector('label');\n // A label can wrap its control; a select's options are not its name.\n const text = named?.cloneNode(true) as Element;\n text?.querySelectorAll('select, textarea').forEach((control) => control.remove());\n const label = text?.textContent ?? field.getAttribute('aria-label') ?? '';\n const link = document.createElement('a');\n link.href = `#${field.id}`;\n link.textContent = [label.replace(/\\s+/g, ' ').trim(), field.validationMessage].filter(Boolean).join(': ');\n const item = document.createElement('li');\n item.append(link);\n return [item];\n });\n list.replaceChildren(...items);\n if (!summary.hasAttribute('tabindex')) summary.tabIndex = -1;\n summary.hidden = false;\n summary.focus();\n }\n\n /**\n * A summary link focuses its field instead of only scrolling to it. An\n * enhanced select passes that focus on to its generated input itself.\n */\n static focusSummaryField(e: MouseEvent) {\n const link = Utils.closestInPath(e, '.error-summary a[href^=\"#\"]');\n const field = link && Utils.getElementById(link, link.getAttribute('href').slice(1));\n if (!field) return;\n e.preventDefault();\n field.focus();\n }\n\n /**\n * The native file input covers its .drop-zone, so the browser already takes\n * a dropped file. This only shows the drag: the input is the topmost\n * element, so every drag event over the zone targets it and leaving it is\n * leaving the zone.\n */\n static markDropZone(e: DragEvent) {\n const input = Utils.eventTarget(e);\n if (!(input instanceof HTMLInputElement) || input.type !== 'file') return;\n const zone = input.closest('.drop-zone');\n if (!zone) return;\n const over = e.type === 'dragenter' || e.type === 'dragover';\n zone.classList.toggle('dragover', over && !input.disabled);\n }\n\n /** Lists the chosen files, name and size, in the zone's .drop-zone-files. */\n static listDropZoneFiles(zone: Element, input: HTMLInputElement) {\n const list = Array.from(zone.querySelectorAll('.drop-zone-files')).find((list) => list.closest('.drop-zone') === zone);\n if (!list) return;\n const size = (bytes: number) => {\n const [value, unit] =\n bytes >= 1e6 ? [bytes / 1e6, 'megabyte'] : bytes >= 1e3 ? [bytes / 1e3, 'kilobyte'] : [bytes, 'byte'];\n return new Intl.NumberFormat(undefined, { style: 'unit', unit, maximumFractionDigits: 1 }).format(value);\n };\n list.replaceChildren(\n ...Array.from(input.files ?? [], (file) => {\n const item = document.createElement('li');\n const name = document.createElement('span');\n const meta = document.createElement('span');\n name.textContent = file.name;\n meta.textContent = size(file.size);\n item.append(name, meta);\n return item;\n })\n );\n }\n\n static InitTextarea(textarea: HTMLTextAreaElement) {\n // Measured afresh by textareaAutoResize, which skips a hidden textarea.\n textarea.removeAttribute('original-height');\n Forms.textareaAutoResize(textarea);\n // `input` rather than keydown + keyup: it fires once per actual value\n // change and also covers paste, drag-drop and IME composition, which the\n // key events missed.\n textarea.addEventListener('input', (e) => Forms.textareaAutoResize(e.target));\n // One that was hidden at init gets its first measurement once shown.\n textarea.addEventListener('focus', () => {\n if (!textarea.hasAttribute('original-height')) Forms.textareaAutoResize(textarea);\n });\n }\n\n static InitFileInputPath(fileInput: HTMLInputElement) {\n fileInput.addEventListener('change', () => {\n const fileField = fileInput.closest('.file-field');\n const pathInput = fileField?.querySelector<HTMLInputElement>('input.file-path');\n if (!pathInput) return;\n pathInput.value = Array.from(fileInput.files, (f) => f.name).join(', ');\n pathInput.dispatchEvent(\n new Event('change', { bubbles: true, cancelable: true, composed: true })\n );\n });\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["list"]
|
|
7
|
-
}
|