@expressivecss/expressive 0.12.0 → 0.14.1

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 (258) hide show
  1. package/CHANGELOG.md +339 -1
  2. package/README.md +38 -1
  3. package/dist/css/expressive.css +5342 -105
  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/fonts/material-symbols-outlined.woff2 +0 -0
  8. package/dist/fonts/material-symbols-rounded.woff2 +0 -0
  9. package/dist/fonts/material-symbols-sharp.woff2 +0 -0
  10. package/dist/js/chunks/chunk-3DHK5CZU.mjs +105 -0
  11. package/dist/js/chunks/chunk-3DHK5CZU.mjs.map +7 -0
  12. package/dist/js/chunks/{chunk-HB6IW7QQ.mjs → chunk-3GVFZ4XO.mjs} +3 -3
  13. package/dist/js/chunks/{chunk-HLDXZ7XB.mjs → chunk-4HZMB7LI.mjs} +22 -8
  14. package/dist/js/chunks/chunk-4HZMB7LI.mjs.map +7 -0
  15. package/dist/js/chunks/chunk-4KMNFIFZ.mjs +270 -0
  16. package/dist/js/chunks/chunk-4KMNFIFZ.mjs.map +7 -0
  17. package/dist/js/chunks/chunk-4TKTLGEM.mjs +262 -0
  18. package/dist/js/chunks/chunk-4TKTLGEM.mjs.map +7 -0
  19. package/dist/js/chunks/{chunk-3VOK6J7U.mjs → chunk-5BKHWHYY.mjs} +13 -6
  20. package/dist/js/chunks/chunk-5BKHWHYY.mjs.map +7 -0
  21. package/dist/js/chunks/{chunk-H2WA4XHH.mjs → chunk-5HQSGDZ5.mjs} +16 -7
  22. package/dist/js/chunks/chunk-5HQSGDZ5.mjs.map +7 -0
  23. package/dist/js/chunks/{chunk-LWBQIX5J.mjs → chunk-A7ALMYUR.mjs} +41 -44
  24. package/dist/js/chunks/chunk-A7ALMYUR.mjs.map +7 -0
  25. package/dist/js/chunks/chunk-BG6ZRB5H.mjs +154 -0
  26. package/dist/js/chunks/chunk-BG6ZRB5H.mjs.map +7 -0
  27. package/dist/js/chunks/{chunk-DLWYKFEI.mjs → chunk-CUQPB25U.mjs} +3 -3
  28. package/dist/js/chunks/{chunk-6WLSDZ4O.mjs → chunk-DAIU5SLG.mjs} +2 -2
  29. package/dist/js/chunks/chunk-FS7XY3HT.mjs +124 -0
  30. package/dist/js/chunks/chunk-FS7XY3HT.mjs.map +7 -0
  31. package/dist/js/chunks/{chunk-WJXDBPXQ.mjs → chunk-GIW4K4SE.mjs} +8 -12
  32. package/dist/js/chunks/chunk-GIW4K4SE.mjs.map +7 -0
  33. package/dist/js/chunks/chunk-GUB3TNO2.mjs +164 -0
  34. package/dist/js/chunks/chunk-GUB3TNO2.mjs.map +7 -0
  35. package/dist/js/chunks/chunk-GVGT6MIU.mjs +47 -0
  36. package/dist/js/chunks/chunk-GVGT6MIU.mjs.map +7 -0
  37. package/dist/js/chunks/{chunk-HNFSMIBY.mjs → chunk-GZKEFWPM.mjs} +83 -22
  38. package/dist/js/chunks/chunk-GZKEFWPM.mjs.map +7 -0
  39. package/dist/js/chunks/chunk-HKT2S7VM.mjs +48 -0
  40. package/dist/js/chunks/chunk-HKT2S7VM.mjs.map +7 -0
  41. package/dist/js/chunks/chunk-ILP3PDTL.mjs +187 -0
  42. package/dist/js/chunks/chunk-ILP3PDTL.mjs.map +7 -0
  43. package/dist/js/chunks/{chunk-YSBCHYXP.mjs → chunk-JIDMQGK6.mjs} +118 -13
  44. package/dist/js/chunks/chunk-JIDMQGK6.mjs.map +7 -0
  45. package/dist/js/chunks/chunk-KBNN3QDH.mjs +7 -0
  46. package/dist/js/chunks/chunk-KBNN3QDH.mjs.map +7 -0
  47. package/dist/js/chunks/{chunk-NNYP33NB.mjs → chunk-KHV6DZXX.mjs} +5 -4
  48. package/dist/js/chunks/chunk-KHV6DZXX.mjs.map +7 -0
  49. package/dist/js/chunks/{chunk-RFZZCYVU.mjs → chunk-KY6U46SM.mjs} +3 -3
  50. package/dist/js/chunks/{chunk-CKQP6P76.mjs → chunk-LRZMJZ3T.mjs} +4 -3
  51. package/dist/js/chunks/chunk-LRZMJZ3T.mjs.map +7 -0
  52. package/dist/js/chunks/{chunk-6OMRGML6.mjs → chunk-MNPROCZF.mjs} +4 -4
  53. package/dist/js/chunks/{chunk-6OMRGML6.mjs.map → chunk-MNPROCZF.mjs.map} +2 -2
  54. package/dist/js/chunks/{chunk-QV2JAWIZ.mjs → chunk-MZ6Z24BX.mjs} +3 -2
  55. package/dist/js/chunks/{chunk-QV2JAWIZ.mjs.map → chunk-MZ6Z24BX.mjs.map} +2 -2
  56. package/dist/js/chunks/chunk-NS2UMNZV.mjs +292 -0
  57. package/dist/js/chunks/chunk-NS2UMNZV.mjs.map +7 -0
  58. package/dist/js/chunks/chunk-O5XPWXIQ.mjs +406 -0
  59. package/dist/js/chunks/chunk-O5XPWXIQ.mjs.map +7 -0
  60. package/dist/js/chunks/{chunk-UBLRRJ7N.mjs → chunk-PM655FXL.mjs} +2 -2
  61. package/dist/js/chunks/{chunk-IFXVDDDH.mjs → chunk-QERLECVU.mjs} +3 -3
  62. package/dist/js/chunks/{chunk-GZWPXXY6.mjs → chunk-QJABDLSD.mjs} +5 -2
  63. package/dist/js/chunks/chunk-QJABDLSD.mjs.map +7 -0
  64. package/dist/js/chunks/chunk-RHRQKTTX.mjs +139 -0
  65. package/dist/js/chunks/chunk-RHRQKTTX.mjs.map +7 -0
  66. package/dist/js/chunks/{chunk-UNEMYWEW.mjs → chunk-S3XDFGSZ.mjs} +2 -2
  67. package/dist/js/chunks/chunk-SPETGK25.mjs +59 -0
  68. package/dist/js/chunks/chunk-SPETGK25.mjs.map +7 -0
  69. package/dist/js/chunks/chunk-TBM3FT7G.mjs +398 -0
  70. package/dist/js/chunks/chunk-TBM3FT7G.mjs.map +7 -0
  71. package/dist/js/chunks/chunk-UEXCIMJZ.mjs +214 -0
  72. package/dist/js/chunks/chunk-UEXCIMJZ.mjs.map +7 -0
  73. package/dist/js/chunks/chunk-VGZSAFTX.mjs +173 -0
  74. package/dist/js/chunks/chunk-VGZSAFTX.mjs.map +7 -0
  75. package/dist/js/chunks/{chunk-UAEAQBRC.mjs → chunk-X7OCHZVF.mjs} +2 -2
  76. package/dist/js/chunks/{chunk-EC63CHXU.mjs → chunk-YMSXJON6.mjs} +7 -6
  77. package/dist/js/chunks/chunk-YMSXJON6.mjs.map +7 -0
  78. package/dist/js/chunks/{chunk-QVVEWBOF.mjs → chunk-Z2NRKI7R.mjs} +2 -2
  79. package/dist/js/chunks/{chunk-PIJ2TAR3.mjs → chunk-ZAS25YFD.mjs} +2 -2
  80. package/dist/js/chunks/chunk-ZKZKNSLC.mjs +1 -0
  81. package/dist/js/expressive.cjs +3113 -148
  82. package/dist/js/expressive.cjs.map +4 -4
  83. package/dist/js/expressive.js +3113 -148
  84. package/dist/js/expressive.js.map +4 -4
  85. package/dist/js/expressive.min.js +11 -11
  86. package/dist/js/expressive.min.js.map +4 -4
  87. package/dist/js/expressive.mjs +95 -35
  88. package/dist/js/expressive.mjs.map +1 -1
  89. package/dist/js/internal/behaviors/bottomSheets.mjs +3 -3
  90. package/dist/js/internal/behaviors/dialogs.mjs +2 -2
  91. package/dist/js/internal/behaviors/forms.mjs +2 -2
  92. package/dist/js/internal/behaviors/sheetDrag.mjs +2 -2
  93. package/dist/js/internal/behaviors/sideSheets.mjs +3 -3
  94. package/dist/js/internal/components/autocomplete.mjs +3 -3
  95. package/dist/js/internal/components/barChart.mjs +10 -0
  96. package/dist/js/internal/components/barChart.mjs.map +7 -0
  97. package/dist/js/internal/components/buttons.mjs +2 -2
  98. package/dist/js/internal/components/cards.mjs +2 -2
  99. package/dist/js/internal/components/carousel.mjs +2 -2
  100. package/dist/js/internal/components/chips.mjs +4 -4
  101. package/dist/js/internal/components/columnChart.mjs +9 -0
  102. package/dist/js/internal/components/columnChart.mjs.map +7 -0
  103. package/dist/js/internal/components/commandPalette.mjs +9 -0
  104. package/dist/js/internal/components/commandPalette.mjs.map +7 -0
  105. package/dist/js/internal/components/confetti.mjs +8 -0
  106. package/dist/js/internal/components/confetti.mjs.map +7 -0
  107. package/dist/js/internal/components/datepicker.mjs +5 -5
  108. package/dist/js/internal/components/expandingCard.mjs +2 -2
  109. package/dist/js/internal/components/heatmapChart.mjs +9 -0
  110. package/dist/js/internal/components/heatmapChart.mjs.map +7 -0
  111. package/dist/js/internal/components/index.mjs +88 -28
  112. package/dist/js/internal/components/lightbox.mjs +2 -2
  113. package/dist/js/internal/components/lineChart.mjs +12 -0
  114. package/dist/js/internal/components/lineChart.mjs.map +7 -0
  115. package/dist/js/internal/components/mapView.mjs +9 -0
  116. package/dist/js/internal/components/mapView.mjs.map +7 -0
  117. package/dist/js/internal/components/menu.mjs +2 -2
  118. package/dist/js/internal/components/messageScroller.mjs +9 -0
  119. package/dist/js/internal/components/messageScroller.mjs.map +7 -0
  120. package/dist/js/internal/components/mixedChart.mjs +10 -0
  121. package/dist/js/internal/components/mixedChart.mjs.map +7 -0
  122. package/dist/js/internal/components/particles.mjs +8 -0
  123. package/dist/js/internal/components/particles.mjs.map +7 -0
  124. package/dist/js/internal/components/pieChart.mjs +9 -0
  125. package/dist/js/internal/components/pieChart.mjs.map +7 -0
  126. package/dist/js/internal/components/questionnaire.mjs +9 -0
  127. package/dist/js/internal/components/questionnaire.mjs.map +7 -0
  128. package/dist/js/internal/components/radarChart.mjs +9 -0
  129. package/dist/js/internal/components/radarChart.mjs.map +7 -0
  130. package/dist/js/internal/components/radialChart.mjs +9 -0
  131. package/dist/js/internal/components/radialChart.mjs.map +7 -0
  132. package/dist/js/internal/components/registry.mjs +35 -20
  133. package/dist/js/internal/components/richTextEditor.mjs +9 -0
  134. package/dist/js/internal/components/richTextEditor.mjs.map +7 -0
  135. package/dist/js/internal/components/scrollspy.mjs +1 -1
  136. package/dist/js/internal/components/select.mjs +3 -3
  137. package/dist/js/internal/components/slider.mjs +2 -2
  138. package/dist/js/internal/components/snackbar.mjs +2 -2
  139. package/dist/js/internal/components/tabs.mjs +3 -3
  140. package/dist/js/internal/components/timepicker.mjs +3 -3
  141. package/dist/js/internal/components/tooltip.mjs +2 -2
  142. package/dist/js/internal/core/utils.mjs +1 -1
  143. package/dist/js/internal/plugins/dockedDisplayPlugin.mjs +2 -2
  144. package/dist/js/modular.mjs +95 -35
  145. package/dist/types/behaviors/forms.d.ts +27 -0
  146. package/dist/types/components/barChart.d.ts +24 -0
  147. package/dist/types/components/carousel.d.ts +2 -0
  148. package/dist/types/components/columnChart.d.ts +21 -0
  149. package/dist/types/components/commandPalette.d.ts +96 -0
  150. package/dist/types/components/confetti.d.ts +103 -0
  151. package/dist/types/components/datepicker.d.ts +2 -0
  152. package/dist/types/components/heatmapChart.d.ts +49 -0
  153. package/dist/types/components/index.d.ts +15 -0
  154. package/dist/types/components/lineChart.d.ts +134 -0
  155. package/dist/types/components/mapView.d.ts +151 -0
  156. package/dist/types/components/menu.d.ts +31 -0
  157. package/dist/types/components/messageScroller.d.ts +111 -0
  158. package/dist/types/components/mixedChart.d.ts +25 -0
  159. package/dist/types/components/particles.d.ts +72 -0
  160. package/dist/types/components/pieChart.d.ts +43 -0
  161. package/dist/types/components/questionnaire.d.ts +96 -0
  162. package/dist/types/components/radarChart.d.ts +39 -0
  163. package/dist/types/components/radialChart.d.ts +45 -0
  164. package/dist/types/components/registry.d.ts +52 -0
  165. package/dist/types/components/richTextEditor.d.ts +71 -0
  166. package/dist/types/components/slider.d.ts +1 -1
  167. package/dist/types/components/snackbar.d.ts +2 -0
  168. package/dist/types/components/tabs.d.ts +1 -1
  169. package/dist/types/modular.d.ts +10 -1
  170. package/dist/types/plugins/dockedDisplayPlugin.d.ts +3 -3
  171. package/package.json +5 -1
  172. package/src/sass/README.md +3 -6
  173. package/src/sass/abstracts/_index.scss +1 -1
  174. package/src/sass/abstracts/_mixins.scss +226 -0
  175. package/src/sass/abstracts/_variables.scss +14 -0
  176. package/src/sass/base/_typography.scss +45 -0
  177. package/src/sass/components/_accordion.scss +161 -0
  178. package/src/sass/components/_aura.scss +119 -0
  179. package/src/sass/components/_avatar.scss +86 -0
  180. package/src/sass/components/_bar-chart.scss +285 -0
  181. package/src/sass/components/_bottom-sheet.scss +1 -0
  182. package/src/sass/components/_button-groups.scss +13 -3
  183. package/src/sass/components/_buttons.scss +1 -1
  184. package/src/sass/components/_cards.scss +16 -13
  185. package/src/sass/components/_column-chart.scss +134 -0
  186. package/src/sass/components/_command-palette.scss +140 -0
  187. package/src/sass/components/_confetti.scss +14 -0
  188. package/src/sass/components/_countdown.scss +89 -0
  189. package/src/sass/components/_data-table.scss +188 -0
  190. package/src/sass/components/_dialog.scss +1 -0
  191. package/src/sass/components/_empty-state.scss +78 -0
  192. package/src/sass/components/_expanding-card.scss +3 -0
  193. package/src/sass/components/_heatmap-chart.scss +156 -0
  194. package/src/sass/components/_index.scss +30 -0
  195. package/src/sass/components/_kpi.scss +162 -0
  196. package/src/sass/components/_line-chart.scss +102 -0
  197. package/src/sass/components/_map.scss +188 -0
  198. package/src/sass/components/_marquee.scss +111 -0
  199. package/src/sass/components/_menu.scss +10 -0
  200. package/src/sass/components/_message-scroller.scss +66 -0
  201. package/src/sass/components/_message.scss +202 -0
  202. package/src/sass/components/_mixed-chart.scss +157 -0
  203. package/src/sass/components/_navigation-bar.scss +1 -0
  204. package/src/sass/components/_navigation-rail.scss +9 -0
  205. package/src/sass/components/_particles.scss +14 -0
  206. package/src/sass/components/_pie-chart.scss +203 -0
  207. package/src/sass/components/_popover.scss +112 -0
  208. package/src/sass/components/_questionnaire.scss +144 -0
  209. package/src/sass/components/_radar-chart.scss +205 -0
  210. package/src/sass/components/_radial-chart.scss +174 -0
  211. package/src/sass/components/_rich-text-editor.scss +99 -0
  212. package/src/sass/components/_search.scss +1 -0
  213. package/src/sass/components/_side-sheet.scss +1 -0
  214. package/src/sass/components/_skeleton.scss +81 -0
  215. package/src/sass/components/_snackbar.scss +1 -0
  216. package/src/sass/components/_stat.scss +86 -0
  217. package/src/sass/components/_stepper.scss +190 -0
  218. package/src/sass/components/_table_of_contents.scss +3 -1
  219. package/src/sass/components/_timeline.scss +114 -0
  220. package/src/sass/components/_toolbar.scss +1 -0
  221. package/src/sass/components/_tooltip.scss +2 -0
  222. package/src/sass/components/_tree.scss +139 -0
  223. package/src/sass/components/forms/_checkboxes.scss +7 -2
  224. package/src/sass/components/forms/_drop-zone.scss +128 -0
  225. package/src/sass/components/forms/_index.scss +2 -0
  226. package/src/sass/components/forms/_input-fields.scss +133 -2
  227. package/src/sass/components/forms/_rating.scss +165 -0
  228. package/src/sass/tokens/_reference.scss +3 -15
  229. package/src/sass/utilities/_index.scss +2 -0
  230. package/src/sass/utilities/_scroll-area.scss +35 -0
  231. package/src/sass/utilities/_shapes.scss +164 -0
  232. package/dist/js/chunks/chunk-3VOK6J7U.mjs.map +0 -7
  233. package/dist/js/chunks/chunk-CKQP6P76.mjs.map +0 -7
  234. package/dist/js/chunks/chunk-EC63CHXU.mjs.map +0 -7
  235. package/dist/js/chunks/chunk-G3I5H2U3.mjs +0 -7
  236. package/dist/js/chunks/chunk-G3I5H2U3.mjs.map +0 -7
  237. package/dist/js/chunks/chunk-GZWPXXY6.mjs.map +0 -7
  238. package/dist/js/chunks/chunk-H2WA4XHH.mjs.map +0 -7
  239. package/dist/js/chunks/chunk-HLDXZ7XB.mjs.map +0 -7
  240. package/dist/js/chunks/chunk-HNFSMIBY.mjs.map +0 -7
  241. package/dist/js/chunks/chunk-LWBQIX5J.mjs.map +0 -7
  242. package/dist/js/chunks/chunk-NNYP33NB.mjs.map +0 -7
  243. package/dist/js/chunks/chunk-PSSHQWCX.mjs +0 -100
  244. package/dist/js/chunks/chunk-PSSHQWCX.mjs.map +0 -7
  245. package/dist/js/chunks/chunk-WJXDBPXQ.mjs.map +0 -7
  246. package/dist/js/chunks/chunk-WWPAPHMA.mjs +0 -1
  247. package/dist/js/chunks/chunk-YSBCHYXP.mjs.map +0 -7
  248. /package/dist/js/chunks/{chunk-HB6IW7QQ.mjs.map → chunk-3GVFZ4XO.mjs.map} +0 -0
  249. /package/dist/js/chunks/{chunk-DLWYKFEI.mjs.map → chunk-CUQPB25U.mjs.map} +0 -0
  250. /package/dist/js/chunks/{chunk-6WLSDZ4O.mjs.map → chunk-DAIU5SLG.mjs.map} +0 -0
  251. /package/dist/js/chunks/{chunk-RFZZCYVU.mjs.map → chunk-KY6U46SM.mjs.map} +0 -0
  252. /package/dist/js/chunks/{chunk-UBLRRJ7N.mjs.map → chunk-PM655FXL.mjs.map} +0 -0
  253. /package/dist/js/chunks/{chunk-IFXVDDDH.mjs.map → chunk-QERLECVU.mjs.map} +0 -0
  254. /package/dist/js/chunks/{chunk-UNEMYWEW.mjs.map → chunk-S3XDFGSZ.mjs.map} +0 -0
  255. /package/dist/js/chunks/{chunk-UAEAQBRC.mjs.map → chunk-X7OCHZVF.mjs.map} +0 -0
  256. /package/dist/js/chunks/{chunk-QVVEWBOF.mjs.map → chunk-Z2NRKI7R.mjs.map} +0 -0
  257. /package/dist/js/chunks/{chunk-PIJ2TAR3.mjs.map → chunk-ZAS25YFD.mjs.map} +0 -0
  258. /package/dist/js/chunks/{chunk-WWPAPHMA.mjs.map → chunk-ZKZKNSLC.mjs.map} +0 -0
@@ -0,0 +1,139 @@
1
+ import {
2
+ COLORS,
3
+ LineChart,
4
+ svgNode
5
+ } from "./chunk-O5XPWXIQ.mjs";
6
+
7
+ // src/ts/components/radialChart.ts
8
+ var RADIUS = 46;
9
+ var FILL = 0.8;
10
+ var RadialChart = class extends LineChart {
11
+ get _type() {
12
+ return "radial-chart";
13
+ }
14
+ get _key() {
15
+ return "Expressive_RadialChart";
16
+ }
17
+ get _points() {
18
+ return false;
19
+ }
20
+ get _circular() {
21
+ return true;
22
+ }
23
+ get _gauge() {
24
+ return this.el.classList.contains("gauge");
25
+ }
26
+ static init(els, options = {}) {
27
+ return super.init(els, options);
28
+ }
29
+ static getInstance(el) {
30
+ return el["Expressive_RadialChart"];
31
+ }
32
+ show(index) {
33
+ if (!this._tooltip || index === this.activeIndex) return;
34
+ super.show(index);
35
+ this._rings.forEach((ring, i) => ring.classList.toggle("active", i === index));
36
+ if (this._tooltip.hidden) return;
37
+ const color = this._color(index);
38
+ this._tooltip.querySelectorAll("[data-series]").forEach((span) => {
39
+ span.dataset.series = color;
40
+ });
41
+ }
42
+ /** The tooltip sits where the ring's fill ends. */
43
+ _place(index) {
44
+ const turn = this._turn(this._fractions[index]);
45
+ const r = this._radii[index];
46
+ const [x, y] = [r * Math.sin(turn * 2 * Math.PI), -r * Math.cos(turn * 2 * Math.PI)];
47
+ this._tooltip.style.left = `${50 + x}%`;
48
+ this._tooltip.style.top = `${(50 + y) / (this._gauge ? 50 : 100) * 100}%`;
49
+ this._tooltip.classList.toggle("end", x > 0);
50
+ }
51
+ _color(index) {
52
+ return String(index % COLORS + 1);
53
+ }
54
+ /** A fraction of the ring as a turn clockwise from the top. */
55
+ _turn(fraction) {
56
+ return this._gauge ? fraction / 2 - 0.25 : fraction;
57
+ }
58
+ /** For more than one row, a legend of every row with its color and cell. */
59
+ _guides() {
60
+ if (this.labels.length < 2) return [];
61
+ const legend = document.createElement("ul");
62
+ legend.className = "radial-chart-legend";
63
+ legend.setAttribute("aria-hidden", "true");
64
+ const text = this.series[0].text;
65
+ legend.append(...this.labels.map((label, i) => {
66
+ const li = document.createElement("li");
67
+ li.dataset.series = this._color(i);
68
+ const [name, value] = [label, text[i]].map((content) => {
69
+ const span = document.createElement("span");
70
+ span.textContent = content;
71
+ return span;
72
+ });
73
+ li.append(name, value);
74
+ return li;
75
+ }));
76
+ return [legend];
77
+ }
78
+ /** The ring under the pointer by its distance from the middle, or -1. */
79
+ _indexAt(e) {
80
+ const box = this._plot.getBoundingClientRect();
81
+ const [x, y] = [e.clientX - box.left - box.width / 2, e.clientY - box.top - box.width / 2];
82
+ if (this._gauge && y > 0) return -1;
83
+ const distance = Math.hypot(x, y) / box.width * 100;
84
+ const step = this._radii.length > 1 ? this._radii[0] - this._radii[1] : this._width;
85
+ return this._radii.findIndex((r) => Math.abs(distance - r) <= step / 2);
86
+ }
87
+ /**
88
+ * An SVG of rings in a -50 to 50 box, the top half for a gauge. Each row
89
+ * is a track circle and a fill circle whose dash is its share; CSS draws
90
+ * them from --radial-chart-dash. The total is HTML over it.
91
+ */
92
+ _draw() {
93
+ const style = getComputedStyle(this.el);
94
+ const token = (name, fallback) => {
95
+ const value = parseFloat(style.getPropertyValue(`--md-comp-radial-chart-${name}`));
96
+ return Number.isFinite(value) ? value : fallback;
97
+ };
98
+ const count = this.labels.length;
99
+ let [width, gap] = [Math.max(0, token("thickness", 8)), Math.max(0, token("gap", 2))];
100
+ const scale = Math.min(1, RADIUS * FILL / (count * width + (count - 1) * gap || 1));
101
+ [width, gap] = [width * scale, gap * scale];
102
+ this._width = width;
103
+ this._radii = this.labels.map((_, i) => RADIUS - width / 2 - i * (width + gap));
104
+ const max = [parseFloat(this.el.dataset.max ?? ""), this.options.max ?? NaN, 100].find((value) => value > 0);
105
+ this._fractions = this.series[0].values.map((value) => Math.min(1, Math.max(0, (value ?? 0) / max)));
106
+ const gauge = this._gauge;
107
+ const svg = svgNode("svg", { viewBox: gauge ? "-50 -50 100 50" : "-50 -50 100 100", focusable: "false" });
108
+ const transform = gauge ? "rotate(180)" : "rotate(-90)";
109
+ const span = gauge ? 0.5 : 1;
110
+ this._rings = this._radii.map((r, i) => {
111
+ const length = 2 * Math.PI * r;
112
+ const circle = (name, fraction, capped) => {
113
+ const ring2 = svgNode("circle", { class: name, r: r.toFixed(3), transform, "stroke-width": width.toFixed(3) });
114
+ const dash = Math.max(1e-3, fraction * span * length - (capped ? width : 0));
115
+ ring2.style.setProperty("--radial-chart-dash", `${dash.toFixed(3)} ${length.toFixed(3)}`);
116
+ if (capped) ring2.style.setProperty("--radial-chart-offset", (-width / 2).toFixed(3));
117
+ return ring2;
118
+ };
119
+ const ring = circle("radial-chart-ring", this._fractions[i], true);
120
+ ring.dataset.series = this._color(i);
121
+ if (!this._fractions[i]) ring.classList.add("empty");
122
+ svg.append(circle("radial-chart-track", 1, gauge), ring);
123
+ return ring;
124
+ });
125
+ const rings = document.createElement("div");
126
+ rings.className = "radial-chart-rings";
127
+ rings.setAttribute("aria-hidden", "true");
128
+ rings.style.setProperty("--radial-chart-middle", `${(this._radii[count - 1] - this._width / 2) * 2}%`);
129
+ rings.append(svg);
130
+ const total = this._total("radial-chart-total");
131
+ if (total) rings.append(total);
132
+ return rings;
133
+ }
134
+ };
135
+
136
+ export {
137
+ RadialChart
138
+ };
139
+ //# sourceMappingURL=chunk-RHRQKTTX.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/ts/components/radialChart.ts"],
4
+ "sourcesContent": ["import { InitElements, InitElement } from '../core/component';\nimport { COLORS, LineChart, LineChartOptions, svgNode as node } from './lineChart';\n\nexport type RadialChartOptions = LineChartOptions;\n\n/** The outer ring's outer edge in a 100-unit box. */\nconst RADIUS = 46;\n/** The rings never fill more of the radius than this, leaving a middle. */\nconst FILL = 0.8;\n\n/**\n * Radial chart. It reads its <table> like LineChart, but draws each row of\n * the first value column as a ring, outermost first, filled clockwise from\n * the top as a share of `data-max` above zero (100 by default). With `.gauge` the rings\n * are half circles over the middle. A <tfoot> row shows in the middle, and\n * a legend lists the rows when there is more than one. Further columns show\n * in the tooltip.\n *\n * Re-run `RadialChart.init(el)` after changing the table or the ring tokens.\n */\nexport class RadialChart extends LineChart {\n // No initializers: LineChart's constructor draws before they would run.\n /** Each ring's middle radius, and their shared width. */\n private _radii: number[];\n private _width: number;\n /** Each row's share of the maximum, from 0 to 1. */\n private _fractions: number[];\n private _rings: SVGCircleElement[];\n\n protected get _type() {\n return 'radial-chart';\n }\n\n protected get _key() {\n return 'Expressive_RadialChart';\n }\n\n protected get _points() {\n return false;\n }\n\n protected get _circular() {\n return true;\n }\n\n private get _gauge() {\n return this.el.classList.contains('gauge');\n }\n\n static init(el: HTMLElement, options?: Partial<RadialChartOptions>): RadialChart;\n static init(els: InitElements<InitElement>, options?: Partial<RadialChartOptions>): RadialChart[];\n static init(\n els: HTMLElement | InitElements<InitElement>,\n options: Partial<RadialChartOptions> = {}\n ): RadialChart | RadialChart[] {\n return super.init(els as HTMLElement, options) as RadialChart | RadialChart[];\n }\n\n static getInstance(el: HTMLElement): RadialChart {\n return el['Expressive_RadialChart'];\n }\n\n show(index: number) {\n if (!this._tooltip || index === this.activeIndex) return;\n super.show(index);\n this._rings.forEach((ring, i) => ring.classList.toggle('active', i === index));\n // LineChart hides the tooltip for -1 and for an index past the last row.\n if (this._tooltip.hidden) return;\n const color = this._color(index);\n this._tooltip.querySelectorAll<HTMLElement>('[data-series]').forEach((span) => {\n span.dataset.series = color;\n });\n }\n\n /** The tooltip sits where the ring's fill ends. */\n protected _place(index: number) {\n const turn = this._turn(this._fractions[index]);\n const r = this._radii[index];\n const [x, y] = [r * Math.sin(turn * 2 * Math.PI), -r * Math.cos(turn * 2 * Math.PI)];\n this._tooltip.style.left = `${50 + x}%`;\n this._tooltip.style.top = `${((50 + y) / (this._gauge ? 50 : 100)) * 100}%`;\n // On the right half it opens leftwards, over the rings.\n this._tooltip.classList.toggle('end', x > 0);\n }\n\n private _color(index: number) {\n return String((index % COLORS) + 1);\n }\n\n /** A fraction of the ring as a turn clockwise from the top. */\n private _turn(fraction: number) {\n return this._gauge ? fraction / 2 - 0.25 : fraction;\n }\n\n /** For more than one row, a legend of every row with its color and cell. */\n protected _guides(): Element[] {\n if (this.labels.length < 2) return [];\n const legend = document.createElement('ul');\n legend.className = 'radial-chart-legend';\n legend.setAttribute('aria-hidden', 'true');\n const text = this.series[0].text;\n legend.append(...this.labels.map((label, i) => {\n const li = document.createElement('li');\n li.dataset.series = this._color(i);\n const [name, value] = [label, text[i]].map((content) => {\n const span = document.createElement('span');\n span.textContent = content;\n return span;\n });\n li.append(name, value);\n return li;\n }));\n return [legend];\n }\n\n /** The ring under the pointer by its distance from the middle, or -1. */\n protected _indexAt(e: PointerEvent) {\n const box = this._plot.getBoundingClientRect();\n // The middle is half the width down in both shapes.\n const [x, y] = [e.clientX - box.left - box.width / 2, e.clientY - box.top - box.width / 2];\n if (this._gauge && y > 0) return -1;\n // The distance in the SVG's 100-unit box; a gap belongs to a ring beside it.\n const distance = (Math.hypot(x, y) / box.width) * 100;\n const step = this._radii.length > 1 ? this._radii[0] - this._radii[1] : this._width;\n return this._radii.findIndex((r) => Math.abs(distance - r) <= step / 2);\n }\n\n /**\n * An SVG of rings in a -50 to 50 box, the top half for a gauge. Each row\n * is a track circle and a fill circle whose dash is its share; CSS draws\n * them from --radial-chart-dash. The total is HTML over it.\n */\n protected _draw(): Element {\n const style = getComputedStyle(this.el);\n const token = (name: string, fallback: number) => {\n const value = parseFloat(style.getPropertyValue(`--md-comp-radial-chart-${name}`));\n return Number.isFinite(value) ? value : fallback;\n };\n const count = this.labels.length;\n let [width, gap] = [Math.max(0, token('thickness', 8)), Math.max(0, token('gap', 2))];\n // Too many rings to leave a middle thin, with their gaps, to fit.\n // ponytail: past about 18 rings they are hairlines; that many values want a bar chart.\n const scale = Math.min(1, (RADIUS * FILL) / (count * width + (count - 1) * gap || 1));\n [width, gap] = [width * scale, gap * scale];\n this._width = width;\n this._radii = this.labels.map((_, i) => RADIUS - width / 2 - i * (width + gap));\n // A maximum of zero or less means nothing, so it falls back.\n const max = [parseFloat(this.el.dataset.max ?? ''), this.options.max ?? NaN, 100].find((value) => value > 0)!;\n this._fractions = this.series[0].values.map((value) => Math.min(1, Math.max(0, (value ?? 0) / max)));\n\n const gauge = this._gauge;\n const svg = node('svg', { viewBox: gauge ? '-50 -50 100 50' : '-50 -50 100 100', focusable: 'false' });\n // A circle starts at three o'clock; turn it to the top, or to nine for a gauge.\n const transform = gauge ? 'rotate(180)' : 'rotate(-90)';\n const span = gauge ? 0.5 : 1;\n this._rings = this._radii.map((r, i) => {\n const length = 2 * Math.PI * r;\n // Round caps reach half the width past each end of a dash, so a capped\n // dash is one width shorter and starts half a width in. One shorter\n // than the width is a dot at the start.\n const circle = (name: string, fraction: number, capped: boolean) => {\n const ring = node('circle', { class: name, r: r.toFixed(3), transform, 'stroke-width': width.toFixed(3) });\n const dash = Math.max(0.001, fraction * span * length - (capped ? width : 0));\n ring.style.setProperty('--radial-chart-dash', `${dash.toFixed(3)} ${length.toFixed(3)}`);\n if (capped) ring.style.setProperty('--radial-chart-offset', (-width / 2).toFixed(3));\n return ring;\n };\n const ring = circle('radial-chart-ring', this._fractions[i], true) as SVGCircleElement;\n ring.dataset.series = this._color(i);\n // An empty ring would still draw its round cap.\n if (!this._fractions[i]) ring.classList.add('empty');\n // Only a gauge's track has ends to round.\n svg.append(circle('radial-chart-track', 1, gauge), ring);\n return ring;\n });\n\n const rings = document.createElement('div');\n rings.className = 'radial-chart-rings';\n rings.setAttribute('aria-hidden', 'true');\n rings.style.setProperty('--radial-chart-middle', `${(this._radii[count - 1] - this._width / 2) * 2}%`);\n rings.append(svg);\n\n const total = this._total('radial-chart-total');\n if (total) rings.append(total);\n return rings;\n }\n}\n"],
5
+ "mappings": ";;;;;;;AAMA,IAAM,SAAS;AAEf,IAAM,OAAO;AAYN,IAAM,cAAN,cAA0B,UAAU;AAAA,EASzC,IAAc,QAAQ;AACpB,WAAO;AAAA,EACT;AAAA,EAEA,IAAc,OAAO;AACnB,WAAO;AAAA,EACT;AAAA,EAEA,IAAc,UAAU;AACtB,WAAO;AAAA,EACT;AAAA,EAEA,IAAc,YAAY;AACxB,WAAO;AAAA,EACT;AAAA,EAEA,IAAY,SAAS;AACnB,WAAO,KAAK,GAAG,UAAU,SAAS,OAAO;AAAA,EAC3C;AAAA,EAIA,OAAO,KACL,KACA,UAAuC,CAAC,GACX;AAC7B,WAAO,MAAM,KAAK,KAAoB,OAAO;AAAA,EAC/C;AAAA,EAEA,OAAO,YAAY,IAA8B;AAC/C,WAAO,GAAG,wBAAwB;AAAA,EACpC;AAAA,EAEA,KAAK,OAAe;AAClB,QAAI,CAAC,KAAK,YAAY,UAAU,KAAK,YAAa;AAClD,UAAM,KAAK,KAAK;AAChB,SAAK,OAAO,QAAQ,CAAC,MAAM,MAAM,KAAK,UAAU,OAAO,UAAU,MAAM,KAAK,CAAC;AAE7E,QAAI,KAAK,SAAS,OAAQ;AAC1B,UAAM,QAAQ,KAAK,OAAO,KAAK;AAC/B,SAAK,SAAS,iBAA8B,eAAe,EAAE,QAAQ,CAAC,SAAS;AAC7E,WAAK,QAAQ,SAAS;AAAA,IACxB,CAAC;AAAA,EACH;AAAA;AAAA,EAGU,OAAO,OAAe;AAC9B,UAAM,OAAO,KAAK,MAAM,KAAK,WAAW,KAAK,CAAC;AAC9C,UAAM,IAAI,KAAK,OAAO,KAAK;AAC3B,UAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,OAAO,IAAI,KAAK,EAAE,GAAG,CAAC,IAAI,KAAK,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC;AACnF,SAAK,SAAS,MAAM,OAAO,GAAG,KAAK,CAAC;AACpC,SAAK,SAAS,MAAM,MAAM,IAAK,KAAK,MAAM,KAAK,SAAS,KAAK,OAAQ,GAAG;AAExE,SAAK,SAAS,UAAU,OAAO,OAAO,IAAI,CAAC;AAAA,EAC7C;AAAA,EAEQ,OAAO,OAAe;AAC5B,WAAO,OAAQ,QAAQ,SAAU,CAAC;AAAA,EACpC;AAAA;AAAA,EAGQ,MAAM,UAAkB;AAC9B,WAAO,KAAK,SAAS,WAAW,IAAI,OAAO;AAAA,EAC7C;AAAA;AAAA,EAGU,UAAqB;AAC7B,QAAI,KAAK,OAAO,SAAS,EAAG,QAAO,CAAC;AACpC,UAAM,SAAS,SAAS,cAAc,IAAI;AAC1C,WAAO,YAAY;AACnB,WAAO,aAAa,eAAe,MAAM;AACzC,UAAM,OAAO,KAAK,OAAO,CAAC,EAAE;AAC5B,WAAO,OAAO,GAAG,KAAK,OAAO,IAAI,CAAC,OAAO,MAAM;AAC7C,YAAM,KAAK,SAAS,cAAc,IAAI;AACtC,SAAG,QAAQ,SAAS,KAAK,OAAO,CAAC;AACjC,YAAM,CAAC,MAAM,KAAK,IAAI,CAAC,OAAO,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,YAAY;AACtD,cAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,aAAK,cAAc;AACnB,eAAO;AAAA,MACT,CAAC;AACD,SAAG,OAAO,MAAM,KAAK;AACrB,aAAO;AAAA,IACT,CAAC,CAAC;AACF,WAAO,CAAC,MAAM;AAAA,EAChB;AAAA;AAAA,EAGU,SAAS,GAAiB;AAClC,UAAM,MAAM,KAAK,MAAM,sBAAsB;AAE7C,UAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,UAAU,IAAI,OAAO,IAAI,QAAQ,GAAG,EAAE,UAAU,IAAI,MAAM,IAAI,QAAQ,CAAC;AACzF,QAAI,KAAK,UAAU,IAAI,EAAG,QAAO;AAEjC,UAAM,WAAY,KAAK,MAAM,GAAG,CAAC,IAAI,IAAI,QAAS;AAClD,UAAM,OAAO,KAAK,OAAO,SAAS,IAAI,KAAK,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,KAAK;AAC7E,WAAO,KAAK,OAAO,UAAU,CAAC,MAAM,KAAK,IAAI,WAAW,CAAC,KAAK,OAAO,CAAC;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,QAAiB;AACzB,UAAM,QAAQ,iBAAiB,KAAK,EAAE;AACtC,UAAM,QAAQ,CAAC,MAAc,aAAqB;AAChD,YAAM,QAAQ,WAAW,MAAM,iBAAiB,0BAA0B,IAAI,EAAE,CAAC;AACjF,aAAO,OAAO,SAAS,KAAK,IAAI,QAAQ;AAAA,IAC1C;AACA,UAAM,QAAQ,KAAK,OAAO;AAC1B,QAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,IAAI,GAAG,MAAM,aAAa,CAAC,CAAC,GAAG,KAAK,IAAI,GAAG,MAAM,OAAO,CAAC,CAAC,CAAC;AAGpF,UAAM,QAAQ,KAAK,IAAI,GAAI,SAAS,QAAS,QAAQ,SAAS,QAAQ,KAAK,OAAO,EAAE;AACpF,KAAC,OAAO,GAAG,IAAI,CAAC,QAAQ,OAAO,MAAM,KAAK;AAC1C,SAAK,SAAS;AACd,SAAK,SAAS,KAAK,OAAO,IAAI,CAAC,GAAG,MAAM,SAAS,QAAQ,IAAI,KAAK,QAAQ,IAAI;AAE9E,UAAM,MAAM,CAAC,WAAW,KAAK,GAAG,QAAQ,OAAO,EAAE,GAAG,KAAK,QAAQ,OAAO,KAAK,GAAG,EAAE,KAAK,CAAC,UAAU,QAAQ,CAAC;AAC3G,SAAK,aAAa,KAAK,OAAO,CAAC,EAAE,OAAO,IAAI,CAAC,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,SAAS,KAAK,GAAG,CAAC,CAAC;AAEnG,UAAM,QAAQ,KAAK;AACnB,UAAM,MAAM,QAAK,OAAO,EAAE,SAAS,QAAQ,mBAAmB,mBAAmB,WAAW,QAAQ,CAAC;AAErG,UAAM,YAAY,QAAQ,gBAAgB;AAC1C,UAAM,OAAO,QAAQ,MAAM;AAC3B,SAAK,SAAS,KAAK,OAAO,IAAI,CAAC,GAAG,MAAM;AACtC,YAAM,SAAS,IAAI,KAAK,KAAK;AAI7B,YAAM,SAAS,CAAC,MAAc,UAAkB,WAAoB;AAClE,cAAMA,QAAO,QAAK,UAAU,EAAE,OAAO,MAAM,GAAG,EAAE,QAAQ,CAAC,GAAG,WAAW,gBAAgB,MAAM,QAAQ,CAAC,EAAE,CAAC;AACzG,cAAM,OAAO,KAAK,IAAI,MAAO,WAAW,OAAO,UAAU,SAAS,QAAQ,EAAE;AAC5E,QAAAA,MAAK,MAAM,YAAY,uBAAuB,GAAG,KAAK,QAAQ,CAAC,CAAC,IAAI,OAAO,QAAQ,CAAC,CAAC,EAAE;AACvF,YAAI,OAAQ,CAAAA,MAAK,MAAM,YAAY,0BAA0B,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC;AACnF,eAAOA;AAAA,MACT;AACA,YAAM,OAAO,OAAO,qBAAqB,KAAK,WAAW,CAAC,GAAG,IAAI;AACjE,WAAK,QAAQ,SAAS,KAAK,OAAO,CAAC;AAEnC,UAAI,CAAC,KAAK,WAAW,CAAC,EAAG,MAAK,UAAU,IAAI,OAAO;AAEnD,UAAI,OAAO,OAAO,sBAAsB,GAAG,KAAK,GAAG,IAAI;AACvD,aAAO;AAAA,IACT,CAAC;AAED,UAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,UAAM,YAAY;AAClB,UAAM,aAAa,eAAe,MAAM;AACxC,UAAM,MAAM,YAAY,yBAAyB,IAAI,KAAK,OAAO,QAAQ,CAAC,IAAI,KAAK,SAAS,KAAK,CAAC,GAAG;AACrG,UAAM,OAAO,GAAG;AAEhB,UAAM,QAAQ,KAAK,OAAO,oBAAoB;AAC9C,QAAI,MAAO,OAAM,OAAO,KAAK;AAC7B,WAAO;AAAA,EACT;AACF;",
6
+ "names": ["ring"]
7
+ }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Utils
3
- } from "./chunk-6OMRGML6.mjs";
3
+ } from "./chunk-MNPROCZF.mjs";
4
4
  import {
5
5
  Component
6
6
  } from "./chunk-LTWPGFBR.mjs";
@@ -362,4 +362,4 @@ var Lightbox = _Lightbox;
362
362
  export {
363
363
  Lightbox
364
364
  };
365
- //# sourceMappingURL=chunk-UNEMYWEW.mjs.map
365
+ //# sourceMappingURL=chunk-S3XDFGSZ.mjs.map
@@ -0,0 +1,59 @@
1
+ import {
2
+ COLORS,
3
+ LineChart
4
+ } from "./chunk-O5XPWXIQ.mjs";
5
+
6
+ // src/ts/components/columnChart.ts
7
+ var ColumnChart = class extends LineChart {
8
+ get _type() {
9
+ return "column-chart";
10
+ }
11
+ get _key() {
12
+ return "Expressive_ColumnChart";
13
+ }
14
+ get _fromZero() {
15
+ return true;
16
+ }
17
+ get _points() {
18
+ return false;
19
+ }
20
+ static init(els, options = {}) {
21
+ return super.init(els, options);
22
+ }
23
+ static getInstance(el) {
24
+ return el["Expressive_ColumnChart"];
25
+ }
26
+ _draw(drawn = this.series) {
27
+ const columns = document.createElement("div");
28
+ columns.className = "column-chart-columns";
29
+ columns.setAttribute("aria-hidden", "true");
30
+ const clamp = (value, y = drawn[0]?.y ?? this._y) => Math.min(100, Math.max(0, y(value)));
31
+ columns.style.setProperty("--zero", `${clamp(0)}%`);
32
+ this._plot.style.setProperty("--rows", String(this.labels.length));
33
+ this.labels.forEach((_, index) => {
34
+ const row = document.createElement("div");
35
+ drawn.forEach((series) => {
36
+ const to = series.tops[index];
37
+ const from = series.base?.[index] ?? 0;
38
+ if (series.base && (to === null || from === null)) return;
39
+ const column = document.createElement("span");
40
+ if (to !== null) {
41
+ column.className = series.className;
42
+ column.dataset.series = String(this.series.indexOf(series) % COLORS + 1);
43
+ column.classList.toggle("negative", !series.base && to < from);
44
+ column.style.setProperty("--top", `${clamp(Math.max(from, to), series.y)}%`);
45
+ column.style.setProperty("--bottom", `${100 - clamp(Math.min(from, to), series.y)}%`);
46
+ if (this._horizontal) column.dataset.text = series.text[index];
47
+ }
48
+ row.append(column);
49
+ });
50
+ columns.append(row);
51
+ });
52
+ return columns;
53
+ }
54
+ };
55
+
56
+ export {
57
+ ColumnChart
58
+ };
59
+ //# sourceMappingURL=chunk-SPETGK25.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/ts/components/columnChart.ts"],
4
+ "sourcesContent": ["import { InitElements, InitElement } from '../core/component';\nimport { COLORS, LineChart, LineChartOptions } from './lineChart';\n\nexport type ColumnChartOptions = LineChartOptions;\n\n/**\n * Column chart. It reads its <table>, scales, labels and tooltip like\n * LineChart, but draws each row as a group of columns from zero, or one\n * column of segments with `stacked`. Columns are HTML clipped to their\n * value, so their rounded corners keep their shape at any size.\n *\n * Re-run `ColumnChart.init(el)` after changing the table.\n */\nexport class ColumnChart extends LineChart {\n protected get _type() {\n return 'column-chart';\n }\n\n protected get _key() {\n return 'Expressive_ColumnChart';\n }\n\n protected get _fromZero() {\n return true;\n }\n\n protected get _points() {\n return false;\n }\n\n static init(el: HTMLElement, options?: Partial<ColumnChartOptions>): ColumnChart;\n static init(els: InitElements<InitElement>, options?: Partial<ColumnChartOptions>): ColumnChart[];\n static init(\n els: HTMLElement | InitElements<InitElement>,\n options: Partial<ColumnChartOptions> = {}\n ): ColumnChart | ColumnChart[] {\n return super.init(els as HTMLElement, options) as ColumnChart | ColumnChart[];\n }\n\n static getInstance(el: HTMLElement): ColumnChart {\n return el['Expressive_ColumnChart'];\n }\n\n protected _draw(drawn = this.series): Element {\n const columns = document.createElement('div');\n columns.className = 'column-chart-columns';\n columns.setAttribute('aria-hidden', 'true');\n const clamp = (value: number, y = drawn[0]?.y ?? this._y) => Math.min(100, Math.max(0, y(value)));\n // Columns grow from zero, or from the plot edge when zero is off the scale.\n columns.style.setProperty('--zero', `${clamp(0)}%`);\n this._plot.style.setProperty('--rows', String(this.labels.length));\n\n this.labels.forEach((_, index) => {\n const row = document.createElement('div');\n drawn.forEach((series) => {\n // A stacked segment above a gap has no known base, so it is left out.\n const to = series.tops[index];\n const from = series.base?.[index] ?? 0;\n if (series.base && (to === null || from === null)) return;\n const column = document.createElement('span');\n // A gap in a grouped row keeps its empty slot, so the series stay aligned.\n if (to !== null) {\n column.className = series.className;\n column.dataset.series = String((this.series.indexOf(series) % COLORS) + 1);\n // A stacked segment never hangs from zero, so it keeps the top rounding.\n column.classList.toggle('negative', !series.base && to < from);\n column.style.setProperty('--top', `${clamp(Math.max(from, to), series.y)}%`);\n column.style.setProperty('--bottom', `${100 - clamp(Math.min(from, to), series.y)}%`);\n // The cell text, which a bar chart with .values writes along its bar.\n if (this._horizontal) column.dataset.text = series.text[index];\n }\n row.append(column);\n });\n columns.append(row);\n });\n return columns;\n }\n}\n"],
5
+ "mappings": ";;;;;;AAaO,IAAM,cAAN,cAA0B,UAAU;AAAA,EACzC,IAAc,QAAQ;AACpB,WAAO;AAAA,EACT;AAAA,EAEA,IAAc,OAAO;AACnB,WAAO;AAAA,EACT;AAAA,EAEA,IAAc,YAAY;AACxB,WAAO;AAAA,EACT;AAAA,EAEA,IAAc,UAAU;AACtB,WAAO;AAAA,EACT;AAAA,EAIA,OAAO,KACL,KACA,UAAuC,CAAC,GACX;AAC7B,WAAO,MAAM,KAAK,KAAoB,OAAO;AAAA,EAC/C;AAAA,EAEA,OAAO,YAAY,IAA8B;AAC/C,WAAO,GAAG,wBAAwB;AAAA,EACpC;AAAA,EAEU,MAAM,QAAQ,KAAK,QAAiB;AAC5C,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,YAAQ,YAAY;AACpB,YAAQ,aAAa,eAAe,MAAM;AAC1C,UAAM,QAAQ,CAAC,OAAe,IAAI,MAAM,CAAC,GAAG,KAAK,KAAK,OAAO,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,EAAE,KAAK,CAAC,CAAC;AAEhG,YAAQ,MAAM,YAAY,UAAU,GAAG,MAAM,CAAC,CAAC,GAAG;AAClD,SAAK,MAAM,MAAM,YAAY,UAAU,OAAO,KAAK,OAAO,MAAM,CAAC;AAEjE,SAAK,OAAO,QAAQ,CAAC,GAAG,UAAU;AAChC,YAAM,MAAM,SAAS,cAAc,KAAK;AACxC,YAAM,QAAQ,CAAC,WAAW;AAExB,cAAM,KAAK,OAAO,KAAK,KAAK;AAC5B,cAAM,OAAO,OAAO,OAAO,KAAK,KAAK;AACrC,YAAI,OAAO,SAAS,OAAO,QAAQ,SAAS,MAAO;AACnD,cAAM,SAAS,SAAS,cAAc,MAAM;AAE5C,YAAI,OAAO,MAAM;AACf,iBAAO,YAAY,OAAO;AAC1B,iBAAO,QAAQ,SAAS,OAAQ,KAAK,OAAO,QAAQ,MAAM,IAAI,SAAU,CAAC;AAEzE,iBAAO,UAAU,OAAO,YAAY,CAAC,OAAO,QAAQ,KAAK,IAAI;AAC7D,iBAAO,MAAM,YAAY,SAAS,GAAG,MAAM,KAAK,IAAI,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG;AAC3E,iBAAO,MAAM,YAAY,YAAY,GAAG,MAAM,MAAM,KAAK,IAAI,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG;AAEpF,cAAI,KAAK,YAAa,QAAO,QAAQ,OAAO,OAAO,KAAK,KAAK;AAAA,QAC/D;AACA,YAAI,OAAO,MAAM;AAAA,MACnB,CAAC;AACD,cAAQ,OAAO,GAAG;AAAA,IACpB,CAAC;AACD,WAAO;AAAA,EACT;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,398 @@
1
+ import {
2
+ Utils
3
+ } from "./chunk-MNPROCZF.mjs";
4
+ import {
5
+ Component
6
+ } from "./chunk-LTWPGFBR.mjs";
7
+
8
+ // src/ts/components/mapView.ts
9
+ var OPENFREEMAP = "https://tiles.openfreemap.org/styles/";
10
+ var _defaults = {
11
+ maplibregl: null,
12
+ style: { light: `${OPENFREEMAP}positron`, dark: `${OPENFREEMAP}dark` },
13
+ center: [0, 20],
14
+ zoom: 1,
15
+ mapOptions: {}
16
+ };
17
+ var lngLat = (el) => el.dataset.lngLat.split(",").map(Number);
18
+ function arc([x0, y0], [x2, y2], steps = 32) {
19
+ const bow = x2 >= x0 ? 0.25 : -0.25;
20
+ const x1 = (x0 + x2) / 2 - (y2 - y0) * bow;
21
+ const y1 = (y0 + y2) / 2 + (x2 - x0) * bow;
22
+ return Array.from({ length: steps + 1 }, (_, i) => {
23
+ const t = i / steps, u = 1 - t;
24
+ return [u * u * x0 + 2 * u * t * x1 + t * t * x2, u * u * y0 + 2 * u * t * y1 + t * t * y2];
25
+ });
26
+ }
27
+ var MapView = class _MapView extends Component {
28
+ constructor(el, options) {
29
+ super(el, options, _MapView);
30
+ /** The MapLibre map. */
31
+ this.map = null;
32
+ /** The MapLibre markers made from `.map-marker` children, in order. */
33
+ this.markers = [];
34
+ this._children = [];
35
+ this._popups = [];
36
+ this._markerPopups = /* @__PURE__ */ new Map();
37
+ this._overlays = /* @__PURE__ */ new Map();
38
+ this._styleReady = false;
39
+ this._dark = false;
40
+ this._location = null;
41
+ this._media = null;
42
+ this._observer = null;
43
+ // Looked up once: `move` fires every frame of a pan or zoom.
44
+ this._zoomIn = [];
45
+ this._zoomOut = [];
46
+ this._handleStyleLoad = () => {
47
+ this._styleReady = true;
48
+ for (const overlay of this._overlays.values()) overlay.draw();
49
+ };
50
+ this._handleScheme = () => {
51
+ const dark = this._isDark();
52
+ if (dark === this._dark) return;
53
+ this._dark = dark;
54
+ this._styleReady = false;
55
+ this.map.setStyle(this._style(), { diff: false });
56
+ };
57
+ this._sync = () => {
58
+ const zoom = this.map.getZoom();
59
+ for (const button of this._zoomIn) button.disabled = zoom >= this.map.getMaxZoom();
60
+ for (const button of this._zoomOut) button.disabled = zoom <= this.map.getMinZoom();
61
+ this.el.style.setProperty("--md-comp-map-bearing", `${-this.map.getBearing()}deg`);
62
+ };
63
+ this._handleFullscreen = () => {
64
+ for (const button of this._buttons("fullscreen")) {
65
+ button.setAttribute("aria-pressed", String(document.fullscreenElement === this.el));
66
+ }
67
+ };
68
+ this._handleClick = (e) => {
69
+ const target = e.target;
70
+ const button = target.closest(".map-controls [data-action]");
71
+ const action = button?.dataset.action;
72
+ if (action === "zoom-in") this.map.zoomIn();
73
+ else if (action === "zoom-out") this.map.zoomOut();
74
+ else if (action === "compass") this.map.resetNorthPitch();
75
+ else if (action === "locate") this._locate(button);
76
+ else if (action === "fullscreen") {
77
+ if (document.fullscreenElement === this.el) document.exitFullscreen();
78
+ else this.el.requestFullscreen();
79
+ } else {
80
+ const marker = target.closest(".map-marker");
81
+ if (this._markerPopups.has(marker)) this._toggle(marker);
82
+ }
83
+ };
84
+ // A click on the map closes marker popups, but not the one being toggled.
85
+ this._handleMapClick = (e) => {
86
+ const target = e.originalEvent.target;
87
+ for (const [marker, popup] of this._markerPopups) {
88
+ if (!marker.contains(target) && !popup.getElement()?.contains(target)) popup.remove();
89
+ }
90
+ };
91
+ this._handleKeydown = (e) => {
92
+ if (e.key !== "Escape") return;
93
+ for (const popup of this._popups) {
94
+ if (popup.getElement()?.contains(e.target)) {
95
+ e.preventDefault();
96
+ popup.remove();
97
+ }
98
+ }
99
+ };
100
+ this.el["Expressive_MapView"] = this;
101
+ this.options = {
102
+ ..._MapView.defaults,
103
+ ...options
104
+ };
105
+ const lib = this.options.maplibregl;
106
+ if (!lib) {
107
+ console.error("MapView needs the maplibre-gl module in options.maplibregl.");
108
+ return;
109
+ }
110
+ this._children = [...el.children];
111
+ this._zoomIn = [...this._buttons("zoom-in")];
112
+ this._zoomOut = [...this._buttons("zoom-out")];
113
+ this._dark = this._isDark();
114
+ this.map = new lib.Map({
115
+ ...this.options.mapOptions,
116
+ container: el,
117
+ style: this._style(),
118
+ center: this.options.center,
119
+ zoom: this.options.zoom
120
+ });
121
+ this.map.on("style.load", this._handleStyleLoad);
122
+ this.map.on("move", this._sync);
123
+ this.map.on("click", this._handleMapClick);
124
+ const children = this._children.filter((child) => child instanceof HTMLElement);
125
+ const claimed = /* @__PURE__ */ new Set();
126
+ for (const marker of children.filter((child) => child.matches(".map-marker[data-lng-lat]"))) {
127
+ const target = marker.hasAttribute("aria-controls") ? Utils.getElementById(marker, marker.getAttribute("aria-controls")) : null;
128
+ const popup = target?.parentElement === el && target.matches(".map-popup") ? target : null;
129
+ if (popup) claimed.add(popup);
130
+ this._addMarker(marker, popup);
131
+ }
132
+ for (const popup of children.filter((child) => child.matches(".map-popup[data-lng-lat]") && !claimed.has(child))) {
133
+ this._popup(popup, 0).setLngLat(lngLat(popup)).addTo(this.map);
134
+ }
135
+ if (this._themed()) {
136
+ this._media = matchMedia("(prefers-color-scheme: dark)");
137
+ this._media.addEventListener("change", this._handleScheme);
138
+ this._observer = new MutationObserver(this._handleScheme);
139
+ this._observer.observe(document.documentElement, { attributes: true, attributeFilter: ["theme"], subtree: true });
140
+ }
141
+ for (const button of this._buttons("fullscreen")) button.hidden = !document.fullscreenEnabled;
142
+ document.addEventListener("fullscreenchange", this._handleFullscreen);
143
+ el.addEventListener("click", this._handleClick);
144
+ el.addEventListener("keydown", this._handleKeydown);
145
+ this._sync();
146
+ }
147
+ static get defaults() {
148
+ return _defaults;
149
+ }
150
+ /**
151
+ * Initializes instances of MapView.
152
+ * @param els HTML elements.
153
+ * @param options Component options.
154
+ */
155
+ static init(els, options = {}) {
156
+ return super.init(els, options, _MapView);
157
+ }
158
+ static getInstance(el) {
159
+ return el["Expressive_MapView"];
160
+ }
161
+ destroy() {
162
+ this.el["Expressive_MapView"] = void 0;
163
+ if (!this.map) return;
164
+ this.el.removeEventListener("click", this._handleClick);
165
+ this.el.removeEventListener("keydown", this._handleKeydown);
166
+ document.removeEventListener("fullscreenchange", this._handleFullscreen);
167
+ this._media?.removeEventListener("change", this._handleScheme);
168
+ this._observer?.disconnect();
169
+ for (const overlay of this._overlays.values()) overlay.off?.();
170
+ for (const popup of this._popups) popup.remove();
171
+ for (const marker of this.markers) {
172
+ marker.remove();
173
+ const element = marker.getElement();
174
+ element.classList.remove(...[...element.classList].filter((name) => name.startsWith("maplibregl-")));
175
+ element.style.removeProperty("transform");
176
+ element.style.removeProperty("opacity");
177
+ if (element.hasAttribute("aria-controls")) element.removeAttribute("aria-expanded");
178
+ }
179
+ this._location?.remove();
180
+ this._location = null;
181
+ this.map.remove();
182
+ this.map = null;
183
+ this.markers = [];
184
+ this._popups = [];
185
+ this._markerPopups.clear();
186
+ this._overlays.clear();
187
+ this.el.style.removeProperty("--md-comp-map-bearing");
188
+ for (const button of this.el.querySelectorAll(".map-controls [data-action]")) {
189
+ button.disabled = false;
190
+ button.hidden = false;
191
+ button.removeAttribute("aria-pressed");
192
+ }
193
+ this.el.append(...this._children);
194
+ }
195
+ /** Draws a line through `[longitude, latitude]` points. Replaces an overlay with the same id. */
196
+ addRoute(id, coordinates, options = {}) {
197
+ this._line(id, { type: "LineString", coordinates }, "route", { width: 4, ...options });
198
+ }
199
+ /** Draws a curved line for each `{ from, to }`. Replaces an overlay with the same id. */
200
+ addArcs(id, arcs, options = {}) {
201
+ this._line(id, { type: "MultiLineString", coordinates: arcs.map(({ from, to }) => arc(from, to)) }, "arc", { width: 2, ...options });
202
+ }
203
+ /**
204
+ * Draws GeoJSON points, or the URL of a GeoJSON file, as clusters that
205
+ * show their count and zoom in when clicked. The layers are
206
+ * `${id}-clusters`, `${id}-count` and `${id}-points`.
207
+ */
208
+ addClusters(id, data, options = {}) {
209
+ const clusters = `${id}-clusters`, points = `${id}-points`;
210
+ const zoomIn = async (e) => {
211
+ const [feature] = e.features;
212
+ const zoom = await this.map.getSource(id).getClusterExpansionZoom(feature.properties.cluster_id);
213
+ this.map.easeTo({ center: feature.geometry.coordinates, zoom });
214
+ };
215
+ const pointer = () => {
216
+ this.map.getCanvas().style.cursor = "pointer";
217
+ };
218
+ const reset = () => {
219
+ this.map.getCanvas().style.cursor = "";
220
+ };
221
+ this._draw(id, {
222
+ draw: () => {
223
+ const color = options.color ?? this._color("var(--md-comp-map-cluster-color)");
224
+ const surface = this._color("var(--md-comp-map-marker-ring-color)");
225
+ this.map.addSource(id, {
226
+ type: "geojson",
227
+ data,
228
+ cluster: true,
229
+ clusterRadius: options.radius ?? 50,
230
+ clusterMaxZoom: options.maxZoom ?? 14
231
+ });
232
+ this.map.addLayer({
233
+ id: clusters,
234
+ type: "circle",
235
+ source: id,
236
+ filter: ["has", "point_count"],
237
+ paint: {
238
+ "circle-color": color,
239
+ "circle-radius": ["step", ["get", "point_count"], 16, 10, 20, 100, 26],
240
+ "circle-stroke-width": 6,
241
+ "circle-stroke-color": color,
242
+ "circle-stroke-opacity": 0.3
243
+ }
244
+ });
245
+ const style = this.map.getStyle();
246
+ const font = style.glyphs && style.layers.find((layer) => layer.layout?.["text-font"])?.layout["text-font"];
247
+ if (font) {
248
+ this.map.addLayer({
249
+ id: `${id}-count`,
250
+ type: "symbol",
251
+ source: id,
252
+ filter: ["has", "point_count"],
253
+ layout: { "text-field": ["get", "point_count_abbreviated"], "text-font": font, "text-size": 12 },
254
+ paint: { "text-color": this._color("var(--md-comp-map-cluster-label-color)") }
255
+ });
256
+ }
257
+ this.map.addLayer({
258
+ id: points,
259
+ type: "circle",
260
+ source: id,
261
+ filter: ["!", ["has", "point_count"]],
262
+ paint: { "circle-color": color, "circle-radius": 6, "circle-stroke-width": 2, "circle-stroke-color": surface }
263
+ });
264
+ },
265
+ off: () => {
266
+ this.map.off("click", clusters, zoomIn);
267
+ for (const layer of [clusters, points]) {
268
+ this.map.off("mouseenter", layer, pointer);
269
+ this.map.off("mouseleave", layer, reset);
270
+ }
271
+ }
272
+ });
273
+ this.map.on("click", clusters, zoomIn);
274
+ for (const layer of [clusters, points]) {
275
+ this.map.on("mouseenter", layer, pointer);
276
+ this.map.on("mouseleave", layer, reset);
277
+ }
278
+ }
279
+ /** Removes a route, arcs or clusters added with this id. */
280
+ removeOverlay(id) {
281
+ const overlay = this._overlays.get(id);
282
+ if (!overlay) return;
283
+ this._overlays.delete(id);
284
+ overlay.off?.();
285
+ if (!this._styleReady || !this.map.getSource(id)) return;
286
+ for (const layer of this.map.getStyle().layers) if (layer.source === id) this.map.removeLayer(layer.id);
287
+ this.map.removeSource(id);
288
+ }
289
+ _line(id, geometry, token, options) {
290
+ this._draw(id, {
291
+ draw: () => {
292
+ this.map.addSource(id, { type: "geojson", data: { type: "Feature", properties: {}, geometry } });
293
+ this.map.addLayer({
294
+ id,
295
+ type: "line",
296
+ source: id,
297
+ layout: { "line-cap": "round", "line-join": "round" },
298
+ paint: {
299
+ "line-color": options.color ?? this._color(`var(--md-comp-map-${token}-color)`),
300
+ "line-width": options.width,
301
+ "line-opacity": options.opacity ?? 1,
302
+ ...options.dashArray && { "line-dasharray": options.dashArray }
303
+ }
304
+ });
305
+ }
306
+ });
307
+ }
308
+ // Sources and layers go with the style, so every overlay is drawn again
309
+ // when a theme change swaps it.
310
+ _draw(id, overlay) {
311
+ this.removeOverlay(id);
312
+ this._overlays.set(id, overlay);
313
+ if (this._styleReady) overlay.draw();
314
+ }
315
+ _addMarker(element, content) {
316
+ const marker = new this.options.maplibregl.Marker({
317
+ element,
318
+ draggable: element.hasAttribute("data-draggable")
319
+ }).setLngLat(lngLat(element)).addTo(this.map);
320
+ marker.on("dragend", () => {
321
+ const { lng, lat } = marker.getLngLat();
322
+ element.dataset.lngLat = `${lng},${lat}`;
323
+ element.dispatchEvent(new Event("change", { bubbles: true }));
324
+ });
325
+ this.markers.push(marker);
326
+ if (!content) return;
327
+ element.setAttribute("aria-expanded", "false");
328
+ const popup = this._popup(content, 16);
329
+ popup.on("open", () => element.setAttribute("aria-expanded", "true"));
330
+ popup.on("close", () => {
331
+ element.setAttribute("aria-expanded", "false");
332
+ if (!document.activeElement || document.activeElement === document.body) element.focus();
333
+ });
334
+ this._markerPopups.set(element, popup);
335
+ }
336
+ _popup(content, offset) {
337
+ const popup = new this.options.maplibregl.Popup({ closeOnClick: false, maxWidth: "none", offset }).setDOMContent(content);
338
+ this._popups.push(popup);
339
+ return popup;
340
+ }
341
+ _toggle(marker) {
342
+ const popup = this._markerPopups.get(marker);
343
+ if (popup.isOpen()) popup.remove();
344
+ else popup.setLngLat(this.markers.find((m) => m.getElement() === marker).getLngLat()).addTo(this.map);
345
+ }
346
+ _buttons(action) {
347
+ return this.el.querySelectorAll(`.map-controls [data-action="${action}"]`);
348
+ }
349
+ _locate(button) {
350
+ navigator.geolocation?.getCurrentPosition(
351
+ ({ coords }) => {
352
+ if (!this.map) return;
353
+ const center = [coords.longitude, coords.latitude];
354
+ if (!this._location) {
355
+ const dot = document.createElement("span");
356
+ dot.className = "map-marker location";
357
+ dot.setAttribute("aria-hidden", "true");
358
+ this._location = new this.options.maplibregl.Marker({ element: dot });
359
+ }
360
+ this._location.setLngLat(center).addTo(this.map);
361
+ this.map.flyTo({ center, zoom: Math.max(this.map.getZoom(), 14) });
362
+ },
363
+ (error) => {
364
+ if (this.map && error.code === error.PERMISSION_DENIED) button.disabled = true;
365
+ }
366
+ );
367
+ }
368
+ // Resolves a CSS color where the map is, so light-dark() and scoped
369
+ // themes apply, then paints it on a canvas to read back the sRGB value.
370
+ // MapLibre does not parse the oklch() the theme tokens compute to.
371
+ _color(value) {
372
+ const probe = document.createElement("span");
373
+ probe.hidden = true;
374
+ probe.style.color = value;
375
+ this.el.append(probe);
376
+ const context = document.createElement("canvas").getContext("2d", { willReadFrequently: true });
377
+ context.fillStyle = getComputedStyle(probe).color;
378
+ probe.remove();
379
+ context.fillRect(0, 0, 1, 1);
380
+ const [r, g, b, a] = context.getImageData(0, 0, 1, 1).data;
381
+ return `rgba(${r}, ${g}, ${b}, ${Math.round(a / 255 * 100) / 100})`;
382
+ }
383
+ _isDark() {
384
+ return this._color("light-dark(black, white)") === "rgba(255, 255, 255, 1)";
385
+ }
386
+ _themed() {
387
+ const style = this.options.style;
388
+ return typeof style === "object" && "light" in style && "dark" in style;
389
+ }
390
+ _style() {
391
+ return this._themed() ? this.options.style[this._dark ? "dark" : "light"] : this.options.style;
392
+ }
393
+ };
394
+
395
+ export {
396
+ MapView
397
+ };
398
+ //# sourceMappingURL=chunk-TBM3FT7G.mjs.map