@k2b/ui 0.48.0 → 0.50.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 (304) hide show
  1. package/dist/base.css +40 -2
  2. package/dist/browser/actions/ContextMenu.js +3 -0
  3. package/dist/browser/actions/ContextMenu.js.map +1 -1
  4. package/dist/browser/actions/CopyButton.js +26 -18
  5. package/dist/browser/actions/CopyButton.js.map +1 -1
  6. package/dist/browser/charts/core/area.js +190 -0
  7. package/dist/browser/charts/core/area.js.map +1 -0
  8. package/dist/browser/charts/core/calendar.js +186 -0
  9. package/dist/browser/charts/core/calendar.js.map +1 -0
  10. package/dist/browser/charts/core/chart-map-data.js +9 -0
  11. package/dist/browser/charts/core/chart-map-data.js.map +1 -0
  12. package/dist/browser/charts/core/index.js +12 -0
  13. package/dist/browser/charts/core/index.js.map +1 -0
  14. package/dist/browser/charts/core/inspection.js +9 -0
  15. package/dist/browser/charts/core/inspection.js.map +1 -0
  16. package/dist/browser/charts/core/registry.js +28 -0
  17. package/dist/browser/charts/core/registry.js.map +1 -0
  18. package/dist/browser/charts/core/render.js +103 -0
  19. package/dist/browser/charts/core/render.js.map +1 -0
  20. package/dist/browser/charts/core/snapshot.js +65 -0
  21. package/dist/browser/charts/core/snapshot.js.map +1 -0
  22. package/dist/browser/charts/core/svg.js +2542 -0
  23. package/dist/browser/charts/core/svg.js.map +1 -0
  24. package/dist/browser/charts/core/termination.test-fixture.js +162 -0
  25. package/dist/browser/charts/core/termination.test-fixture.js.map +1 -0
  26. package/dist/browser/charts/core/text.js +13 -0
  27. package/dist/browser/charts/core/text.js.map +1 -0
  28. package/dist/browser/charts/core/types.js +8 -0
  29. package/dist/browser/charts/core/types.js.map +1 -0
  30. package/dist/browser/charts.js +4 -2
  31. package/dist/browser/charts.js.map +1 -1
  32. package/dist/browser/content/BalanceSummary.js +106 -0
  33. package/dist/browser/content/BalanceSummary.js.map +1 -0
  34. package/dist/browser/content/Chart.js +134 -115
  35. package/dist/browser/content/Chart.js.map +1 -1
  36. package/dist/browser/content/ChartExplorer.js +366 -122
  37. package/dist/browser/content/ChartExplorer.js.map +1 -1
  38. package/dist/browser/content/ChartSnapshotView.js +16 -9
  39. package/dist/browser/content/ChartSnapshotView.js.map +1 -1
  40. package/dist/browser/content/DataTable.js +676 -293
  41. package/dist/browser/content/DataTable.js.map +1 -1
  42. package/dist/browser/content/DataTableTools.js +119 -0
  43. package/dist/browser/content/DataTableTools.js.map +1 -0
  44. package/dist/browser/content/FlowAmount.js +82 -0
  45. package/dist/browser/content/FlowAmount.js.map +1 -0
  46. package/dist/browser/content/balance-summary-messages.js +26 -0
  47. package/dist/browser/content/balance-summary-messages.js.map +1 -0
  48. package/dist/browser/content/chart-bar.js +6 -6
  49. package/dist/browser/content/chart-bar.js.map +1 -1
  50. package/dist/browser/content/chart-calendar.js +43 -0
  51. package/dist/browser/content/chart-calendar.js.map +1 -0
  52. package/dist/browser/content/chart-inspection-core.js +164 -37
  53. package/dist/browser/content/chart-inspection-core.js.map +1 -1
  54. package/dist/browser/content/chart-inspection.js.map +1 -1
  55. package/dist/browser/content/chart-line-gaps.js +2 -2
  56. package/dist/browser/content/chart-line-gaps.js.map +1 -1
  57. package/dist/browser/content/chart-map-viewport.js.map +1 -1
  58. package/dist/browser/content/chart-message-catalog.js +164 -0
  59. package/dist/browser/content/chart-message-catalog.js.map +1 -0
  60. package/dist/browser/content/chart-messages.js +2 -138
  61. package/dist/browser/content/chart-messages.js.map +1 -1
  62. package/dist/browser/content/chart-snapshot.js +1 -62
  63. package/dist/browser/content/chart-snapshot.js.map +1 -1
  64. package/dist/browser/content/chart-state-timeline.js +1 -1
  65. package/dist/browser/content/chart-state-timeline.js.map +1 -1
  66. package/dist/browser/content/chart-svg.js +2 -1
  67. package/dist/browser/content/chart-svg.js.map +1 -1
  68. package/dist/browser/content/chart-time-axis.js +139 -0
  69. package/dist/browser/content/chart-time-axis.js.map +1 -0
  70. package/dist/browser/content/data-table-columns.js +160 -0
  71. package/dist/browser/content/data-table-columns.js.map +1 -0
  72. package/dist/browser/content/data-table-messages.js +38 -2
  73. package/dist/browser/content/data-table-messages.js.map +1 -1
  74. package/dist/browser/content/flow-amount-messages.js +26 -0
  75. package/dist/browser/content/flow-amount-messages.js.map +1 -0
  76. package/dist/browser/content/index.js +4 -0
  77. package/dist/browser/content/index.js.map +1 -1
  78. package/dist/browser/feedback/prompt-confirm.js +7 -4
  79. package/dist/browser/feedback/prompt-confirm.js.map +1 -1
  80. package/dist/browser/feedback/prompts.js +3 -3
  81. package/dist/browser/feedback/prompts.js.map +1 -1
  82. package/dist/browser/inputs/DatePicker.js +5 -4
  83. package/dist/browser/inputs/DatePicker.js.map +1 -1
  84. package/dist/browser/inputs/NumberInput.js +17 -5
  85. package/dist/browser/inputs/NumberInput.js.map +1 -1
  86. package/dist/browser/inputs/SelectChip.js +50 -17
  87. package/dist/browser/inputs/SelectChip.js.map +1 -1
  88. package/dist/browser/inputs/date-picker.js +13 -0
  89. package/dist/browser/inputs/date-picker.js.map +1 -1
  90. package/dist/browser/intl/Format.js +31 -8
  91. package/dist/browser/intl/Format.js.map +1 -1
  92. package/dist/browser/layout/AppWorkspace.js +580 -522
  93. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  94. package/dist/browser/layout/MobileShell.js +26 -0
  95. package/dist/browser/layout/MobileShell.js.map +1 -1
  96. package/dist/browser/layout/index.js +1 -0
  97. package/dist/browser/layout/index.js.map +1 -1
  98. package/dist/browser/layout/sheet-handle.js +155 -0
  99. package/dist/browser/layout/sheet-handle.js.map +1 -0
  100. package/dist/browser/surfaces/BudgetList.js +281 -0
  101. package/dist/browser/surfaces/BudgetList.js.map +1 -0
  102. package/dist/browser/surfaces/NoticeCard.js +48 -29
  103. package/dist/browser/surfaces/NoticeCard.js.map +1 -1
  104. package/dist/browser/surfaces/ProgressBar.js +134 -21
  105. package/dist/browser/surfaces/ProgressBar.js.map +1 -1
  106. package/dist/browser/surfaces/StatCell.js +320 -144
  107. package/dist/browser/surfaces/StatCell.js.map +1 -1
  108. package/dist/browser/surfaces/StatGrid.js +75 -57
  109. package/dist/browser/surfaces/StatGrid.js.map +1 -1
  110. package/dist/browser/surfaces/budget-messages.js +64 -0
  111. package/dist/browser/surfaces/budget-messages.js.map +1 -0
  112. package/dist/browser/surfaces/delta-badge.js +65 -0
  113. package/dist/browser/surfaces/delta-badge.js.map +1 -0
  114. package/dist/browser/surfaces/index.js +2 -1
  115. package/dist/browser/surfaces/index.js.map +1 -1
  116. package/dist/browser/surfaces/person-color.js +2 -2
  117. package/dist/browser/surfaces/person-color.js.map +1 -1
  118. package/dist/browser/surfaces/stat-cell-messages.js +41 -0
  119. package/dist/browser/surfaces/stat-cell-messages.js.map +1 -0
  120. package/dist/browser/widgets/Dashboard.js +137 -0
  121. package/dist/browser/widgets/Dashboard.js.map +1 -0
  122. package/dist/browser/widgets/index.js +1 -0
  123. package/dist/browser/widgets/index.js.map +1 -1
  124. package/dist/ssr/actions/ContextMenu.js +3 -0
  125. package/dist/ssr/actions/ContextMenu.js.map +1 -1
  126. package/dist/ssr/actions/CopyButton.js +13 -8
  127. package/dist/ssr/actions/CopyButton.js.map +1 -1
  128. package/dist/ssr/charts/core/area.js +190 -0
  129. package/dist/ssr/charts/core/area.js.map +1 -0
  130. package/dist/ssr/charts/core/calendar.js +186 -0
  131. package/dist/ssr/charts/core/calendar.js.map +1 -0
  132. package/dist/ssr/charts/core/chart-map-data.js +9 -0
  133. package/dist/ssr/charts/core/chart-map-data.js.map +1 -0
  134. package/dist/ssr/charts/core/index.js +12 -0
  135. package/dist/ssr/charts/core/index.js.map +1 -0
  136. package/dist/ssr/charts/core/inspection.js +9 -0
  137. package/dist/ssr/charts/core/inspection.js.map +1 -0
  138. package/dist/ssr/charts/core/registry.js +28 -0
  139. package/dist/ssr/charts/core/registry.js.map +1 -0
  140. package/dist/ssr/charts/core/render.js +103 -0
  141. package/dist/ssr/charts/core/render.js.map +1 -0
  142. package/dist/ssr/charts/core/snapshot.js +65 -0
  143. package/dist/ssr/charts/core/snapshot.js.map +1 -0
  144. package/dist/ssr/charts/core/svg.js +2542 -0
  145. package/dist/ssr/charts/core/svg.js.map +1 -0
  146. package/dist/ssr/charts/core/termination.test-fixture.js +162 -0
  147. package/dist/ssr/charts/core/termination.test-fixture.js.map +1 -0
  148. package/dist/ssr/charts/core/text.js +13 -0
  149. package/dist/ssr/charts/core/text.js.map +1 -0
  150. package/dist/ssr/charts/core/types.js +8 -0
  151. package/dist/ssr/charts/core/types.js.map +1 -0
  152. package/dist/ssr/charts.js +4 -2
  153. package/dist/ssr/charts.js.map +1 -1
  154. package/dist/ssr/content/BalanceSummary.js +75 -0
  155. package/dist/ssr/content/BalanceSummary.js.map +1 -0
  156. package/dist/ssr/content/Chart.js +90 -95
  157. package/dist/ssr/content/Chart.js.map +1 -1
  158. package/dist/ssr/content/ChartExplorer.js +190 -46
  159. package/dist/ssr/content/ChartExplorer.js.map +1 -1
  160. package/dist/ssr/content/ChartSnapshotView.js +5 -1
  161. package/dist/ssr/content/ChartSnapshotView.js.map +1 -1
  162. package/dist/ssr/content/DataTable.js +287 -78
  163. package/dist/ssr/content/DataTable.js.map +1 -1
  164. package/dist/ssr/content/DataTableTools.js +106 -0
  165. package/dist/ssr/content/DataTableTools.js.map +1 -0
  166. package/dist/ssr/content/FlowAmount.js +58 -0
  167. package/dist/ssr/content/FlowAmount.js.map +1 -0
  168. package/dist/ssr/content/balance-summary-messages.js +26 -0
  169. package/dist/ssr/content/balance-summary-messages.js.map +1 -0
  170. package/dist/ssr/content/chart-bar.js +6 -6
  171. package/dist/ssr/content/chart-bar.js.map +1 -1
  172. package/dist/ssr/content/chart-calendar.js +43 -0
  173. package/dist/ssr/content/chart-calendar.js.map +1 -0
  174. package/dist/ssr/content/chart-inspection-core.js +164 -37
  175. package/dist/ssr/content/chart-inspection-core.js.map +1 -1
  176. package/dist/ssr/content/chart-inspection.js.map +1 -1
  177. package/dist/ssr/content/chart-line-gaps.js +2 -2
  178. package/dist/ssr/content/chart-line-gaps.js.map +1 -1
  179. package/dist/ssr/content/chart-map-viewport.js.map +1 -1
  180. package/dist/ssr/content/chart-message-catalog.js +164 -0
  181. package/dist/ssr/content/chart-message-catalog.js.map +1 -0
  182. package/dist/ssr/content/chart-messages.js +2 -138
  183. package/dist/ssr/content/chart-messages.js.map +1 -1
  184. package/dist/ssr/content/chart-snapshot.js +1 -62
  185. package/dist/ssr/content/chart-snapshot.js.map +1 -1
  186. package/dist/ssr/content/chart-state-timeline.js +1 -1
  187. package/dist/ssr/content/chart-state-timeline.js.map +1 -1
  188. package/dist/ssr/content/chart-svg.js +2 -1
  189. package/dist/ssr/content/chart-svg.js.map +1 -1
  190. package/dist/ssr/content/chart-time-axis.js +139 -0
  191. package/dist/ssr/content/chart-time-axis.js.map +1 -0
  192. package/dist/ssr/content/data-table-columns.js +160 -0
  193. package/dist/ssr/content/data-table-columns.js.map +1 -0
  194. package/dist/ssr/content/data-table-messages.js +38 -2
  195. package/dist/ssr/content/data-table-messages.js.map +1 -1
  196. package/dist/ssr/content/flow-amount-messages.js +26 -0
  197. package/dist/ssr/content/flow-amount-messages.js.map +1 -0
  198. package/dist/ssr/content/index.js +4 -0
  199. package/dist/ssr/content/index.js.map +1 -1
  200. package/dist/ssr/feedback/prompt-confirm.js +7 -4
  201. package/dist/ssr/feedback/prompt-confirm.js.map +1 -1
  202. package/dist/ssr/feedback/prompts.js +3 -3
  203. package/dist/ssr/feedback/prompts.js.map +1 -1
  204. package/dist/ssr/inputs/DatePicker.js +5 -4
  205. package/dist/ssr/inputs/DatePicker.js.map +1 -1
  206. package/dist/ssr/inputs/NumberInput.js +17 -5
  207. package/dist/ssr/inputs/NumberInput.js.map +1 -1
  208. package/dist/ssr/inputs/SelectChip.js +26 -9
  209. package/dist/ssr/inputs/SelectChip.js.map +1 -1
  210. package/dist/ssr/inputs/date-picker.js +13 -0
  211. package/dist/ssr/inputs/date-picker.js.map +1 -1
  212. package/dist/ssr/intl/Format.js +22 -2
  213. package/dist/ssr/intl/Format.js.map +1 -1
  214. package/dist/ssr/layout/AppWorkspace.js +158 -114
  215. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  216. package/dist/ssr/layout/MobileShell.js +26 -0
  217. package/dist/ssr/layout/MobileShell.js.map +1 -1
  218. package/dist/ssr/layout/index.js +1 -0
  219. package/dist/ssr/layout/index.js.map +1 -1
  220. package/dist/ssr/layout/sheet-handle.js +155 -0
  221. package/dist/ssr/layout/sheet-handle.js.map +1 -0
  222. package/dist/ssr/surfaces/BudgetList.js +170 -0
  223. package/dist/ssr/surfaces/BudgetList.js.map +1 -0
  224. package/dist/ssr/surfaces/NoticeCard.js +25 -10
  225. package/dist/ssr/surfaces/NoticeCard.js.map +1 -1
  226. package/dist/ssr/surfaces/ProgressBar.js +96 -5
  227. package/dist/ssr/surfaces/ProgressBar.js.map +1 -1
  228. package/dist/ssr/surfaces/StatCell.js +157 -51
  229. package/dist/ssr/surfaces/StatCell.js.map +1 -1
  230. package/dist/ssr/surfaces/StatGrid.js +24 -35
  231. package/dist/ssr/surfaces/StatGrid.js.map +1 -1
  232. package/dist/ssr/surfaces/budget-messages.js +64 -0
  233. package/dist/ssr/surfaces/budget-messages.js.map +1 -0
  234. package/dist/ssr/surfaces/delta-badge.js +41 -0
  235. package/dist/ssr/surfaces/delta-badge.js.map +1 -0
  236. package/dist/ssr/surfaces/index.js +2 -1
  237. package/dist/ssr/surfaces/index.js.map +1 -1
  238. package/dist/ssr/surfaces/person-color.js +2 -2
  239. package/dist/ssr/surfaces/person-color.js.map +1 -1
  240. package/dist/ssr/surfaces/stat-cell-messages.js +41 -0
  241. package/dist/ssr/surfaces/stat-cell-messages.js.map +1 -0
  242. package/dist/ssr/widgets/Dashboard.js +84 -0
  243. package/dist/ssr/widgets/Dashboard.js.map +1 -0
  244. package/dist/ssr/widgets/index.js +1 -0
  245. package/dist/ssr/widgets/index.js.map +1 -1
  246. package/dist/styles.css +1 -1
  247. package/dist/types/charts/core/area.d.ts +62 -0
  248. package/dist/types/charts/core/calendar.d.ts +57 -0
  249. package/dist/types/charts/core/chart-map-data.d.ts +3 -0
  250. package/dist/types/charts/core/index.d.ts +11 -0
  251. package/dist/types/charts/core/inspection.d.ts +16 -0
  252. package/dist/types/charts/core/registry.d.ts +27 -0
  253. package/dist/types/charts/core/render.d.ts +40 -0
  254. package/dist/types/charts/core/snapshot.d.ts +27 -0
  255. package/dist/types/charts/core/svg.d.ts +714 -0
  256. package/dist/types/charts/core/termination.test-fixture.d.ts +1 -0
  257. package/dist/types/charts/core/text.d.ts +5 -0
  258. package/dist/types/charts/core/types.d.ts +31 -0
  259. package/dist/types/charts.d.ts +4 -2
  260. package/dist/types/content/BalanceSummary.d.ts +29 -0
  261. package/dist/types/content/Chart.d.ts +26 -36
  262. package/dist/types/content/ChartExplorer.d.ts +43 -2
  263. package/dist/types/content/ChartSnapshotView.d.ts +1 -0
  264. package/dist/types/content/DataTable.d.ts +28 -0
  265. package/dist/types/content/DataTableTools.d.ts +44 -0
  266. package/dist/types/content/FlowAmount.d.ts +28 -0
  267. package/dist/types/content/balance-summary-messages.d.ts +11 -0
  268. package/dist/types/content/chart-bar.d.ts +1 -1
  269. package/dist/types/content/chart-calendar.d.ts +4 -0
  270. package/dist/types/content/chart-inspection-core.d.ts +21 -16
  271. package/dist/types/content/chart-inspection.d.ts +5 -1
  272. package/dist/types/content/chart-map-viewport.d.ts +1 -1
  273. package/dist/types/content/chart-message-catalog.d.ts +84 -0
  274. package/dist/types/content/chart-messages.d.ts +2 -33
  275. package/dist/types/content/chart-snapshot.d.ts +1 -26
  276. package/dist/types/content/chart-svg.d.ts +1 -1
  277. package/dist/types/content/chart-time-axis.d.ts +26 -0
  278. package/dist/types/content/data-table-columns.d.ts +72 -0
  279. package/dist/types/content/data-table-messages.d.ts +18 -0
  280. package/dist/types/content/flow-amount-messages.d.ts +11 -0
  281. package/dist/types/content/index.d.ts +10 -2
  282. package/dist/types/feedback/prompt-confirm.d.ts +3 -1
  283. package/dist/types/feedback/prompts.d.ts +2 -2
  284. package/dist/types/inputs/NumberInput.d.ts +1 -1
  285. package/dist/types/inputs/SelectChip.d.ts +2 -0
  286. package/dist/types/inputs/date-picker.d.ts +6 -0
  287. package/dist/types/intl/Format.d.ts +5 -0
  288. package/dist/types/layout/AppWorkspace.d.ts +21 -1
  289. package/dist/types/layout/MobileShell.d.ts +5 -0
  290. package/dist/types/layout/index.d.ts +2 -1
  291. package/dist/types/layout/sheet-handle.d.ts +21 -0
  292. package/dist/types/surfaces/BudgetList.d.ts +42 -0
  293. package/dist/types/surfaces/NoticeCard.d.ts +5 -2
  294. package/dist/types/surfaces/ProgressBar.d.ts +38 -2
  295. package/dist/types/surfaces/StatCell.d.ts +35 -2
  296. package/dist/types/surfaces/StatGrid.d.ts +3 -1
  297. package/dist/types/surfaces/budget-messages.d.ts +30 -0
  298. package/dist/types/surfaces/delta-badge.d.ts +10 -0
  299. package/dist/types/surfaces/index.d.ts +4 -3
  300. package/dist/types/surfaces/person-color.d.ts +2 -2
  301. package/dist/types/surfaces/stat-cell-messages.d.ts +19 -0
  302. package/dist/types/widgets/Dashboard.d.ts +42 -0
  303. package/dist/types/widgets/index.d.ts +1 -0
  304. package/package.json +7 -1
package/dist/base.css CHANGED
@@ -35,6 +35,14 @@
35
35
  --stdlib-chart-c6: #06b6d4;
36
36
  --stdlib-chart-c7: #84cc16;
37
37
  --stdlib-chart-c8: #f97316;
38
+ /* Money with a direction, as in the full stylesheet: turquoise comes in, violet goes out. */
39
+ --k2b-flow-in-text: light-dark(#0e7490, #67e8f9);
40
+ --k2b-flow-in-surface: light-dark(#ecfeff, rgb(8 51 68 / 0.55));
41
+ --k2b-flow-in-ring: light-dark(#a5f3fc, #155e75);
42
+ --k2b-flow-in-mark: light-dark(#0891b2, #22d3ee);
43
+ --k2b-flow-out-text: light-dark(#6d28d9, #c4b5fd);
44
+ --k2b-flow-out-surface: light-dark(#f5f3ff, rgb(46 16 101 / 0.55));
45
+ --k2b-flow-out-mark: light-dark(#8b5cf6, #a78bfa);
38
46
 
39
47
  --k2b-surface: light-dark(#ffffff, #11151b);
40
48
  --k2b-surface-canvas: light-dark(#fafafa, #090d12);
@@ -1070,11 +1078,37 @@
1070
1078
  pointer-events: none;
1071
1079
  }
1072
1080
 
1073
- .k2b-chart [data-inspected]:not([data-chart-role="value"]) > :is(rect, path, circle) {
1081
+ /* Calm hover: nothing else dims. A single mark gets a thin outline; a column or row of a category chart gets a
1082
+ light band behind it instead (data-inspecting="category"). */
1083
+ .k2b-chart:not([data-chart-kind="bar"], [data-chart-kind="histogram"], [data-chart-kind="boxplot"]) [data-inspected]:not([data-chart-role="value"]) > :is(rect, path, circle) {
1074
1084
  stroke: var(--k2b-chart-inspection-color);
1075
- stroke-width: 2px;
1076
1085
  vector-effect: non-scaling-stroke;
1077
1086
  }
1087
+ .k2b-chart:not([data-chart-kind="bar"], [data-chart-kind="histogram"], [data-chart-kind="boxplot"]) [data-inspected]:not([data-chart-role="value"]) > :is(rect, path) {
1088
+ stroke-width: 1.5px;
1089
+ }
1090
+ /* Points keep a 2 px ring: a tiny point is hit through its stroke, so a thinner ring would let the drawing take the pointer. */
1091
+ .k2b-chart:not([data-chart-kind="bar"], [data-chart-kind="histogram"], [data-chart-kind="boxplot"]) [data-inspected]:not([data-chart-role="value"]) > circle {
1092
+ stroke-width: 2px;
1093
+ }
1094
+
1095
+ /* The band sits behind the marks without positioning the drawing, which would change what lies on top. */
1096
+ .k2b-chart[data-inspecting="category"] {
1097
+ isolation: isolate;
1098
+ }
1099
+
1100
+ .k2b-chart[data-inspecting="category"]::before {
1101
+ content: "";
1102
+ position: absolute;
1103
+ left: var(--k2b-chart-band-left);
1104
+ top: var(--k2b-chart-band-top);
1105
+ width: var(--k2b-chart-band-width);
1106
+ height: var(--k2b-chart-band-height);
1107
+ z-index: -1;
1108
+ border-radius: 3px;
1109
+ background: color-mix(in srgb, currentColor 7%, transparent);
1110
+ pointer-events: none;
1111
+ }
1078
1112
 
1079
1113
  .k2b-chart [data-inspected] > .stdlib-chart-inspection-point {
1080
1114
  fill: var(--k2b-chart-inspection-color);
@@ -1277,3 +1311,7 @@
1277
1311
  }
1278
1312
  }
1279
1313
  }
1314
+
1315
+ @layer k2b-base {
1316
+ .k2b-chart[data-chart-kind="area"] [data-selected] > .k2b-area-inspection-point { opacity: 1; stroke-width: 1.5px; }
1317
+ }
@@ -110,6 +110,9 @@ export function ContextMenuBase(props) {
110
110
  const close = () => {
111
111
  detachOpenListeners();
112
112
  if (!isOpen()) return;
113
+ // An activated entry closes the menu before its action runs: focus goes back to where the menu opened from, as
114
+ // Escape returns it, so the keyboard never lands on the page body.
115
+ if (menu?.contains(document.activeElement)) returnFocus(opener?.isConnected ? opener : host, hostRing);
113
116
  setPosition();
114
117
  if (closeActiveContextMenu === close) closeActiveContextMenu = undefined;
115
118
  props.onClose?.();
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["actions/ContextMenu.tsx"],"sourcesContent":["import { createMemo, createSignal, createUniqueId, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { Portal } from \"solid-js/web\";\nimport { returnFocus, ringOnReturn } from \"../internal/focus-return\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { type DropdownItem, DropdownItems, type DropdownPosition, dropdownPosition } from \"./Dropdown\";\nimport { focusRowSegment } from \"./menu-rows\";\n\nexport type ContextMenuProps = {\n items: readonly DropdownItem[];\n children: JSX.Element;\n class?: string | ((isOpen: boolean) => string);\n /** Tab order of the context-menu host. Descendant-focused composite widgets use -1. */\n tabIndex?: number;\n disabled?: boolean;\n onClose?: () => void;\n onOpen?: () => void;\n id?: string;\n label?: string;\n /**\n * Links, form fields, editable text, and selected text inside the host keep the browser's own menu, with its Copy,\n * Paste, and Open link. Use it where the host wraps readable content rather than one row.\n */\n keepNativeMenu?: boolean;\n};\n\nconst NATIVE_MENU_TARGETS = \"a[href], input, textarea, select, [contenteditable]:not([contenteditable='false'])\";\n\nlet closeActiveContextMenu: (() => void) | undefined;\n\nconst focusableItems = (menu: HTMLElement | undefined): HTMLElement[] =>\n menu\n ? Array.from(\n menu.querySelectorAll<HTMLElement>(\n [\n \"[role='menuitem']:not([aria-disabled='true'])\",\n \"[role='menuitemcheckbox']:not([aria-disabled='true'])\",\n \"[role='menuitemradio']:not([aria-disabled='true'])\",\n ].join(\", \"),\n ),\n )\n : [];\n\n/** Right-click menu with keyboard invocation, one-open-at-a-time behavior, and viewport clamping. */\nexport function ContextMenu(props: ContextMenuProps): JSX.Element {\n return ContextMenuBase(props);\n}\n\n/**\n * Package-internal, not exported from the package index: `openAt` lets GestureMenu open the menu at a held finger, and\n * `title` names what was pressed above the entries, since the finger covers it.\n */\nexport function ContextMenuBase(\n props: ContextMenuProps & {\n openAt?: (open: (x: number, y: number) => void) => void;\n title?: string;\n closeWith?: (close: () => void) => void;\n },\n): JSX.Element {\n const messages = useUiMessages();\n const generatedId = `k2b-context-${createUniqueId()}`;\n const menuId = `${generatedId}-menu`;\n const [position, setPosition] = createSignal<{ x: number; y: number }>();\n let host: HTMLDivElement | undefined;\n let menu: HTMLDivElement | undefined;\n let listenersAttached = false;\n let hostRing = true;\n /** The element inside the host that had focus as the menu opened, such as a row or a day of a composite widget. */\n let opener: HTMLElement | undefined;\n let anchor = { x: 0, y: 0 };\n let viewport = { width: 0, height: 0 };\n let resizeObserver: ResizeObserver | undefined;\n\n const isOpen = () => position() !== undefined;\n const keepsNativeMenu = (target: EventTarget | null): boolean => {\n if (!props.keepNativeMenu || !(target instanceof Node)) return false;\n const element = target instanceof Element ? target : target.parentElement;\n const native = element?.closest(NATIVE_MENU_TARGETS);\n if (native && host?.contains(native)) return true;\n const selection = window.getSelection();\n return Boolean(selection && !selection.isCollapsed && selection.toString().trim() && selection.containsNode(target, true));\n };\n const hostClass = createMemo(() => (typeof props.class === \"function\" ? props.class(isOpen()) : props.class));\n const items = createMemo<readonly DropdownItem[]>(() => props.items);\n\n const dismiss = (event: PointerEvent) => {\n if (menu?.contains(event.target as Node)) return;\n close();\n };\n const closeOnScroll = (event: Event) => {\n const target = event.target;\n if (target instanceof Node && menu?.contains(target)) return;\n close();\n };\n // A resize event may leave the viewport's size unchanged; headless Chromium\n // was seen to fire one on a fresh page. The clamped menu is still in place.\n const closeOnResize = () => {\n if (window.innerWidth === viewport.width && window.innerHeight === viewport.height) return;\n close();\n };\n const attachOpenListeners = () => {\n if (listenersAttached) return;\n listenersAttached = true;\n document.addEventListener(\"pointerdown\", dismiss);\n document.addEventListener(\"keydown\", keyDown);\n window.addEventListener(\"resize\", closeOnResize);\n window.addEventListener(\"scroll\", closeOnScroll, true);\n };\n const detachOpenListeners = () => {\n if (!listenersAttached) return;\n listenersAttached = false;\n document.removeEventListener(\"pointerdown\", dismiss);\n document.removeEventListener(\"keydown\", keyDown);\n window.removeEventListener(\"resize\", closeOnResize);\n window.removeEventListener(\"scroll\", closeOnScroll, true);\n resizeObserver?.disconnect();\n };\n /** Clamps the rendered menu into the viewport beside the point that opened it. */\n const place = () => {\n if (!isOpen() || !menu?.isConnected) return;\n const point = dropdownPosition(\n new DOMRect(anchor.x, anchor.y, 0, 0),\n menu.getBoundingClientRect(),\n \"bottom-right\" satisfies DropdownPosition,\n { width: window.innerWidth, height: window.innerHeight },\n 0,\n );\n setPosition({ x: point.left, y: point.top });\n };\n const close = () => {\n detachOpenListeners();\n if (!isOpen()) return;\n setPosition();\n if (closeActiveContextMenu === close) closeActiveContextMenu = undefined;\n props.onClose?.();\n };\n const focusItem = (index: number) => {\n const items = focusableItems(menu);\n if (items.length === 0) return;\n items[(index + items.length) % items.length]?.focus();\n };\n const open = (x: number, y: number) => {\n if (props.disabled) return;\n closeActiveContextMenu?.();\n // Focus may sit on a descendant of the host, as in composite widgets; Escape returns it there.\n const focused = document.activeElement;\n opener = focused instanceof HTMLElement && focused !== host && host?.contains(focused) ? focused : undefined;\n hostRing = ringOnReturn(focused);\n anchor = { x, y };\n viewport = { width: window.innerWidth, height: window.innerHeight };\n setPosition({ x, y });\n closeActiveContextMenu = close;\n attachOpenListeners();\n props.onOpen?.();\n // The menu sizes to its entries, so it is measured once rendered and\n // clamped into the viewport before the next paint, and again whenever its\n // entries change its size while it is open.\n queueMicrotask(() => {\n if (!isOpen() || !menu?.isConnected) return;\n place();\n if (typeof ResizeObserver !== \"undefined\") {\n resizeObserver ??= new ResizeObserver(place);\n resizeObserver.observe(menu);\n }\n focusItem(0);\n });\n };\n const keyDown = (event: KeyboardEvent) => {\n if (!isOpen()) return;\n const items = focusableItems(menu);\n const current = items.indexOf(document.activeElement as HTMLElement);\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n focusItem(current + (event.key === \"ArrowDown\" ? 1 : -1));\n } else if (focusRowSegment(items, event.key)) {\n event.preventDefault();\n } else if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n focusItem(event.key === \"Home\" ? 0 : -1);\n } else if (event.key === \"Escape\") {\n event.preventDefault();\n close();\n returnFocus(opener?.isConnected ? opener : host, hostRing);\n } else if (event.key === \"Tab\") {\n close();\n }\n };\n\n props.openAt?.(open);\n // A close from outside, such as a drag taking over the press, returns focus that sits in the menu to where it came from.\n props.closeWith?.(() => {\n if (isOpen() && menu?.contains(document.activeElement)) returnFocus(opener?.isConnected ? opener : host, hostRing);\n close();\n });\n\n onMount(() => {\n onCleanup(() => {\n detachOpenListeners();\n if (closeActiveContextMenu === close) closeActiveContextMenu = undefined;\n });\n });\n\n return (\n <>\n {/* biome-ignore lint/a11y/useAriaPropsSupportedByRole: the named group owns the context-menu relationship without pretending arbitrary children form one button. */}\n <div\n ref={host}\n id={props.id ?? generatedId}\n class={hostClass()}\n role=\"group\"\n tabIndex={props.disabled ? undefined : (props.tabIndex ?? 0)}\n aria-label={props.label ?? messages().contextMenu}\n aria-haspopup=\"menu\"\n aria-expanded={isOpen()}\n aria-controls={isOpen() ? menuId : undefined}\n aria-disabled={props.disabled ? \"true\" : undefined}\n onContextMenu={(event) => {\n if (props.disabled) return;\n // An enclosing context menu must not take over the browser's own either.\n if (keepsNativeMenu(event.target)) return void event.stopPropagation();\n event.preventDefault();\n event.stopPropagation();\n open(event.clientX, event.clientY);\n }}\n onKeyDown={(event) => {\n if (props.disabled || (event.key !== \"ContextMenu\" && !(event.shiftKey && event.key === \"F10\"))) return;\n // A nested context menu already opened its own; a field keeps the browser's.\n if (\n event.defaultPrevented ||\n (props.keepNativeMenu && event.target instanceof Element && event.target.closest(NATIVE_MENU_TARGETS))\n )\n return;\n event.preventDefault();\n // Beside the focused element, such as a row of a composite widget, rather than the corner of the whole host.\n const focused = document.activeElement;\n const rect = (focused instanceof HTMLElement && host?.contains(focused) ? focused : host)?.getBoundingClientRect();\n if (rect) open(rect.left + 12, rect.top + 12);\n }}\n >\n {props.children}\n </div>\n <Show when={position()}>\n {(point) => (\n <Portal>\n <div\n ref={menu}\n id={menuId}\n class=\"k2b-ui k2b-context-menu\"\n role=\"menu\"\n aria-label={props.label ?? messages().contextMenu}\n style={{ left: `${point().x}px`, top: `${point().y}px` }}\n onPointerDown={(event) => event.stopPropagation()}\n >\n {/* The menu carries the same name for assistive technology. */}\n <Show when={props.title}>\n <div class=\"k2b-context-menu__title\" aria-hidden=\"true\">\n {props.title}\n </div>\n </Show>\n <DropdownItems items={items()} close={close} />\n </div>\n </Portal>\n )}\n </Show>\n </>\n );\n}\n\nexport default ContextMenu;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["actions/ContextMenu.tsx"],"sourcesContent":["import { createMemo, createSignal, createUniqueId, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { Portal } from \"solid-js/web\";\nimport { returnFocus, ringOnReturn } from \"../internal/focus-return\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { type DropdownItem, DropdownItems, type DropdownPosition, dropdownPosition } from \"./Dropdown\";\nimport { focusRowSegment } from \"./menu-rows\";\n\nexport type ContextMenuProps = {\n items: readonly DropdownItem[];\n children: JSX.Element;\n class?: string | ((isOpen: boolean) => string);\n /** Tab order of the context-menu host. Descendant-focused composite widgets use -1. */\n tabIndex?: number;\n disabled?: boolean;\n onClose?: () => void;\n onOpen?: () => void;\n id?: string;\n label?: string;\n /**\n * Links, form fields, editable text, and selected text inside the host keep the browser's own menu, with its Copy,\n * Paste, and Open link. Use it where the host wraps readable content rather than one row.\n */\n keepNativeMenu?: boolean;\n};\n\nconst NATIVE_MENU_TARGETS = \"a[href], input, textarea, select, [contenteditable]:not([contenteditable='false'])\";\n\nlet closeActiveContextMenu: (() => void) | undefined;\n\nconst focusableItems = (menu: HTMLElement | undefined): HTMLElement[] =>\n menu\n ? Array.from(\n menu.querySelectorAll<HTMLElement>(\n [\n \"[role='menuitem']:not([aria-disabled='true'])\",\n \"[role='menuitemcheckbox']:not([aria-disabled='true'])\",\n \"[role='menuitemradio']:not([aria-disabled='true'])\",\n ].join(\", \"),\n ),\n )\n : [];\n\n/** Right-click menu with keyboard invocation, one-open-at-a-time behavior, and viewport clamping. */\nexport function ContextMenu(props: ContextMenuProps): JSX.Element {\n return ContextMenuBase(props);\n}\n\n/**\n * Package-internal, not exported from the package index: `openAt` lets GestureMenu open the menu at a held finger, and\n * `title` names what was pressed above the entries, since the finger covers it.\n */\nexport function ContextMenuBase(\n props: ContextMenuProps & {\n openAt?: (open: (x: number, y: number) => void) => void;\n title?: string;\n closeWith?: (close: () => void) => void;\n },\n): JSX.Element {\n const messages = useUiMessages();\n const generatedId = `k2b-context-${createUniqueId()}`;\n const menuId = `${generatedId}-menu`;\n const [position, setPosition] = createSignal<{ x: number; y: number }>();\n let host: HTMLDivElement | undefined;\n let menu: HTMLDivElement | undefined;\n let listenersAttached = false;\n let hostRing = true;\n /** The element inside the host that had focus as the menu opened, such as a row or a day of a composite widget. */\n let opener: HTMLElement | undefined;\n let anchor = { x: 0, y: 0 };\n let viewport = { width: 0, height: 0 };\n let resizeObserver: ResizeObserver | undefined;\n\n const isOpen = () => position() !== undefined;\n const keepsNativeMenu = (target: EventTarget | null): boolean => {\n if (!props.keepNativeMenu || !(target instanceof Node)) return false;\n const element = target instanceof Element ? target : target.parentElement;\n const native = element?.closest(NATIVE_MENU_TARGETS);\n if (native && host?.contains(native)) return true;\n const selection = window.getSelection();\n return Boolean(selection && !selection.isCollapsed && selection.toString().trim() && selection.containsNode(target, true));\n };\n const hostClass = createMemo(() => (typeof props.class === \"function\" ? props.class(isOpen()) : props.class));\n const items = createMemo<readonly DropdownItem[]>(() => props.items);\n\n const dismiss = (event: PointerEvent) => {\n if (menu?.contains(event.target as Node)) return;\n close();\n };\n const closeOnScroll = (event: Event) => {\n const target = event.target;\n if (target instanceof Node && menu?.contains(target)) return;\n close();\n };\n // A resize event may leave the viewport's size unchanged; headless Chromium\n // was seen to fire one on a fresh page. The clamped menu is still in place.\n const closeOnResize = () => {\n if (window.innerWidth === viewport.width && window.innerHeight === viewport.height) return;\n close();\n };\n const attachOpenListeners = () => {\n if (listenersAttached) return;\n listenersAttached = true;\n document.addEventListener(\"pointerdown\", dismiss);\n document.addEventListener(\"keydown\", keyDown);\n window.addEventListener(\"resize\", closeOnResize);\n window.addEventListener(\"scroll\", closeOnScroll, true);\n };\n const detachOpenListeners = () => {\n if (!listenersAttached) return;\n listenersAttached = false;\n document.removeEventListener(\"pointerdown\", dismiss);\n document.removeEventListener(\"keydown\", keyDown);\n window.removeEventListener(\"resize\", closeOnResize);\n window.removeEventListener(\"scroll\", closeOnScroll, true);\n resizeObserver?.disconnect();\n };\n /** Clamps the rendered menu into the viewport beside the point that opened it. */\n const place = () => {\n if (!isOpen() || !menu?.isConnected) return;\n const point = dropdownPosition(\n new DOMRect(anchor.x, anchor.y, 0, 0),\n menu.getBoundingClientRect(),\n \"bottom-right\" satisfies DropdownPosition,\n { width: window.innerWidth, height: window.innerHeight },\n 0,\n );\n setPosition({ x: point.left, y: point.top });\n };\n const close = () => {\n detachOpenListeners();\n if (!isOpen()) return;\n // An activated entry closes the menu before its action runs: focus goes back to where the menu opened from, as\n // Escape returns it, so the keyboard never lands on the page body.\n if (menu?.contains(document.activeElement)) returnFocus(opener?.isConnected ? opener : host, hostRing);\n setPosition();\n if (closeActiveContextMenu === close) closeActiveContextMenu = undefined;\n props.onClose?.();\n };\n const focusItem = (index: number) => {\n const items = focusableItems(menu);\n if (items.length === 0) return;\n items[(index + items.length) % items.length]?.focus();\n };\n const open = (x: number, y: number) => {\n if (props.disabled) return;\n closeActiveContextMenu?.();\n // Focus may sit on a descendant of the host, as in composite widgets; Escape returns it there.\n const focused = document.activeElement;\n opener = focused instanceof HTMLElement && focused !== host && host?.contains(focused) ? focused : undefined;\n hostRing = ringOnReturn(focused);\n anchor = { x, y };\n viewport = { width: window.innerWidth, height: window.innerHeight };\n setPosition({ x, y });\n closeActiveContextMenu = close;\n attachOpenListeners();\n props.onOpen?.();\n // The menu sizes to its entries, so it is measured once rendered and\n // clamped into the viewport before the next paint, and again whenever its\n // entries change its size while it is open.\n queueMicrotask(() => {\n if (!isOpen() || !menu?.isConnected) return;\n place();\n if (typeof ResizeObserver !== \"undefined\") {\n resizeObserver ??= new ResizeObserver(place);\n resizeObserver.observe(menu);\n }\n focusItem(0);\n });\n };\n const keyDown = (event: KeyboardEvent) => {\n if (!isOpen()) return;\n const items = focusableItems(menu);\n const current = items.indexOf(document.activeElement as HTMLElement);\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n focusItem(current + (event.key === \"ArrowDown\" ? 1 : -1));\n } else if (focusRowSegment(items, event.key)) {\n event.preventDefault();\n } else if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n focusItem(event.key === \"Home\" ? 0 : -1);\n } else if (event.key === \"Escape\") {\n event.preventDefault();\n close();\n returnFocus(opener?.isConnected ? opener : host, hostRing);\n } else if (event.key === \"Tab\") {\n close();\n }\n };\n\n props.openAt?.(open);\n // A close from outside, such as a drag taking over the press, returns focus that sits in the menu to where it came from.\n props.closeWith?.(() => {\n if (isOpen() && menu?.contains(document.activeElement)) returnFocus(opener?.isConnected ? opener : host, hostRing);\n close();\n });\n\n onMount(() => {\n onCleanup(() => {\n detachOpenListeners();\n if (closeActiveContextMenu === close) closeActiveContextMenu = undefined;\n });\n });\n\n return (\n <>\n {/* biome-ignore lint/a11y/useAriaPropsSupportedByRole: the named group owns the context-menu relationship without pretending arbitrary children form one button. */}\n <div\n ref={host}\n id={props.id ?? generatedId}\n class={hostClass()}\n role=\"group\"\n tabIndex={props.disabled ? undefined : (props.tabIndex ?? 0)}\n aria-label={props.label ?? messages().contextMenu}\n aria-haspopup=\"menu\"\n aria-expanded={isOpen()}\n aria-controls={isOpen() ? menuId : undefined}\n aria-disabled={props.disabled ? \"true\" : undefined}\n onContextMenu={(event) => {\n if (props.disabled) return;\n // An enclosing context menu must not take over the browser's own either.\n if (keepsNativeMenu(event.target)) return void event.stopPropagation();\n event.preventDefault();\n event.stopPropagation();\n open(event.clientX, event.clientY);\n }}\n onKeyDown={(event) => {\n if (props.disabled || (event.key !== \"ContextMenu\" && !(event.shiftKey && event.key === \"F10\"))) return;\n // A nested context menu already opened its own; a field keeps the browser's.\n if (\n event.defaultPrevented ||\n (props.keepNativeMenu && event.target instanceof Element && event.target.closest(NATIVE_MENU_TARGETS))\n )\n return;\n event.preventDefault();\n // Beside the focused element, such as a row of a composite widget, rather than the corner of the whole host.\n const focused = document.activeElement;\n const rect = (focused instanceof HTMLElement && host?.contains(focused) ? focused : host)?.getBoundingClientRect();\n if (rect) open(rect.left + 12, rect.top + 12);\n }}\n >\n {props.children}\n </div>\n <Show when={position()}>\n {(point) => (\n <Portal>\n <div\n ref={menu}\n id={menuId}\n class=\"k2b-ui k2b-context-menu\"\n role=\"menu\"\n aria-label={props.label ?? messages().contextMenu}\n style={{ left: `${point().x}px`, top: `${point().y}px` }}\n onPointerDown={(event) => event.stopPropagation()}\n >\n {/* The menu carries the same name for assistive technology. */}\n <Show when={props.title}>\n <div class=\"k2b-context-menu__title\" aria-hidden=\"true\">\n {props.title}\n </div>\n </Show>\n <DropdownItems items={items()} close={close} />\n </div>\n </Portal>\n )}\n </Show>\n </>\n );\n}\n\nexport default ContextMenu;\n"],"mappings":"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","ignoreList":[]}
@@ -1,14 +1,15 @@
1
1
  import { template as _$template } from "solid-js/web";
2
- import { insert as _$insert } from "solid-js/web";
2
+ import { setAttribute as _$setAttribute } from "solid-js/web";
3
3
  import { createComponent as _$createComponent } from "solid-js/web";
4
4
  import { mergeProps as _$mergeProps } from "solid-js/web";
5
5
  import { className as _$className } from "solid-js/web";
6
6
  import { effect as _$effect } from "solid-js/web";
7
7
  import { getNextElement as _$getNextElement } from "solid-js/web";
8
+ import { insert as _$insert } from "solid-js/web";
8
9
  import { memo as _$memo } from "solid-js/web";
9
- var _tmpl$ = /*#__PURE__*/_$template(`<i aria-hidden=true>`),
10
- _tmpl$2 = /*#__PURE__*/_$template(`<span>`),
11
- _tmpl$3 = /*#__PURE__*/_$template(`<span class=k2b-sr-only aria-live=polite>`);
10
+ var _tmpl$ = /*#__PURE__*/_$template(`<span class=k2b-sr-only aria-live=polite>`),
11
+ _tmpl$2 = /*#__PURE__*/_$template(`<i aria-hidden=true>`),
12
+ _tmpl$3 = /*#__PURE__*/_$template(`<span class=k2b-copy-button__label><span>`);
12
13
  import { copyToClipboard } from "@k2b/stdlib/browser";
13
14
  import { createSignal, onCleanup, splitProps } from "solid-js";
14
15
  import { useUiMessages } from "../intl/messages";
@@ -44,9 +45,21 @@ export function CopyButton(props) {
44
45
  if (resetTimer) clearTimeout(resetTimer);
45
46
  resetTimer = setTimeout(() => setCopied(false), local.resetAfter ?? 2000);
46
47
  };
47
- const visibleLabel = () => copied() ? local.copiedLabel ?? messages().copied : local.label ?? messages().copy;
48
+ const copyLabel = () => local.label ?? messages().copy;
49
+ const copiedLabel = () => local.copiedLabel ?? messages().copied;
50
+ const visibleLabel = () => copied() ? copiedLabel() : copyLabel();
48
51
  const icon = () => copied() ? "ti ti-check" : "ti ti-copy";
49
52
  const iconOnly = () => local.iconOnly ?? local.label === undefined;
53
+ // Copied often flashes into a row next to a field; the other label, drawn hidden by CSS, keeps the button's width.
54
+ const hiddenLabel = () => copied() ? copyLabel() : copiedLabel();
55
+ const announcement = () => (() => {
56
+ var _el$ = _$getNextElement(_tmpl$);
57
+ _$insert(_el$, (() => {
58
+ var _c$ = _$memo(() => !!copied());
59
+ return () => _c$() ? visibleLabel() : "";
60
+ })());
61
+ return _el$;
62
+ })();
50
63
  const button = tooltip => _$createComponent(Button, _$mergeProps(rest, {
51
64
  tooltip: tooltip,
52
65
  get disabled() {
@@ -76,24 +89,19 @@ export function CopyButton(props) {
76
89
  onClick: copy,
77
90
  get children() {
78
91
  return [(() => {
79
- var _el$ = _$getNextElement(_tmpl$);
80
- _$effect(() => _$className(_el$, icon()));
81
- return _el$;
82
- })(), _$memo(() => _$memo(() => !!!iconOnly())() && (() => {
83
92
  var _el$2 = _$getNextElement(_tmpl$2);
84
- _$insert(_el$2, visibleLabel);
93
+ _$effect(() => _$className(_el$2, icon()));
85
94
  return _el$2;
95
+ })(), _$memo(() => _$memo(() => !!!iconOnly())() && (() => {
96
+ var _el$3 = _$getNextElement(_tmpl$3),
97
+ _el$4 = _el$3.firstChild;
98
+ _$insert(_el$4, visibleLabel);
99
+ _$effect(() => _$setAttribute(_el$3, "data-reserve", hiddenLabel()));
100
+ return _el$3;
86
101
  })())];
87
102
  }
88
103
  }));
89
- return iconOnly() ? [_$memo(() => button(visibleLabel())), (() => {
90
- var _el$3 = _$getNextElement(_tmpl$3);
91
- _$insert(_el$3, (() => {
92
- var _c$ = _$memo(() => !!copied());
93
- return () => _c$() ? visibleLabel() : "";
94
- })());
95
- return _el$3;
96
- })()] : button(undefined);
104
+ return [_$memo(() => button(iconOnly() ? visibleLabel() : undefined)), _$memo(announcement)];
97
105
  }
98
106
  export default CopyButton;
99
107
  //# sourceMappingURL=CopyButton.js.map
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["actions/CopyButton.tsx"],"sourcesContent":["import { copyToClipboard } from \"@k2b/stdlib/browser\";\nimport { createSignal, type JSX, onCleanup, splitProps } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { Button, type ButtonProps } from \"./Button\";\n\nexport type CopyButtonValue = { text: string; value?: string } | { text?: string; value: string };\n\nexport type CopyButtonProps = CopyButtonValue &\n Omit<ButtonProps, \"children\" | \"onClick\"> & {\n label?: string;\n copiedLabel?: string;\n iconOnly?: boolean;\n onCopied?: () => void;\n onCopyError?: (error: unknown) => void;\n resetAfter?: number;\n };\n\nexport async function copyText(\n text: string,\n onCopyError?: (error: unknown) => void,\n copy: (text: string) => Promise<void> = copyToClipboard,\n): Promise<void> {\n try {\n await copy(text);\n } catch (error) {\n onCopyError?.(error);\n throw error;\n }\n}\n\nexport function CopyButton(props: CopyButtonProps): JSX.Element {\n const messages = useUiMessages();\n const [local, rest] = splitProps(props, [\n \"class\",\n \"copiedLabel\",\n \"disabled\",\n \"iconOnly\",\n \"label\",\n \"loading\",\n \"loadingLabel\",\n \"onCopied\",\n \"onCopyError\",\n \"resetAfter\",\n \"size\",\n \"text\",\n \"type\",\n \"value\",\n \"variant\",\n ]);\n const [copied, setCopied] = createSignal(false);\n let resetTimer: ReturnType<typeof setTimeout> | undefined;\n\n onCleanup(() => {\n if (resetTimer) clearTimeout(resetTimer);\n });\n\n const copy = async () => {\n // `copyText` reports through `onCopyError` and then rethrows so direct\n // callers can await it. The click handler is not awaited by anyone, so it\n // has to absorb the rejection here — otherwise a denied clipboard\n // permission surfaces as an unhandled rejection despite `onCopyError`.\n try {\n await copyText(local.text ?? local.value ?? \"\", local.onCopyError);\n } catch {\n return;\n }\n setCopied(true);\n local.onCopied?.();\n if (resetTimer) clearTimeout(resetTimer);\n resetTimer = setTimeout(() => setCopied(false), local.resetAfter ?? 2000);\n };\n\n const visibleLabel = () => (copied() ? (local.copiedLabel ?? messages().copied) : (local.label ?? messages().copy));\n const icon = () => (copied() ? \"ti ti-check\" : \"ti ti-copy\");\n const iconOnly = () => local.iconOnly ?? local.label === undefined;\n const button = (tooltip?: string) => (\n <Button\n {...rest}\n tooltip={tooltip}\n disabled={local.disabled}\n loading={local.loading}\n loadingLabel={local.loadingLabel}\n type={local.type ?? \"button\"}\n class={`k2b-copy-button ${local.class ?? \"\"}`}\n size={local.size ?? \"sm\"}\n variant={local.variant ?? \"ghost\"}\n aria-label={iconOnly() ? visibleLabel() : undefined}\n onClick={copy}\n >\n <i class={icon()} aria-hidden=\"true\" />\n {!iconOnly() && <span>{visibleLabel()}</span>}\n </Button>\n );\n\n return iconOnly() ? (\n <>\n {button(visibleLabel())}\n <span class=\"k2b-sr-only\" aria-live=\"polite\">\n {copied() ? visibleLabel() : \"\"}\n </span>\n </>\n ) : (\n button(undefined)\n );\n}\n\nexport default CopyButton;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["actions/CopyButton.tsx"],"sourcesContent":["import { copyToClipboard } from \"@k2b/stdlib/browser\";\nimport { createSignal, type JSX, onCleanup, splitProps } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { Button, type ButtonProps } from \"./Button\";\n\nexport type CopyButtonValue = { text: string; value?: string } | { text?: string; value: string };\n\nexport type CopyButtonProps = CopyButtonValue &\n Omit<ButtonProps, \"children\" | \"onClick\"> & {\n label?: string;\n copiedLabel?: string;\n iconOnly?: boolean;\n onCopied?: () => void;\n onCopyError?: (error: unknown) => void;\n resetAfter?: number;\n };\n\nexport async function copyText(\n text: string,\n onCopyError?: (error: unknown) => void,\n copy: (text: string) => Promise<void> = copyToClipboard,\n): Promise<void> {\n try {\n await copy(text);\n } catch (error) {\n onCopyError?.(error);\n throw error;\n }\n}\n\nexport function CopyButton(props: CopyButtonProps): JSX.Element {\n const messages = useUiMessages();\n const [local, rest] = splitProps(props, [\n \"class\",\n \"copiedLabel\",\n \"disabled\",\n \"iconOnly\",\n \"label\",\n \"loading\",\n \"loadingLabel\",\n \"onCopied\",\n \"onCopyError\",\n \"resetAfter\",\n \"size\",\n \"text\",\n \"type\",\n \"value\",\n \"variant\",\n ]);\n const [copied, setCopied] = createSignal(false);\n let resetTimer: ReturnType<typeof setTimeout> | undefined;\n\n onCleanup(() => {\n if (resetTimer) clearTimeout(resetTimer);\n });\n\n const copy = async () => {\n // `copyText` reports through `onCopyError` and then rethrows so direct\n // callers can await it. The click handler is not awaited by anyone, so it\n // has to absorb the rejection here — otherwise a denied clipboard\n // permission surfaces as an unhandled rejection despite `onCopyError`.\n try {\n await copyText(local.text ?? local.value ?? \"\", local.onCopyError);\n } catch {\n return;\n }\n setCopied(true);\n local.onCopied?.();\n if (resetTimer) clearTimeout(resetTimer);\n resetTimer = setTimeout(() => setCopied(false), local.resetAfter ?? 2000);\n };\n\n const copyLabel = () => local.label ?? messages().copy;\n const copiedLabel = () => local.copiedLabel ?? messages().copied;\n const visibleLabel = () => (copied() ? copiedLabel() : copyLabel());\n const icon = () => (copied() ? \"ti ti-check\" : \"ti ti-copy\");\n const iconOnly = () => local.iconOnly ?? local.label === undefined;\n // Copied often flashes into a row next to a field; the other label, drawn hidden by CSS, keeps the button's width.\n const hiddenLabel = () => (copied() ? copyLabel() : copiedLabel());\n const announcement = () => (\n <span class=\"k2b-sr-only\" aria-live=\"polite\">\n {copied() ? visibleLabel() : \"\"}\n </span>\n );\n const button = (tooltip?: string) => (\n <Button\n {...rest}\n tooltip={tooltip}\n disabled={local.disabled}\n loading={local.loading}\n loadingLabel={local.loadingLabel}\n type={local.type ?? \"button\"}\n class={`k2b-copy-button ${local.class ?? \"\"}`}\n size={local.size ?? \"sm\"}\n variant={local.variant ?? \"ghost\"}\n aria-label={iconOnly() ? visibleLabel() : undefined}\n onClick={copy}\n >\n <i class={icon()} aria-hidden=\"true\" />\n {!iconOnly() && (\n <span class=\"k2b-copy-button__label\" data-reserve={hiddenLabel()}>\n <span>{visibleLabel()}</span>\n </span>\n )}\n </Button>\n );\n\n return (\n <>\n {button(iconOnly() ? visibleLabel() : undefined)}\n {announcement()}\n </>\n );\n}\n\nexport default CopyButton;\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,190 @@
1
+ import { chartMessages } from "../../content/chart-message-catalog";
2
+ import { chartDatumSvg, escapeXml, niceStep } from "./svg";
3
+ /** Missing observations interrupt the entire stack; zero-sum columns are gaps only in normalized mode. */
4
+ export function areaLayout(spec, size) {
5
+ if (![size.width, size.height].every(v => Number.isFinite(v) && v > 0)) throw new RangeError("Invalid area size");
6
+ if (spec.x.some(x => typeof x === "number" && !Number.isFinite(x))) throw new RangeError("Area X values must be finite");
7
+ if (spec.series.some(s => s.data.length !== spec.x.length)) throw new RangeError("Area series must match x length");
8
+ const totals = spec.x.map((_, i) => {
9
+ let total = 0,
10
+ missing = false;
11
+ for (const series of spec.series) {
12
+ const value = series.data[i];
13
+ if (value === null) {
14
+ missing = true;
15
+ continue;
16
+ }
17
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) throw new RangeError("Area values must be nonnegative finite numbers or null");
18
+ total += value;
19
+ }
20
+ if (!Number.isFinite(total)) throw new RangeError("Area totals must be finite");
21
+ return missing || spec.normalize && total === 0 ? null : total;
22
+ });
23
+ const layers = spec.series.map(() => []);
24
+ totals.forEach((total, index) => {
25
+ let lower = 0;
26
+ spec.series.forEach((series, s) => {
27
+ const amount = series.data[index];
28
+ if (total === null || amount === null || amount === undefined) {
29
+ layers[s].push(null);
30
+ return;
31
+ }
32
+ const share = total === 0 ? 0 : amount / total;
33
+ const upper = lower + (spec.normalize ? share : amount);
34
+ layers[s].push({
35
+ index,
36
+ amount,
37
+ share,
38
+ lower,
39
+ upper
40
+ });
41
+ lower = upper;
42
+ });
43
+ });
44
+ let rawMax = 0;
45
+ for (const total of totals) if (total !== null) rawMax = Math.max(rawMax, total);
46
+ const step = spec.normalize ? 0.25 : niceStep(rawMax || 1, 5);
47
+ const max = spec.normalize ? 1 : Math.ceil((rawMax || 1) / step) * step;
48
+ if (!(step > 0) || !Number.isFinite(max)) throw new RangeError("Area values cannot form a finite axis; rescale them first");
49
+ const ticks = Array.from({
50
+ length: Math.round(max / step) + 1
51
+ }, (_, i) => i * step);
52
+ const format = spec.format ?? new Intl.NumberFormat(spec.locale ?? "en", {
53
+ maximumFractionDigits: 2
54
+ }).format;
55
+ const percent = new Intl.NumberFormat(spec.locale ?? "en", {
56
+ style: "percent",
57
+ minimumFractionDigits: 1,
58
+ maximumFractionDigits: 1
59
+ }).format;
60
+ const axisFormat = spec.normalize ? new Intl.NumberFormat(spec.locale ?? "en", {
61
+ style: "percent",
62
+ maximumFractionDigits: 0
63
+ }).format : format;
64
+ const numericX = new Intl.NumberFormat(spec.locale ?? "en", {
65
+ useGrouping: "min2",
66
+ maximumFractionDigits: 6
67
+ }).format;
68
+ const xFormat = value => typeof value === "number" ? numericX(value) : value;
69
+ const displayWidth = spec.displayWidth ?? 296;
70
+ if (!Number.isFinite(displayWidth) || displayWidth <= 0) throw new RangeError("Invalid area display width");
71
+ const ratio = size.width / displayWidth;
72
+ const left = Math.min(size.width * 0.6, Math.max(44, ...ticks.map(v => axisFormat(v).length * 7 + 12)) * ratio);
73
+ const right = size.width - 12,
74
+ top = (spec.title || spec.subtitle ? 50 : 16) + (spec.legend === false ? 0 : spec.series.length <= 2 ? 20 : 40);
75
+ const bottom = Math.max(top + 1, size.height - 30);
76
+ const projectX = index => spec.x.length < 2 ? (left + right) / 2 : left + index / (spec.x.length - 1) * (right - left);
77
+ const projectY = value => bottom - value / max * (bottom - top);
78
+ return {
79
+ layers,
80
+ totals,
81
+ max,
82
+ ticks,
83
+ format,
84
+ percent,
85
+ axisFormat,
86
+ xFormat,
87
+ ratio,
88
+ left,
89
+ right,
90
+ top,
91
+ bottom,
92
+ projectX,
93
+ projectY
94
+ };
95
+ }
96
+ const f = value => String(Math.round(value * 100) / 100);
97
+ const text = (x, y, label, anchor = "middle", extra = "") => `<text x="${f(x)}" y="${f(y)}" text-anchor="${anchor}" fill="currentColor" stroke="none" font-family="var(--k2b-font-sans, sans-serif)" font-size="11" ${extra}>${escapeXml(label)}</text>`;
98
+ export function renderAreaSvg(spec) {
99
+ const g = areaLayout(spec, spec),
100
+ parts = [];
101
+ if (spec.title) parts.push(text(spec.width / 2, 16, spec.title));
102
+ if (spec.subtitle) parts.push(text(spec.width / 2, spec.title ? 32 : 16, spec.subtitle));
103
+ for (const tick of g.ticks) {
104
+ const y = g.projectY(tick);
105
+ parts.push(`<line x1="${f(g.left)}" x2="${f(g.right)}" y1="${f(y)}" y2="${f(y)}" stroke="currentColor" stroke-opacity="${tick === 0 ? 0.25 : 0.09}"/>`, text(g.left - 8, y + 4, g.axisFormat(tick), "end", 'class="stdlib-chart-tick-label"'));
106
+ }
107
+ parts.push(`<line class="stdlib-chart-axis" x1="${f(g.left)}" x2="${f(g.right)}" y1="${f(g.bottom)}" y2="${f(g.bottom)}" stroke="none"/><line class="stdlib-chart-axis" x1="${f(g.left)}" x2="${f(g.left)}" y1="${f(g.top)}" y2="${f(g.bottom)}" stroke="none"/>`);
108
+ const palette = ["#2563eb", "#16a34a", "#d97706", "#dc2626", "#a855f7", "#0891b2", "#db2777", "#65a30d"];
109
+ if (spec.legend !== false) {
110
+ const entries = spec.series.slice(0, 4);
111
+ const columns = 2;
112
+ const cell = spec.width / columns;
113
+ entries.forEach((series, i) => {
114
+ const x = i % columns * cell + 4,
115
+ y = g.top - (entries.length <= 2 ? 11 : 28) + Math.floor(i / columns) * 17;
116
+ const color = i === 3 && spec.series.length > 4 ? "var(--k2b-text-muted, #8b8b93)" : `var(--stdlib-chart-c${i % 8 + 1}, ${palette[i % 8]})`;
117
+ const point = g.layers[i]?.at(-1);
118
+ const value = point ? spec.normalize ? g.percent(point.share) : g.format(point.amount) : "—";
119
+ const room = Math.floor(cell * (1 / g.ratio) / 6) - 4;
120
+ const showValue = value.length + 3 < room;
121
+ const maxChars = Math.max(1, room - (showValue ? value.length + 1 : 0));
122
+ const label = series.label.length > maxChars ? series.label.slice(0, maxChars - 1) + "…" : series.label;
123
+ const full = i === 3 && spec.series.length > 4 ? spec.series.slice(3).map(s => s.label).join(", ") : series.label;
124
+ const shown = i === 3 && spec.series.length > 4 ? `+${new Intl.NumberFormat(spec.locale ?? "en").format(spec.series.length - 3)}` : label;
125
+ const valueSvg = showValue && !(i === 3 && spec.series.length > 4) ? `<tspan dx="6" font-weight="600" data-chart-legend-value data-series-index="${i}" data-field="${spec.normalize ? "percent" : "value"}" data-default="${escapeXml(value)}">${escapeXml(value)}</tspan>` : "";
126
+ const labelSvg = text(x + 12, y, shown, "start").replace("</text>", `${valueSvg}</text>`);
127
+ parts.push(`<g><title>${escapeXml(full)}</title><rect x="${f(x)}" y="${f(y - 8)}" width="8" height="8" rx="2" fill="${color}" stroke="none"/>${labelSvg}</g>`);
128
+ });
129
+ }
130
+ g.layers.forEach((layer, s) => {
131
+ const color = `var(--stdlib-chart-c${s % 8 + 1}, ${palette[s % 8]})`;
132
+ let run = [];
133
+ const flush = () => {
134
+ if (!run.length) return;
135
+ const halfSlot = Math.min(10 * g.ratio, (g.right - g.left) / Math.max(2, spec.x.length * 2));
136
+ const upper = run.length === 1 ? [[Math.max(g.left, g.projectX(run[0].index) - halfSlot), g.projectY(run[0].upper)], [Math.min(g.right, g.projectX(run[0].index) + halfSlot), g.projectY(run[0].upper)]] : run.map(p => [g.projectX(p.index), g.projectY(p.upper)]);
137
+ const lower = run.length === 1 ? [[upper[1][0], g.projectY(run[0].lower)], [upper[0][0], g.projectY(run[0].lower)]] : run.toReversed().map(p => [g.projectX(p.index), g.projectY(p.lower)]);
138
+ const points = [...upper, ...lower].map(([x, y]) => `${f(x)},${f(y)}`);
139
+ parts.push(`<polygon class="k2b-area-layer" points="${points.join(" ")}" fill="color-mix(in srgb, ${color} 55%, var(--k2b-surface, #ffffff))" stroke="none"/>`, `<polyline class="k2b-area-edge k2b-area-edge-${s % 8}" points="${upper.map(([x, y]) => `${f(x)},${f(y)}`).join(" ")}" fill="none" stroke="${color}" stroke-width="1.5"/>`);
140
+ run = [];
141
+ };
142
+ for (const point of layer) {
143
+ if (point) run.push(point);else flush();
144
+ }
145
+ flush();
146
+ layer.forEach(point => {
147
+ if (!point) return;
148
+ const x = g.projectX(point.index),
149
+ y = g.projectY((point.lower + point.upper) / 2);
150
+ const circle = `<circle class="k2b-area-inspection-point" cx="${f(x)}" cy="${f(y)}" r="3" fill="${color}" opacity="0" stroke="none"/>`;
151
+ parts.push(chartDatumSvg(circle, {
152
+ role: "point",
153
+ index: point.index,
154
+ seriesIndex: s,
155
+ label: spec.series[s].label,
156
+ anchor: [x, g.top],
157
+ values: [{
158
+ key: "x",
159
+ value: spec.x[point.index],
160
+ formatted: g.xFormat(spec.x[point.index])
161
+ }, {
162
+ key: "value",
163
+ value: point.amount,
164
+ formatted: g.format(point.amount)
165
+ }, {
166
+ key: "total",
167
+ value: g.totals[point.index],
168
+ formatted: g.format(g.totals[point.index])
169
+ }, ...(spec.normalize ? [{
170
+ key: "percent",
171
+ value: point.share * 100,
172
+ formatted: g.percent(point.share)
173
+ }] : [])]
174
+ }, spec.inspect ?? false));
175
+ });
176
+ });
177
+ const slot = (g.right - g.left) / Math.max(1, spec.x.length) * (1 / g.ratio);
178
+ const labelWidth = Math.max(1, ...spec.x.map(x => Math.min(24, String(x).length))) * 6;
179
+ const stride = Math.max(1, Math.ceil(labelWidth / Math.max(1, slot)));
180
+ spec.x.forEach((value, i) => {
181
+ if (i % stride !== 0) return;
182
+ const label = g.xFormat(value);
183
+ parts.push(text(g.projectX(i), g.bottom + 20, label.length > 24 ? label.slice(0, 23) + "…" : label, i === 0 ? "start" : i === spec.x.length - 1 ? "end" : "middle", 'class="stdlib-chart-tick-label"'));
184
+ });
185
+ const totalLabel = chartMessages.resolve([spec.locale ?? "en"]).t.chartFields({
186
+ key: "areaTotal"
187
+ });
188
+ return `<svg data-chart-total-label="${escapeXml(totalLabel)}" xmlns="http://www.w3.org/2000/svg" class="stdlib-chart k2b-area ${escapeXml(spec.className ?? "")}" width="${spec.width}" height="${spec.height}" viewBox="0 0 ${spec.width} ${spec.height}" aria-hidden="true" focusable="false">${parts.join("")}</svg>`;
189
+ }
190
+ //# sourceMappingURL=area.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sources":["charts/core/area.ts"],"sourcesContent":["import { chartMessages } from \"../../content/chart-message-catalog\";\nimport { chartDatumSvg, escapeXml, niceStep } from \"./svg\";\n\nexport type AreaOptions = {\n layout: \"stacked\";\n normalize?: boolean;\n x: (string | number)[];\n series: { label: string; data: (number | null)[] }[];\n title?: string;\n subtitle?: string;\n className?: string;\n legend?: boolean;\n format?: (value: number) => string;\n locale?: string;\n /** Narrowest displayed width in CSS pixels; measured hosts pass their actual width. */\n displayWidth?: number;\n};\nexport type AreaPoint = { index: number; amount: number; share: number; lower: number; upper: number };\n\n/** Missing observations interrupt the entire stack; zero-sum columns are gaps only in normalized mode. */\nexport function areaLayout(spec: AreaOptions, size: { width: number; height: number }) {\n if (![size.width, size.height].every((v) => Number.isFinite(v) && v > 0)) throw new RangeError(\"Invalid area size\");\n if (spec.x.some((x) => typeof x === \"number\" && !Number.isFinite(x))) throw new RangeError(\"Area X values must be finite\");\n if (spec.series.some((s) => s.data.length !== spec.x.length)) throw new RangeError(\"Area series must match x length\");\n const totals = spec.x.map((_, i) => {\n let total = 0,\n missing = false;\n for (const series of spec.series) {\n const value = series.data[i];\n if (value === null) {\n missing = true;\n continue;\n }\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0)\n throw new RangeError(\"Area values must be nonnegative finite numbers or null\");\n total += value;\n }\n if (!Number.isFinite(total)) throw new RangeError(\"Area totals must be finite\");\n return missing || (spec.normalize && total === 0) ? null : total;\n });\n const layers: (AreaPoint | null)[][] = spec.series.map(() => []);\n totals.forEach((total, index) => {\n let lower = 0;\n spec.series.forEach((series, s) => {\n const amount = series.data[index];\n if (total === null || amount === null || amount === undefined) {\n layers[s]!.push(null);\n return;\n }\n const share = total === 0 ? 0 : amount / total;\n const upper = lower + (spec.normalize ? share : amount);\n layers[s]!.push({ index, amount, share, lower, upper });\n lower = upper;\n });\n });\n let rawMax = 0;\n for (const total of totals) if (total !== null) rawMax = Math.max(rawMax, total);\n const step = spec.normalize ? 0.25 : niceStep(rawMax || 1, 5);\n const max = spec.normalize ? 1 : Math.ceil((rawMax || 1) / step) * step;\n if (!(step > 0) || !Number.isFinite(max)) throw new RangeError(\"Area values cannot form a finite axis; rescale them first\");\n const ticks = Array.from({ length: Math.round(max / step) + 1 }, (_, i) => i * step);\n const format = spec.format ?? new Intl.NumberFormat(spec.locale ?? \"en\", { maximumFractionDigits: 2 }).format;\n const percent = new Intl.NumberFormat(spec.locale ?? \"en\", { style: \"percent\", minimumFractionDigits: 1, maximumFractionDigits: 1 })\n .format;\n const axisFormat = spec.normalize\n ? new Intl.NumberFormat(spec.locale ?? \"en\", { style: \"percent\", maximumFractionDigits: 0 }).format\n : format;\n const numericX = new Intl.NumberFormat(spec.locale ?? \"en\", { useGrouping: \"min2\", maximumFractionDigits: 6 }).format;\n const xFormat = (value: string | number) => (typeof value === \"number\" ? numericX(value) : value);\n const displayWidth = spec.displayWidth ?? 296;\n if (!Number.isFinite(displayWidth) || displayWidth <= 0) throw new RangeError(\"Invalid area display width\");\n const ratio = size.width / displayWidth;\n const left = Math.min(size.width * 0.6, Math.max(44, ...ticks.map((v) => axisFormat(v).length * 7 + 12)) * ratio);\n const right = size.width - 12,\n top = (spec.title || spec.subtitle ? 50 : 16) + (spec.legend === false ? 0 : spec.series.length <= 2 ? 20 : 40);\n const bottom = Math.max(top + 1, size.height - 30);\n const projectX = (index: number) => (spec.x.length < 2 ? (left + right) / 2 : left + (index / (spec.x.length - 1)) * (right - left));\n const projectY = (value: number) => bottom - (value / max) * (bottom - top);\n return { layers, totals, max, ticks, format, percent, axisFormat, xFormat, ratio, left, right, top, bottom, projectX, projectY };\n}\nconst f = (value: number) => String(Math.round(value * 100) / 100);\nconst text = (x: number, y: number, label: string, anchor = \"middle\", extra = \"\") =>\n `<text x=\"${f(x)}\" y=\"${f(y)}\" text-anchor=\"${anchor}\" fill=\"currentColor\" stroke=\"none\" font-family=\"var(--k2b-font-sans, sans-serif)\" font-size=\"11\" ${extra}>${escapeXml(label)}</text>`;\n\nexport function renderAreaSvg(spec: AreaOptions & { width: number; height: number; inspect?: boolean }): string {\n const g = areaLayout(spec, spec),\n parts: string[] = [];\n if (spec.title) parts.push(text(spec.width / 2, 16, spec.title));\n if (spec.subtitle) parts.push(text(spec.width / 2, spec.title ? 32 : 16, spec.subtitle));\n for (const tick of g.ticks) {\n const y = g.projectY(tick);\n parts.push(\n `<line x1=\"${f(g.left)}\" x2=\"${f(g.right)}\" y1=\"${f(y)}\" y2=\"${f(y)}\" stroke=\"currentColor\" stroke-opacity=\"${tick === 0 ? 0.25 : 0.09}\"/>`,\n text(g.left - 8, y + 4, g.axisFormat(tick), \"end\", 'class=\"stdlib-chart-tick-label\"'),\n );\n }\n parts.push(\n `<line class=\"stdlib-chart-axis\" x1=\"${f(g.left)}\" x2=\"${f(g.right)}\" y1=\"${f(g.bottom)}\" y2=\"${f(g.bottom)}\" stroke=\"none\"/><line class=\"stdlib-chart-axis\" x1=\"${f(g.left)}\" x2=\"${f(g.left)}\" y1=\"${f(g.top)}\" y2=\"${f(g.bottom)}\" stroke=\"none\"/>`,\n );\n const palette = [\"#2563eb\", \"#16a34a\", \"#d97706\", \"#dc2626\", \"#a855f7\", \"#0891b2\", \"#db2777\", \"#65a30d\"];\n if (spec.legend !== false) {\n const entries = spec.series.slice(0, 4);\n const columns = 2;\n const cell = spec.width / columns;\n entries.forEach((series, i) => {\n const x = (i % columns) * cell + 4,\n y = g.top - (entries.length <= 2 ? 11 : 28) + Math.floor(i / columns) * 17;\n const color =\n i === 3 && spec.series.length > 4 ? \"var(--k2b-text-muted, #8b8b93)\" : `var(--stdlib-chart-c${(i % 8) + 1}, ${palette[i % 8]})`;\n const point = g.layers[i]?.at(-1);\n const value = point ? (spec.normalize ? g.percent(point.share) : g.format(point.amount)) : \"—\";\n const room = Math.floor((cell * (1 / g.ratio)) / 6) - 4;\n const showValue = value.length + 3 < room;\n const maxChars = Math.max(1, room - (showValue ? value.length + 1 : 0));\n const label = series.label.length > maxChars ? series.label.slice(0, maxChars - 1) + \"…\" : series.label;\n const full =\n i === 3 && spec.series.length > 4\n ? spec.series\n .slice(3)\n .map((s) => s.label)\n .join(\", \")\n : series.label;\n const shown =\n i === 3 && spec.series.length > 4 ? `+${new Intl.NumberFormat(spec.locale ?? \"en\").format(spec.series.length - 3)}` : label;\n const valueSvg =\n showValue && !(i === 3 && spec.series.length > 4)\n ? `<tspan dx=\"6\" font-weight=\"600\" data-chart-legend-value data-series-index=\"${i}\" data-field=\"${spec.normalize ? \"percent\" : \"value\"}\" data-default=\"${escapeXml(value)}\">${escapeXml(value)}</tspan>`\n : \"\";\n const labelSvg = text(x + 12, y, shown, \"start\").replace(\"</text>\", `${valueSvg}</text>`);\n parts.push(\n `<g><title>${escapeXml(full)}</title><rect x=\"${f(x)}\" y=\"${f(y - 8)}\" width=\"8\" height=\"8\" rx=\"2\" fill=\"${color}\" stroke=\"none\"/>${labelSvg}</g>`,\n );\n });\n }\n g.layers.forEach((layer, s) => {\n const color = `var(--stdlib-chart-c${(s % 8) + 1}, ${palette[s % 8]})`;\n let run: AreaPoint[] = [];\n const flush = () => {\n if (!run.length) return;\n const halfSlot = Math.min(10 * g.ratio, (g.right - g.left) / Math.max(2, spec.x.length * 2));\n const upper =\n run.length === 1\n ? [\n [Math.max(g.left, g.projectX(run[0]!.index) - halfSlot), g.projectY(run[0]!.upper)],\n [Math.min(g.right, g.projectX(run[0]!.index) + halfSlot), g.projectY(run[0]!.upper)],\n ]\n : run.map((p) => [g.projectX(p.index), g.projectY(p.upper)]);\n const lower =\n run.length === 1\n ? [\n [upper[1]![0]!, g.projectY(run[0]!.lower)],\n [upper[0]![0]!, g.projectY(run[0]!.lower)],\n ]\n : run.toReversed().map((p) => [g.projectX(p.index), g.projectY(p.lower)]);\n const points = [...upper, ...lower].map(([x, y]) => `${f(x!)},${f(y!)}`);\n parts.push(\n `<polygon class=\"k2b-area-layer\" points=\"${points.join(\" \")}\" fill=\"color-mix(in srgb, ${color} 55%, var(--k2b-surface, #ffffff))\" stroke=\"none\"/>`,\n `<polyline class=\"k2b-area-edge k2b-area-edge-${s % 8}\" points=\"${upper.map(([x, y]) => `${f(x!)},${f(y!)}`).join(\" \")}\" fill=\"none\" stroke=\"${color}\" stroke-width=\"1.5\"/>`,\n );\n run = [];\n };\n for (const point of layer) {\n if (point) run.push(point);\n else flush();\n }\n flush();\n layer.forEach((point) => {\n if (!point) return;\n const x = g.projectX(point.index),\n y = g.projectY((point.lower + point.upper) / 2);\n const circle = `<circle class=\"k2b-area-inspection-point\" cx=\"${f(x)}\" cy=\"${f(y)}\" r=\"3\" fill=\"${color}\" opacity=\"0\" stroke=\"none\"/>`;\n parts.push(\n chartDatumSvg(\n circle,\n {\n role: \"point\",\n index: point.index,\n seriesIndex: s,\n label: spec.series[s]!.label,\n anchor: [x, g.top],\n values: [\n {\n key: \"x\",\n value: spec.x[point.index]!,\n formatted: g.xFormat(spec.x[point.index]!),\n },\n { key: \"value\", value: point.amount, formatted: g.format(point.amount) },\n { key: \"total\", value: g.totals[point.index]!, formatted: g.format(g.totals[point.index]!) },\n ...(spec.normalize ? [{ key: \"percent\", value: point.share * 100, formatted: g.percent(point.share) }] : []),\n ],\n },\n spec.inspect ?? false,\n ),\n );\n });\n });\n const slot = ((g.right - g.left) / Math.max(1, spec.x.length)) * (1 / g.ratio);\n const labelWidth = Math.max(1, ...spec.x.map((x) => Math.min(24, String(x).length))) * 6;\n const stride = Math.max(1, Math.ceil(labelWidth / Math.max(1, slot)));\n spec.x.forEach((value, i) => {\n if (i % stride !== 0) return;\n const label = g.xFormat(value);\n parts.push(\n text(\n g.projectX(i),\n g.bottom + 20,\n label.length > 24 ? label.slice(0, 23) + \"…\" : label,\n i === 0 ? \"start\" : i === spec.x.length - 1 ? \"end\" : \"middle\",\n 'class=\"stdlib-chart-tick-label\"',\n ),\n );\n });\n const totalLabel = chartMessages.resolve([spec.locale ?? \"en\"]).t.chartFields({ key: \"areaTotal\" });\n return `<svg data-chart-total-label=\"${escapeXml(totalLabel)}\" xmlns=\"http://www.w3.org/2000/svg\" class=\"stdlib-chart k2b-area ${escapeXml(spec.className ?? \"\")}\" width=\"${spec.width}\" height=\"${spec.height}\" viewBox=\"0 0 ${spec.width} ${spec.height}\" aria-hidden=\"true\" focusable=\"false\">${parts.join(\"\")}</svg>`;\n}\n"],"mappings":"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","ignoreList":[]}