@expressivecss/expressive 0.13.1 → 0.15.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.
Files changed (257) hide show
  1. package/CHANGELOG.md +196 -1
  2. package/README.md +2 -1
  3. package/dist/css/expressive.css +432 -311
  4. package/dist/css/expressive.css.map +1 -1
  5. package/dist/css/expressive.min.css +1 -1
  6. package/dist/css/expressive.min.css.map +1 -1
  7. package/dist/js/chunks/{chunk-DTKR54I6.mjs → chunk-33QVDDGR.mjs} +3 -3
  8. package/dist/js/chunks/{chunk-SPETGK25.mjs → chunk-45FER6RI.mjs} +5 -5
  9. package/dist/js/chunks/chunk-45FER6RI.mjs.map +7 -0
  10. package/dist/js/chunks/{chunk-WJXDBPXQ.mjs → chunk-5CEAOLUA.mjs} +17 -20
  11. package/dist/js/chunks/chunk-5CEAOLUA.mjs.map +7 -0
  12. package/dist/js/chunks/{chunk-CKQP6P76.mjs → chunk-6VATUZC6.mjs} +12 -7
  13. package/dist/js/chunks/chunk-6VATUZC6.mjs.map +7 -0
  14. package/dist/js/chunks/{chunk-QDAL4IYN.mjs → chunk-74MXKKLN.mjs} +2 -2
  15. package/dist/js/chunks/{chunk-QDAL4IYN.mjs.map → chunk-74MXKKLN.mjs.map} +2 -2
  16. package/dist/js/chunks/{chunk-DLWYKFEI.mjs → chunk-AIURVCG6.mjs} +3 -3
  17. package/dist/js/chunks/{chunk-NNYP33NB.mjs → chunk-BGZLF6JZ.mjs} +19 -18
  18. package/dist/js/chunks/chunk-BGZLF6JZ.mjs.map +7 -0
  19. package/dist/js/chunks/chunk-C6CHEWYP.mjs +154 -0
  20. package/dist/js/chunks/chunk-C6CHEWYP.mjs.map +7 -0
  21. package/dist/js/chunks/{chunk-GVGT6MIU.mjs → chunk-CK2XCICY.mjs} +2 -2
  22. package/dist/js/chunks/{chunk-XGHORT7J.mjs → chunk-CXXM2L4F.mjs} +8 -9
  23. package/dist/js/chunks/chunk-CXXM2L4F.mjs.map +7 -0
  24. package/dist/js/chunks/{chunk-QVVEWBOF.mjs → chunk-DXGRXYYL.mjs} +25 -37
  25. package/dist/js/chunks/chunk-DXGRXYYL.mjs.map +7 -0
  26. package/dist/js/chunks/{chunk-QV2JAWIZ.mjs → chunk-FM5CZOUB.mjs} +5 -8
  27. package/dist/js/chunks/{chunk-QV2JAWIZ.mjs.map → chunk-FM5CZOUB.mjs.map} +2 -2
  28. package/dist/js/chunks/{chunk-PLYXLSH3.mjs → chunk-GJL6GCIU.mjs} +46 -58
  29. package/dist/js/chunks/chunk-GJL6GCIU.mjs.map +7 -0
  30. package/dist/js/chunks/chunk-K3HZMFMD.mjs +135 -0
  31. package/dist/js/chunks/chunk-K3HZMFMD.mjs.map +7 -0
  32. package/dist/js/chunks/chunk-KHXZ2A4K.mjs +395 -0
  33. package/dist/js/chunks/chunk-KHXZ2A4K.mjs.map +7 -0
  34. package/dist/js/chunks/chunk-KQACNQ22.mjs +7 -0
  35. package/dist/js/chunks/{chunk-4PWAPV6F.mjs.map → chunk-KQACNQ22.mjs.map} +1 -1
  36. package/dist/js/chunks/chunk-KUFHW3DS.mjs +214 -0
  37. package/dist/js/chunks/chunk-KUFHW3DS.mjs.map +7 -0
  38. package/dist/js/chunks/{chunk-LWBQIX5J.mjs → chunk-KVJAVDBC.mjs} +46 -57
  39. package/dist/js/chunks/chunk-KVJAVDBC.mjs.map +7 -0
  40. package/dist/js/chunks/{chunk-YDCS5S3J.mjs → chunk-L27Q6ZMI.mjs} +2 -2
  41. package/dist/js/chunks/{chunk-CCWDV5CR.mjs → chunk-LQWUDNHZ.mjs} +3 -3
  42. package/dist/js/chunks/{chunk-6OMRGML6.mjs → chunk-M372EDXD.mjs} +7 -13
  43. package/dist/js/chunks/{chunk-6OMRGML6.mjs.map → chunk-M372EDXD.mjs.map} +2 -2
  44. package/dist/js/chunks/{chunk-EC63CHXU.mjs → chunk-M3MURWMB.mjs} +20 -16
  45. package/dist/js/chunks/chunk-M3MURWMB.mjs.map +7 -0
  46. package/dist/js/chunks/{chunk-U2OTHOTI.mjs → chunk-NUHMOAOY.mjs} +19 -33
  47. package/dist/js/chunks/chunk-NUHMOAOY.mjs.map +7 -0
  48. package/dist/js/chunks/{chunk-P3G3QHII.mjs → chunk-OWG3LMUL.mjs} +17 -14
  49. package/dist/js/chunks/chunk-OWG3LMUL.mjs.map +7 -0
  50. package/dist/js/chunks/{chunk-LTWPGFBR.mjs → chunk-PD6HYHAE.mjs} +4 -15
  51. package/dist/js/chunks/chunk-PD6HYHAE.mjs.map +7 -0
  52. package/dist/js/chunks/{chunk-PIJ2TAR3.mjs → chunk-PDG64UHF.mjs} +3 -3
  53. package/dist/js/chunks/{chunk-IFXVDDDH.mjs → chunk-PO3AXVR3.mjs} +38 -64
  54. package/dist/js/chunks/chunk-PO3AXVR3.mjs.map +7 -0
  55. package/dist/js/chunks/{chunk-QKWPQK5N.mjs → chunk-QYGK36OG.mjs} +16 -14
  56. package/dist/js/chunks/chunk-QYGK36OG.mjs.map +7 -0
  57. package/dist/js/chunks/{chunk-UNEMYWEW.mjs → chunk-SFI2U4YW.mjs} +28 -44
  58. package/dist/js/chunks/chunk-SFI2U4YW.mjs.map +7 -0
  59. package/dist/js/chunks/{chunk-VTLBW7QS.mjs → chunk-SMY7GJSS.mjs} +3 -3
  60. package/dist/js/chunks/{chunk-O5XPWXIQ.mjs → chunk-TCCA2HDG.mjs} +39 -31
  61. package/dist/js/chunks/chunk-TCCA2HDG.mjs.map +7 -0
  62. package/dist/js/chunks/{chunk-UBLRRJ7N.mjs → chunk-TSZYSW7F.mjs} +4 -4
  63. package/dist/js/chunks/{chunk-UBLRRJ7N.mjs.map → chunk-TSZYSW7F.mjs.map} +2 -2
  64. package/dist/js/chunks/{chunk-UEZUJQ66.mjs → chunk-UAZSDUVP.mjs} +3 -4
  65. package/dist/js/chunks/{chunk-UEZUJQ66.mjs.map → chunk-UAZSDUVP.mjs.map} +2 -2
  66. package/dist/js/chunks/{chunk-6N2XAEFK.mjs → chunk-UBRZZWRA.mjs} +10 -8
  67. package/dist/js/chunks/chunk-UBRZZWRA.mjs.map +7 -0
  68. package/dist/js/chunks/{chunk-3VOK6J7U.mjs → chunk-UCOE7ZDL.mjs} +47 -45
  69. package/dist/js/chunks/chunk-UCOE7ZDL.mjs.map +7 -0
  70. package/dist/js/chunks/{chunk-K4CJCRGE.mjs → chunk-UETTGDLI.mjs} +3 -3
  71. package/dist/js/chunks/{chunk-RHRQKTTX.mjs → chunk-UNCRDLP6.mjs} +6 -9
  72. package/dist/js/chunks/chunk-UNCRDLP6.mjs.map +7 -0
  73. package/dist/js/chunks/{chunk-LNCCYGPC.mjs → chunk-VGNYF6FB.mjs} +8 -10
  74. package/dist/js/chunks/chunk-VGNYF6FB.mjs.map +7 -0
  75. package/dist/js/chunks/{chunk-UAEAQBRC.mjs → chunk-VGPGBNGL.mjs} +4 -12
  76. package/dist/js/chunks/chunk-VGPGBNGL.mjs.map +7 -0
  77. package/dist/js/chunks/chunk-VKAUVTQY.mjs +1 -0
  78. package/dist/js/chunks/{chunk-HKT2S7VM.mjs → chunk-VM4FTS7L.mjs} +3 -3
  79. package/dist/js/chunks/{chunk-55IA2XUC.mjs → chunk-WDK4T63U.mjs} +8 -11
  80. package/dist/js/chunks/chunk-WDK4T63U.mjs.map +7 -0
  81. package/dist/js/chunks/{chunk-XH6BEEMY.mjs → chunk-WOCCTVUF.mjs} +51 -39
  82. package/dist/js/chunks/chunk-WOCCTVUF.mjs.map +7 -0
  83. package/dist/js/chunks/{chunk-GZWPXXY6.mjs → chunk-WQYN5L4E.mjs} +14 -16
  84. package/dist/js/chunks/chunk-WQYN5L4E.mjs.map +7 -0
  85. package/dist/js/chunks/{chunk-6WLSDZ4O.mjs → chunk-X4ISMKE2.mjs} +2 -2
  86. package/dist/js/chunks/{chunk-3DHK5CZU.mjs → chunk-XAEAEHIX.mjs} +6 -8
  87. package/dist/js/chunks/chunk-XAEAEHIX.mjs.map +7 -0
  88. package/dist/js/chunks/{chunk-3CLXLPYS.mjs → chunk-ZX6M7SWO.mjs} +43 -29
  89. package/dist/js/chunks/chunk-ZX6M7SWO.mjs.map +7 -0
  90. package/dist/js/expressive.cjs +1337 -572
  91. package/dist/js/expressive.cjs.map +4 -4
  92. package/dist/js/expressive.js +1337 -572
  93. package/dist/js/expressive.js.map +4 -4
  94. package/dist/js/expressive.min.js +10 -13
  95. package/dist/js/expressive.min.js.map +4 -4
  96. package/dist/js/expressive.mjs +71 -55
  97. package/dist/js/expressive.mjs.map +1 -1
  98. package/dist/js/internal/behaviors/bottomSheets.mjs +3 -3
  99. package/dist/js/internal/behaviors/dialogs.mjs +2 -2
  100. package/dist/js/internal/behaviors/forms.mjs +2 -2
  101. package/dist/js/internal/behaviors/sheetDrag.mjs +2 -2
  102. package/dist/js/internal/behaviors/sideSheets.mjs +3 -3
  103. package/dist/js/internal/components/appBar.mjs +2 -2
  104. package/dist/js/internal/components/autocomplete.mjs +4 -4
  105. package/dist/js/internal/components/barChart.mjs +4 -4
  106. package/dist/js/internal/components/buttonGroup.mjs +2 -2
  107. package/dist/js/internal/components/buttons.mjs +3 -3
  108. package/dist/js/internal/components/cards.mjs +3 -3
  109. package/dist/js/internal/components/carousel.mjs +3 -3
  110. package/dist/js/internal/components/characterCounter.mjs +2 -2
  111. package/dist/js/internal/components/chips.mjs +5 -5
  112. package/dist/js/internal/components/columnChart.mjs +3 -3
  113. package/dist/js/internal/components/commandPalette.mjs +3 -3
  114. package/dist/js/internal/components/confetti.mjs +8 -0
  115. package/dist/js/internal/components/confetti.mjs.map +7 -0
  116. package/dist/js/internal/components/datepicker.mjs +6 -6
  117. package/dist/js/internal/components/expandingCard.mjs +3 -3
  118. package/dist/js/internal/components/heatmapChart.mjs +3 -3
  119. package/dist/js/internal/components/index.mjs +64 -48
  120. package/dist/js/internal/components/keypad.mjs +9 -0
  121. package/dist/js/internal/components/keypad.mjs.map +7 -0
  122. package/dist/js/internal/components/lightbox.mjs +3 -3
  123. package/dist/js/internal/components/lineChart.mjs +6 -2
  124. package/dist/js/internal/components/mapView.mjs +9 -0
  125. package/dist/js/internal/components/mapView.mjs.map +7 -0
  126. package/dist/js/internal/components/menu.mjs +3 -3
  127. package/dist/js/internal/components/messageScroller.mjs +3 -3
  128. package/dist/js/internal/components/mixedChart.mjs +4 -4
  129. package/dist/js/internal/components/navigationRail.mjs +2 -2
  130. package/dist/js/internal/components/particles.mjs +8 -0
  131. package/dist/js/internal/components/particles.mjs.map +7 -0
  132. package/dist/js/internal/components/pieChart.mjs +3 -3
  133. package/dist/js/internal/components/questionnaire.mjs +3 -3
  134. package/dist/js/internal/components/radarChart.mjs +3 -3
  135. package/dist/js/internal/components/radialChart.mjs +3 -3
  136. package/dist/js/internal/components/registry.mjs +41 -37
  137. package/dist/js/internal/components/richTextEditor.mjs +3 -3
  138. package/dist/js/internal/components/scrollspy.mjs +2 -2
  139. package/dist/js/internal/components/select.mjs +4 -4
  140. package/dist/js/internal/components/slider.mjs +3 -3
  141. package/dist/js/internal/components/snackbar.mjs +2 -2
  142. package/dist/js/internal/components/tabs.mjs +4 -4
  143. package/dist/js/internal/components/timepicker.mjs +4 -4
  144. package/dist/js/internal/components/tooltip.mjs +3 -3
  145. package/dist/js/internal/core/component.mjs +1 -1
  146. package/dist/js/internal/core/utils.mjs +1 -1
  147. package/dist/js/internal/plugins/dockedDisplayPlugin.mjs +2 -2
  148. package/dist/js/modular.mjs +71 -55
  149. package/dist/types/behaviors/forms.d.ts +5 -0
  150. package/dist/types/components/autocomplete.d.ts +1 -0
  151. package/dist/types/components/carousel.d.ts +2 -0
  152. package/dist/types/components/confetti.d.ts +103 -0
  153. package/dist/types/components/datepicker.d.ts +5 -4
  154. package/dist/types/components/expandingCard.d.ts +2 -0
  155. package/dist/types/components/index.d.ts +4 -0
  156. package/dist/types/components/keypad.d.ts +34 -0
  157. package/dist/types/components/lightbox.d.ts +3 -5
  158. package/dist/types/components/lineChart.d.ts +4 -0
  159. package/dist/types/components/mapView.d.ts +151 -0
  160. package/dist/types/components/menu.d.ts +1 -0
  161. package/dist/types/components/particles.d.ts +72 -0
  162. package/dist/types/components/pieChart.d.ts +3 -0
  163. package/dist/types/components/radialChart.d.ts +0 -1
  164. package/dist/types/components/registry.d.ts +12 -0
  165. package/dist/types/components/slider.d.ts +3 -1
  166. package/dist/types/components/snackbar.d.ts +3 -0
  167. package/dist/types/components/tabs.d.ts +5 -1
  168. package/dist/types/components/timepicker.d.ts +2 -0
  169. package/dist/types/modular.d.ts +1 -1
  170. package/dist/types/plugins/dockedDisplayPlugin.d.ts +4 -3
  171. package/package.json +2 -1
  172. package/src/sass/abstracts/_breakpoints.scss +0 -1
  173. package/src/sass/abstracts/_elevation.scss +1 -1
  174. package/src/sass/abstracts/_mixins.scss +20 -60
  175. package/src/sass/abstracts/_variables.scss +10 -0
  176. package/src/sass/base/_global.scss +3 -12
  177. package/src/sass/base/_index.scss +1 -1
  178. package/src/sass/components/_badges.scss +1 -8
  179. package/src/sass/components/_bar-chart.scss +1 -1
  180. package/src/sass/components/_button-groups.scss +31 -66
  181. package/src/sass/components/_buttons.scss +1 -1
  182. package/src/sass/components/_cards.scss +6 -25
  183. package/src/sass/components/_carousel.scss +16 -55
  184. package/src/sass/components/_chips.scss +0 -6
  185. package/src/sass/components/_column-chart.scss +1 -1
  186. package/src/sass/components/_confetti.scss +14 -0
  187. package/src/sass/components/_data-table.scss +1 -3
  188. package/src/sass/components/_datepicker.scss +3 -22
  189. package/src/sass/components/_dialog.scss +1 -4
  190. package/src/sass/components/_heatmap-chart.scss +2 -2
  191. package/src/sass/components/_icon-buttons.scss +0 -1
  192. package/src/sass/components/_index.scss +4 -0
  193. package/src/sass/components/_keypad.scss +162 -0
  194. package/src/sass/components/_lightbox.scss +3 -8
  195. package/src/sass/components/_map.scss +188 -0
  196. package/src/sass/components/_menu.scss +31 -74
  197. package/src/sass/components/_mixed-chart.scss +1 -1
  198. package/src/sass/components/_navbar.scss +9 -45
  199. package/src/sass/components/_navigation-rail.scss +23 -32
  200. package/src/sass/components/_page-footer.scss +15 -12
  201. package/src/sass/components/_panes.scss +2 -6
  202. package/src/sass/components/_particles.scss +14 -0
  203. package/src/sass/components/_progress.scss +6 -4
  204. package/src/sass/components/_side-sheet.scss +1 -4
  205. package/src/sass/components/_stepper.scss +0 -4
  206. package/src/sass/components/_table_of_contents.scss +3 -1
  207. package/src/sass/components/_timepicker.scss +4 -36
  208. package/src/sass/components/_toolbar.scss +0 -4
  209. package/src/sass/components/forms/_checkboxes.scss +44 -67
  210. package/src/sass/components/forms/_fieldset.scss +3 -3
  211. package/src/sass/components/forms/_file-input.scss +0 -1
  212. package/src/sass/components/forms/_radio-buttons.scss +10 -36
  213. package/src/sass/components/forms/_select.scss +0 -3
  214. package/src/sass/components/forms/_slider.scss +72 -259
  215. package/src/sass/tokens/_state.scss +2 -2
  216. package/src/sass/tokens/_theme.scss +1 -1
  217. package/src/sass/utilities/_colors.scss +6 -1
  218. package/src/sass/utilities/_index.scss +1 -1
  219. package/dist/js/chunks/chunk-3CLXLPYS.mjs.map +0 -7
  220. package/dist/js/chunks/chunk-3DHK5CZU.mjs.map +0 -7
  221. package/dist/js/chunks/chunk-3VOK6J7U.mjs.map +0 -7
  222. package/dist/js/chunks/chunk-4PWAPV6F.mjs +0 -7
  223. package/dist/js/chunks/chunk-55IA2XUC.mjs.map +0 -7
  224. package/dist/js/chunks/chunk-6N2XAEFK.mjs.map +0 -7
  225. package/dist/js/chunks/chunk-CKQP6P76.mjs.map +0 -7
  226. package/dist/js/chunks/chunk-EC63CHXU.mjs.map +0 -7
  227. package/dist/js/chunks/chunk-GZWPXXY6.mjs.map +0 -7
  228. package/dist/js/chunks/chunk-IFXVDDDH.mjs.map +0 -7
  229. package/dist/js/chunks/chunk-LNCCYGPC.mjs.map +0 -7
  230. package/dist/js/chunks/chunk-LTWPGFBR.mjs.map +0 -7
  231. package/dist/js/chunks/chunk-LWBQIX5J.mjs.map +0 -7
  232. package/dist/js/chunks/chunk-NNYP33NB.mjs.map +0 -7
  233. package/dist/js/chunks/chunk-NQLC3YMW.mjs +0 -1
  234. package/dist/js/chunks/chunk-O5XPWXIQ.mjs.map +0 -7
  235. package/dist/js/chunks/chunk-P3G3QHII.mjs.map +0 -7
  236. package/dist/js/chunks/chunk-PLYXLSH3.mjs.map +0 -7
  237. package/dist/js/chunks/chunk-QKWPQK5N.mjs.map +0 -7
  238. package/dist/js/chunks/chunk-QVVEWBOF.mjs.map +0 -7
  239. package/dist/js/chunks/chunk-RHRQKTTX.mjs.map +0 -7
  240. package/dist/js/chunks/chunk-SPETGK25.mjs.map +0 -7
  241. package/dist/js/chunks/chunk-U2OTHOTI.mjs.map +0 -7
  242. package/dist/js/chunks/chunk-UAEAQBRC.mjs.map +0 -7
  243. package/dist/js/chunks/chunk-UNEMYWEW.mjs.map +0 -7
  244. package/dist/js/chunks/chunk-WJXDBPXQ.mjs.map +0 -7
  245. package/dist/js/chunks/chunk-XGHORT7J.mjs.map +0 -7
  246. package/dist/js/chunks/chunk-XH6BEEMY.mjs.map +0 -7
  247. /package/dist/js/chunks/{chunk-DTKR54I6.mjs.map → chunk-33QVDDGR.mjs.map} +0 -0
  248. /package/dist/js/chunks/{chunk-DLWYKFEI.mjs.map → chunk-AIURVCG6.mjs.map} +0 -0
  249. /package/dist/js/chunks/{chunk-GVGT6MIU.mjs.map → chunk-CK2XCICY.mjs.map} +0 -0
  250. /package/dist/js/chunks/{chunk-YDCS5S3J.mjs.map → chunk-L27Q6ZMI.mjs.map} +0 -0
  251. /package/dist/js/chunks/{chunk-CCWDV5CR.mjs.map → chunk-LQWUDNHZ.mjs.map} +0 -0
  252. /package/dist/js/chunks/{chunk-PIJ2TAR3.mjs.map → chunk-PDG64UHF.mjs.map} +0 -0
  253. /package/dist/js/chunks/{chunk-VTLBW7QS.mjs.map → chunk-SMY7GJSS.mjs.map} +0 -0
  254. /package/dist/js/chunks/{chunk-K4CJCRGE.mjs.map → chunk-UETTGDLI.mjs.map} +0 -0
  255. /package/dist/js/chunks/{chunk-NQLC3YMW.mjs.map → chunk-VKAUVTQY.mjs.map} +0 -0
  256. /package/dist/js/chunks/{chunk-HKT2S7VM.mjs.map → chunk-VM4FTS7L.mjs.map} +0 -0
  257. /package/dist/js/chunks/{chunk-6WLSDZ4O.mjs.map → chunk-X4ISMKE2.mjs.map} +0 -0
@@ -31,6 +31,7 @@ __export(index_exports, {
31
31
  Chips: () => Chips,
32
32
  ColumnChart: () => ColumnChart,
33
33
  CommandPalette: () => CommandPalette,
34
+ Confetti: () => Confetti,
34
35
  Datepicker: () => Datepicker,
35
36
  Dialogs: () => Dialogs,
36
37
  ExpandingCard: () => ExpandingCard,
@@ -38,12 +39,15 @@ __export(index_exports, {
38
39
  FormSelect: () => FormSelect,
39
40
  Forms: () => Forms,
40
41
  HeatmapChart: () => HeatmapChart,
42
+ Keypad: () => Keypad,
41
43
  Lightbox: () => Lightbox,
42
44
  LineChart: () => LineChart,
45
+ MapView: () => MapView,
43
46
  Menu: () => Menu,
44
47
  MessageScroller: () => MessageScroller,
45
48
  MixedChart: () => MixedChart,
46
49
  NavigationRail: () => NavigationRail,
50
+ Particles: () => Particles,
47
51
  PieChart: () => PieChart,
48
52
  Questionnaire: () => Questionnaire,
49
53
  RadarChart: () => RadarChart,
@@ -205,12 +209,7 @@ var _Utils = class _Utils {
205
209
  * @param trigger Trigger element.
206
210
  */
207
211
  static getIdFromTrigger(trigger) {
208
- let id = trigger.dataset.target;
209
- if (!id) {
210
- id = trigger.getAttribute("href");
211
- return id ? id.slice(1) : "";
212
- }
213
- return id;
212
+ return trigger.dataset.target || (trigger.getAttribute("href")?.slice(1) ?? "");
214
213
  }
215
214
  /**
216
215
  * Retrieves document scroll postion from top.
@@ -239,9 +238,9 @@ var _Utils = class _Utils {
239
238
  static throttle(func, wait) {
240
239
  let timeout = null;
241
240
  let lastArgs = null;
242
- let previous = 0;
241
+ let previous = -Infinity;
243
242
  return (...args) => {
244
- const now = Date.now();
243
+ const now = performance.now();
245
244
  const remaining = wait - (now - previous);
246
245
  if (remaining <= 0) {
247
246
  clearTimeout(timeout);
@@ -252,7 +251,7 @@ var _Utils = class _Utils {
252
251
  } else if (!timeout) {
253
252
  lastArgs = args;
254
253
  timeout = setTimeout(() => {
255
- previous = Date.now();
254
+ previous = performance.now();
256
255
  timeout = null;
257
256
  func(...lastArgs ?? []);
258
257
  lastArgs = null;
@@ -276,12 +275,11 @@ var _Utils = class _Utils {
276
275
  * Renders a button with optional callback function
277
276
  */
278
277
  static createButton(container, text, className = [], visibility = true, callback = null) {
279
- className = className.concat(["text"]);
280
278
  const button = document.createElement("button");
281
- button.className = className.join(" ");
279
+ button.className = className.concat(["text"]).join(" ");
282
280
  button.style.visibility = visibility ? "visible" : "hidden";
283
281
  button.type = "button";
284
- button.tabIndex = !!visibility ? 0 : -1;
282
+ button.tabIndex = visibility ? 0 : -1;
285
283
  button.innerText = text;
286
284
  if (typeof callback === "function") button.addEventListener("click", callback);
287
285
  container.append(button);
@@ -394,10 +392,7 @@ var Component = class {
394
392
  if (!(el instanceof HTMLElement)) {
395
393
  console.error(Error(el + " is not an HTML Element"));
396
394
  }
397
- const ins = classDef.getInstance(el);
398
- if (!!ins) {
399
- ins.destroy();
400
- }
395
+ classDef.getInstance(el)?.destroy();
401
396
  this.el = el;
402
397
  }
403
398
  /**
@@ -407,16 +402,8 @@ var Component = class {
407
402
  * @param classDef Class definition.
408
403
  */
409
404
  static init(els, options, classDef) {
410
- let instances = null;
411
- if (els instanceof Element) {
412
- instances = new classDef(els, options);
413
- } else if (els) {
414
- instances = [];
415
- for (let i = 0; i < els.length; i++) {
416
- instances.push(new classDef(els[i], options));
417
- }
418
- }
419
- return instances;
405
+ if (els instanceof Element) return new classDef(els, options);
406
+ return els ? Array.from(els, (el) => new classDef(el, options)) : null;
420
407
  }
421
408
  /**
422
409
  * @returns default options for component instance.
@@ -604,7 +591,7 @@ var Cards = class _Cards extends Component {
604
591
  Utils.onDocumentReady(() => {
605
592
  const cards = Array.from(document.querySelectorAll(CARDS_SELECTOR)).filter(isCardReveal);
606
593
  cards.forEach((el) => {
607
- if (el && el["Expressive_Cards"] == void 0) this.init(el);
594
+ if (el["Expressive_Cards"] == void 0) this.init(el);
608
595
  });
609
596
  });
610
597
  }
@@ -647,11 +634,7 @@ var ExpandingCard = class _ExpandingCard extends Component {
647
634
  };
648
635
  this._handleNativeClose = () => {
649
636
  if (this.dialog.open) return;
650
- this.closeGeneration++;
651
- this.isOpen = false;
652
- this.trigger.ariaExpanded = "false";
653
- this.dialog.ariaExpanded = "false";
654
- this.dialog.classList.remove("expanded");
637
+ this._collapse();
655
638
  };
656
639
  this._setTransitionOrigin = () => {
657
640
  if (!this.dialog) return;
@@ -660,26 +643,15 @@ var ExpandingCard = class _ExpandingCard extends Component {
660
643
  ":scope > figure, :scope > img"
661
644
  );
662
645
  const mediaRect = media?.getBoundingClientRect();
663
- this.dialog.style.setProperty(
664
- "--md-comp-expanding-card-from-top",
665
- `${Math.max(0, card.top)}px`
666
- );
667
- this.dialog.style.setProperty(
668
- "--md-comp-expanding-card-from-right",
669
- `${Math.max(0, window.innerWidth - card.right)}px`
670
- );
671
- this.dialog.style.setProperty(
672
- "--md-comp-expanding-card-from-bottom",
673
- `${Math.max(0, window.innerHeight - card.bottom)}px`
674
- );
675
- this.dialog.style.setProperty(
676
- "--md-comp-expanding-card-from-left",
677
- `${Math.max(0, card.left)}px`
678
- );
679
- this.dialog.style.setProperty(
680
- "--md-comp-expanding-card-from-media-height",
681
- `${Math.max(0, mediaRect?.height ?? 0)}px`
646
+ const set = (side, px) => this.dialog.style.setProperty(
647
+ `--md-comp-expanding-card-from-${side}`,
648
+ `${Math.max(0, px)}px`
682
649
  );
650
+ set("top", card.top);
651
+ set("right", window.innerWidth - card.right);
652
+ set("bottom", window.innerHeight - card.bottom);
653
+ set("left", card.left);
654
+ set("media-height", mediaRect?.height ?? 0);
683
655
  };
684
656
  this.open = () => {
685
657
  if (this.isOpen || !this.dialog || !this.trigger) return;
@@ -698,12 +670,9 @@ var ExpandingCard = class _ExpandingCard extends Component {
698
670
  };
699
671
  this.close = () => {
700
672
  if (!this.isOpen || !this.dialog || !this.trigger) return;
701
- const generation = ++this.closeGeneration;
702
673
  this._setTransitionOrigin();
703
- this.isOpen = false;
704
- this.trigger.ariaExpanded = "false";
705
- this.dialog.ariaExpanded = "false";
706
- this.dialog.classList.remove("expanded");
674
+ this._collapse();
675
+ const generation = this.closeGeneration;
707
676
  if (typeof this.options.onClose === "function") {
708
677
  this.options.onClose.call(this, this.el);
709
678
  }
@@ -754,18 +723,24 @@ var ExpandingCard = class _ExpandingCard extends Component {
754
723
  }
755
724
  destroy() {
756
725
  this._removeEventHandlers();
726
+ this._collapse();
727
+ if (this.dialog?.open) this.dialog.close();
728
+ this.el["Expressive_ExpandingCard"] = void 0;
729
+ }
730
+ /** Marks the card closed and invalidates any pending close. */
731
+ _collapse() {
757
732
  this.closeGeneration++;
758
733
  this.isOpen = false;
759
734
  if (this.trigger) this.trigger.ariaExpanded = "false";
760
- if (this.dialog) this.dialog.ariaExpanded = "false";
761
- this.dialog?.classList.remove("expanded");
762
- if (this.dialog?.open) this.dialog.close();
763
- this.el["Expressive_ExpandingCard"] = void 0;
735
+ if (this.dialog) {
736
+ this.dialog.ariaExpanded = "false";
737
+ this.dialog.classList.remove("expanded");
738
+ }
764
739
  }
765
740
  static Init() {
766
741
  Utils.onDocumentReady(() => {
767
742
  document.querySelectorAll(EXPANDING_CARD_SELECTOR).forEach((el) => {
768
- if (el && el["Expressive_ExpandingCard"] == void 0) {
743
+ if (el["Expressive_ExpandingCard"] == void 0) {
769
744
  this.init(el);
770
745
  }
771
746
  });
@@ -851,15 +826,8 @@ var _Menu = class _Menu extends Component {
851
826
  this.close();
852
827
  return;
853
828
  }
854
- const leaveToMenuContent = !!(this.menuEl && toEl && this.menuEl.contains(toEl));
855
- let leaveToActiveMenuTrigger = false;
856
- const closestTrigger = toEl.closest(".menu-trigger");
857
- if (closestTrigger && !!closestTrigger["Expressive_Menu"] && closestTrigger["Expressive_Menu"].isOpen) {
858
- leaveToActiveMenuTrigger = true;
859
- }
860
- if (!leaveToActiveMenuTrigger && !leaveToMenuContent) {
861
- this.close();
862
- }
829
+ const leaveToActiveMenuTrigger = toEl.closest(".menu-trigger")?.["Expressive_Menu"]?.isOpen;
830
+ if (!leaveToActiveMenuTrigger && !this.menuEl?.contains(toEl)) this.close();
863
831
  };
864
832
  this._handleDocumentClick = (e) => {
865
833
  const path = e.composedPath();
@@ -871,11 +839,7 @@ var _Menu = class _Menu extends Component {
871
839
  if (this.options.closeOnClick && inside && !this.isTouchMoving) {
872
840
  this.close();
873
841
  } else if (!inside) {
874
- this._schedule(() => {
875
- if (this.isOpen) {
876
- this.close();
877
- }
878
- }, 0);
842
+ this._schedule(() => this.close(), 0);
879
843
  }
880
844
  this.isTouchMoving = false;
881
845
  };
@@ -951,11 +915,10 @@ var _Menu = class _Menu extends Component {
951
915
  if (submenu) {
952
916
  e.preventDefault();
953
917
  const parentLi = submenu.parentElement;
954
- parentLi.classList.remove("open", "submenu-start");
955
- this._syncSubmenuAria(parentLi, false);
918
+ this._closeSubmenu(parentLi);
956
919
  this._focusRow(parentLi);
957
920
  }
958
- } else if (arrowUpOrDown && this.isOpen) {
921
+ } else if (arrowUpOrDown) {
959
922
  e.preventDefault();
960
923
  const direction = e.key === Utils.keys.ARROW_DOWN ? 1 : -1;
961
924
  const row = this._focusedRow(e);
@@ -974,7 +937,7 @@ var _Menu = class _Menu extends Component {
974
937
  item.classList.add("active");
975
938
  this._focusRow(item);
976
939
  }
977
- } else if ((e.key === Utils.keys.ENTER || e.key === SPACE) && this.isOpen) {
940
+ } else if (e.key === Utils.keys.ENTER || e.key === SPACE) {
978
941
  const li = this._focusedRow(e);
979
942
  e.preventDefault();
980
943
  if (li?.matches('.disabled, [aria-disabled="true"]')) return;
@@ -989,19 +952,18 @@ var _Menu = class _Menu extends Component {
989
952
  } else if (focusedElement instanceof HTMLElement) {
990
953
  focusedElement.click();
991
954
  }
992
- } else if (e.key === Utils.keys.ESC && this.isOpen) {
955
+ } else if (e.key === Utils.keys.ESC) {
993
956
  e.preventDefault();
994
957
  const openSub = this._containingSubmenu(e)?.parentElement ?? Array.from(this.menuEl.querySelectorAll("li.open")).reverse()[0];
995
958
  if (openSub) {
996
- openSub.classList.remove("open", "submenu-start");
997
- this._syncSubmenuAria(openSub, false);
959
+ this._closeSubmenu(openSub);
998
960
  this._focusRow(openSub);
999
961
  } else {
1000
962
  this.close();
1001
963
  }
1002
964
  }
1003
965
  const keyText = e.key.toLowerCase();
1004
- if (e.key.length === 1 && e.key !== SPACE && !e.ctrlKey && !e.metaKey && !e.altKey && !e.isComposing) {
966
+ if (e.key.length === 1 && e.key !== SPACE) {
1005
967
  this.filterQuery.push(keyText);
1006
968
  const string = this.filterQuery.join("");
1007
969
  const newOptionEl = Array.from(list.querySelectorAll(":scope > li")).find(
@@ -1226,10 +1188,7 @@ var _Menu = class _Menu extends Component {
1226
1188
  _toggleSubmenu(li) {
1227
1189
  const open = !li.classList.contains("open");
1228
1190
  li.parentElement?.querySelectorAll(":scope > li.open").forEach((other) => {
1229
- if (other !== li) {
1230
- other.classList.remove("open", "submenu-start");
1231
- this._syncSubmenuAria(other, false);
1232
- }
1191
+ if (other !== li) this._closeSubmenu(other);
1233
1192
  });
1234
1193
  li.classList.toggle("open", open);
1235
1194
  if (open) this._alignSubmenu(li);
@@ -1246,11 +1205,12 @@ var _Menu = class _Menu extends Component {
1246
1205
  const rect = menu.getBoundingClientRect();
1247
1206
  if (rect.left < 8 || rect.right > window.innerWidth - 8) li.classList.add("submenu-start");
1248
1207
  }
1208
+ _closeSubmenu(li) {
1209
+ li.classList.remove("open", "submenu-start");
1210
+ this._syncSubmenuAria(li, false);
1211
+ }
1249
1212
  _closeSubmenus() {
1250
- this.menuEl?.querySelectorAll("li.open").forEach((li) => {
1251
- li.classList.remove("open", "submenu-start");
1252
- this._syncSubmenuAria(li, false);
1253
- });
1213
+ this.menuEl?.querySelectorAll("li.open").forEach((li) => this._closeSubmenu(li));
1254
1214
  }
1255
1215
  _containingSubmenu(e) {
1256
1216
  const target = e.target;
@@ -1276,6 +1236,7 @@ var _Menu = class _Menu extends Component {
1276
1236
  item.scrollIntoView({ block: "nearest", inline: "nearest" });
1277
1237
  }
1278
1238
  _resetMenuStyles() {
1239
+ if (!this.menuEl) return;
1279
1240
  this.menuEl.style.display = "";
1280
1241
  this._resetMenuPositioningStyles();
1281
1242
  this.menuEl.style.transform = "";
@@ -1560,13 +1521,11 @@ var _defaults4 = {
1560
1521
  isMultiSelect: false,
1561
1522
  onSearch: (text, autocomplete) => {
1562
1523
  const normSearch = text.toLocaleLowerCase();
1563
- const data = autocomplete.options.data;
1564
1524
  autocomplete.setMenuItems(
1565
- data.filter(
1525
+ autocomplete.options.data.filter(
1566
1526
  (option) => option.id.toString().toLocaleLowerCase().includes(normSearch) || option.text?.toLocaleLowerCase().includes(normSearch)
1567
1527
  )
1568
1528
  );
1569
- autocomplete.options.data = data;
1570
1529
  },
1571
1530
  maxMenuHeight: "300px",
1572
1531
  allowUnsafeHTML: false,
@@ -1587,8 +1546,9 @@ var _Autocomplete = class _Autocomplete extends Component {
1587
1546
  this._handleInput = () => {
1588
1547
  this.count = 0;
1589
1548
  const actualValue = this.el.value.toLocaleLowerCase();
1590
- if (this.oldVal !== actualValue && this.el.matches(":focus-visible")) {
1591
- this.open();
1549
+ if (this.oldVal !== actualValue) {
1550
+ this._resetCurrentElementPosition();
1551
+ if (this.el.matches(":focus-visible") && (!this.menu.isOpen || actualValue.length < this.options.minLength)) this.open();
1592
1552
  }
1593
1553
  this._inputChangeDetection(actualValue);
1594
1554
  };
@@ -1598,17 +1558,13 @@ var _Autocomplete = class _Autocomplete extends Component {
1598
1558
  this._inputChangeDetection(actualValue);
1599
1559
  };
1600
1560
  this._inputChangeDetection = (value) => {
1601
- if (!this.options.isMultiSelect && this.selectedValues.length && this.el.value !== (this.selectedValues[0].text || String(this.selectedValues[0].id))) {
1602
- this.selectedValues = [];
1603
- }
1561
+ const deselected = !this.options.isMultiSelect && this.selectedValues.length > 0 && this.el.value !== (this.selectedValues[0].text || String(this.selectedValues[0].id));
1562
+ if (deselected) this.selectedValues = [];
1604
1563
  if (this.oldVal !== value) {
1605
1564
  this._setStatusLoading();
1606
1565
  this.options.onSearch(this.el.value, this);
1607
1566
  }
1608
- if (!this.options.isMultiSelect && this.el.value.length === 0) {
1609
- this.selectedValues = [];
1610
- this._triggerChanged();
1611
- }
1567
+ if (deselected) this._triggerChanged();
1612
1568
  this.oldVal = value;
1613
1569
  };
1614
1570
  this._handleInputKeydown = (e) => {
@@ -1629,6 +1585,10 @@ var _Autocomplete = class _Autocomplete extends Component {
1629
1585
  }
1630
1586
  if (e.key === Utils.keys.ARROW_UP || e.key === Utils.keys.ARROW_DOWN) {
1631
1587
  e.preventDefault();
1588
+ if (!this.menu.isOpen && this._openTimer === void 0) {
1589
+ this.open();
1590
+ return;
1591
+ }
1632
1592
  if (e.key === Utils.keys.ARROW_UP && this.activeIndex > 0) this.activeIndex--;
1633
1593
  if (e.key === Utils.keys.ARROW_DOWN && this.activeIndex < numItems - 1)
1634
1594
  this.activeIndex++;
@@ -1666,7 +1626,7 @@ var _Autocomplete = class _Autocomplete extends Component {
1666
1626
  this._resetAutocomplete();
1667
1627
  if (inputText.length >= this.options.minLength) {
1668
1628
  this._renderMenu();
1669
- this._announce(this.menuItems.length ? this.options.i18n.results(this.menuItems.length) : this.options.i18n.noResults);
1629
+ this._announce(this._resultsMessage(this.menuItems.length));
1670
1630
  }
1671
1631
  if (!this.menu.isOpen) {
1672
1632
  if (this._openTimer !== void 0) clearTimeout(this._openTimer);
@@ -1828,6 +1788,7 @@ var _Autocomplete = class _Autocomplete extends Component {
1828
1788
  const label = this.el.parentElement.querySelector("label");
1829
1789
  if (label) this.el.after(label);
1830
1790
  this.el.removeEventListener("click", this.menu._handleClick);
1791
+ this.el.removeEventListener("keydown", this.menu._handleTriggerKeydown);
1831
1792
  if (!this.options.isMultiSelect) this._refreshInputText();
1832
1793
  if (this.el.value) this.selectOption(this.el.value);
1833
1794
  const div = document.createElement("div");
@@ -1859,7 +1820,7 @@ var _Autocomplete = class _Autocomplete extends Component {
1859
1820
  this._pointerDown = false;
1860
1821
  }
1861
1822
  _highlightPartialText(input, label) {
1862
- const start = label.toLocaleLowerCase().indexOf("" + input.toLocaleLowerCase());
1823
+ const start = label.toLocaleLowerCase().indexOf(input.toLocaleLowerCase());
1863
1824
  const end = start + input.length - 1;
1864
1825
  if (start == -1 || end == -1) {
1865
1826
  return [label, "", ""];
@@ -1898,11 +1859,24 @@ var _Autocomplete = class _Autocomplete extends Component {
1898
1859
  item.appendChild(img);
1899
1860
  }
1900
1861
  const inputText = this.el.value.toLocaleLowerCase();
1901
- const parts = this._highlightPartialText(inputText, (entry.text || entry.id).toString());
1862
+ const label = (entry.text || entry.id).toString();
1863
+ const parts = this._highlightPartialText(inputText, label);
1902
1864
  const div = document.createElement("div");
1903
1865
  div.setAttribute("style", "line-height:1.2;font-weight:500;");
1904
1866
  if (this.options.allowUnsafeHTML) {
1905
- div.innerHTML = parts[0] + '<span class="highlight">' + parts[1] + "</span>" + parts[2];
1867
+ div.innerHTML = label;
1868
+ const walker = document.createTreeWalker(div, NodeFilter.SHOW_TEXT);
1869
+ for (let node = walker.nextNode(); node; node = walker.nextNode()) {
1870
+ const [before, match] = this._highlightPartialText(inputText, node.data);
1871
+ if (!match) continue;
1872
+ const matched = node.splitText(before.length);
1873
+ matched.splitText(match.length);
1874
+ const highlight = document.createElement("span");
1875
+ highlight.classList.add("highlight");
1876
+ matched.replaceWith(highlight);
1877
+ highlight.append(matched);
1878
+ break;
1879
+ }
1906
1880
  } else {
1907
1881
  div.appendChild(document.createTextNode(parts[0]));
1908
1882
  if (parts[1]) {
@@ -1917,7 +1891,7 @@ var _Autocomplete = class _Autocomplete extends Component {
1917
1891
  itemText.classList.add("item-text");
1918
1892
  itemText.setAttribute("style", "padding:5px;overflow:hidden;");
1919
1893
  item.appendChild(itemText);
1920
- item.querySelector(".item-text").appendChild(div);
1894
+ itemText.appendChild(div);
1921
1895
  if (typeof entry.description === "string" || typeof entry.description === "number" && !isNaN(entry.description)) {
1922
1896
  const description = document.createElement("small");
1923
1897
  description.setAttribute(
@@ -1925,7 +1899,7 @@ var _Autocomplete = class _Autocomplete extends Component {
1925
1899
  "line-height:1.3;color:grey;white-space:nowrap;text-overflow:ellipsis;display:block;width:90%;overflow:hidden;"
1926
1900
  );
1927
1901
  description.innerText = entry.description;
1928
- item.querySelector(".item-text").appendChild(description);
1902
+ itemText.appendChild(description);
1929
1903
  }
1930
1904
  const getGridConfig = () => {
1931
1905
  if (this.options.isMultiSelect) {
@@ -1958,6 +1932,9 @@ var _Autocomplete = class _Autocomplete extends Component {
1958
1932
  const text = this.el.matches(":focus") && this.el.value.length >= this.options.minLength ? message : "";
1959
1933
  if (this._announcer.textContent !== text) this._announcer.textContent = text;
1960
1934
  }
1935
+ _resultsMessage(count) {
1936
+ return count ? this.options.i18n.results(count) : this.options.i18n.noResults;
1937
+ }
1961
1938
  _updateSelectedInfo() {
1962
1939
  const statusElement = this._statusInfo;
1963
1940
  if (statusElement) {
@@ -1987,21 +1964,20 @@ var _Autocomplete = class _Autocomplete extends Component {
1987
1964
  if (this.el["Expressive_Autocomplete"] !== this) return;
1988
1965
  const resultCount = menuItems.length;
1989
1966
  this.menuItems = menuItems;
1990
- this.options.data = menuItems;
1991
1967
  if (selected) {
1992
1968
  this.selectedValues = this.menuItems.filter(
1993
1969
  (item) => !(selected.indexOf(item.id) === -1)
1994
1970
  );
1995
1971
  }
1996
1972
  if (this.options.isMultiSelect) {
1997
- this._renderMenu();
1973
+ if (!open) this._renderMenu();
1998
1974
  } else {
1999
1975
  this._refreshInputText();
2000
1976
  }
2001
1977
  if (open) this.open();
2002
1978
  this._updateSelectedInfo();
2003
- this._announce(open ? resultCount ? this.options.i18n.results(resultCount) : this.options.i18n.noResults : "");
2004
- this._triggerChanged();
1979
+ this._announce(open ? this._resultsMessage(resultCount) : "");
1980
+ if (selected) this._triggerChanged();
2005
1981
  }
2006
1982
  /**
2007
1983
  * Select a specific autocomplete option via id-property.
@@ -2011,9 +1987,8 @@ var _Autocomplete = class _Autocomplete extends Component {
2011
1987
  const entry = this.menuItems.find((item) => item.id == id);
2012
1988
  if (!entry) return;
2013
1989
  if (this.options.isMultiSelect) {
2014
- if (!(this.selectedValues.filter(
2015
- (selectedEntry) => selectedEntry.id === entry.id
2016
- ).length >= 1)) this.selectedValues.push(entry);
1990
+ if (!this.selectedValues.some((selectedEntry) => selectedEntry.id === entry.id))
1991
+ this.selectedValues.push(entry);
2017
1992
  else this.selectedValues = this.selectedValues.filter(
2018
1993
  (selectedEntry) => selectedEntry.id !== entry.id
2019
1994
  );
@@ -2086,7 +2061,7 @@ var _Chips = class _Chips extends Component {
2086
2061
  return;
2087
2062
  }
2088
2063
  e.preventDefault();
2089
- if (!this.hasAutocomplete || this.hasAutocomplete && !this.options.autocompleteOnly) {
2064
+ if (!this.hasAutocomplete || !this.options.autocompleteOnly) {
2090
2065
  this.addChip({ id: this._input.value });
2091
2066
  }
2092
2067
  this._input.value = "";
@@ -2179,9 +2154,8 @@ var _Chips = class _Chips extends Component {
2179
2154
  static _handleChipsKeydown(e) {
2180
2155
  _Chips._keydown = true;
2181
2156
  const chips = e.target.closest(".chips");
2182
- const chipsKeydown = e.target && chips;
2183
2157
  const tag = e.target.tagName;
2184
- if (tag === "INPUT" || tag === "TEXTAREA" || !chipsKeydown) return;
2158
+ if (tag === "INPUT" || tag === "TEXTAREA" || !chips) return;
2185
2159
  const currChips = chips["Expressive_Chips"];
2186
2160
  if (!currChips) return;
2187
2161
  if (e.key === Utils.keys.BACKSPACE || e.key === Utils.keys.DELETE) {
@@ -2281,9 +2255,9 @@ var _Chips = class _Chips extends Component {
2281
2255
  }
2282
2256
  _setPlaceholder() {
2283
2257
  if (!this._input) return;
2284
- if (this.chipsData !== void 0 && !this.chipsData.length && this.options.placeholder) {
2258
+ if (!this.chipsData.length && this.options.placeholder) {
2285
2259
  this._input.placeholder = this.options.placeholder;
2286
- } else if ((this.chipsData === void 0 || !!this.chipsData.length) && this.options.secondaryPlaceholder) {
2260
+ } else if (this.chipsData.length && this.options.secondaryPlaceholder) {
2287
2261
  this._input.placeholder = this.options.secondaryPlaceholder;
2288
2262
  }
2289
2263
  }
@@ -2392,12 +2366,10 @@ var Slider = class _Slider extends Component {
2392
2366
  this._sync();
2393
2367
  this.thumb.classList.add("active");
2394
2368
  };
2395
- this._handleRangeInputOrMove = (e) => {
2396
- if (e.type === "input" || this._pointerDown) {
2397
- this._clampDual();
2398
- this._sync();
2399
- this.thumb.classList.add("active");
2400
- }
2369
+ this._handleRangeInput = () => {
2370
+ this._clampDual();
2371
+ this._sync();
2372
+ this.thumb.classList.add("active");
2401
2373
  };
2402
2374
  this._handleRangePointerUp = (e) => {
2403
2375
  if (!e.isPrimary) return;
@@ -2461,8 +2433,7 @@ var Slider = class _Slider extends Component {
2461
2433
  _setupEventHandlers() {
2462
2434
  this.el.addEventListener("change", this._handleRangeChange);
2463
2435
  this.el.addEventListener("pointerdown", this._handleRangePointerDown);
2464
- this.el.addEventListener("input", this._handleRangeInputOrMove);
2465
- this.el.addEventListener("pointermove", this._handleRangeInputOrMove, { passive: true });
2436
+ this.el.addEventListener("input", this._handleRangeInput);
2466
2437
  this.el.addEventListener("pointerup", this._handleRangePointerUp);
2467
2438
  this.el.addEventListener("pointercancel", this._handleRangePointerUp);
2468
2439
  this.el.addEventListener("blur", this._handleRangeRelease);
@@ -2471,8 +2442,7 @@ var Slider = class _Slider extends Component {
2471
2442
  _removeEventHandlers() {
2472
2443
  this.el.removeEventListener("change", this._handleRangeChange);
2473
2444
  this.el.removeEventListener("pointerdown", this._handleRangePointerDown);
2474
- this.el.removeEventListener("input", this._handleRangeInputOrMove);
2475
- this.el.removeEventListener("pointermove", this._handleRangeInputOrMove);
2445
+ this.el.removeEventListener("input", this._handleRangeInput);
2476
2446
  this.el.removeEventListener("pointerup", this._handleRangePointerUp);
2477
2447
  this.el.removeEventListener("pointercancel", this._handleRangePointerUp);
2478
2448
  this.el.removeEventListener("blur", this._handleRangeRelease);
@@ -2504,10 +2474,13 @@ var Slider = class _Slider extends Component {
2504
2474
  if (this.el === start && +start.value > +end.value) start.value = end.value;
2505
2475
  if (this.el === end && +end.value < +start.value) end.value = start.value;
2506
2476
  }
2507
- _fraction(el) {
2477
+ /** The input's range, defaulting like the browser does: 0 to 100. */
2478
+ _bounds(el) {
2508
2479
  const parsedMax = parseFloat(el.max);
2509
- const max = Number.isNaN(parsedMax) ? 100 : parsedMax;
2510
- const min = parseFloat(el.min) || 0;
2480
+ return { max: Number.isNaN(parsedMax) ? 100 : parsedMax, min: parseFloat(el.min) || 0 };
2481
+ }
2482
+ _fraction(el) {
2483
+ const { max, min } = this._bounds(el);
2511
2484
  const val = parseFloat(el.value) || 0;
2512
2485
  return max === min ? 0 : (val - min) / (max - min);
2513
2486
  }
@@ -2536,9 +2509,7 @@ var Slider = class _Slider extends Component {
2536
2509
  this._set(host, "--md-comp-slider-end-position", `${handle / 2 + Math.max(...nums) * (length - handle)}px`);
2537
2510
  }
2538
2511
  if (host?.classList.contains("stops")) {
2539
- const parsedMax = parseFloat(this.el.max);
2540
- const max = Number.isNaN(parsedMax) ? 100 : parsedMax;
2541
- const min = parseFloat(this.el.min) || 0;
2512
+ const { max, min } = this._bounds(this.el);
2542
2513
  const step = parseFloat(this.el.step);
2543
2514
  const stops = step > 0 && Number.isFinite(step) && max > min;
2544
2515
  this._set(host, "--md-comp-slider-stop-count", stops ? String(Math.floor((max - min) / step + 1e-9) + 1) : "");
@@ -2562,7 +2533,7 @@ var Slider = class _Slider extends Component {
2562
2533
  */
2563
2534
  static Init() {
2564
2535
  Utils.onDocumentReady(() => {
2565
- _Slider.init(document.querySelectorAll("input[type=range]"), {});
2536
+ _Slider.init(document.querySelectorAll("input[type=range]"));
2566
2537
  });
2567
2538
  }
2568
2539
  };
@@ -2577,16 +2548,8 @@ var _Dialogs = class _Dialogs {
2577
2548
  });
2578
2549
  }
2579
2550
  static _onPointerDown(event) {
2580
- if (!_Dialogs._isPrimaryPress(event)) {
2581
- _Dialogs._down = null;
2582
- return;
2583
- }
2584
- const dialog = _Dialogs._backdropDialog(event);
2585
- if (!dialog || !_Dialogs._lightDismissible(dialog) || !_Dialogs._outside(event, dialog)) {
2586
- _Dialogs._down = null;
2587
- return;
2588
- }
2589
- _Dialogs._down = { dialog, pointerId: event.pointerId };
2551
+ const dialog = _Dialogs._isPrimaryPress(event) ? _Dialogs._backdropDialog(event) : null;
2552
+ _Dialogs._down = dialog && _Dialogs._lightDismissible(dialog) && _Dialogs._outside(event, dialog) ? { dialog, pointerId: event.pointerId } : null;
2590
2553
  }
2591
2554
  static _onPointerUp(event) {
2592
2555
  const started = _Dialogs._down;
@@ -2640,7 +2603,10 @@ var DISMISS_DISTANCE = 96;
2640
2603
  var DISMISS_VELOCITY = 0.5;
2641
2604
  var FLICK_TIMEOUT = 100;
2642
2605
  var DRAG_SLOP = 4;
2606
+ var installed = /* @__PURE__ */ new Set();
2643
2607
  function installSheetDrag(config) {
2608
+ if (installed.has(config.selector)) return;
2609
+ installed.add(config.selector);
2644
2610
  const coord = (event) => config.axis === "x" ? event.clientX : event.clientY;
2645
2611
  let observer;
2646
2612
  let drag = null;
@@ -2659,21 +2625,15 @@ function installSheetDrag(config) {
2659
2625
  onCancel();
2660
2626
  config.onPress?.();
2661
2627
  const dialog = sheetFor(event.target);
2662
- if (!dialog?.open) {
2663
- drag = null;
2664
- return;
2665
- }
2666
- if (!config.inHandle(event, dialog)) {
2667
- drag = null;
2668
- return;
2669
- }
2628
+ if (!dialog?.open || !config.inHandle(event, dialog)) return;
2670
2629
  dialog.style.transition = "none";
2630
+ const at = coord(event);
2671
2631
  drag = {
2672
2632
  dialog,
2673
2633
  pointerId: event.pointerId,
2674
2634
  direction: config.direction(dialog),
2675
- start: coord(event),
2676
- last: coord(event),
2635
+ start: at,
2636
+ last: at,
2677
2637
  lastT: Date.now(),
2678
2638
  velocity: 0,
2679
2639
  shift: 0
@@ -2686,12 +2646,13 @@ function installSheetDrag(config) {
2686
2646
  onCancel();
2687
2647
  return;
2688
2648
  }
2689
- const delta = coord(event) - drag.start;
2649
+ const at = coord(event);
2650
+ const delta = at - drag.start;
2690
2651
  drag.shift = drag.direction === 1 ? Math.max(0, delta) : Math.min(0, delta);
2691
- if (coord(event) !== drag.last) {
2652
+ if (at !== drag.last) {
2692
2653
  const now = Date.now();
2693
- drag.velocity = (coord(event) - drag.last) / Math.max(1, now - drag.lastT);
2694
- drag.last = coord(event);
2654
+ drag.velocity = (at - drag.last) / Math.max(1, now - drag.lastT);
2655
+ drag.last = at;
2695
2656
  drag.lastT = now;
2696
2657
  }
2697
2658
  drag.dialog.style.setProperty(config.property, `${drag.shift}px`);
@@ -2801,7 +2762,7 @@ var SideSheets = class {
2801
2762
  };
2802
2763
 
2803
2764
  // src/ts/behaviors/forms.ts
2804
- var Forms = class _Forms {
2765
+ var _Forms = class _Forms {
2805
2766
  /**
2806
2767
  * Checks if the label has validation and apply
2807
2768
  * the correct class and styles
@@ -2818,7 +2779,7 @@ var Forms = class _Forms {
2818
2779
  if (len === 0 && textfield.validity.badInput === false && !textfield.required && textfield.classList.contains("validate")) {
2819
2780
  textfield.classList.remove("invalid");
2820
2781
  } else if (textfield.classList.contains("validate")) {
2821
- if (textfield.validity.valid && hasLength && len <= lenAttr || textfield.validity.valid && !hasLength) {
2782
+ if (textfield.validity.valid && (!hasLength || len <= lenAttr)) {
2822
2783
  textfield.classList.remove("invalid");
2823
2784
  } else {
2824
2785
  textfield.classList.add("invalid");
@@ -2843,17 +2804,22 @@ var Forms = class _Forms {
2843
2804
  const contentHeight = textarea.scrollHeight + borders;
2844
2805
  textarea.style.height = Math.max(originalHeight, contentHeight) + "px";
2845
2806
  }
2807
+ /**
2808
+ * Safe to call more than once: the root entry calls it on import, and a page
2809
+ * that also loads the modular entry may call it again.
2810
+ */
2846
2811
  static Init() {
2812
+ if (_Forms._initialized) return;
2813
+ _Forms._initialized = true;
2847
2814
  Utils.onDocumentReady(() => {
2848
2815
  document.addEventListener("change", (e) => {
2849
2816
  const target = e.target;
2850
- if (target instanceof HTMLInputElement && target.type === "file") {
2817
+ if (!(target instanceof HTMLInputElement)) return;
2818
+ if (target.type === "file") {
2851
2819
  const zone = target.closest(".drop-zone");
2852
2820
  if (zone) _Forms.listDropZoneFiles(zone, target);
2853
2821
  }
2854
- if (target instanceof HTMLInputElement) {
2855
- _Forms.validateField(target);
2856
- }
2822
+ _Forms.validateField(target);
2857
2823
  });
2858
2824
  document.addEventListener("keyup", (e) => {
2859
2825
  const target = e.target;
@@ -2958,18 +2924,15 @@ var Forms = class _Forms {
2958
2924
  fileInput.addEventListener("change", () => {
2959
2925
  const fileField = fileInput.closest(".file-field");
2960
2926
  const pathInput = fileField.querySelector("input.file-path");
2961
- const files = fileInput.files;
2962
- const filenames = [];
2963
- for (let i = 0; i < files.length; i++) {
2964
- filenames.push(files[i].name);
2965
- }
2966
- pathInput.value = filenames.join(", ");
2927
+ pathInput.value = Array.from(fileInput.files, (f) => f.name).join(", ");
2967
2928
  pathInput.dispatchEvent(
2968
2929
  new Event("change", { bubbles: true, cancelable: true, composed: true })
2969
2930
  );
2970
2931
  });
2971
2932
  }
2972
2933
  };
2934
+ _Forms._initialized = false;
2935
+ var Forms = _Forms;
2973
2936
 
2974
2937
  // src/ts/components/appBar.ts
2975
2938
  var _defaults7 = {};
@@ -3043,8 +3006,7 @@ var AppBar = class _AppBar extends Component {
3043
3006
  this._input = this.el.querySelector('input[type="search"]');
3044
3007
  if (!this._input) return;
3045
3008
  const id = this._input.getAttribute("aria-controls");
3046
- if (id) this._view = document.getElementById(id);
3047
- if (!this._view) this._view = this.el.querySelector(".search-view");
3009
+ this._view = id && document.getElementById(id) || this.el.querySelector(".search-view");
3048
3010
  if (!this._view) return;
3049
3011
  this._input.addEventListener("focus", this._onSearchFocus);
3050
3012
  this._input.addEventListener("click", this._onSearchFocus);
@@ -3372,6 +3334,7 @@ var _defaults10 = {
3372
3334
  slide: "Slide"
3373
3335
  }
3374
3336
  };
3337
+ var naturallyFocusable = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
3375
3338
  var _Carousel = class _Carousel extends Component {
3376
3339
  constructor(el, options) {
3377
3340
  super(el, options, _Carousel);
@@ -3462,6 +3425,7 @@ var _Carousel = class _Carousel extends Component {
3462
3425
  this._dragStartX = e.clientX;
3463
3426
  this._dragStartY = e.clientY;
3464
3427
  this._dragStartScroll = this._vertical ? this._scroller.scrollTop : this._scroller.scrollLeft;
3428
+ this._setDragListeners(true);
3465
3429
  };
3466
3430
  this._handleTrackPointerMove = (e) => {
3467
3431
  if (!this.pressed || e.pointerId !== this._dragPointerId) return;
@@ -3486,6 +3450,7 @@ var _Carousel = class _Carousel extends Component {
3486
3450
  if (!this.pressed || e.pointerId !== this._dragPointerId) return;
3487
3451
  this.pressed = false;
3488
3452
  this._dragPointerId = null;
3453
+ this._setDragListeners(false);
3489
3454
  this.el.classList.remove("dragging");
3490
3455
  try {
3491
3456
  this._scroller.releasePointerCapture(e.pointerId);
@@ -3552,9 +3517,8 @@ var _Carousel = class _Carousel extends Component {
3552
3517
  if (this._trackRaf !== null) return;
3553
3518
  this._trackRaf = requestAnimationFrame(() => {
3554
3519
  this._trackRaf = null;
3520
+ const index = this._ignoreScroll ? this.center : this._nearestIndex();
3555
3521
  this._updateParallax();
3556
- if (this._ignoreScroll) return;
3557
- const index = this._nearestIndex();
3558
3522
  if (index !== this.center) this._syncActive(index, this.dragged);
3559
3523
  });
3560
3524
  };
@@ -3567,6 +3531,7 @@ var _Carousel = class _Carousel extends Component {
3567
3531
  };
3568
3532
  this._finishScroll = () => {
3569
3533
  this._ignoreScroll = false;
3534
+ this._scroller.style.scrollSnapType = "";
3570
3535
  clearTimeout(this._scrollEndTimeout);
3571
3536
  this._scroller.removeEventListener("scrollend", this._handleScrollEnd);
3572
3537
  };
@@ -3671,7 +3636,6 @@ var _Carousel = class _Carousel extends Component {
3671
3636
  this.el.setAttribute("aria-roledescription", "carousel");
3672
3637
  this._generatedContainerDescription = true;
3673
3638
  }
3674
- const naturallyFocusable = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
3675
3639
  this.images.forEach((item, index) => {
3676
3640
  if (!item.hasAttribute("aria-roledescription")) {
3677
3641
  item.setAttribute("aria-roledescription", "slide");
@@ -3704,10 +3668,6 @@ var _Carousel = class _Carousel extends Component {
3704
3668
  const button = document.createElement("button");
3705
3669
  button.type = "button";
3706
3670
  button.classList.add("indicator-item");
3707
- if (i === 0) {
3708
- button.classList.add("active");
3709
- button.setAttribute("aria-current", "true");
3710
- }
3711
3671
  button.setAttribute("aria-label", `${this.options.i18n.slide} ${i + 1}`);
3712
3672
  this._indicators.appendChild(button);
3713
3673
  });
@@ -3746,9 +3706,6 @@ var _Carousel = class _Carousel extends Component {
3746
3706
  });
3747
3707
  this._scroller.addEventListener("pointerdown", this._handleTrackPointerDown);
3748
3708
  this._scroller.addEventListener("wheel", this._handleNativeScroll, { passive: true });
3749
- document.addEventListener("pointermove", this._handleTrackPointerMove);
3750
- document.addEventListener("pointerup", this._handleTrackPointerUp);
3751
- document.addEventListener("pointercancel", this._handleTrackPointerUp);
3752
3709
  this._scroller.addEventListener("click", this._handleTrackClick, true);
3753
3710
  this._scroller.addEventListener("dragstart", this._handleTrackDragStart);
3754
3711
  this._scroller.addEventListener("transitionend", this._handleItemResize);
@@ -3767,9 +3724,7 @@ var _Carousel = class _Carousel extends Component {
3767
3724
  this._scroller.removeEventListener("scroll", this._handleTrackScroll);
3768
3725
  this._scroller.removeEventListener("pointerdown", this._handleTrackPointerDown);
3769
3726
  this._scroller.removeEventListener("wheel", this._handleNativeScroll);
3770
- document.removeEventListener("pointermove", this._handleTrackPointerMove);
3771
- document.removeEventListener("pointerup", this._handleTrackPointerUp);
3772
- document.removeEventListener("pointercancel", this._handleTrackPointerUp);
3727
+ this._setDragListeners(false);
3773
3728
  this._scroller.removeEventListener("click", this._handleTrackClick, true);
3774
3729
  this._scroller.removeEventListener("dragstart", this._handleTrackDragStart);
3775
3730
  this._scroller.removeEventListener("transitionend", this._handleItemResize);
@@ -3836,6 +3791,13 @@ var _Carousel = class _Carousel extends Component {
3836
3791
  this._autoAdvanceTimer = null;
3837
3792
  }
3838
3793
  }
3794
+ /** The document only hears from a carousel while a mouse press is down on its track. */
3795
+ _setDragListeners(on) {
3796
+ const method = on ? "addEventListener" : "removeEventListener";
3797
+ document[method]("pointermove", this._handleTrackPointerMove);
3798
+ document[method]("pointerup", this._handleTrackPointerUp);
3799
+ document[method]("pointercancel", this._handleTrackPointerUp);
3800
+ }
3839
3801
  _paintIndicators(center) {
3840
3802
  if (!this.showIndicators || !this._indicators) return;
3841
3803
  const pos = (center % this.count + this.count) % this.count;
@@ -3862,40 +3824,31 @@ var _Carousel = class _Carousel extends Component {
3862
3824
  }
3863
3825
  }
3864
3826
  _syncLayoutRoles(index) {
3865
- const setSize = (item, size) => {
3866
- if (this._authoredItemSizes.has(item)) return;
3867
- item.setAttribute("data-carousel-size", size);
3868
- this._generatedItemSizes.add(item);
3827
+ const sizes = this.images.map(() => "large");
3828
+ const setSize = (i, size) => {
3829
+ if (this.images[i]) sizes[i] = size;
3869
3830
  };
3870
- this.images.forEach((item) => setSize(item, "large"));
3871
3831
  if (this.el.classList.contains("flat") || this.el.classList.contains("uncontained") || this.el.classList.contains("full-screen") && this._vertical) {
3872
- return;
3873
- }
3874
- if (this.el.classList.contains("hero") || this.el.classList.contains("full-screen-horizontal")) {
3875
- const next = this.images[index + 1];
3876
- if (next) setSize(next, "small");
3877
- if (this.el.classList.contains("center-aligned")) {
3878
- const previous = this.images[index - 1];
3879
- if (previous) setSize(previous, "small");
3880
- }
3881
- return;
3882
- }
3883
- const width = this.el.clientWidth;
3884
- const desiredLargeCount = width >= 1600 ? 4 : width >= 1200 ? 3 : width >= 600 ? 2 : 1;
3885
- const largeCount = Math.min(desiredLargeCount, Math.max(1, this.count - 2));
3886
- this.el.classList.remove("multi-wide", "multi-large", "multi-extra-large");
3887
- if (largeCount === 2) this.el.classList.add("multi-wide");
3888
- else if (largeCount === 3) this.el.classList.add("multi-large");
3889
- else if (largeCount >= 4) this.el.classList.add("multi-extra-large");
3890
- this._generatedWideLayout = this._generatedWideLayout || largeCount > 1;
3891
- for (let offset = 1; offset < largeCount; offset += 1) {
3892
- const item = this.images[index + offset];
3893
- if (item) setSize(item, "large");
3894
- }
3895
- const medium = this.images[index + largeCount];
3896
- const small = this.images[index + largeCount + 1];
3897
- if (medium) setSize(medium, "medium");
3898
- if (small) setSize(small, "small");
3832
+ } else if (this.el.classList.contains("hero") || this.el.classList.contains("full-screen-horizontal")) {
3833
+ setSize(index + 1, "small");
3834
+ if (this.el.classList.contains("center-aligned")) setSize(index - 1, "small");
3835
+ } else {
3836
+ const width = this.el.clientWidth;
3837
+ const desiredLargeCount = width >= 1600 ? 4 : width >= 1200 ? 3 : width >= 600 ? 2 : 1;
3838
+ const largeCount = Math.min(desiredLargeCount, Math.max(1, this.count - 2));
3839
+ this.el.classList.remove("multi-wide", "multi-large", "multi-extra-large");
3840
+ if (largeCount === 2) this.el.classList.add("multi-wide");
3841
+ else if (largeCount === 3) this.el.classList.add("multi-large");
3842
+ else if (largeCount >= 4) this.el.classList.add("multi-extra-large");
3843
+ this._generatedWideLayout = this._generatedWideLayout || largeCount > 1;
3844
+ setSize(index + largeCount, "medium");
3845
+ setSize(index + largeCount + 1, "small");
3846
+ }
3847
+ this.images.forEach((item, i) => {
3848
+ if (this._authoredItemSizes.has(item)) return;
3849
+ item.setAttribute("data-carousel-size", sizes[i]);
3850
+ this._generatedItemSizes.add(item);
3851
+ });
3899
3852
  }
3900
3853
  _syncAdaptiveMode() {
3901
3854
  if (!this.el.classList.contains("full-screen")) return;
@@ -3912,15 +3865,11 @@ var _Carousel = class _Carousel extends Component {
3912
3865
  _focusItem(index) {
3913
3866
  const item = this.images[index];
3914
3867
  if (!item) return;
3915
- const focusable = item.matches(
3916
- 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
3917
- ) ? item : item.querySelector(
3918
- 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
3919
- );
3868
+ const focusable = item.matches(naturallyFocusable) ? item : item.querySelector(naturallyFocusable);
3920
3869
  (focusable ?? item).focus({ preventScroll: true });
3921
3870
  }
3922
3871
  _updateParallax() {
3923
- if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
3872
+ if (this._motion.matches) {
3924
3873
  this.images.forEach(
3925
3874
  (item) => item.style.setProperty("--md-comp-carousel-item-parallax", "0px")
3926
3875
  );
@@ -3929,8 +3878,9 @@ var _Carousel = class _Carousel extends Component {
3929
3878
  const scrollerRect = this._scroller.getBoundingClientRect();
3930
3879
  const viewportCenter = this._vertical ? scrollerRect.top + scrollerRect.height / 2 : scrollerRect.left + scrollerRect.width / 2;
3931
3880
  const viewportSize = Math.max(1, this._vertical ? scrollerRect.height : scrollerRect.width);
3932
- this.images.forEach((item) => {
3933
- const rect = item.getBoundingClientRect();
3881
+ const rects = this.images.map((item) => item.getBoundingClientRect());
3882
+ this.images.forEach((item, i) => {
3883
+ const rect = rects[i];
3934
3884
  const itemCenter = this._vertical ? rect.top + rect.height / 2 : rect.left + rect.width / 2;
3935
3885
  const progress = Math.max(-1, Math.min(1, (itemCenter - viewportCenter) / viewportSize));
3936
3886
  item.style.setProperty("--md-comp-carousel-item-parallax", `${progress * -24}px`);
@@ -3983,6 +3933,7 @@ var _Carousel = class _Carousel extends Component {
3983
3933
  const left = centered ? el.offsetLeft - (this._scroller.clientWidth - el.offsetWidth) / 2 : style.direction === "rtl" ? el.offsetLeft + el.offsetWidth - this._scroller.clientWidth + inlinePadding : el.offsetLeft - inlinePadding;
3984
3934
  const top = el.offsetTop - blockPadding;
3985
3935
  this._ignoreScroll = true;
3936
+ this._scroller.style.scrollSnapType = "none";
3986
3937
  this._scroller.scrollTo({
3987
3938
  left: this._vertical ? 0 : left,
3988
3939
  top: this._vertical ? top : 0,
@@ -4011,13 +3962,13 @@ var _Carousel = class _Carousel extends Component {
4011
3962
  this._syncAutoAdvance();
4012
3963
  }
4013
3964
  next(n = 1) {
4014
- if (n === void 0 || isNaN(n)) n = 1;
3965
+ if (isNaN(n)) n = 1;
4015
3966
  const index = this.center + n;
4016
3967
  if (index >= this.count || index < 0) return;
4017
3968
  this._cycleTo(index);
4018
3969
  }
4019
3970
  prev(n = 1) {
4020
- if (n === void 0 || isNaN(n)) n = 1;
3971
+ if (isNaN(n)) n = 1;
4021
3972
  const index = this.center - n;
4022
3973
  if (index >= this.count || index < 0) return;
4023
3974
  this._cycleTo(index);
@@ -4112,8 +4063,484 @@ var CharacterCounter = class _CharacterCounter extends Component {
4112
4063
  }
4113
4064
  };
4114
4065
 
4115
- // src/ts/components/commandPalette.ts
4066
+ // src/ts/components/confetti.ts
4116
4067
  var _defaults12 = {
4068
+ particleCount: 50,
4069
+ angle: 90,
4070
+ spread: 45,
4071
+ startVelocity: 45,
4072
+ decay: 0.9,
4073
+ gravity: 1,
4074
+ drift: 0,
4075
+ ticks: 200,
4076
+ origin: { x: 0.5, y: 0.5 },
4077
+ colors: [],
4078
+ shapes: ["square", "circle"],
4079
+ scalar: 1,
4080
+ manualStart: false
4081
+ };
4082
+ var THEME_COLORS = ["primary", "secondary", "tertiary", "primary-container", "secondary-container", "tertiary-container"];
4083
+ var FALLBACK_COLORS = ["#26ccff", "#a25afd", "#ff5e7e", "#88ff5a", "#fcff42", "#ffa62d", "#ff36ff"];
4084
+ var RAD = Math.PI / 180;
4085
+ var scenes = /* @__PURE__ */ new Map();
4086
+ var overlay = null;
4087
+ var Confetti = class _Confetti extends Component {
4088
+ constructor(el, options) {
4089
+ super(el, options, _Confetti);
4090
+ this._onClick = () => {
4091
+ this.fire();
4092
+ };
4093
+ this.el["Expressive_Confetti"] = this;
4094
+ this.options = { ..._Confetti.defaults, ...options };
4095
+ if (!(el instanceof HTMLCanvasElement)) el.addEventListener("click", this._onClick);
4096
+ else if (!this.options.manualStart) this.fire();
4097
+ }
4098
+ static get defaults() {
4099
+ return _defaults12;
4100
+ }
4101
+ static init(els, options = {}) {
4102
+ return super.init(els, options, _Confetti);
4103
+ }
4104
+ static getInstance(el) {
4105
+ return el["Expressive_Confetti"];
4106
+ }
4107
+ /**
4108
+ * Bursts over the whole viewport. Resolves when the last piece is gone.
4109
+ */
4110
+ static fire(options = {}) {
4111
+ return burst(viewportCanvas, document.body, { ..._Confetti.defaults, ...options });
4112
+ }
4113
+ /**
4114
+ * Bursts on this canvas, or from this element's center over the viewport.
4115
+ * Resolves when the last piece is gone.
4116
+ */
4117
+ fire(options = {}) {
4118
+ const merged = { ...this.options, ...options };
4119
+ if (this.el instanceof HTMLCanvasElement) {
4120
+ const canvas = this.el;
4121
+ return burst(() => canvas, canvas.parentElement ?? document.body, merged);
4122
+ }
4123
+ const r = this.el.getBoundingClientRect();
4124
+ merged.origin = { x: (r.left + r.width / 2) / innerWidth, y: (r.top + r.height / 2) / innerHeight };
4125
+ return burst(viewportCanvas, this.el.parentElement ?? document.body, merged);
4126
+ }
4127
+ destroy() {
4128
+ this.el.removeEventListener("click", this._onClick);
4129
+ if (this.el instanceof HTMLCanvasElement) stop(this.el);
4130
+ this.el["Expressive_Confetti"] = void 0;
4131
+ }
4132
+ };
4133
+ function burst(getCanvas, themed, o) {
4134
+ if (typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches) return Promise.resolve();
4135
+ const canvas = getCanvas();
4136
+ let scene = scenes.get(canvas);
4137
+ if (!scene) {
4138
+ const ctx = canvas.getContext("2d");
4139
+ if (!ctx) return Promise.resolve();
4140
+ scene = { ctx, pieces: [], frame: 0, last: 0, done: [], overlay: canvas === overlay };
4141
+ scenes.set(canvas, scene);
4142
+ }
4143
+ const { width, height } = fit(canvas);
4144
+ const colors = o.colors.length ? o.colors : themeColors(themed);
4145
+ const x = (o.origin.x ?? 0.5) * width;
4146
+ const y = (o.origin.y ?? 0.5) * height;
4147
+ for (let i = 0; i < o.particleCount; i++) {
4148
+ scene.pieces.push({
4149
+ x,
4150
+ y,
4151
+ velocity: o.startVelocity * (0.5 + Math.random()),
4152
+ angle: -o.angle * RAD + (0.5 - Math.random()) * o.spread * RAD,
4153
+ wobble: Math.random() * 10,
4154
+ wobbleSpeed: 0.05 + Math.random() * 0.05,
4155
+ tilt: (0.25 + Math.random() / 2) * Math.PI,
4156
+ tick: 0,
4157
+ color: colors[i % colors.length],
4158
+ shape: o.shapes[Math.floor(Math.random() * o.shapes.length)] ?? "square",
4159
+ options: o
4160
+ });
4161
+ }
4162
+ const s = scene;
4163
+ if (!s.frame) s.frame = requestAnimationFrame((now) => {
4164
+ s.last = now;
4165
+ draw(canvas, s, now);
4166
+ });
4167
+ return new Promise((resolve) => s.done.push(resolve));
4168
+ }
4169
+ function draw(canvas, scene, now) {
4170
+ const step = Math.min((now - scene.last) / (1e3 / 60), 4);
4171
+ scene.last = now;
4172
+ const { width, height } = fit(canvas);
4173
+ const { ctx } = scene;
4174
+ const dpr = canvas.width / (width || 1);
4175
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
4176
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
4177
+ scene.pieces = scene.pieces.filter((p) => {
4178
+ const o = p.options;
4179
+ p.x += (Math.cos(p.angle) * p.velocity + o.drift) * step;
4180
+ p.y += (Math.sin(p.angle) * p.velocity + o.gravity * 3) * step;
4181
+ p.velocity *= o.decay ** step;
4182
+ p.wobble += p.wobbleSpeed * step;
4183
+ p.tilt += 0.1 * step;
4184
+ p.tick += step;
4185
+ if (p.tick >= o.ticks) return false;
4186
+ const size = 8 * o.scalar;
4187
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
4188
+ ctx.translate(p.x + 10 * o.scalar * Math.cos(p.wobble), p.y + 10 * o.scalar * Math.sin(p.wobble));
4189
+ ctx.rotate(p.tilt);
4190
+ ctx.scale(1, Math.cos(p.wobble));
4191
+ ctx.globalAlpha = 1 - p.tick / o.ticks;
4192
+ ctx.fillStyle = p.color;
4193
+ ctx.beginPath();
4194
+ if (p.shape === "circle") ctx.arc(0, 0, size / 2, 0, 2 * Math.PI);
4195
+ else if (p.shape === "star") star(ctx, size * 0.75);
4196
+ else ctx.rect(-size / 2, -size / 2, size, size);
4197
+ ctx.fill();
4198
+ return true;
4199
+ });
4200
+ if (scene.pieces.length) scene.frame = requestAnimationFrame((t) => draw(canvas, scene, t));
4201
+ else stop(canvas);
4202
+ }
4203
+ function stop(canvas) {
4204
+ const scene = scenes.get(canvas);
4205
+ if (!scene) return;
4206
+ cancelAnimationFrame(scene.frame);
4207
+ scenes.delete(canvas);
4208
+ scene.ctx.setTransform(1, 0, 0, 1, 0, 0);
4209
+ scene.ctx.clearRect(0, 0, canvas.width, canvas.height);
4210
+ if (scene.overlay) {
4211
+ canvas.remove();
4212
+ overlay = null;
4213
+ }
4214
+ for (const resolve of scene.done) resolve();
4215
+ }
4216
+ function star(ctx, r) {
4217
+ for (let i = 0; i < 10; i++) {
4218
+ const a = i * Math.PI / 5 - Math.PI / 2;
4219
+ const d = i % 2 ? r / 2 : r;
4220
+ ctx.lineTo(Math.cos(a) * d, Math.sin(a) * d);
4221
+ }
4222
+ ctx.closePath();
4223
+ }
4224
+ function fit(canvas) {
4225
+ const width = canvas.clientWidth;
4226
+ const height = canvas.clientHeight;
4227
+ const w = Math.round(width * devicePixelRatio);
4228
+ const h = Math.round(height * devicePixelRatio);
4229
+ if (canvas.width !== w || canvas.height !== h) {
4230
+ canvas.width = w;
4231
+ canvas.height = h;
4232
+ }
4233
+ return { width, height };
4234
+ }
4235
+ function viewportCanvas() {
4236
+ if (overlay?.isConnected) return overlay;
4237
+ overlay = document.createElement("canvas");
4238
+ overlay.className = "confetti-overlay";
4239
+ overlay.setAttribute("aria-hidden", "true");
4240
+ Object.assign(overlay.style, {
4241
+ position: "fixed",
4242
+ inset: "0",
4243
+ width: "100%",
4244
+ height: "100%",
4245
+ margin: "0",
4246
+ padding: "0",
4247
+ border: "0",
4248
+ background: "transparent",
4249
+ pointerEvents: "none",
4250
+ zIndex: "10001"
4251
+ });
4252
+ document.body.append(overlay);
4253
+ if (typeof overlay.showPopover === "function") {
4254
+ overlay.popover = "manual";
4255
+ overlay.showPopover();
4256
+ }
4257
+ return overlay;
4258
+ }
4259
+ function themeColors(themed) {
4260
+ const probe = document.createElement("span");
4261
+ probe.hidden = true;
4262
+ themed.append(probe);
4263
+ const style = getComputedStyle(probe);
4264
+ const colors = THEME_COLORS.filter((role) => style.getPropertyValue(`--md-sys-color-${role}`).trim()).map((role) => {
4265
+ probe.style.color = `var(--md-sys-color-${role})`;
4266
+ return getComputedStyle(probe).color;
4267
+ });
4268
+ probe.remove();
4269
+ return colors.length ? colors : FALLBACK_COLORS;
4270
+ }
4271
+
4272
+ // src/ts/components/particles.ts
4273
+ var _defaults13 = {
4274
+ quantity: 100,
4275
+ staticity: 50,
4276
+ ease: 50,
4277
+ size: 0.4,
4278
+ color: "",
4279
+ vx: 0,
4280
+ vy: 0
4281
+ };
4282
+ var Particles = class _Particles extends Component {
4283
+ constructor(el, options) {
4284
+ super(el, options, _Particles);
4285
+ this._particles = [];
4286
+ this._width = 0;
4287
+ this._height = 0;
4288
+ this._frame = 0;
4289
+ this._last = 0;
4290
+ // Pointer offset from the canvas center, kept from its last move inside.
4291
+ this._mouse = { x: 0, y: 0 };
4292
+ this._still = false;
4293
+ this._resizeObserver = null;
4294
+ this._visibility = null;
4295
+ this._onPointerMove = (e) => {
4296
+ const r = this.el.getBoundingClientRect();
4297
+ const x = e.clientX - r.left - r.width / 2;
4298
+ const y = e.clientY - r.top - r.height / 2;
4299
+ if (Math.abs(x) < r.width / 2 && Math.abs(y) < r.height / 2) this._mouse = { x, y };
4300
+ };
4301
+ this.el["Expressive_Particles"] = this;
4302
+ this.options = { ..._Particles.defaults, ...options };
4303
+ this._ctx = this.el.getContext("2d");
4304
+ if (!this._ctx) return;
4305
+ this._style = getComputedStyle(this.el);
4306
+ this._still = typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
4307
+ this._reset();
4308
+ if (typeof ResizeObserver !== "undefined") {
4309
+ this._resizeObserver = new ResizeObserver(() => {
4310
+ if (this.el.clientWidth !== this._width || this.el.clientHeight !== this._height) this._reset();
4311
+ });
4312
+ this._resizeObserver.observe(this.el);
4313
+ }
4314
+ if (this._still) return;
4315
+ if (typeof IntersectionObserver === "undefined") {
4316
+ this._start();
4317
+ return;
4318
+ }
4319
+ this._visibility = new IntersectionObserver(([entry]) => entry.isIntersecting ? this._start() : this._stop());
4320
+ this._visibility.observe(this.el);
4321
+ }
4322
+ static get defaults() {
4323
+ return _defaults13;
4324
+ }
4325
+ static init(els, options = {}) {
4326
+ return super.init(els, options, _Particles);
4327
+ }
4328
+ static getInstance(el) {
4329
+ return el["Expressive_Particles"];
4330
+ }
4331
+ destroy() {
4332
+ this._stop();
4333
+ this._resizeObserver?.disconnect();
4334
+ this._visibility?.disconnect();
4335
+ if (this._ctx) {
4336
+ this._ctx.setTransform(1, 0, 0, 1, 0, 0);
4337
+ this._ctx.clearRect(0, 0, this.el.width, this.el.height);
4338
+ }
4339
+ this.el["Expressive_Particles"] = void 0;
4340
+ }
4341
+ _start() {
4342
+ if (this._frame) return;
4343
+ window.addEventListener("pointermove", this._onPointerMove, { passive: true });
4344
+ this._frame = requestAnimationFrame((now) => {
4345
+ this._last = now;
4346
+ this._draw(now);
4347
+ });
4348
+ }
4349
+ _stop() {
4350
+ cancelAnimationFrame(this._frame);
4351
+ this._frame = 0;
4352
+ window.removeEventListener("pointermove", this._onPointerMove);
4353
+ }
4354
+ // Matches the pixel buffer to the canvas box and scatters a new set.
4355
+ _reset() {
4356
+ this._width = this.el.clientWidth;
4357
+ this._height = this.el.clientHeight;
4358
+ this.el.width = Math.round(this._width * devicePixelRatio);
4359
+ this.el.height = Math.round(this._height * devicePixelRatio);
4360
+ this._particles = Array.from({ length: this.options.quantity }, () => this._particle());
4361
+ if (this._still) {
4362
+ for (const p of this._particles) p.alpha = p.targetAlpha;
4363
+ this._paint();
4364
+ }
4365
+ }
4366
+ _particle() {
4367
+ return {
4368
+ x: Math.floor(Math.random() * this._width),
4369
+ y: Math.floor(Math.random() * this._height),
4370
+ translateX: 0,
4371
+ translateY: 0,
4372
+ size: Math.floor(Math.random() * 2) + this.options.size,
4373
+ alpha: 0,
4374
+ targetAlpha: Math.round((Math.random() * 0.6 + 0.1) * 10) / 10,
4375
+ dx: (Math.random() - 0.5) * 0.1,
4376
+ dy: (Math.random() - 0.5) * 0.1,
4377
+ magnetism: 0.1 + Math.random() * 4
4378
+ };
4379
+ }
4380
+ _draw(now) {
4381
+ const step = Math.min((now - this._last) / (1e3 / 60), 4);
4382
+ this._last = now;
4383
+ const { staticity, ease, vx, vy } = this.options;
4384
+ const follow = Math.min(step / ease, 1);
4385
+ this._particles = this._particles.map((p) => {
4386
+ p.x += (p.dx + vx) * step;
4387
+ p.y += (p.dy + vy) * step;
4388
+ p.translateX += (this._mouse.x / (staticity / p.magnetism) - p.translateX) * follow;
4389
+ p.translateY += (this._mouse.y / (staticity / p.magnetism) - p.translateY) * follow;
4390
+ const x = p.x + p.translateX;
4391
+ const y = p.y + p.translateY;
4392
+ const edge = Math.min(x - p.size, this._width - x - p.size, y - p.size, this._height - y - p.size) / 20;
4393
+ p.alpha = edge > 1 ? Math.min(p.alpha + 0.02 * step, p.targetAlpha) : p.targetAlpha * edge;
4394
+ const gone = p.x < -p.size || p.x > this._width + p.size || p.y < -p.size || p.y > this._height + p.size;
4395
+ return gone ? this._particle() : p;
4396
+ });
4397
+ this._paint();
4398
+ this._frame = requestAnimationFrame((t) => this._draw(t));
4399
+ }
4400
+ _paint() {
4401
+ const ctx = this._ctx;
4402
+ const dpr = devicePixelRatio;
4403
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
4404
+ ctx.clearRect(0, 0, this.el.width, this.el.height);
4405
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
4406
+ ctx.fillStyle = this.options.color || this._style.color;
4407
+ for (const p of this._particles) {
4408
+ if (p.alpha <= 0) continue;
4409
+ ctx.globalAlpha = p.alpha;
4410
+ ctx.beginPath();
4411
+ ctx.arc(p.x + p.translateX, p.y + p.translateY, p.size, 0, 2 * Math.PI);
4412
+ ctx.fill();
4413
+ }
4414
+ ctx.globalAlpha = 1;
4415
+ }
4416
+ };
4417
+
4418
+ // src/ts/components/keypad.ts
4419
+ var _defaults14 = {
4420
+ onKey: null
4421
+ };
4422
+ var isField = (el) => el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement;
4423
+ var instances = /* @__PURE__ */ new Set();
4424
+ var touched = /* @__PURE__ */ new WeakSet();
4425
+ var segmenter;
4426
+ function keyFor(e) {
4427
+ const key = e.target.closest?.("button");
4428
+ if (!key) return null;
4429
+ const keypad = key.closest(".keypad, .keyboard")?.["Expressive_Keypad"];
4430
+ if (keypad) return [keypad, key];
4431
+ const wrapper = key.dataset.key && key.closest(".field");
4432
+ if (!wrapper) return null;
4433
+ for (const other of instances) {
4434
+ const field = other.target;
4435
+ if (field && wrapper.contains(field)) return [other, key];
4436
+ }
4437
+ return null;
4438
+ }
4439
+ var rootListeners = [
4440
+ // A pointer press on a key would move focus off the field and hide its
4441
+ // caret. Keep focus where it is while the field has it.
4442
+ ["mousedown", (e) => {
4443
+ const hit = keyFor(e);
4444
+ if (hit && hit[0]._root?.activeElement === hit[0].target) e.preventDefault();
4445
+ }],
4446
+ ["click", (e) => {
4447
+ const hit = keyFor(e);
4448
+ if (hit) hit[0]._press(hit[1]);
4449
+ }],
4450
+ ["focusin", (e) => {
4451
+ if (isField(e.target)) touched.add(e.target);
4452
+ }]
4453
+ ];
4454
+ var Keypad = class _Keypad extends Component {
4455
+ constructor(el, options) {
4456
+ super(el, options, _Keypad);
4457
+ this.el["Expressive_Keypad"] = this;
4458
+ this.options = { ..._Keypad.defaults, ...options };
4459
+ const root = this.el.getRootNode();
4460
+ this._root = root.nodeType === 9 || root.nodeType === 11 ? root : null;
4461
+ if (this._root && !this._shared()) {
4462
+ for (const [type, listener] of rootListeners) this._root.addEventListener(type, listener);
4463
+ }
4464
+ instances.add(this);
4465
+ const active = this._root?.activeElement;
4466
+ if (isField(active)) touched.add(active);
4467
+ }
4468
+ static get defaults() {
4469
+ return _defaults14;
4470
+ }
4471
+ static init(els, options = {}) {
4472
+ return super.init(els, options, _Keypad);
4473
+ }
4474
+ static getInstance(el) {
4475
+ return el["Expressive_Keypad"];
4476
+ }
4477
+ destroy() {
4478
+ instances.delete(this);
4479
+ if (this._root && !this._shared()) {
4480
+ for (const [type, listener] of rootListeners) this._root.removeEventListener(type, listener);
4481
+ }
4482
+ this.el["Expressive_Keypad"] = void 0;
4483
+ }
4484
+ /** The text field named by `aria-controls`, if there is one. */
4485
+ get target() {
4486
+ const id = this.el.getAttribute("aria-controls");
4487
+ const field = id ? Utils.getElementById(this.el, id) : null;
4488
+ return isField(field) ? field : null;
4489
+ }
4490
+ // Whether another keypad already listens on this one's root.
4491
+ _shared() {
4492
+ for (const other of instances) if (other !== this && other._root === this._root) return true;
4493
+ return false;
4494
+ }
4495
+ /** @internal */
4496
+ _press(key) {
4497
+ const name = key.dataset.key;
4498
+ if (key.disabled || !name && !key.hasAttribute("value")) return;
4499
+ if (name === "Shift") {
4500
+ key.setAttribute("aria-pressed", String(key.getAttribute("aria-pressed") !== "true"));
4501
+ this.options.onKey?.(name);
4502
+ return;
4503
+ }
4504
+ let text = name ? "" : key.value;
4505
+ const shift = text && this.el.querySelector('[data-key="Shift"][aria-pressed="true"]');
4506
+ if (shift) {
4507
+ text = text.toUpperCase();
4508
+ shift.setAttribute("aria-pressed", "false");
4509
+ }
4510
+ const field = this.target;
4511
+ if (field && !field.matches(":disabled") && !field.readOnly) {
4512
+ if (name === "Enter" && field instanceof HTMLInputElement) field.form?.requestSubmit();
4513
+ else if (name === "Enter") this._edit(field, "\n", "insertLineBreak");
4514
+ else if (name === "Backspace") this._edit(field, "", "deleteContentBackward");
4515
+ else if (text) this._edit(field, text, "insertText");
4516
+ }
4517
+ this.options.onKey?.(name ?? text);
4518
+ }
4519
+ _edit(field, text, inputType) {
4520
+ const { value } = field;
4521
+ let start = field.selectionStart ?? value.length;
4522
+ let end = field.selectionEnd ?? value.length;
4523
+ if (start === 0 && end === 0 && !touched.has(field)) start = end = value.length;
4524
+ if (inputType === "deleteContentBackward" && start === end && start) {
4525
+ const tail = value.slice(Math.max(0, start - 64), start);
4526
+ start -= (segmenter ?? (segmenter = new Intl.Segmenter())).segment(tail).containing(tail.length - 1).segment.length;
4527
+ }
4528
+ if (start === end && !text) return;
4529
+ if (text && field.maxLength >= 0 && value.length - (end - start) + text.length > field.maxLength) return;
4530
+ const next = value.slice(0, start) + text + value.slice(end);
4531
+ field.value = next;
4532
+ if (next && !field.value) {
4533
+ field.value = value;
4534
+ return;
4535
+ }
4536
+ if (field.selectionStart !== null) field.setSelectionRange(start + text.length, start + text.length);
4537
+ touched.add(field);
4538
+ field.dispatchEvent(new InputEvent("input", { bubbles: true, composed: true, inputType, data: text || null }));
4539
+ }
4540
+ };
4541
+
4542
+ // src/ts/components/commandPalette.ts
4543
+ var _defaults15 = {
4117
4544
  shortcut: "k",
4118
4545
  closeOnRun: true
4119
4546
  };
@@ -4211,7 +4638,7 @@ var CommandPalette = class _CommandPalette extends Component {
4211
4638
  document.addEventListener("keydown", this._handleShortcut);
4212
4639
  }
4213
4640
  static get defaults() {
4214
- return _defaults12;
4641
+ return _defaults15;
4215
4642
  }
4216
4643
  /**
4217
4644
  * Initializes instances of CommandPalette.
@@ -4364,7 +4791,7 @@ var CommandPalette = class _CommandPalette extends Component {
4364
4791
  };
4365
4792
 
4366
4793
  // src/ts/components/questionnaire.ts
4367
- var _defaults13 = {
4794
+ var _defaults16 = {
4368
4795
  progressLabel: "Question {current} of {total}",
4369
4796
  requiredMessage: "Choose an answer to continue."
4370
4797
  };
@@ -4478,7 +4905,7 @@ var Questionnaire = class _Questionnaire extends Component {
4478
4905
  this.el.addEventListener("invalid", this._handleInvalid, true);
4479
4906
  }
4480
4907
  static get defaults() {
4481
- return _defaults13;
4908
+ return _defaults16;
4482
4909
  }
4483
4910
  /**
4484
4911
  * Initializes instances of Questionnaire.
@@ -4623,7 +5050,7 @@ var Questionnaire = class _Questionnaire extends Component {
4623
5050
  };
4624
5051
 
4625
5052
  // src/ts/components/lineChart.ts
4626
- var _defaults14 = {
5053
+ var _defaults17 = {
4627
5054
  min: null,
4628
5055
  max: null
4629
5056
  };
@@ -4634,13 +5061,19 @@ function svgNode(name, attributes = {}) {
4634
5061
  for (const key in attributes) element.setAttribute(key, attributes[key]);
4635
5062
  return element;
4636
5063
  }
5064
+ function polarPoint(turn, r) {
5065
+ const angle = turn * 2 * Math.PI;
5066
+ return `${(r * Math.sin(angle)).toFixed(3)},${(-r * Math.cos(angle)).toFixed(3)}`;
5067
+ }
5068
+ var seriesColor = (i) => String(i % COLORS + 1);
4637
5069
  var _gradientId = 0;
4638
5070
  function cellValue(cell) {
4639
5071
  if (!cell) return null;
4640
5072
  const raw = cell.dataset.value ?? cell.textContent;
4641
5073
  const text = raw.replace(/\u2212/g, "-").replace(/[\s%\p{Sc}]/gu, "");
4642
- if (!/^[+-]?(\d{1,3}(,\d{3})+|\d+)?(\.\d+)?(e[+-]?\d+)?$/i.test(text) || !/\d/.test(text)) return null;
4643
- return parseFloat(text.replace(/,/g, ""));
5074
+ if (!/^[+-]?(\d{1,3}(,\d{3})+|\d+)?(\.\d+)?(e[+-]?\d+)?$/i.test(text)) return null;
5075
+ const value = parseFloat(text.replace(/,/g, ""));
5076
+ return Number.isFinite(value) ? value : null;
4644
5077
  }
4645
5078
  function monotonePath(points) {
4646
5079
  const n = points.length;
@@ -4751,7 +5184,7 @@ var LineChart = class extends Component {
4751
5184
  return "Expressive_LineChart";
4752
5185
  }
4753
5186
  static get defaults() {
4754
- return _defaults14;
5187
+ return _defaults17;
4755
5188
  }
4756
5189
  static init(els, options = {}) {
4757
5190
  return super.init(els, options, this);
@@ -4781,7 +5214,7 @@ var LineChart = class extends Component {
4781
5214
  this.series.forEach((series, i) => {
4782
5215
  const value = series.values[index];
4783
5216
  if (value === null) return;
4784
- const color = String(i % COLORS + 1);
5217
+ const color = seriesColor(i);
4785
5218
  const top = series.tops[index];
4786
5219
  if (top !== null && this._points) {
4787
5220
  const dot = document.createElement("span");
@@ -4933,7 +5366,7 @@ var LineChart = class extends Component {
4933
5366
  legend.setAttribute("aria-hidden", "true");
4934
5367
  legend.append(...this.series.map((series, i) => {
4935
5368
  const li = document.createElement("li");
4936
- li.dataset.series = String(i % COLORS + 1);
5369
+ li.dataset.series = seriesColor(i);
4937
5370
  li.textContent = series.name;
4938
5371
  return li;
4939
5372
  }));
@@ -4941,15 +5374,17 @@ var LineChart = class extends Component {
4941
5374
  }
4942
5375
  /** Draws the series, which fill the plot. */
4943
5376
  _draw(drawn = this.series) {
4944
- const svg = document.createElementNS(SVG, "svg");
4945
- svg.setAttribute("viewBox", "0 0 100 100");
4946
- svg.setAttribute("preserveAspectRatio", "none");
4947
- svg.setAttribute("aria-hidden", "true");
4948
- svg.setAttribute("focusable", "false");
5377
+ const svg = svgNode("svg", {
5378
+ viewBox: "0 0 100 100",
5379
+ preserveAspectRatio: "none",
5380
+ "aria-hidden": "true",
5381
+ focusable: "false"
5382
+ });
4949
5383
  for (const series of drawn) {
4950
- const group = document.createElementNS(SVG, "g");
4951
- group.setAttribute("class", `${this._type}-series ${series.className}`.trim());
4952
- group.dataset.series = String(this.series.indexOf(series) % COLORS + 1);
5384
+ const group = svgNode("g", {
5385
+ class: `${this._type}-series ${series.className}`.trim(),
5386
+ "data-series": seriesColor(this.series.indexOf(series))
5387
+ });
4953
5388
  const runs = [[]];
4954
5389
  series.tops.forEach((value, index) => {
4955
5390
  if (value === null) runs.push([]);
@@ -4959,23 +5394,21 @@ var LineChart = class extends Component {
4959
5394
  const points = (run, values) => run.map((index) => [this._x(index), series.y(values[index])]);
4960
5395
  const tops = filled.map((run) => monotonePath(points(run, series.tops)));
4961
5396
  const id = `line-chart-gradient-${++_gradientId}`;
4962
- const gradient = document.createElementNS(SVG, "linearGradient");
4963
- gradient.id = id;
4964
- gradient.setAttribute("x2", "0");
4965
- gradient.setAttribute("y2", "1");
4966
- gradient.append(document.createElementNS(SVG, "stop"), document.createElementNS(SVG, "stop"));
4967
- gradient.lastElementChild.setAttribute("offset", "1");
4968
- const area = document.createElementNS(SVG, "path");
4969
- area.setAttribute("class", `${this._type}-area`);
4970
- area.setAttribute("fill", `url(#${id})`);
4971
- area.setAttribute("d", filled.map((run, r) => {
4972
- if (!series.base) return `${tops[r]}V100H${this._x(run[0])}Z`;
4973
- const base = points(run, series.base).map(([x, y]) => [x, Math.min(100, y)]);
4974
- return `${tops[r]}L${monotonePath(base.reverse()).slice(1)}Z`;
4975
- }).join(""));
4976
- const line = document.createElementNS(SVG, "path");
4977
- line.setAttribute("class", `${this._type}-line`);
4978
- line.setAttribute("d", tops.join(""));
5397
+ const gradient = svgNode("linearGradient", { id, x2: "0", y2: "1" });
5398
+ gradient.append(svgNode("stop"), svgNode("stop", { offset: "1" }));
5399
+ const area = svgNode("path", {
5400
+ class: `${this._type}-area`,
5401
+ fill: `url(#${id})`,
5402
+ // A stacked area runs back along the series below; the reversed curve
5403
+ // is the same curve. Its base stops at the plot bottom when the y axis
5404
+ // starts above zero.
5405
+ d: filled.map((run, r) => {
5406
+ if (!series.base) return `${tops[r]}V100H${this._x(run[0])}Z`;
5407
+ const base = points(run, series.base).map(([x, y]) => [x, Math.min(100, y)]);
5408
+ return `${tops[r]}L${monotonePath(base.reverse()).slice(1)}Z`;
5409
+ }).join("")
5410
+ });
5411
+ const line = svgNode("path", { class: `${this._type}-line`, d: tops.join("") });
4979
5412
  group.append(gradient, area, line);
4980
5413
  svg.append(group);
4981
5414
  }
@@ -5054,7 +5487,7 @@ var ColumnChart = class extends LineChart {
5054
5487
  const column = document.createElement("span");
5055
5488
  if (to !== null) {
5056
5489
  column.className = series.className;
5057
- column.dataset.series = String(this.series.indexOf(series) % COLORS + 1);
5490
+ column.dataset.series = seriesColor(this.series.indexOf(series));
5058
5491
  column.classList.toggle("negative", !series.base && to < from);
5059
5492
  column.style.setProperty("--top", `${clamp(Math.max(from, to), series.y)}%`);
5060
5493
  column.style.setProperty("--bottom", `${100 - clamp(Math.min(from, to), series.y)}%`);
@@ -5154,18 +5587,25 @@ var PieChart = class extends LineChart {
5154
5587
  }
5155
5588
  /** The row's share of the whole as a percentage, or '' for none. */
5156
5589
  _share(index) {
5590
+ var _a;
5157
5591
  const [start, end] = this._turns[index];
5158
5592
  if (end <= start) return "";
5159
5593
  const share = end - start;
5160
- const options = { style: "percent", maximumFractionDigits: share < 0.1 ? 1 : 0 };
5594
+ const digits = share < 0.1 ? 1 : 0;
5595
+ (_a = this._percents ?? (this._percents = []))[digits] ?? (_a[digits] = this._percent(digits));
5596
+ return this._percents[digits].format(share);
5597
+ }
5598
+ _percent(digits) {
5599
+ const options = { style: "percent", maximumFractionDigits: digits };
5161
5600
  try {
5162
- return share.toLocaleString(this.el.closest("[lang]")?.lang || void 0, options);
5601
+ return new Intl.NumberFormat(this.el.closest("[lang]")?.lang || void 0, options);
5163
5602
  } catch {
5164
- return share.toLocaleString(void 0, options);
5603
+ return new Intl.NumberFormat(void 0, options);
5165
5604
  }
5166
5605
  }
5167
5606
  /** The legend: every row with its color, its cell and its share. */
5168
5607
  _guides() {
5608
+ this._percents = [];
5169
5609
  const legend = document.createElement("ul");
5170
5610
  legend.className = "pie-chart-legend";
5171
5611
  legend.setAttribute("aria-hidden", "true");
@@ -5202,17 +5642,13 @@ var PieChart = class extends LineChart {
5202
5642
  const total = values.reduce((sum, value) => sum + value, 0);
5203
5643
  let turn = 0;
5204
5644
  this._turns = values.map((value) => [turn, turn += total ? value / total : 0]);
5205
- const drawn = this._turns.filter(([start, end]) => end > start).length;
5645
+ const drawn = this._turns.filter(([start, end]) => end > start);
5206
5646
  let slice = 0;
5207
5647
  this._colors = this._turns.map(([start, end]) => {
5208
5648
  if (end <= start) return void 0;
5209
5649
  const index = slice++;
5210
- return String(index === drawn - 1 && index > 0 && index % COLORS2 === 0 ? 2 : index % COLORS2 + 1);
5650
+ return String(index === drawn.length - 1 && index > 0 && index % COLORS2 === 0 ? 2 : index % COLORS2 + 1);
5211
5651
  });
5212
- const at = (t, r = RADIUS) => {
5213
- const angle = t * 2 * Math.PI;
5214
- return `${(r * Math.sin(angle)).toFixed(3)},${(-r * Math.cos(angle)).toFixed(3)}`;
5215
- };
5216
5652
  const pie = document.createElement("div");
5217
5653
  pie.className = "pie-chart-pie";
5218
5654
  pie.setAttribute("aria-hidden", "true");
@@ -5220,25 +5656,24 @@ var PieChart = class extends LineChart {
5220
5656
  const id = `pie-chart-mask-${++_maskId}`;
5221
5657
  const area = { x: "-50", y: "-50", width: "100", height: "100" };
5222
5658
  const mask = svgNode("mask", { id, maskUnits: "userSpaceOnUse", ...area });
5223
- const edges = this._turns.filter(([start, end]) => end > start);
5224
5659
  mask.append(
5225
5660
  svgNode("rect", { ...area, fill: "white" }),
5226
5661
  svgNode("path", {
5227
5662
  class: "pie-chart-gaps",
5228
5663
  stroke: "black",
5229
- d: edges.length > 1 ? edges.map(([start]) => `M0,0L${at(start, 50)}`).join("") : ""
5664
+ d: drawn.length > 1 ? drawn.map(([start]) => `M0,0L${polarPoint(start, 50)}`).join("") : ""
5230
5665
  }),
5231
5666
  svgNode("circle", { class: "pie-chart-hole", r: String(RADIUS), fill: "black" })
5232
5667
  );
5233
5668
  const slices = svgNode("g", { mask: `url(#${id})` });
5234
- const arc = `A${RADIUS},${RADIUS} 0`;
5669
+ const arc2 = `A${RADIUS},${RADIUS} 0`;
5235
5670
  this._slices = this._turns.map(([start, end], i) => {
5236
5671
  if (end <= start) return null;
5237
5672
  const slice2 = svgNode("path", {
5238
5673
  class: "pie-chart-slice",
5239
5674
  "data-series": this._colors[i],
5240
5675
  // A whole circle is two half arcs; one arc cannot end where it starts.
5241
- d: end - start >= 1 ? `M0,${-RADIUS}${arc} 1 1 0,${RADIUS}${arc} 1 1 0,${-RADIUS}Z` : `M0,0L${at(start)}${arc} ${end - start > 0.5 ? 1 : 0} 1 ${at(end)}Z`
5676
+ d: end - start >= 1 ? `M0,${-RADIUS}${arc2} 1 1 0,${RADIUS}${arc2} 1 1 0,${-RADIUS}Z` : `M0,0L${polarPoint(start, RADIUS)}${arc2} ${end - start > 0.5 ? 1 : 0} 1 ${polarPoint(end, RADIUS)}Z`
5242
5677
  });
5243
5678
  slices.append(slice2);
5244
5679
  return slice2;
@@ -5281,9 +5716,10 @@ var HeatmapChart = class extends LineChart {
5281
5716
  /** Highlights one cell, numbered row by row. Pass -1 to hide the tooltip. */
5282
5717
  show(index) {
5283
5718
  if (!this._tooltip || index === this.activeIndex) return;
5719
+ const cell = this._cells[index];
5720
+ const [left, top, width, plotWidth] = cell ? [cell.offsetLeft, cell.offsetTop, cell.offsetWidth, this._plot.clientWidth] : [];
5284
5721
  this._cells[this.activeIndex]?.classList.remove("active");
5285
5722
  this.activeIndex = index;
5286
- const cell = this._cells[index];
5287
5723
  this._tooltip.hidden = !cell;
5288
5724
  if (!cell) return;
5289
5725
  cell.classList.add("active");
@@ -5297,10 +5733,10 @@ var HeatmapChart = class extends LineChart {
5297
5733
  else name.style.setProperty("--level", String(this._levels[index]));
5298
5734
  text.textContent = series.text[row];
5299
5735
  this._tooltip.replaceChildren(title, name, text);
5300
- const end = cell.offsetLeft + cell.offsetWidth / 2 > this._plot.clientWidth / 2;
5736
+ const end = left + width / 2 > plotWidth / 2;
5301
5737
  this._tooltip.classList.toggle("end", end);
5302
- this._tooltip.style.left = `${cell.offsetLeft + (end ? 0 : cell.offsetWidth)}px`;
5303
- this._tooltip.style.top = `${cell.offsetTop}px`;
5738
+ this._tooltip.style.left = `${left + (end ? 0 : width)}px`;
5739
+ this._tooltip.style.top = `${top}px`;
5304
5740
  }
5305
5741
  /** Arrows move the way they point, so left and right swap in RTL. */
5306
5742
  _keyTarget(key) {
@@ -5370,10 +5806,7 @@ var HeatmapChart = class extends LineChart {
5370
5806
  if (value < low) [low, this._ends[0]] = [value, series.text[row]];
5371
5807
  if (value > high) [high, this._ends[1]] = [value, series.text[row]];
5372
5808
  }));
5373
- const option = (name) => {
5374
- const value = parseFloat(this.el.dataset[name] ?? "");
5375
- return Number.isFinite(value) ? value : this.options[name];
5376
- };
5809
+ const option = (name) => this._number(name) ?? this.options[name];
5377
5810
  const [min, max] = [option("min") ?? low, option("max") ?? high];
5378
5811
  const shade = (value) => Math.min(1, Math.max(0, (value - min) / (max - min || 1)));
5379
5812
  this._endLevels = [shade(low), shade(high)];
@@ -5474,10 +5907,7 @@ var RadarChart = class extends LineChart {
5474
5907
  * the labels round it are HTML.
5475
5908
  */
5476
5909
  _draw() {
5477
- const at = (index, share2) => {
5478
- const angle = this._turn(index) * 2 * Math.PI;
5479
- return `${(50 * share2 * Math.sin(angle)).toFixed(3)},${(-50 * share2 * Math.cos(angle)).toFixed(3)}`;
5480
- };
5910
+ const at = (index, share2) => polarPoint(this._turn(index), 50 * share2);
5481
5911
  const share = (value) => Math.min(1, Math.max(0, 1 - this._y(value) / 100));
5482
5912
  const rows = this.labels.map((_, i) => i);
5483
5913
  const ring = (r) => `M${rows.map((i) => at(i, r)).join("L")}Z`;
@@ -5490,7 +5920,7 @@ var RadarChart = class extends LineChart {
5490
5920
  this.series.forEach((series, s) => {
5491
5921
  const group = svgNode("g", {
5492
5922
  class: `radar-chart-series ${series.className}`.trim(),
5493
- "data-series": String(s % COLORS + 1)
5923
+ "data-series": seriesColor(s)
5494
5924
  });
5495
5925
  const drawn = rows.filter((i) => series.values[i] !== null);
5496
5926
  const corners = drawn.map((i) => at(i, share(series.values[i])));
@@ -5544,7 +5974,7 @@ var RadialChart = class extends LineChart {
5544
5974
  super.show(index);
5545
5975
  this._rings.forEach((ring, i) => ring.classList.toggle("active", i === index));
5546
5976
  if (this._tooltip.hidden) return;
5547
- const color = this._color(index);
5977
+ const color = seriesColor(index);
5548
5978
  this._tooltip.querySelectorAll("[data-series]").forEach((span) => {
5549
5979
  span.dataset.series = color;
5550
5980
  });
@@ -5558,9 +5988,6 @@ var RadialChart = class extends LineChart {
5558
5988
  this._tooltip.style.top = `${(50 + y) / (this._gauge ? 50 : 100) * 100}%`;
5559
5989
  this._tooltip.classList.toggle("end", x > 0);
5560
5990
  }
5561
- _color(index) {
5562
- return String(index % COLORS + 1);
5563
- }
5564
5991
  /** A fraction of the ring as a turn clockwise from the top. */
5565
5992
  _turn(fraction) {
5566
5993
  return this._gauge ? fraction / 2 - 0.25 : fraction;
@@ -5574,7 +6001,7 @@ var RadialChart = class extends LineChart {
5574
6001
  const text = this.series[0].text;
5575
6002
  legend.append(...this.labels.map((label, i) => {
5576
6003
  const li = document.createElement("li");
5577
- li.dataset.series = this._color(i);
6004
+ li.dataset.series = seriesColor(i);
5578
6005
  const [name, value] = [label, text[i]].map((content) => {
5579
6006
  const span = document.createElement("span");
5580
6007
  span.textContent = content;
@@ -5627,7 +6054,7 @@ var RadialChart = class extends LineChart {
5627
6054
  return ring2;
5628
6055
  };
5629
6056
  const ring = circle("radial-chart-ring", this._fractions[i], true);
5630
- ring.dataset.series = this._color(i);
6057
+ ring.dataset.series = seriesColor(i);
5631
6058
  if (!this._fractions[i]) ring.classList.add("empty");
5632
6059
  svg.append(circle("radial-chart-track", 1, gauge), ring);
5633
6060
  return ring;
@@ -5681,7 +6108,7 @@ var MixedChart = class extends ColumnChart {
5681
6108
  };
5682
6109
 
5683
6110
  // src/ts/components/select.ts
5684
- var _defaults15 = {
6111
+ var _defaults18 = {
5685
6112
  classes: "",
5686
6113
  menuOptions: {}
5687
6114
  };
@@ -5755,7 +6182,7 @@ var FormSelect = class _FormSelect extends Component {
5755
6182
  ...options
5756
6183
  };
5757
6184
  this.isMultiple = this.el.multiple;
5758
- this.nativeTabIndex = this.el.tabIndex ?? -1;
6185
+ this.nativeTabIndex = this.el.tabIndex;
5759
6186
  this.el.tabIndex = -1;
5760
6187
  this._values = [];
5761
6188
  this._createdWrapper = false;
@@ -5763,7 +6190,7 @@ var FormSelect = class _FormSelect extends Component {
5763
6190
  this._setupEventHandlers();
5764
6191
  }
5765
6192
  static get defaults() {
5766
- return _defaults15;
6193
+ return _defaults18;
5767
6194
  }
5768
6195
  /**
5769
6196
  * Initializes instances of FormSelect.
@@ -5998,13 +6425,13 @@ var FormSelect = class _FormSelect extends Component {
5998
6425
  if (selectedOption.id) this.input.setAttribute("aria-activedescendant", selectedOption.id);
5999
6426
  }
6000
6427
  this.input.ariaExpanded = "true";
6001
- if (userOnOpenEnd && typeof userOnOpenEnd === "function")
6428
+ if (typeof userOnOpenEnd === "function")
6002
6429
  userOnOpenEnd.call(this.menu, this.el);
6003
6430
  };
6004
6431
  menuOptions.onCloseEnd = () => {
6005
6432
  this.input.ariaExpanded = "false";
6006
6433
  this.input.removeAttribute("aria-activedescendant");
6007
- if (userOnCloseEnd && typeof userOnCloseEnd === "function")
6434
+ if (typeof userOnCloseEnd === "function")
6008
6435
  userOnCloseEnd.call(this.menu, this.el);
6009
6436
  };
6010
6437
  menuOptions.closeOnClick = false;
@@ -6154,10 +6581,7 @@ var FormSelect = class _FormSelect extends Component {
6154
6581
  else this._selectValue(value);
6155
6582
  }
6156
6583
  _getSelectedOptions() {
6157
- return Array.prototype.filter.call(
6158
- this.el.selectedOptions,
6159
- (realOption) => realOption
6160
- );
6584
+ return Array.from(this.el.selectedOptions);
6161
6585
  }
6162
6586
  _setValueToInput() {
6163
6587
  this.input.value = this._getSelectedOptions().map((option) => option.textContent.trim()).join(", ");
@@ -6188,7 +6612,7 @@ var FormSelect = class _FormSelect extends Component {
6188
6612
  };
6189
6613
 
6190
6614
  // src/ts/plugins/dockedDisplayPlugin.ts
6191
- var _defaults16 = {
6615
+ var _defaults19 = {
6192
6616
  margin: 5,
6193
6617
  transition: 10,
6194
6618
  duration: 250,
@@ -6197,14 +6621,14 @@ var _defaults16 = {
6197
6621
  var DockedDisplayPlugin = class _DockedDisplayPlugin {
6198
6622
  constructor(el, container, options) {
6199
6623
  this._handleDocumentClick = (e) => {
6200
- if (this.visible && !e.composedPath().includes(this.el) && !e.composedPath().includes(this.container)) {
6201
- this.hide();
6202
- }
6624
+ if (!this.visible) return;
6625
+ const path = e.composedPath();
6626
+ if (!path.includes(this.el) && !path.includes(this.container)) this.hide();
6203
6627
  };
6204
6628
  /**
6205
- * Tears the plugin down. The document listener holds a reference to this
6206
- * instance - and through it the whole picker subtree - so the owning
6207
- * component must call this from its own destroy().
6629
+ * Tears the plugin down. While shown, the document listener holds a
6630
+ * reference to this instance - and through it the whole picker subtree - so
6631
+ * the owning component must call this from its own destroy().
6208
6632
  */
6209
6633
  this.destroy = () => {
6210
6634
  document.removeEventListener("click", this._handleDocumentClick);
@@ -6213,23 +6637,21 @@ var DockedDisplayPlugin = class _DockedDisplayPlugin {
6213
6637
  this.show = () => {
6214
6638
  if (this.visible) return;
6215
6639
  this.visible = true;
6640
+ document.addEventListener("click", this._handleDocumentClick);
6216
6641
  const coordinates = Utils._setAbsolutePosition(this.el, this.container, "bottom", this.options.margin, this.options.transition, this.options.align);
6217
6642
  this.container.style.visibility = "visible";
6218
- this.container.style.transition = `
6219
- transform ${this.options.duration}ms ease-out,
6220
- opacity ${this.options.duration}ms ease-out`;
6643
+ this.container.style.transition = this._transition;
6221
6644
  setTimeout(() => {
6222
6645
  this.container.style.transform = `translateX(${coordinates.x}px) translateY(${coordinates.y}px)`;
6223
- this.container.style.opacity = 1 .toString();
6646
+ this.container.style.opacity = "1";
6224
6647
  }, 1);
6225
6648
  };
6226
6649
  this.hide = () => {
6227
6650
  if (!this.visible) return;
6228
6651
  this.visible = false;
6652
+ document.removeEventListener("click", this._handleDocumentClick);
6229
6653
  this.container.removeAttribute("style");
6230
- this.container.style.transition = `
6231
- transform ${this.options.duration}ms ease-out,
6232
- opacity ${this.options.duration}ms ease-out`;
6654
+ this.container.style.transition = this._transition;
6233
6655
  setTimeout(() => {
6234
6656
  this.container.style.transform = `translateX(0px) translateY(0px)`;
6235
6657
  this.container.style.opacity = "0";
@@ -6237,14 +6659,20 @@ var DockedDisplayPlugin = class _DockedDisplayPlugin {
6237
6659
  };
6238
6660
  this.el = el;
6239
6661
  this.options = {
6240
- ..._defaults16,
6662
+ ..._defaults19,
6241
6663
  ...options
6242
6664
  };
6243
6665
  this.container = document.createElement("div");
6244
6666
  this.container.classList.add("display-docked");
6245
6667
  this.container.append(container);
6246
6668
  el.parentElement.append(this.container);
6247
- document.addEventListener("click", this._handleDocumentClick);
6669
+ }
6670
+ // @todo move to Util? -> duplicate code fragment with tooltip
6671
+ // easeOutCubic
6672
+ get _transition() {
6673
+ return `
6674
+ transform ${this.options.duration}ms ease-out,
6675
+ opacity ${this.options.duration}ms ease-out`;
6248
6676
  }
6249
6677
  /**
6250
6678
  * Initializes instance of DockedDisplayPlugin
@@ -6258,7 +6686,7 @@ var DockedDisplayPlugin = class _DockedDisplayPlugin {
6258
6686
  };
6259
6687
 
6260
6688
  // src/ts/components/datepicker.ts
6261
- var _defaults17 = {
6689
+ var _defaults20 = {
6262
6690
  // the default output format for the input field value
6263
6691
  format: "mmm dd, yyyy",
6264
6692
  // Used to create date object from current input string
@@ -6362,6 +6790,10 @@ var _Datepicker = class _Datepicker extends Component {
6362
6790
  constructor(el, options) {
6363
6791
  super(el, options, _Datepicker);
6364
6792
  this.multiple = false;
6793
+ /** What setInputValue last wrote, so reading it back does not depend on the parser. */
6794
+ this._writtenInputs = /* @__PURE__ */ new WeakMap();
6795
+ /** Rows renderRow has already checked, so renderBody does not parse them again. */
6796
+ this._checkedRows = /* @__PURE__ */ new Set();
6365
6797
  /** Nesting depth of {@link _batchDraws}; > 0 means draws are being collected. */
6366
6798
  this._drawDepth = 0;
6367
6799
  /** Whether a draw was requested while batching. */
@@ -6428,7 +6860,9 @@ var _Datepicker = class _Datepicker extends Component {
6428
6860
  if (maxDate && date > maxDate) date.setTime(maxDate.getTime());
6429
6861
  if (date.getFullYear() < minYear || date.getFullYear() > maxYear || date.getFullYear() === minYear && date.getMonth() < (minMonth ?? 0) || date.getFullYear() === maxYear && date.getMonth() > (maxMonth ?? 11)) return;
6430
6862
  this._focusedDate = date;
6431
- this.gotoDate(date);
6863
+ const { year, month } = this.calendars[0];
6864
+ if (date.getFullYear() === year && date.getMonth() === month) this._syncCalendarFocus(true);
6865
+ else this.gotoDate(date);
6432
6866
  };
6433
6867
  this._handleCalendarClick = (e) => {
6434
6868
  const target = e.target;
@@ -6440,7 +6874,7 @@ var _Datepicker = class _Datepicker extends Component {
6440
6874
  e.target.getAttribute("data-month"),
6441
6875
  e.target.getAttribute("data-day")
6442
6876
  );
6443
- if (!this.multiple || this.multiple && this.options.isMultipleSelection) {
6877
+ if (!this.multiple || this.options.isMultipleSelection) {
6444
6878
  this.setDate(selectedDate);
6445
6879
  }
6446
6880
  if (this.options.isDateRange) {
@@ -6538,12 +6972,12 @@ var _Datepicker = class _Datepicker extends Component {
6538
6972
  }
6539
6973
  }
6540
6974
  }
6541
- if (this.options.displayPlugin) {
6542
- if (this.options.displayPlugin === "docked") this.displayPlugin = DockedDisplayPlugin.init(this.el, this.containerEl, this.options.displayPluginOptions);
6975
+ if (this.options.displayPlugin === "docked") {
6976
+ this.displayPlugin = DockedDisplayPlugin.init(this.el, this.containerEl, this.options.displayPluginOptions);
6543
6977
  }
6544
6978
  }
6545
6979
  static get defaults() {
6546
- return _defaults17;
6980
+ return _defaults20;
6547
6981
  }
6548
6982
  /**
6549
6983
  * Initializes instances of Datepicker.
@@ -6696,7 +7130,8 @@ var _Datepicker = class _Datepicker extends Component {
6696
7130
  this.draw();
6697
7131
  return;
6698
7132
  }
6699
- const parsedDate = this._parseInput(el.value);
7133
+ const written = !this.options.parse && this._writtenInputs.get(el);
7134
+ const parsedDate = written && written.value === el.value ? written.date : this._parseInput(el.value);
6700
7135
  if (!_Datepicker._isDate(parsedDate)) return;
6701
7136
  const date = new Date(parsedDate.getTime());
6702
7137
  _Datepicker._setToStartOfDay(date);
@@ -6754,7 +7189,7 @@ var _Datepicker = class _Datepicker extends Component {
6754
7189
  setSingleDate(date, isEndDate) {
6755
7190
  if (!isEndDate) {
6756
7191
  this.date = date;
6757
- } else if (isEndDate) {
7192
+ } else {
6758
7193
  this.endDate = date;
6759
7194
  }
6760
7195
  }
@@ -6763,13 +7198,11 @@ var _Datepicker = class _Datepicker extends Component {
6763
7198
  * @param date Date to set on the datepicker.
6764
7199
  */
6765
7200
  setMultiDate(date) {
6766
- const selectedDate = this.dates?.find((item) => {
6767
- return item.getTime() === date.getTime() ? item : false;
6768
- });
6769
- if (!selectedDate) {
7201
+ const index = this.dates.findIndex((item) => item.getTime() === date.getTime());
7202
+ if (index === -1) {
6770
7203
  this.dates.push(date);
6771
7204
  } else {
6772
- this.dates.splice(this.dates.indexOf(selectedDate), 1);
7205
+ this.dates.splice(index, 1);
6773
7206
  }
6774
7207
  this.dates.sort((a, b) => a.getTime() < b.getTime() ? -1 : 0);
6775
7208
  }
@@ -6811,6 +7244,7 @@ var _Datepicker = class _Datepicker extends Component {
6811
7244
  } else {
6812
7245
  el.value = this.toString(date);
6813
7246
  }
7247
+ this._writtenInputs.set(el, { value: el.value, date: _Datepicker._isDate(date) ? new Date(date.getTime()) : null });
6814
7248
  el.dispatchEvent(
6815
7249
  new CustomEvent("change", {
6816
7250
  bubbles: true,
@@ -6895,12 +7329,7 @@ var _Datepicker = class _Datepicker extends Component {
6895
7329
  }
6896
7330
  }
6897
7331
  const previousMonth = month === 0 ? 11 : month - 1, nextMonth = month === 11 ? 0 : month + 1, yearOfPreviousMonth = month === 0 ? year - 1 : year, yearOfNextMonth = month === 11 ? year + 1 : year, daysInPreviousMonth = _Datepicker._getDaysInMonth(yearOfPreviousMonth, previousMonth);
6898
- let cells = days + before, after = cells;
6899
- while (after > 7) {
6900
- after -= 7;
6901
- }
6902
- cells += 7 - after;
6903
- let isWeekSelected = false;
7332
+ const cells = Math.ceil((days + before) / 7) * 7;
6904
7333
  for (let i = 0, r = 0; i < cells; i++) {
6905
7334
  const day = new Date(year, month, 1 + (i - before)), isToday = _Datepicker._compareDates(day, now), hasEvent = this.options.events.indexOf(day.toDateString()) !== -1, isEmpty = i < before || i >= days + before, isStartRange = this.options.startRange && _Datepicker._compareDates(this.options.startRange, day), isEndRange = this.options.endRange && _Datepicker._compareDates(this.options.endRange, day), isInRange = this.options.startRange && this.options.endRange && this.options.startRange < day && day < this.options.endRange, isDisabled = this.options.minDate && day < this.options.minDate || this.options.maxDate && day > this.options.maxDate || this.options.disableWeekends && _Datepicker._isWeekend(day) || this.options.disableDayFn && this.options.disableDayFn(day), isDateRangeStart = this.options.isDateRange && this.date && this.endDate && _Datepicker._compareDates(this.date, day), isDateRangeEnd = this.options.isDateRange && this.endDate && _Datepicker._compareDates(this.endDate, day), isDateRange = this.options.isDateRange && _Datepicker._isDate(this.date) && _Datepicker._isDate(this.endDate) && _Datepicker._compareWithinRange(day, this.date, this.endDate);
6906
7335
  let dayNumber = 1 + (i - before), monthNumber = month, yearNumber = year;
@@ -6944,10 +7373,9 @@ var _Datepicker = class _Datepicker extends Component {
6944
7373
  };
6945
7374
  row.push(this.renderDay(dayConfig));
6946
7375
  if (++r === 7) {
6947
- data.push(this.renderRow(row, this.options.isRTL, isWeekSelected));
7376
+ data.push(this.renderRow(row, this.options.isRTL, false));
6948
7377
  row = [];
6949
7378
  r = 0;
6950
- isWeekSelected = false;
6951
7379
  }
6952
7380
  }
6953
7381
  return this.renderTable(this.options, data, randId);
@@ -6964,7 +7392,7 @@ var _Datepicker = class _Datepicker extends Component {
6964
7392
  isDateRangeStart: "is-daterange-start",
6965
7393
  isDateRangeEnd: "is-daterange-end",
6966
7394
  isDateRange: "is-daterange"
6967
- }, ariaSelected = !(["isSelected", "isDateRange"].filter((prop) => !!(opts.hasOwnProperty(prop) && opts[prop] === true)).length === 0), arr = ["datepicker-day"];
7395
+ }, ariaSelected = opts.isSelected === true || opts.isDateRange === true, arr = ["datepicker-day"];
6968
7396
  if (opts.isEmpty) {
6969
7397
  if (opts.showDaysInNextAndPreviousMonths) {
6970
7398
  arr.push("is-outside-current-month");
@@ -6985,7 +7413,9 @@ var _Datepicker = class _Datepicker extends Component {
6985
7413
  }
6986
7414
  /** Assemble calendar cells; reject unsupported elements and attributes. */
6987
7415
  renderRow(days, isRTL, isRowSelected) {
6988
- return '<tr class="datepicker-row' + (isRowSelected ? " is-selected" : "") + '">' + _Datepicker._calendarMarkup((isRTL ? days.reverse() : days).join(""), "tr") + "</tr>";
7416
+ const row = '<tr class="datepicker-row' + (isRowSelected ? " is-selected" : "") + '">' + _Datepicker._calendarMarkup((isRTL ? days.reverse() : days).join(""), "tr") + "</tr>";
7417
+ this._checkedRows.add(row);
7418
+ return row;
6989
7419
  }
6990
7420
  /** Assemble calendar rows; reject unsupported elements and attributes. */
6991
7421
  renderTable(opts, data, randId) {
@@ -7003,11 +7433,15 @@ var _Datepicker = class _Datepicker extends Component {
7003
7433
  }
7004
7434
  /** Wrap calendar rows after validating and encoding their contents. */
7005
7435
  renderBody(rows) {
7006
- return "<tbody>" + _Datepicker._calendarMarkup(rows.join(""), "tbody") + "</tbody>";
7436
+ const html = rows.join("");
7437
+ const safeHtml = _Datepicker._calendarMarkup(html, "tbody");
7438
+ this._checkedRows.clear();
7439
+ return "<tbody>" + safeHtml + "</tbody>";
7007
7440
  }
7008
7441
  static _calendarMarkup(html, parent) {
7009
7442
  const template = document.createElement("template");
7010
7443
  template.innerHTML = html;
7444
+ const childOf = { tbody: "tr", tr: "td", td: "button" };
7011
7445
  const attributes = {
7012
7446
  tr: ["class"],
7013
7447
  td: ["class", "data-day", "aria-selected"],
@@ -7021,8 +7455,8 @@ var _Datepicker = class _Datepicker extends Component {
7021
7455
  return _Datepicker._escape(node.textContent);
7022
7456
  }
7023
7457
  if (!(node instanceof HTMLElement)) throw new TypeError("Unsupported calendar row content");
7024
- const tag = node.localName === "tr" ? "tr" : node.localName === "td" ? "td" : node.localName === "button" ? "button" : null;
7025
- if (!tag || !(container === "tbody" && tag === "tr" || container === "tr" && tag === "td" || container === "td" && tag === "button")) {
7458
+ const tag = childOf[container];
7459
+ if (!tag || node.localName !== tag) {
7026
7460
  throw new TypeError("Unsupported calendar row element");
7027
7461
  }
7028
7462
  if ([...node.attributes].some((attr) => !attributes[tag].includes(attr.name))) {
@@ -7146,26 +7580,9 @@ var _Datepicker = class _Datepicker extends Component {
7146
7580
  const active = this.calendarEl.getRootNode().activeElement;
7147
7581
  const restoreDayFocus = active?.matches(".datepicker-day-button") && this.calendarEl.contains(active);
7148
7582
  const restoreArrow = this.calendarEl.contains(active) && active?.matches(".month-prev, .month-next") ? active.classList.contains("month-prev") ? ".month-prev" : ".month-next" : null;
7149
- const opts = this.options, minYear = opts.minYear, maxYear = opts.maxYear, minMonth = opts.minMonth, maxMonth = opts.maxMonth;
7150
- if (this._y <= minYear) {
7151
- this._y = minYear;
7152
- if (!isNaN(minMonth) && this._m < minMonth) {
7153
- this._m = minMonth;
7154
- }
7155
- }
7156
- if (this._y >= maxYear) {
7157
- this._y = maxYear;
7158
- if (!isNaN(maxMonth) && this._m > maxMonth) {
7159
- this._m = maxMonth;
7160
- }
7161
- }
7162
7583
  const year = this.calendars[0].year;
7163
7584
  const month = this.calendars[0].month;
7164
- if (!this.options.isDateRange) {
7165
- this._renderDateDisplay(this.date);
7166
- } else {
7167
- this._renderDateDisplay(this.date, this.endDate);
7168
- }
7585
+ this._renderDateDisplay(this.date, this.endDate);
7169
7586
  const key = this._controlsCacheKey(year);
7170
7587
  if (key === this._controlsKey && this.calendarEl.querySelector(".datepicker-controls")) {
7171
7588
  this._reuseControls(year, month);
@@ -7220,12 +7637,8 @@ var _Datepicker = class _Datepicker extends Component {
7220
7637
  else this.calendarEl.insertAdjacentHTML("beforeend", html);
7221
7638
  }
7222
7639
  _setupEventHandlers() {
7223
- this.el.addEventListener("click", this._handleInputClick);
7224
- this.el.addEventListener("keydown", this._handleInputKeydown);
7225
- this.el.addEventListener("change", this._handleInputChange);
7226
- this.endDateEl?.addEventListener("click", this._handleInputClick);
7227
- this.endDateEl?.addEventListener("keydown", this._handleInputKeydown);
7228
- this.endDateEl?.addEventListener("change", this._handleInputChange);
7640
+ this._addInputEventHandlers(this.el);
7641
+ if (this.endDateEl) this._addInputEventHandlers(this.endDateEl);
7229
7642
  this.calendarEl.addEventListener("click", this._handleCalendarClick);
7230
7643
  this.calendarEl.addEventListener("keydown", this._handleCalendarKeydown);
7231
7644
  this.calendarEl.addEventListener("focusin", this._handleCalendarFocus);
@@ -7282,6 +7695,11 @@ var _Datepicker = class _Datepicker extends Component {
7282
7695
  this._removeInputEventHandlers(this.endDateEl);
7283
7696
  }
7284
7697
  }
7698
+ _addInputEventHandlers(input) {
7699
+ input.addEventListener("click", this._handleInputClick);
7700
+ input.addEventListener("keydown", this._handleInputKeydown);
7701
+ input.addEventListener("change", this._handleInputChange);
7702
+ }
7285
7703
  _removeInputEventHandlers(input) {
7286
7704
  input.removeEventListener("click", this._handleInputClick);
7287
7705
  input.removeEventListener("keydown", this._handleInputKeydown);
@@ -7338,9 +7756,7 @@ var _Datepicker = class _Datepicker extends Component {
7338
7756
  const dateInput = this.el.cloneNode(true);
7339
7757
  dateInput.removeAttribute("id");
7340
7758
  dateInput.classList.add("no-autoinit");
7341
- dateInput.addEventListener("click", this._handleInputClick);
7342
- dateInput.addEventListener("keydown", this._handleInputKeydown);
7343
- dateInput.addEventListener("change", this._handleInputChange);
7759
+ this._addInputEventHandlers(dateInput);
7344
7760
  this.el.parentElement.appendChild(dateInput);
7345
7761
  return dateInput;
7346
7762
  }
@@ -7359,7 +7775,7 @@ _Datepicker._template = `
7359
7775
  var Datepicker = _Datepicker;
7360
7776
 
7361
7777
  // src/ts/components/messageScroller.ts
7362
- var _defaults18 = {
7778
+ var _defaults21 = {
7363
7779
  autoScroll: true,
7364
7780
  defaultScrollPosition: "end",
7365
7781
  peek: 64
@@ -7482,7 +7898,7 @@ var MessageScroller = class _MessageScroller extends Component {
7482
7898
  this.button?.addEventListener("click", this._handleButtonClick);
7483
7899
  }
7484
7900
  static get defaults() {
7485
- return _defaults18;
7901
+ return _defaults21;
7486
7902
  }
7487
7903
  /**
7488
7904
  * Initializes instances of MessageScroller.
@@ -7640,7 +8056,7 @@ var MessageScroller = class _MessageScroller extends Component {
7640
8056
  };
7641
8057
 
7642
8058
  // src/ts/components/richTextEditor.ts
7643
- var _defaults19 = {
8059
+ var _defaults22 = {
7644
8060
  Editor: null,
7645
8061
  extensions: []
7646
8062
  };
@@ -7720,7 +8136,7 @@ var RichTextEditor = class _RichTextEditor extends Component {
7720
8136
  el.addEventListener("click", this._handleClick);
7721
8137
  }
7722
8138
  static get defaults() {
7723
- return _defaults19;
8139
+ return _defaults22;
7724
8140
  }
7725
8141
  /**
7726
8142
  * Initializes instances of RichTextEditor.
@@ -7752,8 +8168,392 @@ var RichTextEditor = class _RichTextEditor extends Component {
7752
8168
  }
7753
8169
  };
7754
8170
 
8171
+ // src/ts/components/mapView.ts
8172
+ var OPENFREEMAP = "https://tiles.openfreemap.org/styles/";
8173
+ var _defaults23 = {
8174
+ maplibregl: null,
8175
+ style: { light: `${OPENFREEMAP}positron`, dark: `${OPENFREEMAP}dark` },
8176
+ center: [0, 20],
8177
+ zoom: 1,
8178
+ mapOptions: {}
8179
+ };
8180
+ var lngLat = (el) => el.dataset.lngLat.split(",").map(Number);
8181
+ function arc([x0, y0], [x2, y2], steps = 32) {
8182
+ const bow = x2 >= x0 ? 0.25 : -0.25;
8183
+ const x1 = (x0 + x2) / 2 - (y2 - y0) * bow;
8184
+ const y1 = (y0 + y2) / 2 + (x2 - x0) * bow;
8185
+ return Array.from({ length: steps + 1 }, (_, i) => {
8186
+ const t = i / steps, u = 1 - t;
8187
+ return [u * u * x0 + 2 * u * t * x1 + t * t * x2, u * u * y0 + 2 * u * t * y1 + t * t * y2];
8188
+ });
8189
+ }
8190
+ var MapView = class _MapView extends Component {
8191
+ constructor(el, options) {
8192
+ super(el, options, _MapView);
8193
+ /** The MapLibre map. */
8194
+ this.map = null;
8195
+ /** The MapLibre markers made from `.map-marker` children, in order. */
8196
+ this.markers = [];
8197
+ this._children = [];
8198
+ this._popups = [];
8199
+ this._markerPopups = /* @__PURE__ */ new Map();
8200
+ this._overlays = /* @__PURE__ */ new Map();
8201
+ this._styleReady = false;
8202
+ this._dark = false;
8203
+ this._location = null;
8204
+ this._media = null;
8205
+ this._observer = null;
8206
+ // Looked up once: `move` fires every frame of a pan or zoom.
8207
+ this._zoomIn = [];
8208
+ this._zoomOut = [];
8209
+ this._handleStyleLoad = () => {
8210
+ this._styleReady = true;
8211
+ for (const overlay2 of this._overlays.values()) overlay2.draw();
8212
+ };
8213
+ this._handleScheme = () => {
8214
+ const dark = this._isDark();
8215
+ if (dark === this._dark) return;
8216
+ this._dark = dark;
8217
+ this._styleReady = false;
8218
+ this.map.setStyle(this._style(), { diff: false });
8219
+ };
8220
+ this._sync = () => {
8221
+ const zoom = this.map.getZoom();
8222
+ for (const button of this._zoomIn) button.disabled = zoom >= this.map.getMaxZoom();
8223
+ for (const button of this._zoomOut) button.disabled = zoom <= this.map.getMinZoom();
8224
+ this.el.style.setProperty("--md-comp-map-bearing", `${-this.map.getBearing()}deg`);
8225
+ };
8226
+ this._handleFullscreen = () => {
8227
+ for (const button of this._buttons("fullscreen")) {
8228
+ button.setAttribute("aria-pressed", String(document.fullscreenElement === this.el));
8229
+ }
8230
+ };
8231
+ this._handleClick = (e) => {
8232
+ const target = e.target;
8233
+ const button = target.closest(".map-controls [data-action]");
8234
+ const action = button?.dataset.action;
8235
+ if (action === "zoom-in") this.map.zoomIn();
8236
+ else if (action === "zoom-out") this.map.zoomOut();
8237
+ else if (action === "compass") this.map.resetNorthPitch();
8238
+ else if (action === "locate") this._locate(button);
8239
+ else if (action === "fullscreen") {
8240
+ if (document.fullscreenElement === this.el) document.exitFullscreen();
8241
+ else this.el.requestFullscreen();
8242
+ } else {
8243
+ const marker = target.closest(".map-marker");
8244
+ if (this._markerPopups.has(marker)) this._toggle(marker);
8245
+ }
8246
+ };
8247
+ // A click on the map closes marker popups, but not the one being toggled.
8248
+ this._handleMapClick = (e) => {
8249
+ const target = e.originalEvent.target;
8250
+ for (const [marker, popup] of this._markerPopups) {
8251
+ if (!marker.contains(target) && !popup.getElement()?.contains(target)) popup.remove();
8252
+ }
8253
+ };
8254
+ this._handleKeydown = (e) => {
8255
+ if (e.key !== "Escape") return;
8256
+ for (const popup of this._popups) {
8257
+ if (popup.getElement()?.contains(e.target)) {
8258
+ e.preventDefault();
8259
+ popup.remove();
8260
+ }
8261
+ }
8262
+ };
8263
+ this.el["Expressive_MapView"] = this;
8264
+ this.options = {
8265
+ ..._MapView.defaults,
8266
+ ...options
8267
+ };
8268
+ const lib = this.options.maplibregl;
8269
+ if (!lib) {
8270
+ console.error("MapView needs the maplibre-gl module in options.maplibregl.");
8271
+ return;
8272
+ }
8273
+ this._children = [...el.children];
8274
+ this._zoomIn = [...this._buttons("zoom-in")];
8275
+ this._zoomOut = [...this._buttons("zoom-out")];
8276
+ this._dark = this._isDark();
8277
+ this.map = new lib.Map({
8278
+ ...this.options.mapOptions,
8279
+ container: el,
8280
+ style: this._style(),
8281
+ center: this.options.center,
8282
+ zoom: this.options.zoom
8283
+ });
8284
+ this.map.on("style.load", this._handleStyleLoad);
8285
+ this.map.on("move", this._sync);
8286
+ this.map.on("click", this._handleMapClick);
8287
+ const children = this._children.filter((child) => child instanceof HTMLElement);
8288
+ const claimed = /* @__PURE__ */ new Set();
8289
+ for (const marker of children.filter((child) => child.matches(".map-marker[data-lng-lat]"))) {
8290
+ const target = marker.hasAttribute("aria-controls") ? Utils.getElementById(marker, marker.getAttribute("aria-controls")) : null;
8291
+ const popup = target?.parentElement === el && target.matches(".map-popup") ? target : null;
8292
+ if (popup) claimed.add(popup);
8293
+ this._addMarker(marker, popup);
8294
+ }
8295
+ for (const popup of children.filter((child) => child.matches(".map-popup[data-lng-lat]") && !claimed.has(child))) {
8296
+ this._popup(popup, 0).setLngLat(lngLat(popup)).addTo(this.map);
8297
+ }
8298
+ if (this._themed()) {
8299
+ this._media = matchMedia("(prefers-color-scheme: dark)");
8300
+ this._media.addEventListener("change", this._handleScheme);
8301
+ this._observer = new MutationObserver(this._handleScheme);
8302
+ this._observer.observe(document.documentElement, { attributes: true, attributeFilter: ["theme"], subtree: true });
8303
+ }
8304
+ for (const button of this._buttons("fullscreen")) button.hidden = !document.fullscreenEnabled;
8305
+ document.addEventListener("fullscreenchange", this._handleFullscreen);
8306
+ el.addEventListener("click", this._handleClick);
8307
+ el.addEventListener("keydown", this._handleKeydown);
8308
+ this._sync();
8309
+ }
8310
+ static get defaults() {
8311
+ return _defaults23;
8312
+ }
8313
+ /**
8314
+ * Initializes instances of MapView.
8315
+ * @param els HTML elements.
8316
+ * @param options Component options.
8317
+ */
8318
+ static init(els, options = {}) {
8319
+ return super.init(els, options, _MapView);
8320
+ }
8321
+ static getInstance(el) {
8322
+ return el["Expressive_MapView"];
8323
+ }
8324
+ destroy() {
8325
+ this.el["Expressive_MapView"] = void 0;
8326
+ if (!this.map) return;
8327
+ this.el.removeEventListener("click", this._handleClick);
8328
+ this.el.removeEventListener("keydown", this._handleKeydown);
8329
+ document.removeEventListener("fullscreenchange", this._handleFullscreen);
8330
+ this._media?.removeEventListener("change", this._handleScheme);
8331
+ this._observer?.disconnect();
8332
+ for (const overlay2 of this._overlays.values()) overlay2.off?.();
8333
+ for (const popup of this._popups) popup.remove();
8334
+ for (const marker of this.markers) {
8335
+ marker.remove();
8336
+ const element = marker.getElement();
8337
+ element.classList.remove(...[...element.classList].filter((name) => name.startsWith("maplibregl-")));
8338
+ element.style.removeProperty("transform");
8339
+ element.style.removeProperty("opacity");
8340
+ if (element.hasAttribute("aria-controls")) element.removeAttribute("aria-expanded");
8341
+ }
8342
+ this._location?.remove();
8343
+ this._location = null;
8344
+ this.map.remove();
8345
+ this.map = null;
8346
+ this.markers = [];
8347
+ this._popups = [];
8348
+ this._markerPopups.clear();
8349
+ this._overlays.clear();
8350
+ this.el.style.removeProperty("--md-comp-map-bearing");
8351
+ for (const button of this.el.querySelectorAll(".map-controls [data-action]")) {
8352
+ button.disabled = false;
8353
+ button.hidden = false;
8354
+ button.removeAttribute("aria-pressed");
8355
+ }
8356
+ this.el.append(...this._children);
8357
+ }
8358
+ /** Draws a line through `[longitude, latitude]` points. Replaces an overlay with the same id. */
8359
+ addRoute(id, coordinates, options = {}) {
8360
+ this._line(id, { type: "LineString", coordinates }, "route", { width: 4, ...options });
8361
+ }
8362
+ /** Draws a curved line for each `{ from, to }`. Replaces an overlay with the same id. */
8363
+ addArcs(id, arcs, options = {}) {
8364
+ this._line(id, { type: "MultiLineString", coordinates: arcs.map(({ from, to }) => arc(from, to)) }, "arc", { width: 2, ...options });
8365
+ }
8366
+ /**
8367
+ * Draws GeoJSON points, or the URL of a GeoJSON file, as clusters that
8368
+ * show their count and zoom in when clicked. The layers are
8369
+ * `${id}-clusters`, `${id}-count` and `${id}-points`.
8370
+ */
8371
+ addClusters(id, data, options = {}) {
8372
+ const clusters = `${id}-clusters`, points = `${id}-points`;
8373
+ const zoomIn = async (e) => {
8374
+ const [feature] = e.features;
8375
+ const zoom = await this.map.getSource(id).getClusterExpansionZoom(feature.properties.cluster_id);
8376
+ this.map.easeTo({ center: feature.geometry.coordinates, zoom });
8377
+ };
8378
+ const pointer = () => {
8379
+ this.map.getCanvas().style.cursor = "pointer";
8380
+ };
8381
+ const reset = () => {
8382
+ this.map.getCanvas().style.cursor = "";
8383
+ };
8384
+ const listen = (method) => {
8385
+ this.map[method]("click", clusters, zoomIn);
8386
+ for (const layer of [clusters, points]) {
8387
+ this.map[method]("mouseenter", layer, pointer);
8388
+ this.map[method]("mouseleave", layer, reset);
8389
+ }
8390
+ };
8391
+ this._draw(id, {
8392
+ draw: () => {
8393
+ const color = options.color ?? this._color("var(--md-comp-map-cluster-color)");
8394
+ const surface = this._color("var(--md-comp-map-marker-ring-color)");
8395
+ this.map.addSource(id, {
8396
+ type: "geojson",
8397
+ data,
8398
+ cluster: true,
8399
+ clusterRadius: options.radius ?? 50,
8400
+ clusterMaxZoom: options.maxZoom ?? 14
8401
+ });
8402
+ this.map.addLayer({
8403
+ id: clusters,
8404
+ type: "circle",
8405
+ source: id,
8406
+ filter: ["has", "point_count"],
8407
+ paint: {
8408
+ "circle-color": color,
8409
+ "circle-radius": ["step", ["get", "point_count"], 16, 10, 20, 100, 26],
8410
+ "circle-stroke-width": 6,
8411
+ "circle-stroke-color": color,
8412
+ "circle-stroke-opacity": 0.3
8413
+ }
8414
+ });
8415
+ const style = this.map.getStyle();
8416
+ const font = style.glyphs && style.layers.find((layer) => layer.layout?.["text-font"])?.layout["text-font"];
8417
+ if (font) {
8418
+ this.map.addLayer({
8419
+ id: `${id}-count`,
8420
+ type: "symbol",
8421
+ source: id,
8422
+ filter: ["has", "point_count"],
8423
+ layout: { "text-field": ["get", "point_count_abbreviated"], "text-font": font, "text-size": 12 },
8424
+ paint: { "text-color": this._color("var(--md-comp-map-cluster-label-color)") }
8425
+ });
8426
+ }
8427
+ this.map.addLayer({
8428
+ id: points,
8429
+ type: "circle",
8430
+ source: id,
8431
+ filter: ["!", ["has", "point_count"]],
8432
+ paint: { "circle-color": color, "circle-radius": 6, "circle-stroke-width": 2, "circle-stroke-color": surface }
8433
+ });
8434
+ },
8435
+ off: () => listen("off")
8436
+ });
8437
+ listen("on");
8438
+ }
8439
+ /** Removes a route, arcs or clusters added with this id. */
8440
+ removeOverlay(id) {
8441
+ const overlay2 = this._overlays.get(id);
8442
+ if (!overlay2) return;
8443
+ this._overlays.delete(id);
8444
+ overlay2.off?.();
8445
+ if (!this._styleReady || !this.map.getSource(id)) return;
8446
+ for (const layer of this.map.getStyle().layers) if (layer.source === id) this.map.removeLayer(layer.id);
8447
+ this.map.removeSource(id);
8448
+ }
8449
+ _line(id, geometry, token, options) {
8450
+ this._draw(id, {
8451
+ draw: () => {
8452
+ this.map.addSource(id, { type: "geojson", data: { type: "Feature", properties: {}, geometry } });
8453
+ this.map.addLayer({
8454
+ id,
8455
+ type: "line",
8456
+ source: id,
8457
+ layout: { "line-cap": "round", "line-join": "round" },
8458
+ paint: {
8459
+ "line-color": options.color ?? this._color(`var(--md-comp-map-${token}-color)`),
8460
+ "line-width": options.width,
8461
+ "line-opacity": options.opacity ?? 1,
8462
+ ...options.dashArray && { "line-dasharray": options.dashArray }
8463
+ }
8464
+ });
8465
+ }
8466
+ });
8467
+ }
8468
+ // Sources and layers go with the style, so every overlay is drawn again
8469
+ // when a theme change swaps it.
8470
+ _draw(id, overlay2) {
8471
+ this.removeOverlay(id);
8472
+ this._overlays.set(id, overlay2);
8473
+ if (this._styleReady) overlay2.draw();
8474
+ }
8475
+ _addMarker(element, content) {
8476
+ const marker = new this.options.maplibregl.Marker({
8477
+ element,
8478
+ draggable: element.hasAttribute("data-draggable")
8479
+ }).setLngLat(lngLat(element)).addTo(this.map);
8480
+ marker.on("dragend", () => {
8481
+ const { lng, lat } = marker.getLngLat();
8482
+ element.dataset.lngLat = `${lng},${lat}`;
8483
+ element.dispatchEvent(new Event("change", { bubbles: true }));
8484
+ });
8485
+ this.markers.push(marker);
8486
+ if (!content) return;
8487
+ element.setAttribute("aria-expanded", "false");
8488
+ const popup = this._popup(content, 16);
8489
+ popup.on("open", () => element.setAttribute("aria-expanded", "true"));
8490
+ popup.on("close", () => {
8491
+ element.setAttribute("aria-expanded", "false");
8492
+ if (!document.activeElement || document.activeElement === document.body) element.focus();
8493
+ });
8494
+ this._markerPopups.set(element, popup);
8495
+ }
8496
+ _popup(content, offset) {
8497
+ const popup = new this.options.maplibregl.Popup({ closeOnClick: false, maxWidth: "none", offset }).setDOMContent(content);
8498
+ this._popups.push(popup);
8499
+ return popup;
8500
+ }
8501
+ _toggle(marker) {
8502
+ const popup = this._markerPopups.get(marker);
8503
+ if (popup.isOpen()) popup.remove();
8504
+ else popup.setLngLat(this.markers.find((m) => m.getElement() === marker).getLngLat()).addTo(this.map);
8505
+ }
8506
+ _buttons(action) {
8507
+ return this.el.querySelectorAll(`.map-controls [data-action="${action}"]`);
8508
+ }
8509
+ _locate(button) {
8510
+ navigator.geolocation?.getCurrentPosition(
8511
+ ({ coords }) => {
8512
+ if (!this.map) return;
8513
+ const center = [coords.longitude, coords.latitude];
8514
+ if (!this._location) {
8515
+ const dot = document.createElement("span");
8516
+ dot.className = "map-marker location";
8517
+ dot.setAttribute("aria-hidden", "true");
8518
+ this._location = new this.options.maplibregl.Marker({ element: dot });
8519
+ }
8520
+ this._location.setLngLat(center).addTo(this.map);
8521
+ this.map.flyTo({ center, zoom: Math.max(this.map.getZoom(), 14) });
8522
+ },
8523
+ (error) => {
8524
+ if (this.map && error.code === error.PERMISSION_DENIED) button.disabled = true;
8525
+ }
8526
+ );
8527
+ }
8528
+ // Resolves a CSS color where the map is, so light-dark() and scoped
8529
+ // themes apply, then paints it on a canvas to read back the sRGB value.
8530
+ // MapLibre does not parse the oklch() the theme tokens compute to.
8531
+ _color(value) {
8532
+ const probe = document.createElement("span");
8533
+ probe.hidden = true;
8534
+ probe.style.color = value;
8535
+ this.el.append(probe);
8536
+ const context = document.createElement("canvas").getContext("2d", { willReadFrequently: true });
8537
+ context.fillStyle = getComputedStyle(probe).color;
8538
+ probe.remove();
8539
+ context.fillRect(0, 0, 1, 1);
8540
+ const [r, g, b, a] = context.getImageData(0, 0, 1, 1).data;
8541
+ return `rgba(${r}, ${g}, ${b}, ${Math.round(a / 255 * 100) / 100})`;
8542
+ }
8543
+ _isDark() {
8544
+ return this._color("light-dark(black, white)") === "rgba(255, 255, 255, 1)";
8545
+ }
8546
+ _themed() {
8547
+ const style = this.options.style;
8548
+ return typeof style === "object" && "light" in style && "dark" in style;
8549
+ }
8550
+ _style() {
8551
+ return this._themed() ? this.options.style[this._dark ? "dark" : "light"] : this.options.style;
8552
+ }
8553
+ };
8554
+
7755
8555
  // src/ts/components/lightbox.ts
7756
- var _defaults20 = {
8556
+ var _defaults24 = {
7757
8557
  inDuration: 275,
7758
8558
  outDuration: 200,
7759
8559
  onOpenStart: null,
@@ -7783,9 +8583,6 @@ var _Lightbox = class _Lightbox extends Component {
7783
8583
  for (const el of [this.el, this._overlay, this._photoCaption]) if (el) el.style.transition = "none";
7784
8584
  }
7785
8585
  };
7786
- this._handleLightboxClick = () => {
7787
- this._handleLightboxToggle();
7788
- };
7789
8586
  this._handleLightboxKeypress = (e) => {
7790
8587
  if (this._trigger === this.el && (e.key === Utils.keys.ENTER || e.key === " ")) {
7791
8588
  e.preventDefault();
@@ -7796,10 +8593,7 @@ var _Lightbox = class _Lightbox extends Component {
7796
8593
  if (this._isOpen) this.close();
7797
8594
  else this.open();
7798
8595
  };
7799
- this._handleWindowScroll = () => {
7800
- if (this.overlayActive) this.close();
7801
- };
7802
- this._handleWindowResize = () => {
8596
+ this._handleWindowChange = () => {
7803
8597
  if (this.overlayActive) this.close();
7804
8598
  };
7805
8599
  this._handleWindowEscape = (e) => {
@@ -7847,8 +8641,6 @@ var _Lightbox = class _Lightbox extends Component {
7847
8641
  if (this.caption !== "") this._addCaption();
7848
8642
  const widthPercent = this.originalWidth / this.windowWidth;
7849
8643
  const heightPercent = this.originalHeight / this.windowHeight;
7850
- this.newWidth = 0;
7851
- this.newHeight = 0;
7852
8644
  if (widthPercent > heightPercent) {
7853
8645
  const ratio = this.originalHeight / this.originalWidth;
7854
8646
  this.newWidth = this.windowWidth * 0.9;
@@ -7858,8 +8650,8 @@ var _Lightbox = class _Lightbox extends Component {
7858
8650
  this.newWidth = this.windowHeight * 0.9 * ratio;
7859
8651
  this.newHeight = this.windowHeight * 0.9;
7860
8652
  }
7861
- window.addEventListener("scroll", this._handleWindowScroll, { passive: true });
7862
- window.addEventListener("resize", this._handleWindowResize, { passive: true });
8653
+ window.addEventListener("scroll", this._handleWindowChange, { passive: true });
8654
+ window.addEventListener("resize", this._handleWindowChange, { passive: true });
7863
8655
  window.addEventListener("keyup", this._handleWindowEscape);
7864
8656
  this._animateImageIn();
7865
8657
  };
@@ -7874,11 +8666,11 @@ var _Lightbox = class _Lightbox extends Component {
7874
8666
  if (typeof this.options.onCloseStart === "function")
7875
8667
  this.options.onCloseStart.call(this, this.el);
7876
8668
  if (revision !== this._revision) return;
7877
- window.removeEventListener("scroll", this._handleWindowScroll);
7878
- window.removeEventListener("resize", this._handleWindowResize);
8669
+ window.removeEventListener("scroll", this._handleWindowChange);
8670
+ window.removeEventListener("resize", this._handleWindowChange);
7879
8671
  window.removeEventListener("keyup", this._handleWindowEscape);
7880
- if (this._overlay) this._removeOverlay();
7881
- if (this._photoCaption) this._removeCaption();
8672
+ if (this._overlay) this._fadeOut(this._overlay);
8673
+ if (this._photoCaption) this._fadeOut(this._photoCaption);
7882
8674
  this._animateImageOut();
7883
8675
  };
7884
8676
  this.el["Expressive_Lightbox"] = this;
@@ -7902,7 +8694,7 @@ var _Lightbox = class _Lightbox extends Component {
7902
8694
  this._setupEventHandlers();
7903
8695
  }
7904
8696
  static get defaults() {
7905
- return _defaults20;
8697
+ return _defaults24;
7906
8698
  }
7907
8699
  /**
7908
8700
  * Initializes instances of Lightbox.
@@ -7932,8 +8724,8 @@ var _Lightbox = class _Lightbox extends Component {
7932
8724
  this.el["Expressive_Lightbox"] = void 0;
7933
8725
  }
7934
8726
  _reset() {
7935
- window.removeEventListener("scroll", this._handleWindowScroll);
7936
- window.removeEventListener("resize", this._handleWindowResize);
8727
+ window.removeEventListener("scroll", this._handleWindowChange);
8728
+ window.removeEventListener("resize", this._handleWindowChange);
7937
8729
  window.removeEventListener("keyup", this._handleWindowEscape);
7938
8730
  this._overlay?.remove();
7939
8731
  this._photoCaption?.remove();
@@ -7945,8 +8737,8 @@ var _Lightbox = class _Lightbox extends Component {
7945
8737
  }
7946
8738
  }
7947
8739
  this._changedAncestorList = [];
7948
- if (this.attrWidth !== null && this.attrWidth !== void 0) this.el.setAttribute("width", this.attrWidth);
7949
- if (this.attrHeight !== null && this.attrHeight !== void 0) this.el.setAttribute("height", this.attrHeight);
8740
+ if (this.attrWidth != null) this.el.setAttribute("width", this.attrWidth);
8741
+ if (this.attrHeight != null) this.el.setAttribute("height", this.attrHeight);
7950
8742
  this.el.classList.remove("active");
7951
8743
  this.placeholder.removeAttribute("style");
7952
8744
  if (this.originInlineStyles === null) this.el.removeAttribute("style");
@@ -7973,18 +8765,18 @@ var _Lightbox = class _Lightbox extends Component {
7973
8765
  }
7974
8766
  _setupEventHandlers() {
7975
8767
  this._motion.addEventListener("change", this._handleMotionChange);
7976
- this._trigger.addEventListener("click", this._handleLightboxClick);
8768
+ this._trigger.addEventListener("click", this._handleLightboxToggle);
7977
8769
  this.el.addEventListener("keydown", this._handleLightboxKeypress);
7978
8770
  }
7979
8771
  _removeEventHandlers() {
7980
8772
  this._motion.removeEventListener("change", this._handleMotionChange);
7981
- this._trigger.removeEventListener("click", this._handleLightboxClick);
8773
+ this._trigger.removeEventListener("click", this._handleLightboxToggle);
7982
8774
  this.el.removeEventListener("keydown", this._handleLightboxKeypress);
7983
8775
  }
7984
8776
  _makeAncestorsOverflowVisible() {
7985
8777
  this._changedAncestorList = [];
7986
8778
  let ancestor = this.placeholder.parentNode;
7987
- while (ancestor !== null && ancestor !== void 0 && ancestor !== document) {
8779
+ while (ancestor != null && ancestor !== document) {
7988
8780
  const curr = ancestor;
7989
8781
  if (curr.style && (curr.style.overflow !== "visible" || _Lightbox._overflow.has(curr))) {
7990
8782
  const saved = _Lightbox._overflow.get(curr) ?? { count: 0, value: curr.style.overflow, priority: curr.style.getPropertyPriority("overflow") };
@@ -8058,18 +8850,7 @@ var _Lightbox = class _Lightbox extends Component {
8058
8850
  this._photoCaption.innerText = this.caption;
8059
8851
  Utils.portalRoot(this.el).append(this._photoCaption);
8060
8852
  this._photoCaption.style.display = "inline";
8061
- this._photoCaption.style.transition = "none";
8062
- this._photoCaption.style.opacity = "0";
8063
- const duration = this._motion.matches ? 0 : this.options.inDuration;
8064
- this._schedule(() => {
8065
- this._photoCaption.style.transition = `opacity ${duration}ms ease`;
8066
- this._photoCaption.style.opacity = "1";
8067
- }, 1);
8068
- }
8069
- _removeCaption() {
8070
- const duration = this._motion.matches ? 0 : this.options.outDuration;
8071
- this._photoCaption.style.transition = `opacity ${duration}ms ease`;
8072
- this._photoCaption.style.opacity = "0";
8853
+ this._fadeIn(this._photoCaption);
8073
8854
  }
8074
8855
  // Overlay
8075
8856
  _addOverlay() {
@@ -8089,18 +8870,21 @@ var _Lightbox = class _Lightbox extends Component {
8089
8870
  this._overlay.style.height = this.windowHeight + "px";
8090
8871
  this._overlay.style.left = -1 * overlayOffset.left + "px";
8091
8872
  this._overlay.style.top = -1 * overlayOffset.top + "px";
8092
- this._overlay.style.transition = "none";
8093
- this._overlay.style.opacity = "0";
8873
+ this._fadeIn(this._overlay);
8874
+ }
8875
+ _fadeIn(el) {
8876
+ el.style.transition = "none";
8877
+ el.style.opacity = "0";
8094
8878
  const duration = this._motion.matches ? 0 : this.options.inDuration;
8095
8879
  this._schedule(() => {
8096
- this._overlay.style.transition = `opacity ${duration}ms ease`;
8097
- this._overlay.style.opacity = "1";
8880
+ el.style.transition = `opacity ${duration}ms ease`;
8881
+ el.style.opacity = "1";
8098
8882
  }, 1);
8099
8883
  }
8100
- _removeOverlay() {
8884
+ _fadeOut(el) {
8101
8885
  const duration = this._motion.matches ? 0 : this.options.outDuration;
8102
- this._overlay.style.transition = `opacity ${duration}ms ease`;
8103
- this._overlay.style.opacity = "0";
8886
+ el.style.transition = `opacity ${duration}ms ease`;
8887
+ el.style.opacity = "0";
8104
8888
  }
8105
8889
  };
8106
8890
  _Lightbox._overflow = /* @__PURE__ */ new WeakMap();
@@ -8108,7 +8892,7 @@ var Lightbox = _Lightbox;
8108
8892
 
8109
8893
  // src/ts/components/scrollspy.ts
8110
8894
  var _defaultGetActiveElement = (id) => `a[href="#${id}"]`;
8111
- var _defaults21 = {
8895
+ var _defaults25 = {
8112
8896
  scrollOffset: 200,
8113
8897
  activeClass: "active",
8114
8898
  getActiveElement: _defaultGetActiveElement,
@@ -8144,7 +8928,7 @@ var _ScrollSpy = class _ScrollSpy extends Component {
8144
8928
  }
8145
8929
  }
8146
8930
  static get defaults() {
8147
- return _defaults21;
8931
+ return _defaults25;
8148
8932
  }
8149
8933
  static init(els, options = {}) {
8150
8934
  return super.init(els, options, _ScrollSpy);
@@ -8178,8 +8962,9 @@ var _ScrollSpy = class _ScrollSpy extends Component {
8178
8962
  const retained = elements.filter((spy) => spy.options.keepTopElementActive);
8179
8963
  best = _ScrollSpy._nearestAbove(retained) ?? retained[0];
8180
8964
  }
8181
- const next = best ? _ScrollSpy._linkFor(best.el.id, best.options) : null;
8182
8965
  const active = _ScrollSpy._active.get(resolver);
8966
+ if (best && active === best && best._link?.isConnected) return;
8967
+ const next = best ? _ScrollSpy._linkFor(best.el.id, best.options) : null;
8183
8968
  if (active === best && active?._link === next) return;
8184
8969
  _ScrollSpy._clearActive(resolver);
8185
8970
  if (!next) return;
@@ -8222,11 +9007,7 @@ var _ScrollSpy = class _ScrollSpy extends Component {
8222
9007
  }
8223
9008
  }
8224
9009
  const href = `#${id}`;
8225
- const links = document.querySelectorAll('a[href^="#"]');
8226
- for (let i = 0; i < links.length; i++) {
8227
- if (links[i].getAttribute("href") === href) return links[i];
8228
- }
8229
- return null;
9010
+ return Array.from(document.querySelectorAll('a[href^="#"]')).find((link) => link.getAttribute("href") === href) ?? null;
8230
9011
  }
8231
9012
  };
8232
9013
  _ScrollSpy._elements = [];
@@ -8234,13 +9015,18 @@ _ScrollSpy._active = /* @__PURE__ */ new Map();
8234
9015
  var ScrollSpy = _ScrollSpy;
8235
9016
 
8236
9017
  // src/ts/components/navigationRail.ts
8237
- var _defaults22 = {
9018
+ var _defaults26 = {
8238
9019
  onOpenStart: null,
8239
9020
  onOpenEnd: null,
8240
9021
  onCloseStart: null,
8241
9022
  onCloseEnd: null
8242
9023
  };
8243
9024
  var COMPACT = "(width < 600px)";
9025
+ function deepActiveElement(root) {
9026
+ let active = root.activeElement;
9027
+ while (active?.shadowRoot?.activeElement) active = active.shadowRoot.activeElement;
9028
+ return active;
9029
+ }
8244
9030
  var NavigationRail = class _NavigationRail extends Component {
8245
9031
  constructor(el, options) {
8246
9032
  super(el, options, _NavigationRail);
@@ -8284,7 +9070,7 @@ var NavigationRail = class _NavigationRail extends Component {
8284
9070
  this._onClick = (e) => {
8285
9071
  const target = e.target;
8286
9072
  if (!(target instanceof Node)) return;
8287
- if (this._toggle && (target === this._toggle || this._toggle.contains(target))) {
9073
+ if (this._toggle?.contains(target)) {
8288
9074
  this.toggle();
8289
9075
  e.preventDefault();
8290
9076
  return;
@@ -8298,12 +9084,9 @@ var NavigationRail = class _NavigationRail extends Component {
8298
9084
  if (this.isExpanded && this._isModal()) {
8299
9085
  const root = this.el.getRootNode();
8300
9086
  const restoreFocus = this.el.contains(root.activeElement);
8301
- let focused = root.activeElement;
8302
- while (focused?.shadowRoot?.activeElement) focused = focused.shadowRoot.activeElement;
9087
+ const focused = deepActiveElement(root);
8303
9088
  this.collapse();
8304
- let active = root.activeElement;
8305
- while (active?.shadowRoot?.activeElement) active = active.shadowRoot.activeElement;
8306
- if (!this.isExpanded && restoreFocus && active === focused) {
9089
+ if (!this.isExpanded && restoreFocus && deepActiveElement(root) === focused) {
8307
9090
  this._toggle?.focus();
8308
9091
  }
8309
9092
  }
@@ -8321,7 +9104,7 @@ var NavigationRail = class _NavigationRail extends Component {
8321
9104
  document.addEventListener("keydown", this._onKeyDown);
8322
9105
  }
8323
9106
  static get defaults() {
8324
- return _defaults22;
9107
+ return _defaults26;
8325
9108
  }
8326
9109
  static init(els, options = {}) {
8327
9110
  return super.init(els, options, _NavigationRail);
@@ -8351,7 +9134,7 @@ var NavigationRail = class _NavigationRail extends Component {
8351
9134
  };
8352
9135
 
8353
9136
  // src/ts/components/tabs.ts
8354
- var _defaults23 = {
9137
+ var _defaults27 = {
8355
9138
  duration: 300,
8356
9139
  onShow: null,
8357
9140
  swipeable: false,
@@ -8364,13 +9147,12 @@ var Tabs = class _Tabs extends Component {
8364
9147
  super(el, options, _Tabs);
8365
9148
  this._originalPanels = /* @__PURE__ */ new Map();
8366
9149
  this._originalLinks = /* @__PURE__ */ new Map();
8367
- this._handleWindowResize = () => {
9150
+ // Throttled like Carousel's: every bar re-measures on resize, and the left
9151
+ // and right positions are both read before either is written.
9152
+ this._handleWindowResize = Utils.throttle(() => {
8368
9153
  this._setTabsAndTabWidth();
8369
- if (this._tabWidth !== 0 && this._tabsWidth !== 0) {
8370
- this._indicator.style.left = this._calcLeftPos(this._activeTabLink) + "px";
8371
- this._indicator.style.right = this._calcRightPos(this._activeTabLink) + "px";
8372
- }
8373
- };
9154
+ if (this._tabWidth !== 0 && this._tabsWidth !== 0) this._positionIndicator();
9155
+ }, 200);
8374
9156
  this._handleTabClick = (e) => {
8375
9157
  const target = e.target;
8376
9158
  if (!target) return;
@@ -8384,8 +9166,7 @@ var Tabs = class _Tabs extends Component {
8384
9166
  }
8385
9167
  if (tabLink.hasAttribute("target")) return;
8386
9168
  if (this.options.swipeable) {
8387
- const panel = tabLink.hash && document.getElementById(tabLink.hash.slice(1));
8388
- const index = this._tabsCarousel.images.indexOf(panel);
9169
+ const index = this._tabsCarousel.images.indexOf(this._panelFor(tabLink));
8389
9170
  if (index >= 0) this._tabsCarousel.set(index);
8390
9171
  e.preventDefault();
8391
9172
  return;
@@ -8414,10 +9195,13 @@ var Tabs = class _Tabs extends Component {
8414
9195
  ...options
8415
9196
  };
8416
9197
  this._tabLinks = this._queryTabLinks();
9198
+ if (!this._tabLinks.length) {
9199
+ console.error("Tabs: no tab links (an <a> child, or one inside .tab) to show");
9200
+ return;
9201
+ }
8417
9202
  this._tabLinks.forEach((link) => {
8418
9203
  this._originalLinks.set(link, { active: link.classList.contains("active"), current: link.getAttribute("aria-current") });
8419
- if (link.hasAttribute("target")) return;
8420
- const panel = link.hash && document.getElementById(link.hash.slice(1));
9204
+ const panel = this._panelFor(link);
8421
9205
  if (panel) this._originalPanels.set(panel, {
8422
9206
  display: panel.style.display,
8423
9207
  priority: panel.style.getPropertyPriority("display"),
@@ -8425,7 +9209,7 @@ var Tabs = class _Tabs extends Component {
8425
9209
  carousel: panel.classList.contains("carousel-item")
8426
9210
  });
8427
9211
  });
8428
- (_a = this.options).swipeable && (_a.swipeable = window.innerWidth <= this.options.responsiveThreshold);
9212
+ (_a = this.options).swipeable && (_a.swipeable = window.innerWidth <= this.options.responsiveThreshold && this._originalPanels.size > 0);
8429
9213
  this._index = 0;
8430
9214
  this._setupActiveTabLink();
8431
9215
  if (this.options.swipeable) {
@@ -8436,9 +9220,12 @@ var Tabs = class _Tabs extends Component {
8436
9220
  this._setTabsAndTabWidth();
8437
9221
  this._createIndicator();
8438
9222
  this._setupEventHandlers();
9223
+ document.fonts?.ready.then(() => {
9224
+ if (this.el["Expressive_Tabs"] === this) this._handleWindowResize();
9225
+ });
8439
9226
  }
8440
9227
  static get defaults() {
8441
- return _defaults23;
9228
+ return _defaults27;
8442
9229
  }
8443
9230
  /**
8444
9231
  * Initializes instances of Tabs.
@@ -8453,8 +9240,8 @@ var Tabs = class _Tabs extends Component {
8453
9240
  }
8454
9241
  destroy() {
8455
9242
  this._removeEventHandlers();
8456
- this._indicator.remove();
8457
- if (this.options.swipeable) {
9243
+ this._indicator?.remove();
9244
+ if (this._tabsCarousel) {
8458
9245
  this._teardownSwipeableTabs();
8459
9246
  }
8460
9247
  this._originalPanels.forEach((original, panel) => {
@@ -8495,8 +9282,19 @@ var Tabs = class _Tabs extends Component {
8495
9282
  indicator.classList.add("indicator");
8496
9283
  this.el.appendChild(indicator);
8497
9284
  this._indicator = indicator;
8498
- this._indicator.style.left = this._calcLeftPos(this._activeTabLink) + "px";
8499
- this._indicator.style.right = this._calcRightPos(this._activeTabLink) + "px";
9285
+ this._positionIndicator();
9286
+ }
9287
+ /** Reads both positions before writing either. */
9288
+ _positionIndicator() {
9289
+ const left = this._calcLeftPos(this._activeTabLink);
9290
+ const right = this._calcRightPos(this._activeTabLink);
9291
+ this._indicator.style.left = left + "px";
9292
+ this._indicator.style.right = right + "px";
9293
+ }
9294
+ /** The panel a link shows, or null for a `target` link or one without a hash. */
9295
+ _panelFor(a) {
9296
+ if (!a.hash || a.hasAttribute("target")) return null;
9297
+ return document.getElementById(a.hash.slice(1));
8500
9298
  }
8501
9299
  /**
8502
9300
  * Which tab is current, for the eye and for assistive technology.
@@ -8518,31 +9316,20 @@ var Tabs = class _Tabs extends Component {
8518
9316
  tabLink.classList.add("active");
8519
9317
  tabLink.setAttribute("aria-current", "page");
8520
9318
  this._index = Array.from(this._tabLinks).indexOf(tabLink);
8521
- this._content = tabLink.hasAttribute("target") ? null : document.getElementById(tabLink.hash.slice(1));
9319
+ this._content = this._panelFor(tabLink);
8522
9320
  }
8523
9321
  _setupActiveTabLink() {
8524
- this._activeTabLink = Array.from(this._tabLinks).find(
8525
- (a) => a.getAttribute("href") === location.hash
8526
- );
8527
- if (!this._activeTabLink) {
8528
- let activeTabLink = this.el.querySelector("a.active");
8529
- if (!activeTabLink) {
8530
- activeTabLink = this._tabLinks[0];
8531
- }
8532
- this._activeTabLink = activeTabLink;
8533
- }
9322
+ this._activeTabLink = Array.from(this._tabLinks).find((a) => a.getAttribute("href") === location.hash) ?? this.el.querySelector("a.active") ?? this._tabLinks[0];
8534
9323
  this._setActiveTabLink(this._activeTabLink);
8535
9324
  this._originalPanels.forEach((_, panel) => panel.classList.toggle("active", panel === this._content));
8536
9325
  }
8537
9326
  _setupSwipeableTabs() {
8538
9327
  const tabsContent = [];
8539
9328
  this._tabLinks.forEach((a) => {
8540
- if (a.hash && !a.hasAttribute("target")) {
8541
- const currContent = document.getElementById(a.hash.slice(1));
8542
- if (!currContent) return;
8543
- currContent.classList.add("carousel-item");
8544
- tabsContent.push(currContent);
8545
- }
9329
+ const currContent = this._panelFor(a);
9330
+ if (!currContent) return;
9331
+ currContent.classList.add("carousel-item");
9332
+ tabsContent.push(currContent);
8546
9333
  });
8547
9334
  const tabsWrapper = document.createElement("div");
8548
9335
  tabsWrapper.classList.add("tabs-content", "carousel", "flat");
@@ -8576,11 +9363,9 @@ var Tabs = class _Tabs extends Component {
8576
9363
  }
8577
9364
  _setupNormalTabs() {
8578
9365
  Array.from(this._tabLinks).forEach((a) => {
8579
- if (a === this._activeTabLink || a.hasAttribute("target")) return;
8580
- if (a.hash) {
8581
- const currContent = document.getElementById(a.hash.slice(1));
8582
- if (currContent) currContent.style.display = "none";
8583
- }
9366
+ if (a === this._activeTabLink) return;
9367
+ const currContent = this._panelFor(a);
9368
+ if (currContent) currContent.style.display = "none";
8584
9369
  });
8585
9370
  }
8586
9371
  _setTabsAndTabWidth() {
@@ -8609,23 +9394,20 @@ var Tabs = class _Tabs extends Component {
8609
9394
  this._indicator.style.transition = `
8610
9395
  left ${this.options.duration}ms ease-out ${leftDelay}ms,
8611
9396
  right ${this.options.duration}ms ease-out ${rightDelay}ms`;
8612
- this._indicator.style.left = this._calcLeftPos(this._activeTabLink) + "px";
8613
- this._indicator.style.right = this._calcRightPos(this._activeTabLink) + "px";
9397
+ this._positionIndicator();
8614
9398
  }
8615
9399
  /**
8616
9400
  * Show tab content that corresponds to the tab with the id.
8617
9401
  * @param tabId The id of the tab that you want to switch to.
8618
9402
  */
8619
9403
  select(tabId) {
8620
- const tab = Array.from(this._tabLinks).find(
8621
- (a) => a.getAttribute("href") === "#" + tabId
8622
- );
9404
+ const tab = Array.from(this._tabLinks).find((a) => a.getAttribute("href") === "#" + tabId);
8623
9405
  if (tab) tab.click();
8624
9406
  }
8625
9407
  };
8626
9408
 
8627
9409
  // src/ts/components/timepicker.ts
8628
- var _defaults24 = {
9410
+ var _defaults28 = {
8629
9411
  dialRadius: 135,
8630
9412
  outerRadius: 105,
8631
9413
  innerRadius: 70,
@@ -8708,8 +9490,7 @@ var _Timepicker = class _Timepicker extends Component {
8708
9490
  if (e.pointerId !== this._dragPointerId) return;
8709
9491
  this._dragPointerId = null;
8710
9492
  e.preventDefault();
8711
- document.removeEventListener("pointerup", this._handleDocumentClickEnd);
8712
- document.removeEventListener("pointercancel", this._handleDocumentClickCancel);
9493
+ this._removeDragListeners();
8713
9494
  const x = e.clientX - this.x0;
8714
9495
  const y = e.clientY - this.y0;
8715
9496
  if (this.moved && x === this.dx && y === this.dy) {
@@ -8728,7 +9509,6 @@ var _Timepicker = class _Timepicker extends Component {
8728
9509
  if (typeof this.options.onSelect === "function") {
8729
9510
  this.options.onSelect.call(this, this.hours, this.minutes);
8730
9511
  }
8731
- document.removeEventListener("pointermove", this._handleDocumentClickMove);
8732
9512
  };
8733
9513
  /**
8734
9514
  * A cancelled pointer is not a completed selection. The browser or the OS
@@ -8740,9 +9520,7 @@ var _Timepicker = class _Timepicker extends Component {
8740
9520
  if (e.pointerId !== this._dragPointerId) return;
8741
9521
  this._dragPointerId = null;
8742
9522
  this.moved = false;
8743
- document.removeEventListener("pointermove", this._handleDocumentClickMove);
8744
- document.removeEventListener("pointerup", this._handleDocumentClickEnd);
8745
- document.removeEventListener("pointercancel", this._handleDocumentClickCancel);
9523
+ this._removeDragListeners();
8746
9524
  };
8747
9525
  this._handleAmPmClick = (e) => {
8748
9526
  this._handleAmPmInteraction(e.target);
@@ -8816,12 +9594,12 @@ var _Timepicker = class _Timepicker extends Component {
8816
9594
  this._setupVariables();
8817
9595
  this._setupEventHandlers();
8818
9596
  this._pickerSetup();
8819
- if (this.options.displayPlugin) {
8820
- if (this.options.displayPlugin === "docked") this.displayPlugin = DockedDisplayPlugin.init(this.el, this.containerEl, this.options.displayPluginOptions);
9597
+ if (this.options.displayPlugin === "docked") {
9598
+ this.displayPlugin = DockedDisplayPlugin.init(this.el, this.containerEl, this.options.displayPluginOptions);
8821
9599
  }
8822
9600
  }
8823
9601
  static get defaults() {
8824
- return _defaults24;
9602
+ return _defaults28;
8825
9603
  }
8826
9604
  /**
8827
9605
  * Initializes instances of Timepicker.
@@ -8865,6 +9643,9 @@ var _Timepicker = class _Timepicker extends Component {
8865
9643
  this.digitalClock.removeEventListener("input", this._inputFromTextField);
8866
9644
  this.el.removeEventListener("click", this._handleInputClick);
8867
9645
  this.el.removeEventListener("keydown", this._handleInputKeydown);
9646
+ this._removeDragListeners();
9647
+ }
9648
+ _removeDragListeners() {
8868
9649
  document.removeEventListener("pointermove", this._handleDocumentClickMove);
8869
9650
  document.removeEventListener("pointerup", this._handleDocumentClickEnd);
8870
9651
  document.removeEventListener("pointercancel", this._handleDocumentClickCancel);
@@ -8996,25 +9777,22 @@ var _Timepicker = class _Timepicker extends Component {
8996
9777
  }
8997
9778
  }
8998
9779
  _buildHoursTick(i, radian, radius) {
8999
- const tick = document.createElement("div");
9000
- tick.classList.add("timepicker-tick");
9001
- tick.style.left = this.options.dialRadius + Math.sin(radian) * radius - this.options.tickRadius + "px";
9002
- tick.style.top = this.options.dialRadius - Math.cos(radian) * radius - this.options.tickRadius + "px";
9003
- tick.textContent = i === 0 ? "00" : i.toString();
9004
- this.hoursView.appendChild(tick);
9780
+ this._placeTick(this.hoursView, radian, radius, i === 0 ? "00" : i.toString());
9005
9781
  }
9006
9782
  _buildMinutesView() {
9007
- const _tick = document.createElement("div");
9008
- _tick.classList.add("timepicker-tick");
9009
9783
  for (let i = 0; i < 60; i += 5) {
9010
- const tick = _tick.cloneNode(true);
9011
9784
  const radian = i / 30 * Math.PI;
9012
- tick.style.left = this.options.dialRadius + Math.sin(radian) * this.options.outerRadius - this.options.tickRadius + "px";
9013
- tick.style.top = this.options.dialRadius - Math.cos(radian) * this.options.outerRadius - this.options.tickRadius + "px";
9014
- tick.textContent = _Timepicker._addLeadingZero(i);
9015
- this.minutesView.appendChild(tick);
9785
+ this._placeTick(this.minutesView, radian, this.options.outerRadius, _Timepicker._addLeadingZero(i));
9016
9786
  }
9017
9787
  }
9788
+ _placeTick(view, radian, radius, text) {
9789
+ const tick = document.createElement("div");
9790
+ tick.classList.add("timepicker-tick");
9791
+ tick.style.left = this.options.dialRadius + Math.sin(radian) * radius - this.options.tickRadius + "px";
9792
+ tick.style.top = this.options.dialRadius - Math.cos(radian) * radius - this.options.tickRadius + "px";
9793
+ tick.textContent = text;
9794
+ view.appendChild(tick);
9795
+ }
9018
9796
  _updateAmPmView() {
9019
9797
  if (!this._amBtn || !this._pmBtn) return;
9020
9798
  this._amBtn.setAttribute("aria-pressed", String(this.amOrPm === "AM"));
@@ -9081,53 +9859,31 @@ var _Timepicker = class _Timepicker extends Component {
9081
9859
  setHand(x, y, roundBy5 = false) {
9082
9860
  this._cancelClockReset();
9083
9861
  const isHours = this.currentView === "hours", unit = Math.PI / (isHours || roundBy5 ? 6 : 30), z = Math.sqrt(x * x + y * y), inner = isHours && z < (this.options.outerRadius + this.options.innerRadius) / 2;
9084
- let radian = Math.atan2(x, -y), radius = inner ? this.options.innerRadius : this.options.outerRadius;
9085
- if (this.options.twelveHour) {
9086
- radius = this.options.outerRadius;
9087
- }
9862
+ const radius = inner && !this.options.twelveHour ? this.options.innerRadius : this.options.outerRadius;
9863
+ let radian = Math.atan2(x, -y);
9088
9864
  if (radian < 0) {
9089
9865
  radian = Math.PI * 2 + radian;
9090
9866
  }
9091
9867
  let value = Math.round(radian / unit);
9092
9868
  radian = value * unit;
9093
- if (this.options.twelveHour) {
9094
- if (isHours) {
9095
- if (value === 0) value = 12;
9096
- } else {
9097
- if (roundBy5) value *= 5;
9098
- if (value === 60) value = 0;
9099
- }
9100
- } else {
9101
- if (isHours) {
9102
- if (value === 12) {
9103
- value = 0;
9104
- }
9105
- value = inner ? value === 0 ? 12 : value : value === 0 ? 0 : value + 12;
9106
- } else {
9107
- if (roundBy5) {
9108
- value *= 5;
9109
- }
9110
- if (value === 60) {
9111
- value = 0;
9112
- }
9113
- }
9114
- }
9115
- if (this[this.currentView] !== value) {
9116
- if (this.canVibrate && this.options.vibrate) {
9117
- if (!this.vibrateTimer) {
9118
- navigator.vibrate(10);
9119
- this.vibrateTimer = setTimeout(() => {
9120
- this.vibrateTimer = null;
9121
- }, 100);
9122
- }
9123
- }
9869
+ if (!isHours) {
9870
+ if (roundBy5) value *= 5;
9871
+ if (value === 60) value = 0;
9872
+ } else if (this.options.twelveHour) {
9873
+ if (value === 0) value = 12;
9874
+ } else if (value % 12 === 0) {
9875
+ value = inner ? 12 : 0;
9876
+ } else if (!inner) {
9877
+ value += 12;
9878
+ }
9879
+ if (this[this.currentView] !== value && this.canVibrate && this.options.vibrate && !this.vibrateTimer) {
9880
+ navigator.vibrate(10);
9881
+ this.vibrateTimer = setTimeout(() => {
9882
+ this.vibrateTimer = null;
9883
+ }, 100);
9124
9884
  }
9125
9885
  this[this.currentView] = value;
9126
- if (isHours) {
9127
- this.inputHours.value = _Timepicker._addLeadingZero(value);
9128
- } else {
9129
- this.inputMinutes.value = _Timepicker._addLeadingZero(value);
9130
- }
9886
+ (isHours ? this.inputHours : this.inputMinutes).value = _Timepicker._addLeadingZero(value);
9131
9887
  this.setClockAttributes(radian, radius);
9132
9888
  }
9133
9889
  setClockAttributes(radian, radius) {
@@ -9183,7 +9939,7 @@ _Timepicker._template = `<div class="timepicker-container">
9183
9939
  var Timepicker = _Timepicker;
9184
9940
 
9185
9941
  // src/ts/components/snackbar.ts
9186
- var _defaults25 = {
9942
+ var _defaults29 = {
9187
9943
  text: "",
9188
9944
  action: "",
9189
9945
  onAction: null,
@@ -9233,7 +9989,7 @@ var _Snackbar = class _Snackbar {
9233
9989
  this._setTimer();
9234
9990
  }
9235
9991
  static get defaults() {
9236
- return _defaults25;
9992
+ return _defaults29;
9237
9993
  }
9238
9994
  static getInstance(el) {
9239
9995
  return el["Expressive_Snackbar"];
@@ -9273,6 +10029,7 @@ var _Snackbar = class _Snackbar {
9273
10029
  snackbar.velocityX = 0;
9274
10030
  snackbar.time = Date.now();
9275
10031
  snackbar.xPos = e.clientX;
10032
+ snackbar._activationDistance = snackbar.el.offsetWidth * snackbar.options.activationPercent;
9276
10033
  }
9277
10034
  }
9278
10035
  static _onDragMove(e) {
@@ -9285,7 +10042,7 @@ var _Snackbar = class _Snackbar {
9285
10042
  snackbar.velocityX = snackbar.deltaX / (Date.now() - snackbar.time);
9286
10043
  snackbar.time = Date.now();
9287
10044
  const totalDeltaX = snackbar.xPos - snackbar.startingXPos;
9288
- const activationDistance = snackbar.el.offsetWidth * snackbar.options.activationPercent;
10045
+ const activationDistance = snackbar._activationDistance;
9289
10046
  snackbar.el.style.transform = `translateX(${totalDeltaX}px)`;
9290
10047
  snackbar.el.style.opacity = (1 - Math.abs(totalDeltaX / activationDistance)).toString();
9291
10048
  }
@@ -9298,17 +10055,14 @@ var _Snackbar = class _Snackbar {
9298
10055
  snackbar.panning = false;
9299
10056
  snackbar.el.classList.remove("panning");
9300
10057
  const totalDeltaX = snackbar.xPos - snackbar.startingXPos;
9301
- const activationDistance = snackbar.el.offsetWidth * snackbar.options.activationPercent;
10058
+ const activationDistance = snackbar._activationDistance;
9302
10059
  const velocity = Date.now() - snackbar.time < 100 ? snackbar.velocityX : 0;
9303
10060
  const shouldBeDismissed = Math.abs(totalDeltaX) > activationDistance || velocity > 1;
9304
10061
  if (shouldBeDismissed) {
9305
10062
  snackbar.wasSwiped = true;
9306
10063
  snackbar.dismiss();
9307
10064
  } else {
9308
- snackbar.el.style.transition = "transform .2s, opacity .2s";
9309
- snackbar.el.style.transform = "";
9310
- snackbar.el.style.opacity = "";
9311
- snackbar._resumeTimer();
10065
+ snackbar._snapBack();
9312
10066
  }
9313
10067
  _Snackbar._draggedSnackbar = null;
9314
10068
  }
@@ -9325,12 +10079,15 @@ var _Snackbar = class _Snackbar {
9325
10079
  if (!snackbar) return;
9326
10080
  snackbar.panning = false;
9327
10081
  snackbar.el.classList.remove("panning");
9328
- snackbar.el.style.transition = "transform .2s, opacity .2s";
9329
- snackbar.el.style.transform = "";
9330
- snackbar.el.style.opacity = "";
9331
- snackbar._resumeTimer();
10082
+ snackbar._snapBack();
9332
10083
  _Snackbar._draggedSnackbar = null;
9333
10084
  }
10085
+ _snapBack() {
10086
+ this.el.style.transition = "transform .2s, opacity .2s";
10087
+ this.el.style.transform = "";
10088
+ this.el.style.opacity = "";
10089
+ this._resumeTimer();
10090
+ }
9334
10091
  /**
9335
10092
  * dismiss all snackbars.
9336
10093
  */
@@ -9500,15 +10257,15 @@ var _Snackbar = class _Snackbar {
9500
10257
  this.counterTimeout = null;
9501
10258
  this._restoreFocus();
9502
10259
  if (this._events.signal.aborted) return;
9503
- const activationDistance = this.el.offsetWidth * this.options.activationPercent;
10260
+ const duration = this.options.outDuration;
10261
+ const transitions = [`margin ${duration}ms ease`, `opacity ${duration}ms ease`];
9504
10262
  if (this.wasSwiped) {
9505
- this.el.style.transition = "transform .05s, opacity .05s";
9506
- this.el.style.transform = `translateX(${activationDistance}px)`;
10263
+ const direction = this.xPos < this.startingXPos ? -1 : 1;
10264
+ this.el.style.transform = `translateX(${direction * this.el.offsetWidth}px)`;
9507
10265
  this.el.style.opacity = "0";
10266
+ transitions.push(`transform ${duration}ms ease`);
9508
10267
  }
9509
- this.el.style.transition = `
9510
- margin ${this.options.outDuration}ms ease,
9511
- opacity ${this.options.outDuration}ms ease`;
10268
+ this.el.style.transition = transitions.join(", ");
9512
10269
  clearTimeout(this._transitionTimer);
9513
10270
  this._transitionTimer = setTimeout(() => {
9514
10271
  this.el.style.opacity = "0";
@@ -9530,7 +10287,7 @@ _Snackbar._draggedSnackbar = null;
9530
10287
  var Snackbar = _Snackbar;
9531
10288
 
9532
10289
  // src/ts/components/tooltip.ts
9533
- var _defaults26 = {
10290
+ var _defaults30 = {
9534
10291
  exitDelay: 200,
9535
10292
  enterDelay: 0,
9536
10293
  text: "",
@@ -9552,6 +10309,7 @@ var Tooltip = class _Tooltip extends Component {
9552
10309
  clearTimeout(this._exitDelayTimeout);
9553
10310
  clearTimeout(this._animationTimeout);
9554
10311
  this.isOpen = true;
10312
+ this.el.ownerDocument.addEventListener("keydown", this._handleKeydown, true);
9555
10313
  this.options = { ...this.options, ...this._getAttributeOptions() };
9556
10314
  this._updateTooltipContent();
9557
10315
  this._setEnterDelayTimeout(isManual);
@@ -9564,6 +10322,7 @@ var Tooltip = class _Tooltip extends Component {
9564
10322
  this.isHovered = false;
9565
10323
  this.isFocused = false;
9566
10324
  this.isOpen = false;
10325
+ this.el.ownerDocument.removeEventListener("keydown", this._handleKeydown, true);
9567
10326
  clearTimeout(this._enterDelayTimeout);
9568
10327
  this._setExitDelayTimeout();
9569
10328
  };
@@ -9612,7 +10371,7 @@ var Tooltip = class _Tooltip extends Component {
9612
10371
  this._setupEventHandlers();
9613
10372
  }
9614
10373
  static get defaults() {
9615
- return _defaults26;
10374
+ return _defaults30;
9616
10375
  }
9617
10376
  /**
9618
10377
  * Initializes instances of Tooltip.
@@ -9658,8 +10417,12 @@ var Tooltip = class _Tooltip extends Component {
9658
10417
  this.tooltipEl.id = `tooltip-${Utils.guid()}`;
9659
10418
  this.tooltipEl.setAttribute("role", "tooltip");
9660
10419
  this.el.setAttribute("aria-describedby", [this.el.getAttribute("aria-describedby"), this.tooltipEl.id].filter(Boolean).join(" "));
9661
- const tooltipContentEl = this.options.tooltipId ? Utils.getElementById(this.el, this.options.tooltipId) : document.createElement("div");
9662
- if (this.options.tooltipId) {
10420
+ const richContentEl = this.options.tooltipId ? Utils.getElementById(this.el, this.options.tooltipId) : null;
10421
+ if (this.options.tooltipId && !richContentEl) {
10422
+ console.error(`Tooltip: no element with id "${this.options.tooltipId}"; showing the text tooltip instead.`);
10423
+ }
10424
+ const tooltipContentEl = richContentEl ?? document.createElement("div");
10425
+ if (richContentEl) {
9663
10426
  this.tooltipEl.classList.add("rich");
9664
10427
  const marker = document.createComment("");
9665
10428
  tooltipContentEl.before(marker);
@@ -9680,7 +10443,7 @@ var Tooltip = class _Tooltip extends Component {
9680
10443
  Utils.portalRoot(this.el).appendChild(this.tooltipEl);
9681
10444
  }
9682
10445
  _setTooltipContent(tooltipContentEl) {
9683
- if (this.options.tooltipId) return;
10446
+ if (this._originalContent) return;
9684
10447
  tooltipContentEl.innerText = this.options.text;
9685
10448
  }
9686
10449
  _updateTooltipContent() {
@@ -9693,7 +10456,6 @@ var Tooltip = class _Tooltip extends Component {
9693
10456
  el.addEventListener("focus", this._handleFocus, true);
9694
10457
  el.addEventListener("blur", this._handleBlur, true);
9695
10458
  }
9696
- this.el.ownerDocument.addEventListener("keydown", this._handleKeydown, true);
9697
10459
  }
9698
10460
  _removeEventHandlers() {
9699
10461
  for (const el of [this.el, this.tooltipEl]) {
@@ -9831,6 +10593,9 @@ var AUTO_INIT_COMPONENTS = {
9831
10593
  },
9832
10594
  Carousel: { component: Carousel, selector: ".carousel" },
9833
10595
  Chips: { component: Chips, selector: ".chips" },
10596
+ Confetti: { component: Confetti, selector: ".confetti" },
10597
+ Particles: { component: Particles, selector: "canvas.particles" },
10598
+ Keypad: { component: Keypad, selector: ".keypad, .keyboard" },
9834
10599
  ColumnChart: { component: ColumnChart, selector: ".column-chart" },
9835
10600
  BarChart: { component: BarChart, selector: ".bar-chart" },
9836
10601
  PieChart: { component: PieChart, selector: ".pie-chart" },
@@ -9889,7 +10654,7 @@ function AutoInit(context = document.body, options) {
9889
10654
  }
9890
10655
 
9891
10656
  // src/ts/modular.ts
9892
- var version = "0.13.1";
10657
+ var version = "0.15.0";
9893
10658
 
9894
10659
  // src/ts/index.ts
9895
10660
  Forms.Init();