@galaxy-io/dls 1.2.7 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (305) hide show
  1. package/README.md +2 -0
  2. package/dist/avatar/Avatar.d.ts +2 -1
  3. package/dist/avatar/Avatar.js +103 -14
  4. package/dist/buttons/Button.d.ts +6 -1
  5. package/dist/buttons/Button.js +8 -4
  6. package/dist/charts/BarChart.d.ts +30 -20
  7. package/dist/charts/BarChart.js +183 -253
  8. package/dist/charts/ChartAxis.d.ts +47 -22
  9. package/dist/charts/ChartAxis.js +81 -60
  10. package/dist/charts/ChartCategoryTargets.d.ts +27 -0
  11. package/dist/charts/ChartCategoryTargets.js +75 -0
  12. package/dist/charts/ChartEmptyState.d.ts +17 -0
  13. package/dist/charts/ChartEmptyState.js +29 -0
  14. package/dist/charts/ChartFrame.d.ts +110 -0
  15. package/dist/charts/ChartFrame.js +143 -0
  16. package/dist/charts/ChartLegend.d.ts +27 -4
  17. package/dist/charts/ChartLegend.js +46 -23
  18. package/dist/charts/ChartPrimitives.d.ts +230 -0
  19. package/dist/charts/ChartPrimitives.js +305 -0
  20. package/dist/charts/ChartTooltip.d.ts +25 -4
  21. package/dist/charts/ChartTooltip.js +55 -49
  22. package/dist/charts/LineChart.d.ts +42 -20
  23. package/dist/charts/LineChart.js +175 -241
  24. package/dist/charts/PieChart.d.ts +48 -32
  25. package/dist/charts/PieChart.js +180 -170
  26. package/dist/charts/barChartGeometry.d.ts +120 -0
  27. package/dist/charts/barChartGeometry.js +210 -0
  28. package/dist/charts/barChartLegend.d.ts +25 -0
  29. package/dist/charts/barChartLegend.js +23 -0
  30. package/dist/charts/chartFormat.d.ts +27 -0
  31. package/dist/charts/chartFormat.js +71 -0
  32. package/dist/charts/chartScales.d.ts +120 -0
  33. package/dist/charts/chartScales.js +165 -0
  34. package/dist/charts/chartTheme.d.ts +18 -0
  35. package/dist/charts/chartTheme.js +26 -0
  36. package/dist/charts/constants.d.ts +241 -18
  37. package/dist/charts/constants.js +261 -32
  38. package/dist/charts/lineChartGeometry.d.ts +92 -0
  39. package/dist/charts/lineChartGeometry.js +134 -0
  40. package/dist/charts/pieChartGeometry.d.ts +60 -0
  41. package/dist/charts/pieChartGeometry.js +79 -0
  42. package/dist/charts/types.d.ts +428 -54
  43. package/dist/charts/types.js +155 -0
  44. package/dist/charts/useCartesianChartLayout.d.ts +70 -0
  45. package/dist/charts/useCartesianChartLayout.js +56 -0
  46. package/dist/charts/useChartDimensions.d.ts +47 -0
  47. package/dist/charts/useChartDimensions.js +63 -0
  48. package/dist/charts/useChartFormatters.d.ts +19 -0
  49. package/dist/charts/useChartFormatters.js +20 -0
  50. package/dist/charts/useChartInteraction.d.ts +76 -0
  51. package/dist/charts/useChartInteraction.js +126 -0
  52. package/dist/charts/useChartTooltipPosition.d.ts +53 -0
  53. package/dist/charts/useChartTooltipPosition.js +39 -0
  54. package/dist/charts/useSeriesColorResolver.d.ts +37 -0
  55. package/dist/charts/useSeriesColorResolver.js +27 -0
  56. package/dist/hooks/useElementClientSize.d.ts +20 -0
  57. package/dist/hooks/useElementClientSize.js +43 -0
  58. package/dist/inputs/CheckboxInput.d.ts +7 -2
  59. package/dist/inputs/CheckboxInput.js +30 -14
  60. package/dist/inputs/Input.d.ts +1 -1
  61. package/dist/inputs/Input.js +6 -2
  62. package/dist/inputs/MultiSelectInput.js +1 -1
  63. package/dist/inputs/RadioInput.js +7 -2
  64. package/dist/styles.css +69 -74
  65. package/dist/table/InfiniteSpreadsheet.d.ts +6 -0
  66. package/dist/table/InfiniteSpreadsheet.js +235 -0
  67. package/dist/table/InfiniteTable.d.ts +7 -88
  68. package/dist/table/InfiniteTable.js +366 -577
  69. package/dist/{spreadsheet → table}/SpreadsheetCell.d.ts +6 -4
  70. package/dist/table/SpreadsheetCell.js +71 -0
  71. package/dist/{spreadsheet → table}/SpreadsheetCellEditor.js +27 -21
  72. package/dist/table/SpreadsheetHeaderCell.d.ts +23 -0
  73. package/dist/table/SpreadsheetHeaderCell.js +91 -0
  74. package/dist/table/SpreadsheetMenuItem.d.ts +14 -0
  75. package/dist/table/SpreadsheetMenuItem.js +33 -0
  76. package/dist/table/SpreadsheetPrimitives.d.ts +172 -0
  77. package/dist/table/SpreadsheetPrimitives.js +105 -0
  78. package/dist/table/SpreadsheetRow.d.ts +33 -0
  79. package/dist/table/SpreadsheetRow.js +73 -0
  80. package/dist/{spreadsheet → table}/SpreadsheetRowActionCell.d.ts +5 -7
  81. package/dist/table/SpreadsheetRowActionCell.js +51 -0
  82. package/dist/table/TableExpandCell.d.ts +11 -0
  83. package/dist/table/TableExpandCell.js +24 -0
  84. package/dist/table/TableExpandedRow.d.ts +16 -0
  85. package/dist/table/TableExpandedRow.js +77 -0
  86. package/dist/table/TableHeaderCellContent.d.ts +30 -0
  87. package/dist/table/TableHeaderCellContent.js +48 -0
  88. package/dist/table/TablePrimitives.d.ts +307 -0
  89. package/dist/table/TablePrimitives.js +298 -0
  90. package/dist/table/TableSelectCell.d.ts +18 -0
  91. package/dist/table/TableSelectCell.js +26 -0
  92. package/dist/table/TableStatusRow.d.ts +18 -0
  93. package/dist/table/TableStatusRow.js +50 -0
  94. package/dist/table/VirtualizedInfiniteTable.d.ts +11 -27
  95. package/dist/table/VirtualizedInfiniteTable.js +182 -317
  96. package/dist/table/types.d.ts +249 -0
  97. package/dist/table/types.js +51 -0
  98. package/dist/table/useInfiniteScrollSentinel.d.ts +24 -0
  99. package/dist/table/useInfiniteScrollSentinel.js +53 -0
  100. package/dist/{spreadsheet/hooks → table}/useSpreadsheetEditing.d.ts +1 -1
  101. package/dist/{spreadsheet/hooks → table}/useSpreadsheetEditing.js +1 -1
  102. package/dist/table/useTableColumnLayout.d.ts +28 -0
  103. package/dist/table/useTableColumnLayout.js +63 -0
  104. package/dist/table/useTableColumnResize.d.ts +38 -0
  105. package/dist/table/useTableColumnResize.js +155 -0
  106. package/dist/table/useTableKeyboardNavigation.d.ts +25 -0
  107. package/dist/table/useTableKeyboardNavigation.js +83 -0
  108. package/dist/table/useTableRowExpansion.d.ts +24 -0
  109. package/dist/table/useTableRowExpansion.js +62 -0
  110. package/dist/table/useTableRowSelection.d.ts +27 -0
  111. package/dist/table/useTableRowSelection.js +94 -0
  112. package/dist/table/utils.d.ts +50 -0
  113. package/dist/table/utils.js +78 -0
  114. package/dist/text/MarkdownText.js +45 -27
  115. package/dist/theme/variants/dark.js +1 -1
  116. package/dist/widget/Widget.d.ts +2 -0
  117. package/dist/widget/Widget.js +14 -7
  118. package/package.json +1 -5
  119. package/dist/assets/components/enrichment/PerplexityIcon.d.ts +0 -3
  120. package/dist/assets/components/enrichment/PerplexityIcon.js +0 -35
  121. package/dist/assets/components/enrichment/TavilyIcon.d.ts +0 -3
  122. package/dist/assets/components/enrichment/TavilyIcon.js +0 -15
  123. package/dist/assets/components/onboarding/TenantSetupDark.d.ts +0 -3
  124. package/dist/assets/components/onboarding/TenantSetupDark.js +0 -498
  125. package/dist/assets/components/onboarding/TenantSetupLight.d.ts +0 -3
  126. package/dist/assets/components/onboarding/TenantSetupLight.js +0 -482
  127. package/dist/assets/components/onboarding/UserSetupDark.d.ts +0 -3
  128. package/dist/assets/components/onboarding/UserSetupDark.js +0 -1086
  129. package/dist/assets/components/onboarding/UserSetupLight.d.ts +0 -3
  130. package/dist/assets/components/onboarding/UserSetupLight.js +0 -1024
  131. package/dist/assets/components/onboarding/WorkspaceSetupBuildDark.d.ts +0 -3
  132. package/dist/assets/components/onboarding/WorkspaceSetupBuildDark.js +0 -466
  133. package/dist/assets/components/onboarding/WorkspaceSetupBuildLight.d.ts +0 -3
  134. package/dist/assets/components/onboarding/WorkspaceSetupBuildLight.js +0 -460
  135. package/dist/assets/components/onboarding/WorkspaceSetupConnectDark.d.ts +0 -3
  136. package/dist/assets/components/onboarding/WorkspaceSetupConnectDark.js +0 -336
  137. package/dist/assets/components/onboarding/WorkspaceSetupConnectLight.d.ts +0 -3
  138. package/dist/assets/components/onboarding/WorkspaceSetupConnectLight.js +0 -336
  139. package/dist/assets/components/onboarding/WorkspaceSetupIntegrateDark.d.ts +0 -3
  140. package/dist/assets/components/onboarding/WorkspaceSetupIntegrateDark.js +0 -153
  141. package/dist/assets/components/onboarding/WorkspaceSetupIntegrateLight.d.ts +0 -3
  142. package/dist/assets/components/onboarding/WorkspaceSetupIntegrateLight.js +0 -153
  143. package/dist/assets/components/projects/MappingMethodAutoIntrospectDark.d.ts +0 -3
  144. package/dist/assets/components/projects/MappingMethodAutoIntrospectDark.js +0 -117
  145. package/dist/assets/components/projects/MappingMethodAutoIntrospectLight.d.ts +0 -3
  146. package/dist/assets/components/projects/MappingMethodAutoIntrospectLight.js +0 -117
  147. package/dist/assets/components/projects/MappingMethodBlankDark.d.ts +0 -3
  148. package/dist/assets/components/projects/MappingMethodBlankDark.js +0 -150
  149. package/dist/assets/components/projects/MappingMethodBlankDarkHovered.d.ts +0 -3
  150. package/dist/assets/components/projects/MappingMethodBlankDarkHovered.js +0 -150
  151. package/dist/assets/components/projects/MappingMethodBlankLight.d.ts +0 -3
  152. package/dist/assets/components/projects/MappingMethodBlankLight.js +0 -150
  153. package/dist/assets/components/projects/MappingMethodBlankLightHovered.d.ts +0 -3
  154. package/dist/assets/components/projects/MappingMethodBlankLightHovered.js +0 -150
  155. package/dist/assets/components/projects/MappingMethodJsonDark.d.ts +0 -3
  156. package/dist/assets/components/projects/MappingMethodJsonDark.js +0 -90
  157. package/dist/assets/components/projects/MappingMethodJsonDarkHovered.d.ts +0 -3
  158. package/dist/assets/components/projects/MappingMethodJsonDarkHovered.js +0 -90
  159. package/dist/assets/components/projects/MappingMethodJsonLight.d.ts +0 -3
  160. package/dist/assets/components/projects/MappingMethodJsonLight.js +0 -90
  161. package/dist/assets/components/projects/MappingMethodJsonLightHovered.d.ts +0 -3
  162. package/dist/assets/components/projects/MappingMethodJsonLightHovered.js +0 -90
  163. package/dist/assets/components/projects/ProjectsEmptyStateDark.d.ts +0 -3
  164. package/dist/assets/components/projects/ProjectsEmptyStateDark.js +0 -454
  165. package/dist/assets/components/projects/ProjectsEmptyStateLight.d.ts +0 -3
  166. package/dist/assets/components/projects/ProjectsEmptyStateLight.js +0 -456
  167. package/dist/assets/components/root/CreateProjectActionCardDark.d.ts +0 -3
  168. package/dist/assets/components/root/CreateProjectActionCardDark.js +0 -1796
  169. package/dist/assets/components/root/CreateProjectActionCardDarkHovered.d.ts +0 -3
  170. package/dist/assets/components/root/CreateProjectActionCardDarkHovered.js +0 -1796
  171. package/dist/assets/components/root/CreateProjectActionCardLight.d.ts +0 -3
  172. package/dist/assets/components/root/CreateProjectActionCardLight.js +0 -1786
  173. package/dist/assets/components/root/CreateProjectActionCardLightHovered.d.ts +0 -3
  174. package/dist/assets/components/root/CreateProjectActionCardLightHovered.js +0 -1786
  175. package/dist/assets/components/root/CreateSourceActionCardDark.d.ts +0 -3
  176. package/dist/assets/components/root/CreateSourceActionCardDark.js +0 -879
  177. package/dist/assets/components/root/CreateSourceActionCardDarkHovered.d.ts +0 -3
  178. package/dist/assets/components/root/CreateSourceActionCardDarkHovered.js +0 -879
  179. package/dist/assets/components/root/CreateSourceActionCardLight.d.ts +0 -3
  180. package/dist/assets/components/root/CreateSourceActionCardLight.js +0 -889
  181. package/dist/assets/components/root/CreateSourceActionCardLightHovered.d.ts +0 -3
  182. package/dist/assets/components/root/CreateSourceActionCardLightHovered.js +0 -889
  183. package/dist/assets/components/sources/AttioIcon.d.ts +0 -3
  184. package/dist/assets/components/sources/AttioIcon.js +0 -11
  185. package/dist/assets/components/sources/BigquerySourceIcon.d.ts +0 -3
  186. package/dist/assets/components/sources/BigquerySourceIcon.js +0 -39
  187. package/dist/assets/components/sources/BrowserbaseSourceIcon.d.ts +0 -3
  188. package/dist/assets/components/sources/BrowserbaseSourceIcon.js +0 -35
  189. package/dist/assets/components/sources/ClickhouseLogoSourceIconDark.d.ts +0 -3
  190. package/dist/assets/components/sources/ClickhouseLogoSourceIconDark.js +0 -13
  191. package/dist/assets/components/sources/ClickhouseLogoSourceIconLight.d.ts +0 -3
  192. package/dist/assets/components/sources/ClickhouseLogoSourceIconLight.js +0 -13
  193. package/dist/assets/components/sources/ConfluenceSourceIcon.d.ts +0 -3
  194. package/dist/assets/components/sources/ConfluenceSourceIcon.js +0 -30
  195. package/dist/assets/components/sources/GithubSourceIcon.d.ts +0 -3
  196. package/dist/assets/components/sources/GithubSourceIcon.js +0 -27
  197. package/dist/assets/components/sources/GoogleDriveIcon.d.ts +0 -3
  198. package/dist/assets/components/sources/GoogleDriveIcon.js +0 -45
  199. package/dist/assets/components/sources/HubspotSourceIcon.d.ts +0 -3
  200. package/dist/assets/components/sources/HubspotSourceIcon.js +0 -14
  201. package/dist/assets/components/sources/JiraSourceIcon.d.ts +0 -3
  202. package/dist/assets/components/sources/JiraSourceIcon.js +0 -54
  203. package/dist/assets/components/sources/LinearSourceIcon.d.ts +0 -3
  204. package/dist/assets/components/sources/LinearSourceIcon.js +0 -14
  205. package/dist/assets/components/sources/MysqlLogoSourceIconDark.d.ts +0 -3
  206. package/dist/assets/components/sources/MysqlLogoSourceIconDark.js +0 -17
  207. package/dist/assets/components/sources/NetsuiteSourceIcon.d.ts +0 -3
  208. package/dist/assets/components/sources/NetsuiteSourceIcon.js +0 -32
  209. package/dist/assets/components/sources/NotionIcon.d.ts +0 -3
  210. package/dist/assets/components/sources/NotionIcon.js +0 -20
  211. package/dist/assets/components/sources/PostgresqlIcon.d.ts +0 -3
  212. package/dist/assets/components/sources/PostgresqlIcon.js +0 -61
  213. package/dist/assets/components/sources/S3Icon.d.ts +0 -3
  214. package/dist/assets/components/sources/S3Icon.js +0 -76
  215. package/dist/assets/components/sources/SalesforceSourceIcon.d.ts +0 -3
  216. package/dist/assets/components/sources/SalesforceSourceIcon.js +0 -23
  217. package/dist/assets/components/sources/SlackIcon.d.ts +0 -3
  218. package/dist/assets/components/sources/SlackIcon.js +0 -32
  219. package/dist/assets/components/sources/SnowflakeLogoSourceIconDark.d.ts +0 -3
  220. package/dist/assets/components/sources/SnowflakeLogoSourceIconDark.js +0 -14
  221. package/dist/assets/components/sources/SnowflakeLogoSourceIconLight.d.ts +0 -3
  222. package/dist/assets/components/sources/SnowflakeLogoSourceIconLight.js +0 -14
  223. package/dist/assets/components/sources/WikipediaSourceIcon.d.ts +0 -3
  224. package/dist/assets/components/sources/WikipediaSourceIcon.js +0 -1490
  225. package/dist/avatar/AvatarEmpty.d.ts +0 -7
  226. package/dist/avatar/AvatarEmpty.js +0 -99
  227. package/dist/avatar/types.d.ts +0 -5
  228. package/dist/avatar/types.js +0 -9
  229. package/dist/charts/utils.d.ts +0 -29
  230. package/dist/charts/utils.js +0 -62
  231. package/dist/icons/BackIcon.d.ts +0 -3
  232. package/dist/icons/BackIcon.js +0 -13
  233. package/dist/icons/CloseIcon.d.ts +0 -3
  234. package/dist/icons/CloseIcon.js +0 -13
  235. package/dist/icons/CreateIcon.d.ts +0 -3
  236. package/dist/icons/CreateIcon.js +0 -13
  237. package/dist/icons/ForwardIcon.d.ts +0 -3
  238. package/dist/icons/ForwardIcon.js +0 -13
  239. package/dist/icons/HelpIcon.d.ts +0 -3
  240. package/dist/icons/HelpIcon.js +0 -14
  241. package/dist/icons/ProjectsIcon.d.ts +0 -3
  242. package/dist/icons/ProjectsIcon.js +0 -12
  243. package/dist/icons/SearchIcon.d.ts +0 -3
  244. package/dist/icons/SearchIcon.js +0 -12
  245. package/dist/icons/SourcesIcon.d.ts +0 -3
  246. package/dist/icons/SourcesIcon.js +0 -12
  247. package/dist/icons/TextIcon.d.ts +0 -4
  248. package/dist/icons/TextIcon.js +0 -22
  249. package/dist/icons/WebScrapeIcon.d.ts +0 -4
  250. package/dist/icons/WebScrapeIcon.js +0 -22
  251. package/dist/icons/WebhookIcon.d.ts +0 -4
  252. package/dist/icons/WebhookIcon.js +0 -22
  253. package/dist/icons/sources/AttioLogomark.d.ts +0 -4
  254. package/dist/icons/sources/AttioLogomark.js +0 -8
  255. package/dist/icons/sources/BrowserbaseLogomark.d.ts +0 -4
  256. package/dist/icons/sources/BrowserbaseLogomark.js +0 -8
  257. package/dist/icons/sources/ClickhouseLogomark.d.ts +0 -4
  258. package/dist/icons/sources/ClickhouseLogomark.js +0 -16
  259. package/dist/icons/sources/ConfluenceLogomark.d.ts +0 -4
  260. package/dist/icons/sources/ConfluenceLogomark.js +0 -8
  261. package/dist/icons/sources/GithubLogomark.d.ts +0 -4
  262. package/dist/icons/sources/GithubLogomark.js +0 -8
  263. package/dist/icons/sources/GoogleBigqueryLogomark.d.ts +0 -4
  264. package/dist/icons/sources/GoogleBigqueryLogomark.js +0 -8
  265. package/dist/icons/sources/GoogleDriveLogomark.d.ts +0 -4
  266. package/dist/icons/sources/GoogleDriveLogomark.js +0 -8
  267. package/dist/icons/sources/HubspotLogomark.d.ts +0 -4
  268. package/dist/icons/sources/HubspotLogomark.js +0 -8
  269. package/dist/icons/sources/JiraLogomark.d.ts +0 -4
  270. package/dist/icons/sources/JiraLogomark.js +0 -8
  271. package/dist/icons/sources/LinearLogomark.d.ts +0 -4
  272. package/dist/icons/sources/LinearLogomark.js +0 -8
  273. package/dist/icons/sources/MySQLLogomark.d.ts +0 -4
  274. package/dist/icons/sources/MySQLLogomark.js +0 -8
  275. package/dist/icons/sources/NetsuiteLogomark.d.ts +0 -4
  276. package/dist/icons/sources/NetsuiteLogomark.js +0 -8
  277. package/dist/icons/sources/NotionLogomark.d.ts +0 -4
  278. package/dist/icons/sources/NotionLogomark.js +0 -8
  279. package/dist/icons/sources/PostgresLogomark.d.ts +0 -4
  280. package/dist/icons/sources/PostgresLogomark.js +0 -8
  281. package/dist/icons/sources/S3Logomark.d.ts +0 -4
  282. package/dist/icons/sources/S3Logomark.js +0 -8
  283. package/dist/icons/sources/SalesforceLogomark.d.ts +0 -4
  284. package/dist/icons/sources/SalesforceLogomark.js +0 -8
  285. package/dist/icons/sources/SlackLogoIconmark.d.ts +0 -4
  286. package/dist/icons/sources/SlackLogoIconmark.js +0 -8
  287. package/dist/icons/sources/SnowflakeLogomark.d.ts +0 -4
  288. package/dist/icons/sources/SnowflakeLogomark.js +0 -16
  289. package/dist/icons/sources/WikipediaLogomark.d.ts +0 -4
  290. package/dist/icons/sources/WikipediaLogomark.js +0 -8
  291. package/dist/spreadsheet/InfiniteSpreadsheet.d.ts +0 -3
  292. package/dist/spreadsheet/InfiniteSpreadsheet.js +0 -265
  293. package/dist/spreadsheet/SpreadsheetAddColumnButton.d.ts +0 -6
  294. package/dist/spreadsheet/SpreadsheetAddColumnButton.js +0 -32
  295. package/dist/spreadsheet/SpreadsheetCell.js +0 -115
  296. package/dist/spreadsheet/SpreadsheetHeaderCell.d.ts +0 -18
  297. package/dist/spreadsheet/SpreadsheetHeaderCell.js +0 -141
  298. package/dist/spreadsheet/SpreadsheetRow.d.ts +0 -21
  299. package/dist/spreadsheet/SpreadsheetRow.js +0 -68
  300. package/dist/spreadsheet/SpreadsheetRowActionCell.js +0 -78
  301. package/dist/spreadsheet/hooks/useColumnResize.d.ts +0 -6
  302. package/dist/spreadsheet/hooks/useColumnResize.js +0 -46
  303. package/dist/spreadsheet/types.d.ts +0 -92
  304. package/dist/spreadsheet/types.js +0 -21
  305. /package/dist/{spreadsheet → table}/SpreadsheetCellEditor.d.ts +0 -0
@@ -0,0 +1,210 @@
1
+ import { BarChartNormalization, BarCorners } from "./types.js";
2
+ import { BAR_WIDTH_RATIO, MAX_GAP_SHARE } from "./constants.js";
3
+ import { buildValueScale, sanitizeValue } from "./chartScales.js";
4
+ //#region src/charts/barChartGeometry.ts
5
+ /**
6
+ * Pick gap sizes from how crowded the chart is.
7
+ *
8
+ * Sparse charts stay roomy regardless of width; once there are enough bars to
9
+ * matter, the gaps tighten as the plot narrows.
10
+ */
11
+ function getBarSpacing(plotWidth, totalBars) {
12
+ if (totalBars < 13 || plotWidth > 650) return {
13
+ groupGap: 24,
14
+ barGap: 6
15
+ };
16
+ if (plotWidth > 500) return {
17
+ groupGap: 16,
18
+ barGap: 4
19
+ };
20
+ return {
21
+ groupGap: 12,
22
+ barGap: 3
23
+ };
24
+ }
25
+ /**
26
+ * Rectangle with one pair of corners rounded.
27
+ *
28
+ * The radius is clamped to half the height as well as half the width, so a very
29
+ * short bar renders as a symmetric cap instead of a lopsided half-pill.
30
+ */
31
+ function roundedRectPath(x, y, width, height, radius, corners) {
32
+ const r = corners === BarCorners.NONE ? 0 : Math.max(0, Math.min(radius, width / 2, height / 2));
33
+ if (r === 0) return `M${x},${y} h${width} v${height} h${-width} z`;
34
+ if (corners === BarCorners.TOP) return [
35
+ `M${x},${y + r}`,
36
+ `a${r},${r} 0 0 1 ${r},${-r}`,
37
+ `h${width - 2 * r}`,
38
+ `a${r},${r} 0 0 1 ${r},${r}`,
39
+ `v${height - r}`,
40
+ `h${-width}`,
41
+ `z`
42
+ ].join(" ");
43
+ return [
44
+ `M${x},${y}`,
45
+ `h${width}`,
46
+ `v${height - r}`,
47
+ `a${r},${r} 0 0 1 ${-r},${r}`,
48
+ `h${-(width - 2 * r)}`,
49
+ `a${r},${r} 0 0 1 ${-r},${-r}`,
50
+ `z`
51
+ ].join(" ");
52
+ }
53
+ /**
54
+ * Turn one bar's components into stacked `[from, to]` intervals.
55
+ *
56
+ * Positive and negative values accumulate on separate cursors, which is what
57
+ * lets a bar mixing both stack upward and downward from the baseline without
58
+ * any special-casing downstream — and is also why percent normalization is a
59
+ * one-line division rather than a second code path.
60
+ */
61
+ function stackComponents(values, normalization) {
62
+ let positiveCursor = 0;
63
+ let negativeCursor = 0;
64
+ const intervals = values.map((value) => {
65
+ if (value >= 0) {
66
+ const from = positiveCursor;
67
+ positiveCursor += value;
68
+ return {
69
+ value,
70
+ from,
71
+ to: positiveCursor
72
+ };
73
+ }
74
+ const to = negativeCursor;
75
+ negativeCursor += value;
76
+ return {
77
+ value,
78
+ from: negativeCursor,
79
+ to
80
+ };
81
+ });
82
+ if (normalization !== BarChartNormalization.PERCENT) return intervals;
83
+ const magnitude = positiveCursor - negativeCursor;
84
+ if (magnitude === 0) return intervals;
85
+ return intervals.map((interval) => ({
86
+ value: interval.value,
87
+ from: interval.from / magnitude,
88
+ to: interval.to / magnitude
89
+ }));
90
+ }
91
+ /**
92
+ * Signed value domain across every group.
93
+ *
94
+ * Percent-normalized charts always span 0–1, so the axis is stable no matter
95
+ * what the underlying totals are.
96
+ */
97
+ function getBarValueDomain(groups, normalization) {
98
+ if (normalization === BarChartNormalization.PERCENT) return [0, 1];
99
+ let min = 0;
100
+ let max = 0;
101
+ for (const group of groups) for (const bar of group.bars) {
102
+ let positive = 0;
103
+ let negative = 0;
104
+ for (const component of bar.components) {
105
+ const value = sanitizeValue(component.value);
106
+ if (value >= 0) positive += value;
107
+ else negative += value;
108
+ }
109
+ if (positive > max) max = positive;
110
+ if (negative < min) min = negative;
111
+ }
112
+ return [min, max];
113
+ }
114
+ function buildBarChartGeometry({ groups, plotWidth, plotHeight, normalization, isStacked, domain, resolveColor }) {
115
+ const valueScale = buildValueScale(domain, [plotHeight, 0]);
116
+ const baselineY = valueScale(0);
117
+ const rects = [];
118
+ const bands = [];
119
+ if (groups.length === 0 || plotWidth <= 0 || plotHeight <= 0) return {
120
+ rects,
121
+ bands,
122
+ valueScale
123
+ };
124
+ const { groupGap, barGap } = getBarSpacing(plotWidth, groups.reduce((sum, group) => sum + group.bars.length, 0));
125
+ const step = plotWidth / groups.length;
126
+ const effectiveGroupGap = Math.min(groupGap, step * MAX_GAP_SHARE);
127
+ const groupWidth = Math.max(1, step - effectiveGroupGap);
128
+ groups.forEach((group, groupIndex) => {
129
+ const bandX = groupIndex * step;
130
+ const groupX = bandX + (step - groupWidth) / 2;
131
+ const barCount = Math.max(1, group.bars.length);
132
+ const effectiveBarGap = Math.min(barGap, groupWidth / barCount * MAX_GAP_SHARE);
133
+ const slotWidth = (groupWidth - (barCount - 1) * effectiveBarGap) / barCount;
134
+ const barWidth = Math.max(1, Math.min(slotWidth * BAR_WIDTH_RATIO, 44));
135
+ const radius = barWidth < 40 ? 2 : 4;
136
+ const barsStartX = groupX + (groupWidth - (barCount * barWidth + (barCount - 1) * effectiveBarGap)) / 2;
137
+ let groupTopY = baselineY;
138
+ group.bars.forEach((bar, barIndex) => {
139
+ const barX = barsStartX + barIndex * (barWidth + effectiveBarGap);
140
+ const values = bar.components.map((component) => sanitizeValue(component.value));
141
+ const intervals = stackComponents(values, normalization);
142
+ let firstPositive = -1;
143
+ let lastPositive = -1;
144
+ let firstNegative = -1;
145
+ let lastNegative = -1;
146
+ values.forEach((value, index) => {
147
+ if (value > 0) {
148
+ if (firstPositive === -1) firstPositive = index;
149
+ lastPositive = index;
150
+ }
151
+ if (value < 0) {
152
+ if (firstNegative === -1) firstNegative = index;
153
+ lastNegative = index;
154
+ }
155
+ });
156
+ bar.components.forEach((component, componentIndex) => {
157
+ const { value, from, to } = intervals[componentIndex];
158
+ if (value === 0) return;
159
+ const isNegative = value < 0;
160
+ const isCap = componentIndex === (isNegative ? lastNegative : lastPositive);
161
+ const fromY = Math.round(valueScale(from));
162
+ const toY = Math.round(valueScale(to));
163
+ const topY = Math.min(fromY, toY);
164
+ const rawHeight = Math.abs(fromY - toY);
165
+ const isStackedBar = bar.components.length > 1;
166
+ const shave = componentIndex === (isNegative ? firstNegative : firstPositive) ? 0 : 2;
167
+ const height = Math.max(isStackedBar ? 0 : 2, rawHeight - shave);
168
+ const y = isNegative ? topY + shave : topY;
169
+ if (!isNegative && y < groupTopY) groupTopY = y;
170
+ rects.push({
171
+ id: `${groupIndex}:${barIndex}:${component.key}`,
172
+ groupIndex,
173
+ metric: bar.metric,
174
+ componentKey: component.key,
175
+ label: component.label,
176
+ value,
177
+ x: barX,
178
+ y,
179
+ width: barWidth,
180
+ height,
181
+ color: resolveColor({
182
+ metric: bar.metric,
183
+ componentIndex,
184
+ isStacked,
185
+ explicit: component.color
186
+ }),
187
+ corners: isCap ? isNegative ? BarCorners.BOTTOM : BarCorners.TOP : BarCorners.NONE,
188
+ radius
189
+ });
190
+ });
191
+ });
192
+ bands.push({
193
+ groupIndex,
194
+ label: group.label,
195
+ x: bandX,
196
+ y: 0,
197
+ width: step,
198
+ height: plotHeight,
199
+ anchorX: bandX + step / 2,
200
+ anchorY: groupTopY
201
+ });
202
+ });
203
+ return {
204
+ rects,
205
+ bands,
206
+ valueScale
207
+ };
208
+ }
209
+ //#endregion
210
+ export { buildBarChartGeometry, getBarValueDomain, roundedRectPath };
@@ -0,0 +1,25 @@
1
+ import type { BarChartGroupDatum, ChartLegendItem, ChartSeriesStyles } from "./types";
2
+ import type { SeriesColorResolver } from "./useSeriesColorResolver";
3
+ /**
4
+ * Legend entries for a bar chart.
5
+ *
6
+ * A pure walk over the data, kept out of the component because it is the one
7
+ * legend in the DLS that cannot be a `.map()` over the `series` record: a bar's
8
+ * *components* are a second dimension with no record of their own, so a stacked
9
+ * chart's legend has to be recovered from the data itself.
10
+ */
11
+ interface GetBarLegendItemsArgs<TMetric extends string, TComponentKey extends string> {
12
+ /**
13
+ * Whether the chart as a whole is stacked.
14
+ *
15
+ * Decides which dimension the legend names, and must match the flag the
16
+ * geometry coloured with — a legend naming metrics beside bars coloured by
17
+ * component describes a chart that is not on screen.
18
+ */
19
+ isStacked: boolean;
20
+ series: ChartSeriesStyles<TMetric>;
21
+ groups: BarChartGroupDatum<TMetric, TComponentKey>[];
22
+ colors: SeriesColorResolver<TMetric>;
23
+ }
24
+ export declare function getBarLegendItems<TMetric extends string, TComponentKey extends string>({ isStacked, series, groups, colors, }: GetBarLegendItemsArgs<TMetric, TComponentKey>): ChartLegendItem[];
25
+ export {};
@@ -0,0 +1,23 @@
1
+ //#region src/charts/barChartLegend.ts
2
+ function getBarLegendItems({ isStacked, series, groups, colors }) {
3
+ if (!isStacked) return colors.keys.map((metric) => ({
4
+ key: metric,
5
+ label: series[metric].label,
6
+ color: colors.resolve(metric)
7
+ }));
8
+ const seen = /* @__PURE__ */ new Map();
9
+ for (const group of groups) for (const bar of group.bars) bar.components.forEach((component, componentIndex) => {
10
+ if (!seen.has(component.key)) seen.set(component.key, {
11
+ label: component.label,
12
+ index: componentIndex,
13
+ explicit: component.color
14
+ });
15
+ });
16
+ return [...seen.entries()].map(([key, { label, index, explicit }]) => ({
17
+ key,
18
+ label,
19
+ color: colors.resolveByIndex(index, explicit)
20
+ }));
21
+ }
22
+ //#endregion
23
+ export { getBarLegendItems };
@@ -0,0 +1,27 @@
1
+ import { ChartValueUnit } from "./types";
2
+ import type { ChartLabelFormatter, ChartPlotTooltipModel, ChartValueFormatter } from "./types";
3
+ /**
4
+ * Format a value with a built-in unit.
5
+ *
6
+ * `PERCENT` takes a 0–100 value rather than a 0–1 fraction, matching how
7
+ * percentage data usually arrives, and appends the sign itself instead of using
8
+ * `style: "percent"` (which would divide by 100).
9
+ */
10
+ export declare function formatChartValue(value: number, unit: ChartValueUnit): string;
11
+ /**
12
+ * Pick the effective value formatter.
13
+ *
14
+ * An explicit `valueFormatter` always wins; otherwise the unit supplies a
15
+ * default, and `PLAIN` is the fallback when neither is given.
16
+ */
17
+ export declare function resolveValueFormatter(valueFormatter?: ChartValueFormatter, unit?: ChartValueUnit): ChartValueFormatter;
18
+ /** Pick the effective label formatter, defaulting to identity. */
19
+ export declare function resolveLabelFormatter(labelFormatter?: ChartLabelFormatter): ChartLabelFormatter;
20
+ /**
21
+ * Flatten a tooltip model into one sentence, for a screen reader.
22
+ *
23
+ * Derived from the tooltip rather than written separately so the two cannot
24
+ * drift: whatever a sighted reader sees on hover is what a keyboard reader
25
+ * hears on focus, by construction.
26
+ */
27
+ export declare function describeTooltipModel(model: ChartPlotTooltipModel): string;
@@ -0,0 +1,71 @@
1
+ import { ChartValueUnit } from "./types.js";
2
+ import { match } from "ts-pattern";
3
+ //#region src/charts/chartFormat.ts
4
+ /**
5
+ * Value and label formatting for the chart components.
6
+ *
7
+ * Resolving the formatter once, centrally, is what keeps axis ticks, value
8
+ * labels and tooltip rows from drifting apart — a recurring problem when every
9
+ * call site writes its own one-liner.
10
+ */
11
+ /**
12
+ * `Intl` formatters are comparatively expensive to construct, and the charts
13
+ * format every tick and tooltip row on each render, so instances are cached per
14
+ * unit.
15
+ */
16
+ var FORMATTER_CACHE = /* @__PURE__ */ new Map();
17
+ function getIntlFormatter(unit) {
18
+ const cached = FORMATTER_CACHE.get(unit);
19
+ if (cached) return cached;
20
+ const formatter = match(unit).with(ChartValueUnit.PLAIN, () => new Intl.NumberFormat(void 0, { maximumFractionDigits: 2 })).with(ChartValueUnit.CURRENCY, () => new Intl.NumberFormat(void 0, {
21
+ style: "currency",
22
+ currency: "USD",
23
+ maximumFractionDigits: 0
24
+ })).with(ChartValueUnit.PERCENT, () => new Intl.NumberFormat(void 0, { maximumFractionDigits: 1 })).with(ChartValueUnit.COMPACT, () => new Intl.NumberFormat(void 0, {
25
+ notation: "compact",
26
+ maximumFractionDigits: 1
27
+ })).exhaustive();
28
+ FORMATTER_CACHE.set(unit, formatter);
29
+ return formatter;
30
+ }
31
+ /**
32
+ * Format a value with a built-in unit.
33
+ *
34
+ * `PERCENT` takes a 0–100 value rather than a 0–1 fraction, matching how
35
+ * percentage data usually arrives, and appends the sign itself instead of using
36
+ * `style: "percent"` (which would divide by 100).
37
+ */
38
+ function formatChartValue(value, unit) {
39
+ if (!Number.isFinite(value)) return "—";
40
+ const formatted = getIntlFormatter(unit).format(value);
41
+ return unit === ChartValueUnit.PERCENT ? `${formatted}%` : formatted;
42
+ }
43
+ /**
44
+ * Pick the effective value formatter.
45
+ *
46
+ * An explicit `valueFormatter` always wins; otherwise the unit supplies a
47
+ * default, and `PLAIN` is the fallback when neither is given.
48
+ */
49
+ function resolveValueFormatter(valueFormatter, unit) {
50
+ if (valueFormatter) return valueFormatter;
51
+ const resolvedUnit = unit ?? ChartValueUnit.PLAIN;
52
+ return (value) => formatChartValue(value, resolvedUnit);
53
+ }
54
+ /** Pick the effective label formatter, defaulting to identity. */
55
+ function resolveLabelFormatter(labelFormatter) {
56
+ return labelFormatter ?? ((label) => label);
57
+ }
58
+ /**
59
+ * Flatten a tooltip model into one sentence, for a screen reader.
60
+ *
61
+ * Derived from the tooltip rather than written separately so the two cannot
62
+ * drift: whatever a sighted reader sees on hover is what a keyboard reader
63
+ * hears on focus, by construction.
64
+ */
65
+ function describeTooltipModel(model) {
66
+ if (model.rows.length === 0) return model.label;
67
+ const rows = model.rows.map((row) => `${row.label} ${row.formattedValue}`).join(", ");
68
+ return `${model.label}: ${rows}`;
69
+ }
70
+ //#endregion
71
+ export { describeTooltipModel, formatChartValue, resolveLabelFormatter, resolveValueFormatter };
@@ -0,0 +1,120 @@
1
+ import type { ChartMargin, ChartValueDomain, ChartValueFormatter } from "./types";
2
+ /**
3
+ * Scale construction and axis sizing for the chart components.
4
+ *
5
+ * Pure arithmetic with no React and no theme access, so it can be unit-reasoned
6
+ * about and stays safe for Linaria's build-time evaluation.
7
+ */
8
+ export declare function clamp(value: number, min: number, max: number): number;
9
+ /**
10
+ * Coerce a datum value into something safe to feed a scale.
11
+ *
12
+ * A single `NaN` or `Infinity` in consumer data otherwise propagates into every
13
+ * path's `d` attribute and blanks the entire chart rather than one mark.
14
+ */
15
+ export declare function sanitizeValue(value: number | undefined | null): number;
16
+ /**
17
+ * Merge a partial margin over the defaults.
18
+ *
19
+ * Written per-field rather than as a spread: spreading an object that carries
20
+ * an explicit `undefined` overwrites the default with `undefined` rather than
21
+ * falling back to it, which is easy to trip over when the partial is assembled
22
+ * from separate optional values.
23
+ *
24
+ * `defaults` exists because the cartesian default reserves axis gutters a
25
+ * radial chart has no use for. Taking it as a parameter keeps the merge
26
+ * per-field: a chart that substituted its own defaults with `margin ?? OWN`
27
+ * would silently fall back to the *cartesian* defaults the moment a caller
28
+ * passed a partial, handing an axis-less chart a 52px left gutter.
29
+ */
30
+ export declare function resolveMargin(partial?: Partial<ChartMargin>, defaults?: ChartMargin): ChartMargin;
31
+ /** Inner plot dimensions, never negative. */
32
+ export declare function getPlotDimensions(width: number, height: number, margin: ChartMargin): {
33
+ plotWidth: number;
34
+ plotHeight: number;
35
+ };
36
+ /**
37
+ * Widen a margin to leave room for axis titles.
38
+ *
39
+ * The reservation has to happen here rather than inside the axis, because the
40
+ * margin is resolved before any axis renders — and with the root SVG set to
41
+ * `overflow: visible`, an unreserved title would paint outside the container and
42
+ * be clipped by whatever the consumer wraps the chart in.
43
+ *
44
+ * Applied to the caller's *partial* before {@link resolveMargin} fills in the
45
+ * defaults, so an explicit `margin.left` still governs the tick gutter and the
46
+ * title band is added on top of it rather than eating into it. Returns the input
47
+ * untouched when there are no titles, so the common case allocates nothing.
48
+ */
49
+ export declare function addAxisTitleSpace(partial: Partial<ChartMargin> | undefined, { hasValueTitle, hasCategoryTitle }: {
50
+ hasValueTitle: boolean;
51
+ hasCategoryTitle: boolean;
52
+ }): Partial<ChartMargin> | undefined;
53
+ /**
54
+ * Turn a raw data extent into the domain the axis and the marks both use.
55
+ *
56
+ * Applies the caller's override, then three behaviours worth knowing:
57
+ *
58
+ * - **Zero is always in the domain.** Bars need a baseline to grow from, and
59
+ * without this a negative value maps outside the range and renders as a
60
+ * rectangle with negative height, which paints nothing at all.
61
+ * - **A zero-width domain is widened to 0–1.** d3's `normalize()` returns a
62
+ * constant `0.5` when the domain has no extent, so empty or all-zero data
63
+ * would otherwise map every value to the middle of the plot and strand the
64
+ * baseline halfway up.
65
+ * - **`nice()` rounds the ends outward** to values a reader would choose.
66
+ *
67
+ * Split out of {@link buildValueScale} so the domain is computed exactly once
68
+ * per chart and then handed to both the tick list and the geometry. Building it
69
+ * twice — once at a throwaway range to get ticks, once at the real range to
70
+ * place marks — leaves two `nice()` calls that must agree forever.
71
+ *
72
+ * `nice()` deliberately takes **no argument**. The default count is 10, not the
73
+ * five ticks {@link DEFAULT_VALUE_TICK_COUNT} asks for, and nicing to the tick
74
+ * count instead would change the axis extent on every existing chart.
75
+ */
76
+ export declare function resolveValueDomain(raw: [number, number], override?: Partial<ChartValueDomain>): [number, number];
77
+ /**
78
+ * Linear scale over an already-resolved domain.
79
+ *
80
+ * Does no nicing and no zero-forcing — {@link resolveValueDomain} has done
81
+ * both. Takes the domain rather than raw data so the same numbers drive the
82
+ * axis, the ticks and every mark.
83
+ */
84
+ export declare function buildValueScale(domain: [number, number], range: [number, number]): import("d3-scale").ScaleLinear<number, number, never>;
85
+ /** Point scale for categories, used by the line chart. */
86
+ export declare function buildCategoryPointScale(labels: string[], range: [number, number], padding?: number): import("d3-scale").ScalePoint<string>;
87
+ /**
88
+ * Left margin needed to fit the widest formatted tick label.
89
+ *
90
+ * Estimated from character count rather than measured from the DOM, mirroring
91
+ * `estimateColumnWidth` in `table/utils.ts`, so it works during server rendering
92
+ * and build-time evaluation. The estimate only has to be close: tick labels
93
+ * right-align against the plot and ellipsize, so an underestimate truncates one
94
+ * label rather than breaking the layout, and {@link MAX_AUTO_MARGIN_LEFT} caps
95
+ * what a pathological formatter can take from the plot.
96
+ *
97
+ * Rounded up to {@link AUTO_MARGIN_LEFT_STEP} rather than used raw — see that
98
+ * constant for why an exact fit is the wrong target.
99
+ *
100
+ * Safe to call before the chart has been measured: `nice()` and `ticks()` depend
101
+ * on the domain and the requested count, never on the scale's range, so the tick
102
+ * values here are the same ones the axis renders later.
103
+ */
104
+ export declare function estimateValueAxisMargin(ticks: number[], formatter: ChartValueFormatter): number;
105
+ /**
106
+ * How many categories to skip between rendered axis labels.
107
+ *
108
+ * Returns 1 when every label fits, so a chart that is not crowded renders
109
+ * exactly as it would with no skipping at all.
110
+ */
111
+ export declare function getCategoryLabelStride(labels: string[], step: number): number;
112
+ /**
113
+ * Tick values for a resolved domain, honoring an explicit tick count.
114
+ *
115
+ * Needs no dimensions, which is what breaks the apparent circularity in the
116
+ * layout: the left margin must fit the tick labels, the margin decides the plot
117
+ * size, and the plot size builds the scale. Tick *values* fall out of the domain
118
+ * alone, so they can be known before anything is measured.
119
+ */
120
+ export declare function getValueTicks(domain: [number, number], override?: Partial<ChartValueDomain>): number[];
@@ -0,0 +1,165 @@
1
+ import { CAPTION_CHAR_WIDTH_PX, DEFAULT_CHART_MARGIN } from "./constants.js";
2
+ import { scaleLinear, scalePoint } from "d3-scale";
3
+ //#region src/charts/chartScales.ts
4
+ /**
5
+ * Scale construction and axis sizing for the chart components.
6
+ *
7
+ * Pure arithmetic with no React and no theme access, so it can be unit-reasoned
8
+ * about and stays safe for Linaria's build-time evaluation.
9
+ */
10
+ function clamp(value, min, max) {
11
+ return Math.min(Math.max(value, min), max);
12
+ }
13
+ /**
14
+ * Coerce a datum value into something safe to feed a scale.
15
+ *
16
+ * A single `NaN` or `Infinity` in consumer data otherwise propagates into every
17
+ * path's `d` attribute and blanks the entire chart rather than one mark.
18
+ */
19
+ function sanitizeValue(value) {
20
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
21
+ }
22
+ /**
23
+ * Merge a partial margin over the defaults.
24
+ *
25
+ * Written per-field rather than as a spread: spreading an object that carries
26
+ * an explicit `undefined` overwrites the default with `undefined` rather than
27
+ * falling back to it, which is easy to trip over when the partial is assembled
28
+ * from separate optional values.
29
+ *
30
+ * `defaults` exists because the cartesian default reserves axis gutters a
31
+ * radial chart has no use for. Taking it as a parameter keeps the merge
32
+ * per-field: a chart that substituted its own defaults with `margin ?? OWN`
33
+ * would silently fall back to the *cartesian* defaults the moment a caller
34
+ * passed a partial, handing an axis-less chart a 52px left gutter.
35
+ */
36
+ function resolveMargin(partial, defaults = DEFAULT_CHART_MARGIN) {
37
+ return {
38
+ top: partial?.top ?? defaults.top,
39
+ right: partial?.right ?? defaults.right,
40
+ bottom: partial?.bottom ?? defaults.bottom,
41
+ left: partial?.left ?? defaults.left
42
+ };
43
+ }
44
+ /** Inner plot dimensions, never negative. */
45
+ function getPlotDimensions(width, height, margin) {
46
+ return {
47
+ plotWidth: Math.max(0, width - margin.left - margin.right),
48
+ plotHeight: Math.max(0, height - margin.top - margin.bottom)
49
+ };
50
+ }
51
+ /**
52
+ * Widen a margin to leave room for axis titles.
53
+ *
54
+ * The reservation has to happen here rather than inside the axis, because the
55
+ * margin is resolved before any axis renders — and with the root SVG set to
56
+ * `overflow: visible`, an unreserved title would paint outside the container and
57
+ * be clipped by whatever the consumer wraps the chart in.
58
+ *
59
+ * Applied to the caller's *partial* before {@link resolveMargin} fills in the
60
+ * defaults, so an explicit `margin.left` still governs the tick gutter and the
61
+ * title band is added on top of it rather than eating into it. Returns the input
62
+ * untouched when there are no titles, so the common case allocates nothing.
63
+ */
64
+ function addAxisTitleSpace(partial, { hasValueTitle, hasCategoryTitle }) {
65
+ if (!hasValueTitle && !hasCategoryTitle) return partial;
66
+ return {
67
+ ...partial,
68
+ left: (partial?.left ?? DEFAULT_CHART_MARGIN.left) + (hasValueTitle ? 26 : 0),
69
+ bottom: (partial?.bottom ?? DEFAULT_CHART_MARGIN.bottom) + (hasCategoryTitle ? 18 : 0)
70
+ };
71
+ }
72
+ /**
73
+ * Turn a raw data extent into the domain the axis and the marks both use.
74
+ *
75
+ * Applies the caller's override, then three behaviours worth knowing:
76
+ *
77
+ * - **Zero is always in the domain.** Bars need a baseline to grow from, and
78
+ * without this a negative value maps outside the range and renders as a
79
+ * rectangle with negative height, which paints nothing at all.
80
+ * - **A zero-width domain is widened to 0–1.** d3's `normalize()` returns a
81
+ * constant `0.5` when the domain has no extent, so empty or all-zero data
82
+ * would otherwise map every value to the middle of the plot and strand the
83
+ * baseline halfway up.
84
+ * - **`nice()` rounds the ends outward** to values a reader would choose.
85
+ *
86
+ * Split out of {@link buildValueScale} so the domain is computed exactly once
87
+ * per chart and then handed to both the tick list and the geometry. Building it
88
+ * twice — once at a throwaway range to get ticks, once at the real range to
89
+ * place marks — leaves two `nice()` calls that must agree forever.
90
+ *
91
+ * `nice()` deliberately takes **no argument**. The default count is 10, not the
92
+ * five ticks {@link DEFAULT_VALUE_TICK_COUNT} asks for, and nicing to the tick
93
+ * count instead would change the axis extent on every existing chart.
94
+ */
95
+ function resolveValueDomain(raw, override) {
96
+ const min = override?.min ?? raw[0];
97
+ const max = override?.max ?? raw[1];
98
+ const lo = Math.min(0, min);
99
+ const hi = Math.max(0, max);
100
+ const [niceLo, niceHi] = scaleLinear().domain([lo, lo === hi ? hi + 1 : hi]).nice().domain();
101
+ return [niceLo, niceHi];
102
+ }
103
+ /**
104
+ * Linear scale over an already-resolved domain.
105
+ *
106
+ * Does no nicing and no zero-forcing — {@link resolveValueDomain} has done
107
+ * both. Takes the domain rather than raw data so the same numbers drive the
108
+ * axis, the ticks and every mark.
109
+ */
110
+ function buildValueScale(domain, range) {
111
+ return scaleLinear().domain(domain).range(range);
112
+ }
113
+ /** Point scale for categories, used by the line chart. */
114
+ function buildCategoryPointScale(labels, range, padding = 0) {
115
+ return scalePoint().domain(labels).range(range).padding(padding);
116
+ }
117
+ /**
118
+ * Left margin needed to fit the widest formatted tick label.
119
+ *
120
+ * Estimated from character count rather than measured from the DOM, mirroring
121
+ * `estimateColumnWidth` in `table/utils.ts`, so it works during server rendering
122
+ * and build-time evaluation. The estimate only has to be close: tick labels
123
+ * right-align against the plot and ellipsize, so an underestimate truncates one
124
+ * label rather than breaking the layout, and {@link MAX_AUTO_MARGIN_LEFT} caps
125
+ * what a pathological formatter can take from the plot.
126
+ *
127
+ * Rounded up to {@link AUTO_MARGIN_LEFT_STEP} rather than used raw — see that
128
+ * constant for why an exact fit is the wrong target.
129
+ *
130
+ * Safe to call before the chart has been measured: `nice()` and `ticks()` depend
131
+ * on the domain and the requested count, never on the scale's range, so the tick
132
+ * values here are the same ones the axis renders later.
133
+ */
134
+ function estimateValueAxisMargin(ticks, formatter) {
135
+ let widest = 0;
136
+ for (const tick of ticks) widest = Math.max(widest, formatter(tick).length * CAPTION_CHAR_WIDTH_PX);
137
+ const needed = Math.ceil(widest) + 12;
138
+ return clamp(Math.ceil(needed / 8) * 8, 32, 96);
139
+ }
140
+ /**
141
+ * How many categories to skip between rendered axis labels.
142
+ *
143
+ * Returns 1 when every label fits, so a chart that is not crowded renders
144
+ * exactly as it would with no skipping at all.
145
+ */
146
+ function getCategoryLabelStride(labels, step) {
147
+ if (labels.length === 0 || step <= 0) return 1;
148
+ let widest = 0;
149
+ for (const label of labels) widest = Math.max(widest, label.length * CAPTION_CHAR_WIDTH_PX);
150
+ const required = widest + 8;
151
+ return required <= step ? 1 : Math.ceil(required / step);
152
+ }
153
+ /**
154
+ * Tick values for a resolved domain, honoring an explicit tick count.
155
+ *
156
+ * Needs no dimensions, which is what breaks the apparent circularity in the
157
+ * layout: the left margin must fit the tick labels, the margin decides the plot
158
+ * size, and the plot size builds the scale. Tick *values* fall out of the domain
159
+ * alone, so they can be known before anything is measured.
160
+ */
161
+ function getValueTicks(domain, override) {
162
+ return scaleLinear().domain(domain).ticks(override?.tickCount ?? 5);
163
+ }
164
+ //#endregion
165
+ export { addAxisTitleSpace, buildCategoryPointScale, buildValueScale, clamp, estimateValueAxisMargin, getCategoryLabelStride, getPlotDimensions, getValueTicks, resolveMargin, resolveValueDomain, sanitizeValue };
@@ -0,0 +1,18 @@
1
+ import type { Theme } from "../theme/types";
2
+ import { ChartPalette } from "./types";
3
+ /**
4
+ * Palette resolution for the chart components.
5
+ *
6
+ * Consumer data names a {@link ChartPalette} slot; the concrete color is looked
7
+ * up here against the active theme. That keeps raw hex out of application data
8
+ * and guarantees both themes render correctly.
9
+ *
10
+ * Linaria evaluates this module at build time, so it must not import components.
11
+ */
12
+ /** Resolve a palette slot to a concrete color for the active theme. */
13
+ export declare function resolveChartPaletteColor(theme: Theme, palette: ChartPalette): string;
14
+ /**
15
+ * Resolve the color for a series, honoring an explicit slot and otherwise
16
+ * falling back to the series' position in the default palette order.
17
+ */
18
+ export declare function resolveSeriesColor(theme: Theme, index: number, palette?: ChartPalette): string;