@k2b/ui 0.50.0 → 0.51.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 (294) hide show
  1. package/dist/base.css +32 -1
  2. package/dist/browser/actions/Button.js.map +1 -1
  3. package/dist/browser/actions/CommandList.js +861 -0
  4. package/dist/browser/actions/CommandList.js.map +1 -0
  5. package/dist/browser/actions/CommandMenu.js +237 -0
  6. package/dist/browser/actions/CommandMenu.js.map +1 -0
  7. package/dist/browser/actions/Dropdown.js +43 -10
  8. package/dist/browser/actions/Dropdown.js.map +1 -1
  9. package/dist/browser/actions/command-dock.js +47 -0
  10. package/dist/browser/actions/command-dock.js.map +1 -0
  11. package/dist/browser/actions/command-items.js +84 -0
  12. package/dist/browser/actions/command-items.js.map +1 -0
  13. package/dist/browser/actions/command-messages.js +42 -0
  14. package/dist/browser/actions/command-messages.js.map +1 -0
  15. package/dist/browser/actions/index.js +1 -0
  16. package/dist/browser/actions/index.js.map +1 -1
  17. package/dist/browser/charts/core/area.js +3 -5
  18. package/dist/browser/charts/core/area.js.map +1 -1
  19. package/dist/browser/charts/core/calendar.js +1 -1
  20. package/dist/browser/charts/core/calendar.js.map +1 -1
  21. package/dist/browser/charts/core/chart-messages.js +17 -0
  22. package/dist/browser/charts/core/chart-messages.js.map +1 -0
  23. package/dist/browser/charts/core/hbar-layout.js +118 -0
  24. package/dist/browser/charts/core/hbar-layout.js.map +1 -0
  25. package/dist/browser/charts/core/hbar.js +39 -0
  26. package/dist/browser/charts/core/hbar.js.map +1 -0
  27. package/dist/browser/charts/core/index.js +7 -2
  28. package/dist/browser/charts/core/index.js.map +1 -1
  29. package/dist/browser/charts/core/map.js +116 -0
  30. package/dist/browser/charts/core/map.js.map +1 -0
  31. package/dist/browser/charts/core/registry.js +22 -15
  32. package/dist/browser/charts/core/registry.js.map +1 -1
  33. package/dist/browser/charts/core/render-size.js +13 -0
  34. package/dist/browser/charts/core/render-size.js.map +1 -0
  35. package/dist/browser/charts/core/render.js +20 -10
  36. package/dist/browser/charts/core/render.js.map +1 -1
  37. package/dist/browser/charts/core/snapshot.js +3 -3
  38. package/dist/browser/charts/core/snapshot.js.map +1 -1
  39. package/dist/browser/charts/core/svg-renderers.js +2406 -0
  40. package/dist/browser/charts/core/svg-renderers.js.map +1 -0
  41. package/dist/browser/charts/core/svg.js +4 -2525
  42. package/dist/browser/charts/core/svg.js.map +1 -1
  43. package/dist/browser/charts/core/types.js +0 -2
  44. package/dist/browser/charts/core/types.js.map +1 -1
  45. package/dist/browser/charts/core/waterfall.js +162 -0
  46. package/dist/browser/charts/core/waterfall.js.map +1 -0
  47. package/dist/browser/charts/description.js +2 -0
  48. package/dist/browser/charts/description.js.map +1 -0
  49. package/dist/browser/charts.js.map +1 -1
  50. package/dist/browser/content/Chart.js +14 -628
  51. package/dist/browser/content/Chart.js.map +1 -1
  52. package/dist/browser/content/ChartRoot.js +632 -0
  53. package/dist/browser/content/ChartRoot.js.map +1 -0
  54. package/dist/browser/content/ChartSparkline.js +24 -0
  55. package/dist/browser/content/ChartSparkline.js.map +1 -0
  56. package/dist/browser/content/FileView.js +111 -61
  57. package/dist/browser/content/FileView.js.map +1 -1
  58. package/dist/browser/content/Lightbox.js +8 -8
  59. package/dist/browser/content/Lightbox.js.map +1 -1
  60. package/dist/browser/content/MapView.js +30 -28
  61. package/dist/browser/content/MapView.js.map +1 -1
  62. package/dist/browser/content/PdfPreview.js +84 -52
  63. package/dist/browser/content/PdfPreview.js.map +1 -1
  64. package/dist/browser/content/PdfViewer.js +588 -0
  65. package/dist/browser/content/PdfViewer.js.map +1 -0
  66. package/dist/browser/content/chart-bar.js +246 -16
  67. package/dist/browser/content/chart-bar.js.map +1 -1
  68. package/dist/browser/content/chart-inspection-core.js +22 -21
  69. package/dist/browser/content/chart-inspection-core.js.map +1 -1
  70. package/dist/browser/content/chart-line-gaps.js +1 -1
  71. package/dist/browser/content/chart-line-gaps.js.map +1 -1
  72. package/dist/browser/content/chart-message-catalog.js +10 -0
  73. package/dist/browser/content/chart-message-catalog.js.map +1 -1
  74. package/dist/browser/content/chart-state-timeline.js +1 -1
  75. package/dist/browser/content/chart-state-timeline.js.map +1 -1
  76. package/dist/browser/content/chart-svg.js +2 -1
  77. package/dist/browser/content/chart-svg.js.map +1 -1
  78. package/dist/browser/content/index.js +1 -0
  79. package/dist/browser/content/index.js.map +1 -1
  80. package/dist/browser/content/pdf-document.js +29 -0
  81. package/dist/browser/content/pdf-document.js.map +1 -0
  82. package/dist/browser/content/pdf-limits.js +31 -0
  83. package/dist/browser/content/pdf-limits.js.map +1 -0
  84. package/dist/browser/content/pdf-messages.js +34 -2
  85. package/dist/browser/content/pdf-messages.js.map +1 -1
  86. package/dist/browser/content/pdf-viewer-engine.js +57 -0
  87. package/dist/browser/content/pdf-viewer-worker.js +28 -0
  88. package/dist/browser/inputs/ChoiceInputs.js +94 -51
  89. package/dist/browser/inputs/ChoiceInputs.js.map +1 -1
  90. package/dist/browser/inputs/ChoiceSlider.js +75 -58
  91. package/dist/browser/inputs/ChoiceSlider.js.map +1 -1
  92. package/dist/browser/inputs/DatePicker.js +113 -98
  93. package/dist/browser/inputs/DatePicker.js.map +1 -1
  94. package/dist/browser/inputs/PeriodPicker.js +874 -0
  95. package/dist/browser/inputs/PeriodPicker.js.map +1 -0
  96. package/dist/browser/inputs/index.js +4 -1
  97. package/dist/browser/inputs/index.js.map +1 -1
  98. package/dist/browser/inputs/input-messages.js +8 -2
  99. package/dist/browser/inputs/input-messages.js.map +1 -1
  100. package/dist/browser/inputs/markdown/MarkdownEditor.js +14 -10
  101. package/dist/browser/inputs/markdown/MarkdownEditor.js.map +1 -1
  102. package/dist/browser/inputs/markdown/SlashCommands.js +402 -0
  103. package/dist/browser/inputs/markdown/SlashCommands.js.map +1 -0
  104. package/dist/browser/inputs/period-picker-messages.js +71 -0
  105. package/dist/browser/inputs/period-picker-messages.js.map +1 -0
  106. package/dist/browser/inputs/period.js +263 -0
  107. package/dist/browser/inputs/period.js.map +1 -0
  108. package/dist/browser/layout/DetailPanel.js +147 -120
  109. package/dist/browser/layout/DetailPanel.js.map +1 -1
  110. package/dist/browser/layout/Discussion.js +101 -108
  111. package/dist/browser/layout/Discussion.js.map +1 -1
  112. package/dist/browser/layout/index.js.map +1 -1
  113. package/dist/browser/surfaces/DescriptionList.js +5 -2
  114. package/dist/browser/surfaces/DescriptionList.js.map +1 -1
  115. package/dist/browser/surfaces/StatCell.js +19 -14
  116. package/dist/browser/surfaces/StatCell.js.map +1 -1
  117. package/dist/browser/surfaces/delta-badge.js +16 -2
  118. package/dist/browser/surfaces/delta-badge.js.map +1 -1
  119. package/dist/browser/widgets/DashboardFrame.js +310 -0
  120. package/dist/browser/widgets/DashboardFrame.js.map +1 -0
  121. package/dist/browser/widgets/index.js +1 -0
  122. package/dist/browser/widgets/index.js.map +1 -1
  123. package/dist/licenses/pdfjs-dist.txt +177 -0
  124. package/dist/ssr/actions/Button.js.map +1 -1
  125. package/dist/ssr/actions/CommandList.js +638 -0
  126. package/dist/ssr/actions/CommandList.js.map +1 -0
  127. package/dist/ssr/actions/CommandMenu.js +197 -0
  128. package/dist/ssr/actions/CommandMenu.js.map +1 -0
  129. package/dist/ssr/actions/Dropdown.js +43 -10
  130. package/dist/ssr/actions/Dropdown.js.map +1 -1
  131. package/dist/ssr/actions/command-dock.js +47 -0
  132. package/dist/ssr/actions/command-dock.js.map +1 -0
  133. package/dist/ssr/actions/command-items.js +84 -0
  134. package/dist/ssr/actions/command-items.js.map +1 -0
  135. package/dist/ssr/actions/command-messages.js +42 -0
  136. package/dist/ssr/actions/command-messages.js.map +1 -0
  137. package/dist/ssr/actions/index.js +1 -0
  138. package/dist/ssr/actions/index.js.map +1 -1
  139. package/dist/ssr/charts/core/area.js +3 -5
  140. package/dist/ssr/charts/core/area.js.map +1 -1
  141. package/dist/ssr/charts/core/calendar.js +1 -1
  142. package/dist/ssr/charts/core/calendar.js.map +1 -1
  143. package/dist/ssr/charts/core/chart-messages.js +17 -0
  144. package/dist/ssr/charts/core/chart-messages.js.map +1 -0
  145. package/dist/ssr/charts/core/hbar-layout.js +118 -0
  146. package/dist/ssr/charts/core/hbar-layout.js.map +1 -0
  147. package/dist/ssr/charts/core/hbar.js +39 -0
  148. package/dist/ssr/charts/core/hbar.js.map +1 -0
  149. package/dist/ssr/charts/core/index.js +7 -2
  150. package/dist/ssr/charts/core/index.js.map +1 -1
  151. package/dist/ssr/charts/core/map.js +116 -0
  152. package/dist/ssr/charts/core/map.js.map +1 -0
  153. package/dist/ssr/charts/core/registry.js +22 -15
  154. package/dist/ssr/charts/core/registry.js.map +1 -1
  155. package/dist/ssr/charts/core/render-size.js +13 -0
  156. package/dist/ssr/charts/core/render-size.js.map +1 -0
  157. package/dist/ssr/charts/core/render.js +20 -10
  158. package/dist/ssr/charts/core/render.js.map +1 -1
  159. package/dist/ssr/charts/core/snapshot.js +3 -3
  160. package/dist/ssr/charts/core/snapshot.js.map +1 -1
  161. package/dist/ssr/charts/core/svg-renderers.js +2406 -0
  162. package/dist/ssr/charts/core/svg-renderers.js.map +1 -0
  163. package/dist/ssr/charts/core/svg.js +4 -2525
  164. package/dist/ssr/charts/core/svg.js.map +1 -1
  165. package/dist/ssr/charts/core/types.js +0 -2
  166. package/dist/ssr/charts/core/types.js.map +1 -1
  167. package/dist/ssr/charts/core/waterfall.js +162 -0
  168. package/dist/ssr/charts/core/waterfall.js.map +1 -0
  169. package/dist/ssr/charts/description.js +2 -0
  170. package/dist/ssr/charts/description.js.map +1 -0
  171. package/dist/ssr/charts.js.map +1 -1
  172. package/dist/ssr/content/Chart.js +14 -471
  173. package/dist/ssr/content/Chart.js.map +1 -1
  174. package/dist/ssr/content/ChartRoot.js +475 -0
  175. package/dist/ssr/content/ChartRoot.js.map +1 -0
  176. package/dist/ssr/content/ChartSparkline.js +24 -0
  177. package/dist/ssr/content/ChartSparkline.js.map +1 -0
  178. package/dist/ssr/content/FileView.js +56 -7
  179. package/dist/ssr/content/FileView.js.map +1 -1
  180. package/dist/ssr/content/Lightbox.js +8 -8
  181. package/dist/ssr/content/Lightbox.js.map +1 -1
  182. package/dist/ssr/content/MapView.js +9 -9
  183. package/dist/ssr/content/MapView.js.map +1 -1
  184. package/dist/ssr/content/PdfPreview.js +49 -20
  185. package/dist/ssr/content/PdfPreview.js.map +1 -1
  186. package/dist/ssr/content/PdfViewer.js +484 -0
  187. package/dist/ssr/content/PdfViewer.js.map +1 -0
  188. package/dist/ssr/content/chart-bar.js +246 -16
  189. package/dist/ssr/content/chart-bar.js.map +1 -1
  190. package/dist/ssr/content/chart-inspection-core.js +22 -21
  191. package/dist/ssr/content/chart-inspection-core.js.map +1 -1
  192. package/dist/ssr/content/chart-line-gaps.js +1 -1
  193. package/dist/ssr/content/chart-line-gaps.js.map +1 -1
  194. package/dist/ssr/content/chart-message-catalog.js +10 -0
  195. package/dist/ssr/content/chart-message-catalog.js.map +1 -1
  196. package/dist/ssr/content/chart-state-timeline.js +1 -1
  197. package/dist/ssr/content/chart-state-timeline.js.map +1 -1
  198. package/dist/ssr/content/chart-svg.js +2 -1
  199. package/dist/ssr/content/chart-svg.js.map +1 -1
  200. package/dist/ssr/content/index.js +1 -0
  201. package/dist/ssr/content/index.js.map +1 -1
  202. package/dist/ssr/content/pdf-document.js +29 -0
  203. package/dist/ssr/content/pdf-document.js.map +1 -0
  204. package/dist/ssr/content/pdf-limits.js +31 -0
  205. package/dist/ssr/content/pdf-limits.js.map +1 -0
  206. package/dist/ssr/content/pdf-messages.js +34 -2
  207. package/dist/ssr/content/pdf-messages.js.map +1 -1
  208. package/dist/ssr/inputs/ChoiceInputs.js +49 -12
  209. package/dist/ssr/inputs/ChoiceInputs.js.map +1 -1
  210. package/dist/ssr/inputs/ChoiceSlider.js +17 -12
  211. package/dist/ssr/inputs/ChoiceSlider.js.map +1 -1
  212. package/dist/ssr/inputs/DatePicker.js +14 -9
  213. package/dist/ssr/inputs/DatePicker.js.map +1 -1
  214. package/dist/ssr/inputs/PeriodPicker.js +598 -0
  215. package/dist/ssr/inputs/PeriodPicker.js.map +1 -0
  216. package/dist/ssr/inputs/index.js +4 -1
  217. package/dist/ssr/inputs/index.js.map +1 -1
  218. package/dist/ssr/inputs/input-messages.js +8 -2
  219. package/dist/ssr/inputs/input-messages.js.map +1 -1
  220. package/dist/ssr/inputs/markdown/MarkdownEditor.js +3 -2
  221. package/dist/ssr/inputs/markdown/MarkdownEditor.js.map +1 -1
  222. package/dist/ssr/inputs/markdown/SlashCommands.js +339 -0
  223. package/dist/ssr/inputs/markdown/SlashCommands.js.map +1 -0
  224. package/dist/ssr/inputs/period-picker-messages.js +71 -0
  225. package/dist/ssr/inputs/period-picker-messages.js.map +1 -0
  226. package/dist/ssr/inputs/period.js +263 -0
  227. package/dist/ssr/inputs/period.js.map +1 -0
  228. package/dist/ssr/layout/DetailPanel.js +27 -4
  229. package/dist/ssr/layout/DetailPanel.js.map +1 -1
  230. package/dist/ssr/layout/Discussion.js +16 -2
  231. package/dist/ssr/layout/Discussion.js.map +1 -1
  232. package/dist/ssr/layout/index.js.map +1 -1
  233. package/dist/ssr/surfaces/DescriptionList.js +1 -1
  234. package/dist/ssr/surfaces/DescriptionList.js.map +1 -1
  235. package/dist/ssr/surfaces/StatCell.js +4 -5
  236. package/dist/ssr/surfaces/StatCell.js.map +1 -1
  237. package/dist/ssr/surfaces/delta-badge.js +16 -2
  238. package/dist/ssr/surfaces/delta-badge.js.map +1 -1
  239. package/dist/ssr/widgets/DashboardFrame.js +200 -0
  240. package/dist/ssr/widgets/DashboardFrame.js.map +1 -0
  241. package/dist/ssr/widgets/index.js +1 -0
  242. package/dist/ssr/widgets/index.js.map +1 -1
  243. package/dist/styles.css +1 -1
  244. package/dist/types/actions/Button.d.ts +1 -1
  245. package/dist/types/actions/CommandList.d.ts +120 -0
  246. package/dist/types/actions/CommandMenu.d.ts +39 -0
  247. package/dist/types/actions/Dropdown.d.ts +17 -0
  248. package/dist/types/actions/command-dock.d.ts +8 -0
  249. package/dist/types/actions/command-items.d.ts +134 -0
  250. package/dist/types/actions/command-messages.d.ts +19 -0
  251. package/dist/types/actions/index.d.ts +3 -0
  252. package/dist/types/charts/core/calendar.d.ts +1 -1
  253. package/dist/types/charts/core/chart-messages.d.ts +5 -0
  254. package/dist/types/charts/core/hbar-layout.d.ts +74 -0
  255. package/dist/types/charts/core/hbar.d.ts +13 -0
  256. package/dist/types/charts/core/index.d.ts +7 -2
  257. package/dist/types/charts/core/map.d.ts +3 -0
  258. package/dist/types/charts/core/registry.d.ts +17 -11
  259. package/dist/types/charts/core/render-size.d.ts +7 -0
  260. package/dist/types/charts/core/render.d.ts +1 -4
  261. package/dist/types/charts/core/snapshot.d.ts +2 -2
  262. package/dist/types/charts/core/svg-renderers.d.ts +722 -0
  263. package/dist/types/charts/core/svg.d.ts +4 -698
  264. package/dist/types/charts/core/types.d.ts +1 -12
  265. package/dist/types/charts/core/waterfall.d.ts +68 -0
  266. package/dist/types/charts/description.d.ts +226 -0
  267. package/dist/types/charts.d.ts +1 -0
  268. package/dist/types/content/Chart.d.ts +3 -91
  269. package/dist/types/content/ChartRoot.d.ts +92 -0
  270. package/dist/types/content/ChartSparkline.d.ts +5 -0
  271. package/dist/types/content/PdfViewer.d.ts +32 -0
  272. package/dist/types/content/chart-bar.d.ts +95 -2
  273. package/dist/types/content/index.d.ts +2 -0
  274. package/dist/types/content/pdf-document.d.ts +5 -0
  275. package/dist/types/content/pdf-engine.d.ts +9 -0
  276. package/dist/types/content/pdf-limits.d.ts +43 -0
  277. package/dist/types/content/pdf-messages.d.ts +16 -0
  278. package/dist/types/inputs/ChoiceInputs.d.ts +4 -0
  279. package/dist/types/inputs/ChoiceSlider.d.ts +12 -0
  280. package/dist/types/inputs/DatePicker.d.ts +22 -0
  281. package/dist/types/inputs/PeriodPicker.d.ts +24 -0
  282. package/dist/types/inputs/index.d.ts +8 -2
  283. package/dist/types/inputs/input-messages.d.ts +3 -0
  284. package/dist/types/inputs/markdown/MarkdownEditor.d.ts +5 -0
  285. package/dist/types/inputs/markdown/SlashCommands.d.ts +20 -0
  286. package/dist/types/inputs/period-picker-messages.d.ts +34 -0
  287. package/dist/types/inputs/period.d.ts +134 -0
  288. package/dist/types/layout/DetailPanel.d.ts +12 -0
  289. package/dist/types/layout/index.d.ts +1 -1
  290. package/dist/types/surfaces/DescriptionList.d.ts +5 -0
  291. package/dist/types/surfaces/StatCell.d.ts +6 -1
  292. package/dist/types/widgets/DashboardFrame.d.ts +58 -0
  293. package/dist/types/widgets/index.d.ts +1 -0
  294. package/package.json +2 -1
@@ -1,4 +1,5 @@
1
- import { chartDatumSvg, computeDomain, escapeXml, extendDomainToNice, MAX_AXIS_TICKS, mapLog, mapRange, niceLogTicks, niceStep, referenceLineAttributes, svgRoot } from "../charts/core/svg";
1
+ import { chartDatumSvg, computeDomain, escapeXml, extendDomainToNice, MAX_AXIS_TICKS, mapLog, mapRange, niceLogTicks, niceStep, referenceLineAttributes, svgRoot } from "../charts/core/svg-renderers";
2
+ import { chartMessages } from "./chart-message-catalog";
2
3
 
3
4
  /**
4
5
  * Bar chart options: stdlib's `charts.bar` options plus a title for the category axis and a separate value format.
@@ -38,7 +39,7 @@ export const chartTextWidth = (text, size = FONT_PX) => {
38
39
  };
39
40
 
40
41
  /** Split a label into at most `lines` lines of `maxPx`; the last line ends with an ellipsis when the label is longer. */
41
- const wrapLabel = (label, maxPx, lines) => {
42
+ export const wrapLabel = (label, maxPx, lines) => {
42
43
  const words = label.trim().split(/\s+/);
43
44
  const result = [];
44
45
  let current = "";
@@ -128,7 +129,7 @@ const finiteItems = data => data.flatMap((item, index) => Number.isFinite(item.v
128
129
  item,
129
130
  index
130
131
  }] : []);
131
- const headerHeight = opts => opts.title || opts.subtitle ? (opts.title ? 14 : 0) + (opts.subtitle ? 6 : 0) + 16 : 0;
132
+ export const headerHeight = opts => opts.title || opts.subtitle ? (opts.title ? 14 : 0) + (opts.subtitle ? 6 : 0) + 16 : 0;
132
133
  const valueFormat = opts => opts.valueFormat ?? opts.yAxis?.format ?? (value => String(value));
133
134
  const tickFormat = opts => opts.yAxis?.format ?? (value => String(value));
134
135
 
@@ -146,7 +147,13 @@ const columnsFit = (opts, finite, width) => {
146
147
 
147
148
  /** The renderer's plan for a chart: its layout and logical height at `width`, derived from the data alone. */
148
149
  const barChartPlan = (opts, width = 480) => {
149
- const finite = finiteItems(opts.data);
150
+ const finite = finiteItems(opts.data ?? []);
151
+ if (opts.series) return {
152
+ layout: "columns",
153
+ height: 280,
154
+ finite,
155
+ header: headerHeight(opts)
156
+ };
150
157
  const header = headerHeight(opts);
151
158
  if (!finite.length) return {
152
159
  layout: "columns",
@@ -154,7 +161,7 @@ const barChartPlan = (opts, width = 480) => {
154
161
  finite,
155
162
  header
156
163
  };
157
- if (opts.xAxis?.ordered || columnsFit(opts, finite, width)) return {
164
+ if (opts.layout === "columns" || opts.layout !== "rows" && (opts.xAxis?.ordered || columnsFit(opts, finite, width))) return {
158
165
  layout: "columns",
159
166
  height: 280,
160
167
  finite,
@@ -296,7 +303,7 @@ const colorIndex = (item, fallback) => {
296
303
  if (!Number.isInteger(index) || index < 0) throw new RangeError("Chart colorIndex must be a nonnegative integer");
297
304
  return index % 8;
298
305
  };
299
- const renderHeader = (opts, width) => {
306
+ export const renderHeader = (opts, width) => {
300
307
  const parts = [];
301
308
  let y = 16;
302
309
  if (opts.title) {
@@ -350,22 +357,15 @@ const renderColumns = (opts, plan, width, height, inspect) => {
350
357
  const labelY = g.y1;
351
358
  // Unordered columns fit every label (see columnsFit); ordered ones label every n-th column that leaves room, from
352
359
  // the first column whose label stays inside the drawing.
353
- const labelPx = Math.max(...finite.map(({
360
+ const visibleLabels = visibleCategoryLabels(finite.map(({
354
361
  item
355
- }) => chartTextWidth(item.label))) + GAP_PX;
356
- const labelStep = Math.max(1, Math.ceil(labelPx / (slot / units)));
357
- const inside = position => {
358
- const half = chartTextWidth(finite[position].item.label) / 2 * units;
359
- const center = g.x0 + slot * (position + 0.5);
360
- return center - half >= 0 && center + half <= width;
361
- };
362
- const firstLabel = Math.max(0, finite.findIndex((_, position) => inside(position)));
362
+ }) => item.label), g.x0, slot, width, units);
363
363
  finite.forEach(({
364
364
  item,
365
365
  index
366
366
  }, position) => {
367
367
  const center = g.x0 + slot * (position + 0.5);
368
- if (position >= firstLabel && (position - firstLabel) % labelStep === 0 && inside(position)) parts.push(`<text class="stdlib-chart-tick-label stdlib-chart-category-label" x="${fmt(center)}" y="${fmt(labelY)}" dy="16" text-anchor="middle">${escapeXml(item.label)}</text>`);
368
+ if (visibleLabels.has(position)) parts.push(`<text class="stdlib-chart-tick-label stdlib-chart-category-label" x="${fmt(center)}" y="${fmt(labelY)}" dy="16" text-anchor="middle">${escapeXml(item.label)}</text>`);
369
369
  if (g.scale.log && item.value <= 0) return;
370
370
  const valueY = y(item.value);
371
371
  const top = Math.min(valueY, baseline);
@@ -459,6 +459,7 @@ const renderRows = (opts, plan, width, inspect) => {
459
459
  * drawing instead of dropping labels: use {@link barChartLayout} for its logical height.
460
460
  */
461
461
  export const renderBarChartSvg = opts => {
462
+ if (opts.series) return renderSeriesBars(opts);
462
463
  const plan = barChartPlan(opts, opts.width);
463
464
  // The empty drawing of stdlib's bar chart, written here so bundles leave out stdlib's whole bar renderer.
464
465
  if (!plan.finite.length) return svgRoot({
@@ -473,4 +474,233 @@ export const renderBarChartSvg = opts => {
473
474
  className: opts.className
474
475
  }, body).replace("<svg ", `<svg data-bar-layout="${plan.layout}" `);
475
476
  };
477
+
478
+ /** Stable wrapping legend slots reserve the widest total or category value before interaction. */
479
+ export function barSeriesLegend(entries, format, width = 480, displayWidth = 296, maxHeight = Infinity) {
480
+ const unit = width / displayWidth;
481
+ let x = 0,
482
+ row = 0;
483
+ const items = entries.map(entry => {
484
+ const finite = entry.data.filter(v => v !== null && Number.isFinite(v));
485
+ const total = finite.length ? finite.reduce((sum, v) => sum + v, 0) : null;
486
+ const valueWidth = Math.max(chartTextWidth(total === null ? "–" : format(total)), ...entry.data.filter(v => v !== null && Number.isFinite(v)).map(v => chartTextWidth(format(v))));
487
+ const labelWidth = Math.max(8, Math.min(96, displayWidth - valueWidth - 32, chartTextWidth(entry.label)));
488
+ const slot = Math.min(width, (14 + labelWidth + 6 + valueWidth + 16) * unit);
489
+ if (x && x + slot > width) {
490
+ x = 0;
491
+ row++;
492
+ }
493
+ const item = {
494
+ ...entry,
495
+ total,
496
+ x,
497
+ y: row * 20 + 12,
498
+ labelWidth,
499
+ valueX: x + slot - 16 * unit
500
+ };
501
+ x += slot;
502
+ return item;
503
+ });
504
+ const rows = Math.max(1, Math.floor(maxHeight / 20));
505
+ const overflow = row + 1 > rows;
506
+ const visible = overflow ? items.filter(item => item.y <= (rows - 1) * 20) : items;
507
+ return {
508
+ items: visible,
509
+ hidden: items.length - visible.length,
510
+ height: entries.length ? Math.min(row + 1, rows) * 20 : 0
511
+ };
512
+ }
513
+
514
+ /** Category geometry shared by SVG, server snapshots and browser inspection. */
515
+ export function seriesBarLayout(opts, size = {
516
+ width: 480,
517
+ height: 280
518
+ }) {
519
+ const categories = opts.x ?? [];
520
+ const series = opts.series ?? [];
521
+ if (series.some(s => s.data.length !== categories.length) || opts.compare && opts.compare.data.length !== categories.length) throw new RangeError("Bar series must have the same length as x");
522
+ if (opts.compare && series.length !== 1) throw new RangeError("Bar comparison needs exactly one current series");
523
+ if (opts.normalize && opts.layout !== "stacked") throw new RangeError("Normalized bars must be stacked");
524
+ if (opts.layout === "stacked" && opts.yAxis?.scale === "log") throw new RangeError("Stacked bars need a linear axis");
525
+ if (opts.layout === "stacked" && series.some(s => s.data.some(v => v !== null && v < 0))) throw new RangeError("Stacked bars require nonnegative values");
526
+ const totals = categories.map((_, i) => series.some(s => Number.isFinite(s.data[i])) ? series.reduce((sum, s) => sum + (Number.isFinite(s.data[i]) ? s.data[i] : 0), 0) : null);
527
+ const values = opts.layout === "stacked" ? totals.filter(v => v !== null) : series.flatMap(s => s.data.filter(v => v !== null));
528
+ const scale = valueScale(opts.normalize ? [0, 1] : [...values, ...(opts.compare?.data.filter(v => v !== null) ?? [])], opts.yAxis, true);
529
+ const format = valueFormat(opts);
530
+ const units = size.width / narrow(opts);
531
+ const legend = opts.legend !== false;
532
+ // Keep the legend within one quarter of the frame, leaving room for the plot.
533
+ const entries = [...series, ...(opts.compare ? [opts.compare] : [])];
534
+ const legendLayout = barSeriesLegend(entries, format, size.width, narrow(opts), size.height * 0.25);
535
+ const top = headerHeight(opts) + 8 + (legend ? legendLayout.height : 0) + (opts.yAxis?.label ? 16 : 0);
536
+ const left = Math.max(40, ...scale.ticks.map(v => (chartTextWidth(opts.normalize ? `${Math.round(v * 100)}%` : tickFormat(opts)(v)) + 8) * units));
537
+ const right = size.width - 4;
538
+ const bottom = size.height - 24 - (opts.xAxis?.label ? 18 : 0);
539
+ const slot = (right - left) / Math.max(1, categories.length);
540
+ const y = value => project(scale, value, [bottom, top]);
541
+ const columns = categories.map((label, index) => {
542
+ const center = left + slot * (index + 0.5);
543
+ let acc = 0;
544
+ const current = series.map((s, seriesIndex) => {
545
+ const raw = s.data[index];
546
+ const value = raw === null || !Number.isFinite(raw) || opts.normalize && totals[index] === 0 ? null : opts.normalize ? raw / totals[index] : raw;
547
+ const base = opts.layout === "stacked" ? acc : 0;
548
+ if (value !== null && opts.layout === "stacked") acc += value;
549
+ return {
550
+ seriesIndex,
551
+ raw,
552
+ value,
553
+ base
554
+ };
555
+ });
556
+ return {
557
+ label,
558
+ index,
559
+ center,
560
+ current,
561
+ total: totals[index],
562
+ previous: opts.compare?.data[index]
563
+ };
564
+ });
565
+ const barWidthPx = (opts.compare ? Math.min(slot * 0.32, 26) : Math.min(slot * (opts.layout === "stacked" ? 0.56 : 0.8 / Math.max(1, entries.length)), opts.layout === "stacked" ? 40 : 22)) / units;
566
+ return {
567
+ ...size,
568
+ columns,
569
+ totals,
570
+ scale,
571
+ left,
572
+ right,
573
+ top,
574
+ bottom,
575
+ slot,
576
+ y,
577
+ format,
578
+ units,
579
+ entries,
580
+ legend,
581
+ legendLayout,
582
+ barWidthPx
583
+ };
584
+ }
585
+ const renderSeriesBars = opts => {
586
+ const g = seriesBarLayout(opts, opts);
587
+ const parts = [renderHeader(opts, opts.width)];
588
+ const labels = chartMessages.resolve([opts.locale ?? "en"]).t;
589
+ const change = new Intl.NumberFormat(opts.locale ?? "en", {
590
+ style: "percent",
591
+ maximumFractionDigits: 1,
592
+ signDisplay: "exceptZero"
593
+ });
594
+ const text = (x, y, value, cls = "stdlib-chart-tick-label", anchor = "start", extra = "") => `<text class="${cls}" x="${fmt(x)}" y="${fmt(y)}" text-anchor="${anchor}" ${extra}>${escapeXml(value)}</text>`;
595
+ if (g.legend) g.legendLayout.items.forEach((entry, i) => {
596
+ const y = headerHeight(opts) + entry.y;
597
+ const x = entry.x;
598
+ parts.push(`<rect class="stdlib-chart-series-${i < (opts.series?.length ?? 0) ? i % 8 : 0}" x="${x}" y="${y - 8}" width="${8 * g.units}" height="8" ${i >= (opts.series?.length ?? 0) ? 'style="fill:none;stroke:var(--stdlib-chart-c1);"' : ""}/>`);
599
+ if (i >= (opts.series?.length ?? 0)) parts.push(`<path d="M ${x} ${y - 4} l ${4 * g.units} -4 M ${x + 2 * g.units} ${y} l ${6 * g.units} -6 M ${x + 6 * g.units} ${y} l ${2 * g.units} -2" fill="none" stroke="var(--stdlib-chart-c1,#3b82f6)" stroke-width="1"/>`);
600
+ const label = wrapLabel(entry.label, Math.max(8, entry.labelWidth), 1).lines[0] ?? entry.label;
601
+ const value = escapeXml(entry.total === null ? "–" : g.format(entry.total));
602
+ // One text run keeps the value six CSS pixels after its label even when the SVG stretches.
603
+ parts.push(`<text x="${fmt(x + 14 * g.units)}" y="${fmt(y)}"><tspan class="stdlib-chart-tick-label">${escapeXml(label)}</tspan><tspan class="stdlib-chart-bar-value" dx="6" data-chart-legend-value data-field="${i < (opts.series?.length ?? 0) ? `series:${i}` : "previous"}" data-default="${value}">${value}</tspan></text>`);
604
+ });
605
+ if (g.legend && g.legendLayout.hidden) parts.push(text(0, headerHeight(opts) + g.legendLayout.height - 8, `+${g.legendLayout.hidden}`, "stdlib-chart-tick-label"));
606
+ if (opts.yAxis?.label) parts.push(text(0, g.top - 6, opts.yAxis.label, "stdlib-chart-axis-label"));
607
+ for (const tick of g.scale.ticks) {
608
+ parts.push(`<line class="stdlib-chart-grid" x1="${g.left}" x2="${g.right}" y1="${g.y(tick)}" y2="${g.y(tick)}"/>`);
609
+ parts.push(text(g.left - 6 * g.units, g.y(tick) + 4, opts.normalize ? `${Math.round(tick * 100)}%` : tickFormat(opts)(tick), undefined, "end"));
610
+ }
611
+ parts.push(`<line class="stdlib-chart-axis" x1="${g.left}" x2="${g.right}" y1="${g.bottom}" y2="${g.bottom}"/>`);
612
+ const visibleLabels = visibleCategoryLabels(g.columns.map(c => c.label), g.left, g.slot, opts.width, g.units);
613
+ for (const column of g.columns) {
614
+ const fields = column.current.map((v, i) => ({
615
+ key: `series:${i}`,
616
+ value: v.raw === null || !Number.isFinite(v.raw) ? "–" : v.raw,
617
+ formatted: v.raw === null || !Number.isFinite(v.raw) ? "–" : g.format(v.raw)
618
+ }));
619
+ if (opts.compare) {
620
+ const previous = column.previous;
621
+ fields.push({
622
+ key: "previous",
623
+ value: previous ?? "–",
624
+ formatted: previous === null || !Number.isFinite(previous) ? "–" : g.format(previous)
625
+ });
626
+ const current = column.current[0]?.raw;
627
+ const delta = current == null || previous == null || !Number.isFinite(current) || !Number.isFinite(previous) ? null : current - previous;
628
+ fields.push({
629
+ key: "delta",
630
+ value: delta ?? "–",
631
+ formatted: delta === null || previous === 0 ? "–" : change.format(delta / Math.abs(previous))
632
+ });
633
+ } else if (opts.layout === "stacked") {
634
+ fields.reverse();
635
+ fields.push({
636
+ key: "total",
637
+ value: column.total ?? "–",
638
+ formatted: column.total === null ? "–" : g.format(column.total)
639
+ });
640
+ }
641
+ let marks = `<rect class="k2b-chart-category-band" fill="none" pointer-events="all" x="${column.center - g.slot / 2}" y="${g.top}" width="${g.slot}" height="${Math.max(0, g.bottom - g.top)}" rx="6"/>`;
642
+ const bar = (value, base, x, width, color, previous = false) => {
643
+ const y0 = g.y(g.scale.log ? g.scale.domain[0] : base),
644
+ y1 = g.y(base + value);
645
+ const rect = `<rect class="stdlib-chart-bar stdlib-chart-series-${color % 8}" x="${fmt(x)}" y="${fmt(Math.min(y0, y1))}" width="${fmt(Math.max(0, width))}" height="${fmt(Math.abs(y0 - y1))}" rx="3"/>`;
646
+ if (!previous) return rect;
647
+ // Inline strokes avoid document-global SVG pattern IDs, including duplicate charts during SSR.
648
+ const lines = [];
649
+ for (let d = -Math.abs(y0 - y1); d < width; d += 6) {
650
+ const lo = Math.max(0, -d),
651
+ hi = Math.min(Math.abs(y0 - y1), width - d);
652
+ if (hi > lo) lines.push(`<line x1="${x + d + lo}" y1="${Math.max(y0, y1) - lo}" x2="${x + d + hi}" y2="${Math.max(y0, y1) - hi}" stroke="var(--stdlib-chart-c1,#3b82f6)" stroke-width="1.5"/>`);
653
+ }
654
+ return `<g class="k2b-chart-previous">${rect.replace("/>", ' style="fill:var(--stdlib-chart-c1,#3b82f6);fill-opacity:.14" stroke="var(--stdlib-chart-c1,#3b82f6)" stroke-width="1"/>')}${lines.join("")}</g>`;
655
+ };
656
+ if (opts.compare) {
657
+ const bw = Math.min(g.slot * 0.32, 26);
658
+ const gap = Math.min(1.5, g.slot * 0.08);
659
+ if (column.previous !== null && Number.isFinite(column.previous) && (!g.scale.log || column.previous > 0)) marks += bar(column.previous, 0, column.center - bw - gap, bw, 0, true);
660
+ const value = column.current[0]?.value;
661
+ if (value != null && (!g.scale.log || value > 0)) marks += bar(value, 0, column.center + gap, bw, 0);
662
+ } else column.current.forEach(v => {
663
+ if (v.value === null || g.scale.log && v.value <= 0) return;
664
+ const stacked = opts.layout === "stacked";
665
+ const bw = stacked ? Math.min(g.slot * 0.56, 40) : Math.min(g.slot * 0.8 / g.entries.length, 22);
666
+ const gap = bw / g.units > 4 ? 2 : 0;
667
+ const x = stacked ? column.center - bw / 2 : column.center - g.entries.length * bw / 2 + v.seriesIndex * bw + gap / 2;
668
+ const segment = bar(v.value, v.base, x, stacked ? bw : bw - gap, v.seriesIndex);
669
+ if (stacked && v.value > 0 && column.current.some(next => next.seriesIndex > v.seriesIndex && next.value !== null && next.value > 0)) {
670
+ const fullHeight = Math.abs(g.y(v.base) - g.y(v.base + v.value));
671
+ const gap = Math.min(1.5, fullHeight / 2);
672
+ marks += segment.replace(/y="[^"]*"/, `y="${g.y(v.base + v.value) + gap}"`).replace(/height="[^"]*"/, `height="${fullHeight - gap}"`);
673
+ } else marks += segment;
674
+ });
675
+ parts.push(chartDatumSvg(marks, {
676
+ role: "item",
677
+ index: column.index,
678
+ label: column.label,
679
+ anchor: [column.center, g.top],
680
+ values: fields
681
+ }, opts.inspect ?? false, [column.label, ...fields.map(field => `${field.key.startsWith("series:") ? opts.series[Number(field.key.slice(7))].label : field.key === "previous" ? opts.compare.label : field.key === "delta" ? labels.chartFields({
682
+ key: "delta"
683
+ }) : labels.chartFields({
684
+ key: "total"
685
+ })}: ${field.formatted}`)].join(" · ")));
686
+ if (visibleLabels.has(column.index)) parts.push(text(column.center, g.bottom, column.label, "stdlib-chart-tick-label stdlib-chart-category-label", "middle", 'dy="16"'));
687
+ }
688
+ for (const ref of opts.references ?? []) if ((ref.axis ?? "y") === "y" && Number.isFinite(ref.value) && ref.value >= g.scale.domain[0] && ref.value <= g.scale.domain[1]) {
689
+ parts.push(`<line class="stdlib-chart-reference" x1="${g.left}" x2="${g.right}" y1="${g.y(ref.value)}" y2="${g.y(ref.value)}"/>`);
690
+ if (ref.label) parts.push(text(g.right, g.y(ref.value) - 4, ref.label, "stdlib-chart-reference-label", "end"));
691
+ }
692
+ if (opts.xAxis?.label) parts.push(text((g.left + g.right) / 2, opts.height - 2, opts.xAxis.label, "stdlib-chart-axis-label", "middle"));
693
+ return svgRoot(opts, parts.join("")).replace("<svg ", '<svg data-bar-layout="columns" ');
694
+ };
695
+ const visibleCategoryLabels = (labels, left, slot, width, units) => {
696
+ const labelPx = Math.max(0, ...labels.map(label => chartTextWidth(label))) + GAP_PX;
697
+ const step = Math.max(1, Math.ceil(labelPx / (slot / units)));
698
+ const inside = i => {
699
+ const half = chartTextWidth(labels[i]) * units / 2,
700
+ center = left + slot * (i + 0.5);
701
+ return center - half >= 0 && center + half <= width;
702
+ };
703
+ const first = Math.max(0, labels.findIndex((_, i) => inside(i)));
704
+ return new Set(labels.flatMap((_, i) => i >= first && (i - first) % step === 0 && inside(i) ? [i] : []));
705
+ };
476
706
  //# sourceMappingURL=chart-bar.js.map