@cdc/chart 4.26.6 → 4.26.10

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 (276) hide show
  1. package/CONFIG.md +504 -368
  2. package/dist/cdcchart-CYc-Kayd.es.js +22488 -0
  3. package/dist/cdcchart-DCKn8NmI.es.js +20695 -0
  4. package/dist/cdcchart-Dyui9nk_.es.js +45828 -0
  5. package/dist/cdcchart.js +4 -96498
  6. package/examples/__data__/vega-remote-data.json +6 -0
  7. package/examples/dendrogram.json +18 -0
  8. package/examples/feature/bar/bar-chart-race-annual-change.json +68 -0
  9. package/examples/feature/heatmap/average-age-categorical.json +2 -2
  10. package/examples/feature/heatmap/calendar-heatmap.json +2 -2
  11. package/examples/feature/heatmap/cell-values-bottom-axis.json +2 -2
  12. package/examples/feature/heatmap/sparse-aggregation.json +2 -2
  13. package/examples/feature/line/line-chart-race.json +50 -0
  14. package/examples/feature/sankey/sankey-example-data.json +40 -1441
  15. package/examples/feature/sankey/sankey_chart_data.csv +9 -20
  16. package/examples/network.json +31 -0
  17. package/examples/private/box-plot.json +573 -0
  18. package/examples/private/custom-color-issue.json +625 -0
  19. package/examples/private/custom-colors.json +522 -0
  20. package/examples/private/cutoff.json +10750 -0
  21. package/examples/private/flueview.json +22051 -0
  22. package/examples/private/overlay-legend.json +485 -0
  23. package/examples/private/pie-test.json +469 -0
  24. package/examples/vega-remote.json +22 -0
  25. package/package.json +11 -13
  26. package/src/CdcChart.tsx +2 -2
  27. package/src/CdcChartComponent.tsx +444 -217
  28. package/src/_stories/Chart.BarRace.stories.tsx +443 -0
  29. package/src/_stories/Chart.BoxPlotNumericSort.stories.tsx +189 -0
  30. package/src/_stories/Chart.BoxPlotStatsParity.stories.tsx +207 -0
  31. package/src/_stories/Chart.ColorDistribution.stories.tsx +299 -0
  32. package/src/_stories/Chart.DataCutoff.stories.tsx +147 -0
  33. package/src/_stories/Chart.DataTableDownloadFilename.stories.tsx +60 -0
  34. package/src/_stories/Chart.Dendrogram.stories.tsx +373 -0
  35. package/src/_stories/Chart.Forecast.CILegend.stories.tsx +236 -0
  36. package/src/_stories/Chart.HeatMap.stories.tsx +170 -4
  37. package/src/_stories/Chart.Legend.AxisAlign.stories.tsx +119 -0
  38. package/src/_stories/Chart.LineRace.stories.tsx +149 -0
  39. package/src/_stories/Chart.Network.stories.tsx +432 -0
  40. package/src/_stories/Chart.PaletteConversion.Editor.stories.tsx +208 -0
  41. package/src/_stories/Chart.Patterns.smoke.stories.tsx +31 -0
  42. package/src/_stories/Chart.PercentageValue.stories.tsx +311 -0
  43. package/src/_stories/Chart.PieLabels.stories.tsx +49 -0
  44. package/src/_stories/Chart.RankByValueMutation.stories.tsx +206 -0
  45. package/src/_stories/Chart.RequiredFields.stories.tsx +681 -0
  46. package/src/_stories/Chart.Sankey.stories.tsx +417 -0
  47. package/src/_stories/Chart.SeriesColorAssignments.stories.tsx +47 -0
  48. package/src/_stories/Chart.SmallMultiplesNumericTileOrder.stories.tsx +137 -0
  49. package/src/_stories/Chart.TooltipSeriesLabels.stories.tsx +43 -0
  50. package/src/_stories/Chart.VegaRemoteData.stories.tsx +31 -0
  51. package/src/_stories/Chart.smoke.stories.tsx +14 -1
  52. package/src/_stories/ChartAnnotation.Editor.stories.tsx +78 -0
  53. package/src/_stories/ChartAxisTitles.smoke.stories.tsx +48 -0
  54. package/src/_stories/ChartBar.Editor.stories.tsx +499 -57
  55. package/src/_stories/ChartBrush.Editor.stories.tsx +46 -67
  56. package/src/_stories/ChartBrush.Regression.stories.tsx +135 -0
  57. package/src/_stories/ChartEditor.Editor.stories.tsx +33 -3
  58. package/src/_stories/ChartLine.EffectCompatibility.stories.tsx +120 -0
  59. package/src/_stories/ChartPrefixSuffix.smoke.stories.tsx +28 -1
  60. package/src/_stories/_mock/annotation_event-line_mock.json +2 -2
  61. package/src/_stories/_mock/editor-test-configs.json +20 -10
  62. package/src/_stories/_mock/editor-test-datasets.json +38 -42
  63. package/src/_stories/_mock/heatmap-average-age-categorical.json +2 -2
  64. package/src/_stories/_mock/heatmap.json +2 -2
  65. package/src/_stories/_mock/legend-axis-align-stacked-bar.json +125 -0
  66. package/src/_stories/_mock/sankey_mock.json +23 -27
  67. package/src/components/Annotations/components/AnnotationDraggable.styles.css +52 -0
  68. package/src/components/Annotations/components/AnnotationDraggable.tsx +639 -139
  69. package/src/components/Annotations/components/AnnotationDropdown.styles.css +44 -4
  70. package/src/components/Annotations/components/AnnotationDropdown.tsx +10 -32
  71. package/src/components/Annotations/helpers/resolveAnnotationLayout.ts +212 -0
  72. package/src/components/Annotations/tests/AnnotationDraggable.test.tsx +612 -19
  73. package/src/components/Annotations/tests/AnnotationDropdown.test.tsx +50 -0
  74. package/src/components/Annotations/tests/resolveAnnotationLayout.test.ts +203 -0
  75. package/src/components/Axis/BottomAxis.tsx +1 -1
  76. package/src/components/Axis/Categorical.Axis.tsx +3 -3
  77. package/src/components/Axis/RightAxis.tsx +21 -13
  78. package/src/components/BarChart/components/BarChart.Horizontal.tsx +39 -8
  79. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +13 -4
  80. package/src/components/BarChart/components/BarChart.StackedVertical.test.ts +28 -0
  81. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +30 -26
  82. package/src/components/BarChart/components/BarChart.Vertical.tsx +38 -28
  83. package/src/components/BarChart/components/PortionPatternOverlay.tsx +61 -0
  84. package/src/components/BarChart/components/context.tsx +6 -0
  85. package/src/components/BarChart/helpers/getBarData.ts +28 -28
  86. package/src/components/BarChart/helpers/getBarHeights.ts +2 -2
  87. package/src/components/BarChart/helpers/getPatternUrl.ts +2 -5
  88. package/src/components/BarChart/helpers/index.ts +8 -0
  89. package/src/components/BarChart/helpers/portionPattern.ts +243 -0
  90. package/src/components/BarChart/helpers/tests/addMinimumBarHeights.test.ts +42 -0
  91. package/src/components/BarChart/helpers/tests/getPatternUrl.test.ts +13 -0
  92. package/src/components/BarChart/helpers/tests/portionPattern.test.ts +280 -0
  93. package/src/components/BarChart/helpers/tests/useBarChart.test.tsx +202 -0
  94. package/src/components/BarChart/helpers/useBarChart.ts +60 -60
  95. package/src/components/BarChartRace/BarChartRace.test.tsx +199 -0
  96. package/src/components/BarChartRace/BarChartRace.tsx +230 -0
  97. package/src/components/BarChartRace/BarChartRaceFallback.test.tsx +61 -0
  98. package/src/components/BarChartRace/BarChartRaceFallback.tsx +48 -0
  99. package/src/components/BarChartRace/bar-chart-race.css +160 -0
  100. package/src/components/BarChartRace/helpers.test.ts +114 -0
  101. package/src/components/BarChartRace/helpers.ts +185 -0
  102. package/src/components/BarChartRace/index.ts +3 -0
  103. package/src/components/BoxPlot/BoxPlot.Horizontal.tsx +7 -6
  104. package/src/components/BoxPlot/BoxPlot.Vertical.tsx +9 -7
  105. package/src/components/BoxPlot/helpers/index.ts +13 -83
  106. package/src/components/Brush/BrushSelector.tsx +10 -24
  107. package/src/components/Brush/MiniChartPreview.tsx +33 -1
  108. package/src/components/Dendrogram/components/Dendrogram.tsx +374 -0
  109. package/src/components/Dendrogram/dendrogram.css +113 -0
  110. package/src/components/Dendrogram/helpers/layoutDendrogram.test.ts +95 -0
  111. package/src/components/Dendrogram/helpers/layoutDendrogram.ts +56 -0
  112. package/src/components/Dendrogram/helpers/prepareDendrogramData.test.ts +135 -0
  113. package/src/components/Dendrogram/helpers/prepareDendrogramData.ts +166 -0
  114. package/src/components/Dendrogram/helpers/resolveDendrogramLabels.test.ts +196 -0
  115. package/src/components/Dendrogram/helpers/resolveDendrogramLabels.ts +418 -0
  116. package/src/components/Dendrogram/index.tsx +1 -0
  117. package/src/components/Dendrogram/types/index.ts +66 -0
  118. package/src/components/EditorPanel/EditorPanel.tsx +1111 -805
  119. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +50 -5
  120. package/src/components/EditorPanel/components/Panels/Panel.Dendrogram.css +10 -0
  121. package/src/components/EditorPanel/components/Panels/Panel.Dendrogram.tsx +211 -0
  122. package/src/components/EditorPanel/components/Panels/Panel.ForestPlotSettings.tsx +19 -8
  123. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +104 -61
  124. package/src/components/EditorPanel/components/Panels/Panel.Network.css +9 -0
  125. package/src/components/EditorPanel/components/Panels/Panel.Network.tsx +202 -0
  126. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +236 -36
  127. package/src/components/EditorPanel/components/Panels/Panel.Radar.tsx +6 -1
  128. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +89 -105
  129. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +21 -6
  130. package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +1 -1
  131. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +8 -66
  132. package/src/components/EditorPanel/components/Panels/RacingControls.test.tsx +131 -0
  133. package/src/components/EditorPanel/components/Panels/RacingControls.tsx +185 -0
  134. package/src/components/EditorPanel/components/Panels/SeriesColorAssignments.tsx +2 -2
  135. package/src/components/EditorPanel/components/Panels/index.tsx +4 -0
  136. package/src/components/EditorPanel/helpers/getVisualizationTypeConfigUpdate.ts +20 -7
  137. package/src/components/EditorPanel/helpers/tests/getVisualizationTypeConfigUpdate.test.ts +25 -2
  138. package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +5 -4
  139. package/src/components/EditorPanel/useEditorPermissions.test.tsx +94 -0
  140. package/src/components/EditorPanel/useEditorPermissions.ts +75 -25
  141. package/src/components/Forecasting/Forecasting.tsx +16 -7
  142. package/src/components/HeatMap/components/HeatMap.tsx +511 -178
  143. package/src/components/HeatMap/heatmap.constants.ts +7 -3
  144. package/src/components/HeatMap/heatmap.css +101 -2
  145. package/src/components/HeatMap/helpers/layout.ts +80 -0
  146. package/src/components/HeatMap/tests/HeatMap.test.tsx +339 -16
  147. package/src/components/HeatMap/tests/helpers.test.ts +79 -0
  148. package/src/components/Legend/Legend.Component.tsx +163 -148
  149. package/src/components/Legend/Legend.Suppression.tsx +3 -3
  150. package/src/components/Legend/LegendGroup/LegendGroup.styles.css +7 -0
  151. package/src/components/Legend/LegendGroup/LegendGroup.tsx +47 -35
  152. package/src/components/Legend/helpers/createFormatLabels.test.ts +226 -0
  153. package/src/components/Legend/helpers/createFormatLabels.tsx +45 -51
  154. package/src/components/LineChart/components/LineChart.Circle.tsx +3 -3
  155. package/src/components/LineChart/helpers.test.ts +126 -38
  156. package/src/components/LineChart/helpers.ts +9 -6
  157. package/src/components/LineChart/index.tsx +71 -27
  158. package/src/components/LineChart/tests/LineChart.test.tsx +630 -0
  159. package/src/components/LineChartRace/LineChartRace.test.tsx +275 -0
  160. package/src/components/LineChartRace/LineChartRace.tsx +134 -0
  161. package/src/components/LineChartRace/LineChartRaceFallback.tsx +28 -0
  162. package/src/components/LineChartRace/helpers.test.ts +88 -0
  163. package/src/components/LineChartRace/helpers.ts +157 -0
  164. package/src/components/LineChartRace/index.ts +3 -0
  165. package/src/components/LineChartRace/line-chart-race.css +16 -0
  166. package/src/components/LinearChart/ValueAxisAnchors.tsx +58 -0
  167. package/src/components/LinearChart/VisualizationRenderer.tsx +18 -23
  168. package/src/components/LinearChart/tests/LinearChart.test.tsx +412 -13
  169. package/src/components/LinearChart/tests/VisualizationRenderer.test.tsx +141 -0
  170. package/src/components/LinearChart/tests/mockConfigContext.ts +2 -1
  171. package/src/components/LinearChart.tsx +85 -54
  172. package/src/components/Network/components/Network.tsx +372 -0
  173. package/src/components/Network/helpers/layoutNetwork.test.ts +68 -0
  174. package/src/components/Network/helpers/layoutNetwork.ts +87 -0
  175. package/src/components/Network/helpers/prepareNetworkData.test.ts +116 -0
  176. package/src/components/Network/helpers/prepareNetworkData.ts +101 -0
  177. package/src/components/Network/helpers/resolveNetworkLabels.test.ts +112 -0
  178. package/src/components/Network/helpers/resolveNetworkLabels.ts +206 -0
  179. package/src/components/Network/index.tsx +3 -0
  180. package/src/components/Network/network.css +107 -0
  181. package/src/components/Network/types/index.ts +56 -0
  182. package/src/components/PairedBarChart.jsx +5 -10
  183. package/src/components/PairedBarChart.test.tsx +71 -0
  184. package/src/components/PieChart/PieChart.tsx +121 -13
  185. package/src/components/PieChart/helpers/labelPlacement.test.ts +88 -0
  186. package/src/components/PieChart/helpers/labelPlacement.ts +95 -0
  187. package/src/components/RacingChartRenderer.tsx +44 -0
  188. package/src/components/Regions/components/Regions.test.tsx +179 -0
  189. package/src/components/Regions/components/Regions.tsx +104 -69
  190. package/src/components/Regions/index.tsx +2 -3
  191. package/src/components/Sankey/components/Sankey.tsx +264 -437
  192. package/src/components/Sankey/helpers/getSankeyTooltip.ts +12 -0
  193. package/src/components/Sankey/helpers/prepareSankeyData.test.ts +71 -0
  194. package/src/components/Sankey/helpers/prepareSankeyData.ts +90 -0
  195. package/src/components/Sankey/sankey.scss +57 -116
  196. package/src/components/Sankey/types/index.ts +41 -4
  197. package/src/components/ScatterPlot/ScatterPlot.jsx +28 -12
  198. package/src/components/ScatterPlot/ScatterPlot.test.tsx +60 -0
  199. package/src/components/SmallMultiples/SmallMultiples.tsx +12 -12
  200. package/src/components/SmallMultiples/tests/SmallMultipleTile.test.tsx +7 -5
  201. package/src/components/raceTiming.ts +18 -0
  202. package/src/data/initial-state.js +79 -31
  203. package/src/helpers/applyChartTypeContract.ts +71 -0
  204. package/src/helpers/axisLabelFontSize.ts +2 -2
  205. package/src/helpers/boxPlotStats.ts +60 -0
  206. package/src/helpers/bumpChartTooltip.ts +2 -1
  207. package/src/helpers/calculateHorizontalBarCategoryLabelWidth.test.ts +37 -0
  208. package/src/helpers/calculateHorizontalBarCategoryLabelWidth.ts +3 -2
  209. package/src/helpers/calculateRightYAxisWidth.ts +60 -0
  210. package/src/helpers/categoryOrder.ts +60 -0
  211. package/src/helpers/colorAssignmentHelpers.ts +2 -2
  212. package/src/helpers/createNewChartConfig.ts +56 -0
  213. package/src/helpers/dataDrivenYAxisCategories.ts +18 -0
  214. package/src/helpers/forecastLegend.ts +88 -0
  215. package/src/helpers/getBoxPlotConfig.ts +26 -38
  216. package/src/helpers/getChartTypeDefaultPalette.ts +29 -0
  217. package/src/helpers/getColorCodeCategoryColorMap.ts +26 -0
  218. package/src/helpers/getColorScale.ts +31 -22
  219. package/src/helpers/getComboChartConfig.ts +0 -1
  220. package/src/helpers/getDynamicYAxisCategories.ts +69 -0
  221. package/src/helpers/getExcludedData.ts +0 -1
  222. package/src/helpers/getHasBoundarySuppression.ts +4 -3
  223. package/src/helpers/getMinMax.ts +11 -8
  224. package/src/helpers/getNewRuntime.ts +4 -3
  225. package/src/helpers/getPiePercent.ts +3 -3
  226. package/src/helpers/getStackedSeriesMax.ts +51 -0
  227. package/src/helpers/getV21ChartDistributionColors.ts +57 -0
  228. package/src/helpers/handleRankByValue.ts +15 -15
  229. package/src/helpers/isConvertLineToBarGraph.ts +2 -2
  230. package/src/helpers/seriesColumnSettings.ts +31 -3
  231. package/src/helpers/sizeHelpers.ts +4 -5
  232. package/src/helpers/smallMultiplesHelpers.ts +10 -13
  233. package/src/helpers/tests/applyChartTypeContract.test.ts +37 -0
  234. package/src/helpers/tests/boxPlotStats.test.ts +31 -0
  235. package/src/helpers/tests/bumpChartTooltip.test.ts +29 -0
  236. package/src/helpers/tests/calculateRightYAxisWidth.test.ts +105 -0
  237. package/src/helpers/tests/categoryOrder.test.ts +57 -0
  238. package/src/helpers/tests/countNumOfTicks.test.ts +11 -0
  239. package/src/helpers/tests/createNewChartConfig.test.ts +182 -0
  240. package/src/helpers/tests/getBoxPlotConfig.test.ts +70 -0
  241. package/src/helpers/tests/getColorCodeCategoryColorMap.test.ts +113 -0
  242. package/src/helpers/tests/getColorScale.test.ts +226 -1
  243. package/src/helpers/tests/getDynamicYAxisCategories.test.ts +61 -0
  244. package/src/helpers/tests/getMinMax.test.ts +41 -0
  245. package/src/helpers/tests/getStackedSeriesMax.test.ts +26 -0
  246. package/src/helpers/tests/handleRankByValue.test.ts +55 -37
  247. package/src/helpers/tests/seriesColumnSettings.test.ts +83 -0
  248. package/src/helpers/tests/smallMultiplesHelpers.test.ts +37 -1
  249. package/src/helpers/tests/tooltipHelpers.test.ts +80 -0
  250. package/src/helpers/tooltipHelpers.ts +16 -0
  251. package/src/hooks/tests/useRightAxis.test.tsx +143 -2
  252. package/src/hooks/tests/useScales.test.tsx +3 -6
  253. package/src/hooks/tests/useTooltip.test.tsx +484 -0
  254. package/src/hooks/usePrefersReducedMotion.ts +22 -0
  255. package/src/hooks/useReduceData.ts +4 -36
  256. package/src/hooks/useRightAxis.ts +19 -26
  257. package/src/hooks/useScales.ts +15 -0
  258. package/src/hooks/useTooltip.tsx +106 -71
  259. package/src/scss/main.scss +74 -2
  260. package/src/store/chart.reducer.ts +4 -4
  261. package/src/test/CdcChart.dataTable.test.tsx +582 -14
  262. package/src/test/CdcChart.dendrogram.test.tsx +277 -0
  263. package/src/test/CdcChart.finalization.test.tsx +143 -0
  264. package/src/test/CdcChart.network.test.tsx +271 -0
  265. package/src/types/ChartConfig.ts +91 -54
  266. package/src/types/ChartContext.ts +5 -0
  267. package/src/types/Horizon.ts +1 -1
  268. package/LICENSE +0 -201
  269. package/dist/cdcchart-BWVIUcAF.es.js +0 -4802
  270. package/src/_stories/Chart.Sankey.smoke.stories.tsx +0 -62
  271. package/src/components/Sankey/components/ColumnList.tsx +0 -19
  272. package/src/components/Sankey/helpers/getSankeyTooltip.tsx +0 -34
  273. package/src/components/Sankey/useSankeyAlert.tsx +0 -60
  274. package/src/data/legacy-defaults.ts +0 -18
  275. package/src/helpers/ensureSpecialChartAxisTypes.ts +0 -11
  276. package/src/helpers/tests/ensureSpecialChartAxisTypes.test.ts +0 -30
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  createDefaultSeriesColumnConfig,
3
3
  findColumnConfigByName,
4
+ getAdditionalColumnFormattingParams,
4
5
  getSeriesColumnConfig,
5
6
  getSeriesColumnFormattingParams,
6
7
  getSeriesOwnedColumnNames,
@@ -53,6 +54,23 @@ describe('seriesColumnSettings', () => {
53
54
  })
54
55
  })
55
56
 
57
+ it('removes fields when an update value is undefined', () => {
58
+ const updatedColumns = upsertSeriesColumnConfig(
59
+ {
60
+ cases: { name: 'cases', label: 'Cases', roundToPlace: 2 }
61
+ },
62
+ 'cases',
63
+ { roundToPlace: undefined }
64
+ )
65
+
66
+ expect(updatedColumns).toEqual({
67
+ cases: {
68
+ name: 'cases',
69
+ label: 'Cases'
70
+ }
71
+ })
72
+ })
73
+
56
74
  it('does not persist display defaults when creating a new series-owned column config', () => {
57
75
  expect(upsertSeriesColumnConfig({}, 'cases', { label: 'Cases' })).toEqual({
58
76
  cases: {
@@ -62,6 +80,15 @@ describe('seriesColumnSettings', () => {
62
80
  })
63
81
  })
64
82
 
83
+ it('does not create a rounding override when updating unrelated display settings', () => {
84
+ expect(upsertSeriesColumnConfig({}, 'cases', { dataTable: false })).toEqual({
85
+ cases: {
86
+ name: 'cases',
87
+ dataTable: false
88
+ }
89
+ })
90
+ })
91
+
65
92
  it('only returns explicit formatting overrides and preserves falsey values', () => {
66
93
  expect(
67
94
  getSeriesColumnFormattingParams({
@@ -92,7 +119,63 @@ describe('seriesColumnSettings', () => {
92
119
  })
93
120
  })
94
121
 
122
+ it('ignores blank rounding overrides so global formatting can apply', () => {
123
+ expect(
124
+ getSeriesColumnFormattingParams({
125
+ roundToPlace: '',
126
+ commas: false
127
+ })
128
+ ).toEqual({
129
+ addColCommas: false
130
+ })
131
+ })
132
+
133
+ it('normalizes string rounding overrides to numbers', () => {
134
+ expect(
135
+ getSeriesColumnFormattingParams({
136
+ roundToPlace: '0',
137
+ commas: false
138
+ })
139
+ ).toEqual({
140
+ addColRoundTo: 0,
141
+ addColCommas: false
142
+ })
143
+ })
144
+
145
+ it('ignores invalid rounding overrides so global formatting can apply', () => {
146
+ expect(
147
+ getSeriesColumnFormattingParams({
148
+ roundToPlace: 'abc',
149
+ commas: false
150
+ })
151
+ ).toEqual({
152
+ addColCommas: false
153
+ })
154
+ })
155
+
95
156
  it('returns undefined when no formatting overrides were explicitly configured', () => {
96
157
  expect(getSeriesColumnFormattingParams({ label: 'Cases' })).toBeUndefined()
97
158
  })
159
+
160
+ it('blocks global prefix and suffix fallback for additional columns', () => {
161
+ expect(getAdditionalColumnFormattingParams({ label: 'Count' })).toEqual({
162
+ addColPrefix: '',
163
+ addColSuffix: ''
164
+ })
165
+ })
166
+
167
+ it('preserves explicit additional column formatting while blocking missing affixes', () => {
168
+ expect(
169
+ getAdditionalColumnFormattingParams({
170
+ prefix: '$',
171
+ roundToPlace: 0,
172
+ commas: false
173
+ })
174
+ ).toEqual({
175
+ addColPrefix: '$',
176
+ addColSuffix: '',
177
+ addColRoundTo: 0,
178
+ addColCommas: false
179
+ })
180
+ })
98
181
  })
@@ -1,6 +1,6 @@
1
1
  import { scaleOrdinal } from '@visx/scale'
2
2
  import { describe, expect, it } from 'vitest'
3
- import { createTileColorScale } from '../smallMultiplesHelpers'
3
+ import { applyTileOrder, createTileColorScale, getTileKeys } from '../smallMultiplesHelpers'
4
4
  import { ChartConfig } from '../../types/ChartConfig'
5
5
 
6
6
  const buildConfig = (overrides: Partial<ChartConfig> = {}): ChartConfig =>
@@ -97,3 +97,39 @@ describe('smallMultiplesHelpers createTileColorScale', () => {
97
97
  expect(tileScale('Series B')).toBe('#aa0000')
98
98
  })
99
99
  })
100
+
101
+ describe('smallMultiplesHelpers tile ordering', () => {
102
+ it('sorts by-column tile keys in numeric-aware order', () => {
103
+ const config = buildConfig({
104
+ smallMultiples: {
105
+ mode: 'by-column',
106
+ tileColumn: 'Week'
107
+ }
108
+ })
109
+ const data = [{ Week: '10' }, { Week: '2' }, { Week: '1' }, { Week: '20' }, { Week: '3' }, { Week: null }]
110
+
111
+ expect(getTileKeys(config, data)).toEqual(['1', '2', '3', '10', '20'])
112
+ })
113
+
114
+ it('uses numeric-aware order when sorting tile display titles', () => {
115
+ const config = buildConfig({
116
+ smallMultiples: {
117
+ mode: 'by-column',
118
+ tileColumn: 'Week',
119
+ tileTitles: {
120
+ '1': 'Week 1',
121
+ '2': 'Week 2',
122
+ '10': 'Week 10'
123
+ }
124
+ }
125
+ })
126
+ const tileItems = [
127
+ { mode: 'by-column', tileValue: '10', key: '10' },
128
+ { mode: 'by-column', tileValue: '2', key: '2' },
129
+ { mode: 'by-column', tileValue: '1', key: '1' }
130
+ ]
131
+
132
+ expect(applyTileOrder(tileItems, 'asc', [], config).map(item => item.tileValue)).toEqual(['1', '2', '10'])
133
+ expect(applyTileOrder(tileItems, 'desc', [], config).map(item => item.tileValue)).toEqual(['10', '2', '1'])
134
+ })
135
+ })
@@ -4,6 +4,7 @@ import {
4
4
  getTooltipMarkerColor,
5
5
  getTooltipMarkerShape,
6
6
  shouldUseTooltipLegendMarkers,
7
+ shouldShowTooltipSeriesRow,
7
8
  tooltipHasMarkerColumn,
8
9
  tooltipShouldUseMarkerColumn,
9
10
  type TooltipRow
@@ -148,4 +149,83 @@ describe('tooltipHelpers', () => {
148
149
  expect(ambiguousMarkers).not.toContain('tooltip-body--marker-layout')
149
150
  expect(ambiguousMarkers).not.toContain('tooltip-marker-slot')
150
151
  })
152
+
153
+ it('shows normal tooltip series rows by default when isolate has no legend selection', () => {
154
+ expect(
155
+ shouldShowTooltipSeriesRow({
156
+ legendBehavior: 'isolate',
157
+ seriesHighlight: [],
158
+ seriesKey: 'cases'
159
+ })
160
+ ).toBe(true)
161
+ expect(
162
+ shouldShowTooltipSeriesRow({
163
+ seriesKey: 'deaths'
164
+ })
165
+ ).toBe(true)
166
+ })
167
+
168
+ it('limits normal tooltip series rows to one isolated legend selection', () => {
169
+ expect(
170
+ shouldShowTooltipSeriesRow({
171
+ legendBehavior: 'isolate',
172
+ seriesHighlight: ['cases'],
173
+ seriesKey: 'cases'
174
+ })
175
+ ).toBe(true)
176
+ expect(
177
+ shouldShowTooltipSeriesRow({
178
+ legendBehavior: 'isolate',
179
+ seriesHighlight: ['cases'],
180
+ seriesKey: 'deaths'
181
+ })
182
+ ).toBe(false)
183
+ })
184
+
185
+ it('limits normal tooltip series rows to multiple isolated legend selections', () => {
186
+ expect(
187
+ shouldShowTooltipSeriesRow({
188
+ legendBehavior: 'isolate',
189
+ seriesHighlight: ['cases', 'hospitalizations'],
190
+ seriesKey: 'hospitalizations'
191
+ })
192
+ ).toBe(true)
193
+ expect(
194
+ shouldShowTooltipSeriesRow({
195
+ legendBehavior: 'isolate',
196
+ seriesHighlight: ['cases', 'hospitalizations'],
197
+ seriesKey: 'deaths'
198
+ })
199
+ ).toBe(false)
200
+ })
201
+
202
+ it('keeps all normal tooltip series rows visible in highlight mode with selected series', () => {
203
+ expect(
204
+ shouldShowTooltipSeriesRow({
205
+ legendBehavior: 'highlight',
206
+ seriesHighlight: ['cases'],
207
+ seriesKey: 'deaths'
208
+ })
209
+ ).toBe(true)
210
+ })
211
+
212
+ it('can filter normal tooltip rows while preserving headings and additional columns', () => {
213
+ const rows: TooltipRow[] = [
214
+ { key: 'Date', value: '2024-01-01', kind: 'heading' },
215
+ { key: 'Cases', value: '10', kind: 'series', seriesKey: 'cases' },
216
+ { key: 'Deaths', value: '2', kind: 'series', seriesKey: 'deaths' },
217
+ { key: 'Source', value: 'CDC', kind: 'extra' }
218
+ ]
219
+ const filteredRows = rows.filter(
220
+ row =>
221
+ row.kind !== 'series' ||
222
+ shouldShowTooltipSeriesRow({
223
+ legendBehavior: 'isolate',
224
+ seriesHighlight: ['cases'],
225
+ seriesKey: row.seriesKey
226
+ })
227
+ )
228
+
229
+ expect(filteredRows.map(row => row.key)).toEqual(['Date', 'Cases', 'Source'])
230
+ })
151
231
  })
@@ -84,6 +84,22 @@ export const getTooltipSeriesMarker = (
84
84
 
85
85
  export const buildTooltipRow = (row: TooltipRow): TooltipRow => row
86
86
 
87
+ export const shouldShowTooltipSeriesRow = ({
88
+ legendBehavior,
89
+ seriesHighlight = [],
90
+ seriesKey
91
+ }: {
92
+ legendBehavior?: string
93
+ seriesHighlight?: string[]
94
+ seriesKey?: string
95
+ }): boolean => {
96
+ if (legendBehavior === 'isolate' && seriesHighlight.length > 0 && seriesKey) {
97
+ return seriesHighlight.includes(seriesKey)
98
+ }
99
+
100
+ return true
101
+ }
102
+
87
103
  const getMarkerSignature = ({
88
104
  markerColor,
89
105
  markerShape = 'circle'
@@ -27,6 +27,29 @@ const createComboConfig = () =>
27
27
  })
28
28
 
29
29
  describe('useRightAxis', () => {
30
+ it('does not render a right axis for vertical Combo charts with only left-axis series', () => {
31
+ const config = createMockConfig({
32
+ visualizationType: 'Combo',
33
+ orientation: 'vertical',
34
+ series: [leftSeries],
35
+ yAxis: {
36
+ ...createMockConfig().yAxis,
37
+ rightHideAxis: true
38
+ },
39
+ runtime: {
40
+ ...createMockConfig().runtime,
41
+ series: [leftSeries],
42
+ seriesKeys: ['Cases'],
43
+ barSeriesKeys: ['Cases'],
44
+ lineSeriesKeys: []
45
+ } as any
46
+ })
47
+
48
+ const result = renderHook(() => useRightAxis({ config, yMax: 100, data: [{ Cases: 5 }] }))
49
+
50
+ expect(result.result.current.hasRightAxis).toBe(false)
51
+ })
52
+
30
53
  it('builds the right-axis scale from the supplied domain rows', () => {
31
54
  const config = createComboConfig()
32
55
  const renderedRows = [{ Cases: 5, Rate: 12 }]
@@ -57,7 +80,22 @@ describe('useRightAxis', () => {
57
80
  expect(result.result.current.rightTickValues).toBeUndefined()
58
81
  })
59
82
 
60
- it('does not finalize right-axis ticks from the inherited mixed Combo min', () => {
83
+ it('auto-starts positive right-axis data at zero without depending on series-type runtime keys', () => {
84
+ const config = {
85
+ ...createComboConfig(),
86
+ runtime: {
87
+ ...createComboConfig().runtime,
88
+ barSeriesKeys: [],
89
+ lineSeriesKeys: []
90
+ }
91
+ }
92
+
93
+ const result = renderHook(() => useRightAxis({ config, yMax: 100, data: [{ Cases: 5, Rate: 25 }] }))
94
+
95
+ expect(result.result.current.yScaleRight.domain()).toEqual([0, 25])
96
+ })
97
+
98
+ it('does not let left-axis negative data affect the right-axis minimum', () => {
61
99
  const config = {
62
100
  ...createComboConfig(),
63
101
  yAxis: {
@@ -68,10 +106,113 @@ describe('useRightAxis', () => {
68
106
 
69
107
  const result = renderHook(() => useRightAxis({ config, yMax: 100, data: [{ Cases: -100, Rate: 6 }] }))
70
108
 
71
- expect(result.result.current.yScaleRight.domain()).toEqual([-100, 6])
109
+ expect(result.result.current.yScaleRight.domain()).toEqual([0, 6])
72
110
  expect(result.result.current.rightTickValues).toBeUndefined()
73
111
  })
74
112
 
113
+ it('honors a positive rightMin below the right-axis data minimum', () => {
114
+ const config = {
115
+ ...createComboConfig(),
116
+ yAxis: {
117
+ ...createComboConfig().yAxis,
118
+ rightMin: '90',
119
+ rightMax: '100'
120
+ }
121
+ }
122
+
123
+ const result = renderHook(() => useRightAxis({ config, yMax: 100, data: [{ Cases: 5, Rate: 95 }] }))
124
+
125
+ expect(result.result.current.yScaleRight.domain()).toEqual([90, 100])
126
+ })
127
+
128
+ it('uses formatted numeric strings when calculating the right-axis domain', () => {
129
+ const config = createComboConfig()
130
+
131
+ const result = renderHook(() =>
132
+ useRightAxis({
133
+ config,
134
+ yMax: 100,
135
+ data: [
136
+ { Cases: 5, Rate: '$1,000' },
137
+ { Cases: 6, Rate: '2,500' }
138
+ ]
139
+ })
140
+ )
141
+
142
+ expect(result.result.current.yScaleRight.domain()).toEqual([0, 2500])
143
+ })
144
+
145
+ it('ignores a rightMin above the right-axis data minimum and defaults positive domains to zero', () => {
146
+ const config = {
147
+ ...createComboConfig(),
148
+ yAxis: {
149
+ ...createComboConfig().yAxis,
150
+ rightMin: '98'
151
+ }
152
+ }
153
+
154
+ const result = renderHook(() => useRightAxis({ config, yMax: 100, data: [{ Cases: 5, Rate: 95 }] }))
155
+
156
+ expect(result.result.current.yScaleRight.domain()).toEqual([0, 95])
157
+ })
158
+
159
+ it('uses a negative minimum when right-axis data is negative', () => {
160
+ const config = createComboConfig()
161
+
162
+ const result = renderHook(() =>
163
+ useRightAxis({
164
+ config,
165
+ yMax: 100,
166
+ data: [
167
+ { Cases: 5, Rate: -12 },
168
+ { Cases: 6, Rate: -3 }
169
+ ]
170
+ })
171
+ )
172
+
173
+ expect(result.result.current.yScaleRight.domain()).toEqual([-12, -3])
174
+ })
175
+
176
+ it('ignores values that are empty after right-axis numeric cleanup', () => {
177
+ const config = createComboConfig()
178
+
179
+ const result = renderHook(() =>
180
+ useRightAxis({
181
+ config,
182
+ yMax: 100,
183
+ data: [
184
+ { Cases: 5, Rate: '$' },
185
+ { Cases: 6, Rate: '-12' }
186
+ ]
187
+ })
188
+ )
189
+
190
+ expect(result.result.current.yScaleRight.domain()).toEqual([-12, -12])
191
+ })
192
+
193
+ it('honors a negative rightMin below the right-axis data minimum', () => {
194
+ const config = {
195
+ ...createComboConfig(),
196
+ yAxis: {
197
+ ...createComboConfig().yAxis,
198
+ rightMin: '-20'
199
+ }
200
+ }
201
+
202
+ const result = renderHook(() =>
203
+ useRightAxis({
204
+ config,
205
+ yMax: 100,
206
+ data: [
207
+ { Cases: 5, Rate: -12 },
208
+ { Cases: 6, Rate: -3 }
209
+ ]
210
+ })
211
+ )
212
+
213
+ expect(result.result.current.yScaleRight.domain()).toEqual([-20, -3])
214
+ })
215
+
75
216
  it('does not round the right-axis max when rightMax is explicit', () => {
76
217
  const config = {
77
218
  ...createComboConfig(),
@@ -106,12 +106,9 @@ describe('useScales', () => {
106
106
  }
107
107
  })
108
108
 
109
- renderHook(
110
- () => useScales({ ...baseProps, config: configWithManualPadding, hasSpacedInlineLabel: true }),
111
- {
112
- wrapper: createWrapper()
113
- }
114
- )
109
+ renderHook(() => useScales({ ...baseProps, config: configWithManualPadding, hasSpacedInlineLabel: true }), {
110
+ wrapper: createWrapper()
111
+ })
115
112
 
116
113
  expect(mockGetMinMax.mock.calls[0][0].config.yAxis).toMatchObject({
117
114
  enablePadding: false,