@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
@@ -0,0 +1,484 @@
1
+ import React from 'react'
2
+ import { act, render, renderHook, screen } from '@testing-library/react'
3
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
4
+ import ConfigContext from '../../ConfigContext'
5
+ import { createMockChartContext, createMockConfig } from '../../components/LinearChart/tests/mockConfigContext'
6
+ import { type TooltipRow } from '../../helpers/tooltipHelpers'
7
+ import { type ChartConfig } from '../../types/ChartConfig'
8
+ import { type ChartContext } from '../../types/ChartContext'
9
+ import { useTooltip } from '../useTooltip'
10
+
11
+ vi.mock('@visx/event', () => ({
12
+ localPoint: () => ({ x: 5, y: 5 })
13
+ }))
14
+
15
+ describe('useTooltip', () => {
16
+ const showTooltip = vi.fn()
17
+ const hideTooltip = vi.fn()
18
+ const row = {
19
+ 'Cause of death': 'Hypertensive disorders of pregnancy',
20
+ Percentage: 22,
21
+ Count: 146
22
+ }
23
+
24
+ const baseConfig = createMockConfig()
25
+ const config = createMockConfig({
26
+ visualizationType: 'Bar',
27
+ orientation: 'vertical',
28
+ xAxis: {
29
+ ...baseConfig.xAxis,
30
+ type: 'categorical',
31
+ dataKey: 'Cause of death'
32
+ },
33
+ yAxis: {
34
+ ...baseConfig.yAxis,
35
+ inlineLabel: ''
36
+ },
37
+ general: {
38
+ showMissingDataLabel: true,
39
+ hideNullValue: true
40
+ } as any,
41
+ series: [{ dataKey: 'Percentage', type: 'Bar', axis: 'Left', tooltip: true }] as any,
42
+ columns: {
43
+ Count: {
44
+ name: 'Count',
45
+ label: 'Count',
46
+ prefix: '',
47
+ suffix: '',
48
+ roundToPlace: 0,
49
+ commas: true,
50
+ dataTable: true,
51
+ tooltips: true
52
+ }
53
+ } as any,
54
+ dataFormat: {
55
+ abbreviated: false,
56
+ bottomAbbreviated: false,
57
+ bottomPrefix: '',
58
+ bottomRoundTo: 0,
59
+ bottomSuffix: '',
60
+ bottomCommas: false,
61
+ commas: false,
62
+ prefix: '',
63
+ preserveOriginalDecimals: false,
64
+ rightPrefix: '',
65
+ rightRoundTo: 0,
66
+ rightSuffix: '',
67
+ roundTo: 1,
68
+ suffix: '%'
69
+ } as any,
70
+ runtime: {
71
+ ...baseConfig.runtime,
72
+ xAxis: {
73
+ ...baseConfig.runtime.xAxis,
74
+ type: 'categorical',
75
+ dataKey: 'Cause of death'
76
+ },
77
+ yAxis: {
78
+ ...baseConfig.runtime.yAxis,
79
+ dataKey: 'Percentage'
80
+ },
81
+ series: [{ dataKey: 'Percentage', type: 'Bar', axis: 'Left', tooltip: true }],
82
+ seriesKeys: ['Percentage'],
83
+ seriesLabelsAll: ['Percentage']
84
+ } as any
85
+ })
86
+
87
+ const xScale = Object.assign(
88
+ vi.fn(() => 0),
89
+ {
90
+ domain: () => ['Hypertensive disorders of pregnancy'],
91
+ bandwidth: () => 10
92
+ }
93
+ )
94
+ const yScale = Object.assign(
95
+ vi.fn(() => 0),
96
+ {
97
+ domain: () => ['Hypertensive disorders of pregnancy']
98
+ }
99
+ )
100
+
101
+ const wrapper = ({ children }: React.PropsWithChildren) => (
102
+ <ConfigContext.Provider value={createMockChartContext(config, { tableData: [row] })}>
103
+ {children}
104
+ </ConfigContext.Provider>
105
+ )
106
+
107
+ beforeEach(() => {
108
+ showTooltip.mockClear()
109
+ hideTooltip.mockClear()
110
+ })
111
+
112
+ const renderTooltipListItem = (
113
+ tooltipConfig: ChartConfig,
114
+ tooltipRow: TooltipRow,
115
+ {
116
+ index = 1,
117
+ useMarkerColumn = false,
118
+ contextOverrides = {}
119
+ }: { index?: number; useMarkerColumn?: boolean; contextOverrides?: Partial<ChartContext> } = {}
120
+ ) => {
121
+ const tooltipWrapper = ({ children }: React.PropsWithChildren) => (
122
+ <ConfigContext.Provider value={createMockChartContext(tooltipConfig, { tableData: [row], ...contextOverrides })}>
123
+ {children}
124
+ </ConfigContext.Provider>
125
+ )
126
+ const { result } = renderHook(
127
+ () =>
128
+ useTooltip({
129
+ xScale,
130
+ yScale,
131
+ showTooltip,
132
+ hideTooltip,
133
+ yAxisWidth: 0
134
+ }),
135
+ { wrapper: tooltipWrapper }
136
+ )
137
+ const TooltipListItem = result.current.TooltipListItem
138
+
139
+ return render(<TooltipListItem row={tooltipRow} index={index} useMarkerColumn={useMarkerColumn} />)
140
+ }
141
+
142
+ it('does not apply the left-axis suffix to an additional tooltip column', () => {
143
+ const { result } = renderHook(
144
+ () =>
145
+ useTooltip({
146
+ xScale,
147
+ yScale,
148
+ showTooltip,
149
+ hideTooltip,
150
+ yAxisWidth: 0
151
+ }),
152
+ { wrapper }
153
+ )
154
+
155
+ act(() => result.current.handleTooltipMouseOver({}))
156
+
157
+ expect(showTooltip).toHaveBeenCalledOnce()
158
+ expect(showTooltip.mock.calls[0][0].tooltipData.data).toEqual(
159
+ expect.arrayContaining([
160
+ expect.objectContaining({ key: 'Percentage', value: '22.0%', kind: 'series' }),
161
+ expect.objectContaining({ key: 'Count', value: '146', kind: 'extra' })
162
+ ])
163
+ )
164
+ })
165
+
166
+ it.each([
167
+ {
168
+ caseName: 'customized Column Label over an authored Series Name',
169
+ visualizationType: 'Bar',
170
+ seriesName: 'Rate Series',
171
+ columnLabel: 'Rate Column',
172
+ expected: 'Rate Column: 22.0%'
173
+ },
174
+ {
175
+ caseName: 'inferred Series Name when the Column Label matches the data key',
176
+ visualizationType: 'Bar',
177
+ seriesName: undefined,
178
+ columnLabel: 'Percentage',
179
+ expected: 'Percentage: 22.0%'
180
+ },
181
+ {
182
+ caseName: 'authored Series Name when the Column Label matches the data key',
183
+ visualizationType: 'Bar',
184
+ seriesName: 'Rate Series',
185
+ columnLabel: 'Percentage',
186
+ expected: 'Rate Series: 22.0%'
187
+ },
188
+ {
189
+ caseName: 'authored Series Name when the Column Label is cleared',
190
+ visualizationType: 'Bar',
191
+ seriesName: 'Rate Series',
192
+ columnLabel: '',
193
+ expected: 'Rate Series: 22.0%'
194
+ },
195
+ {
196
+ caseName: 'customized Column Label for a Forest Plot',
197
+ visualizationType: 'Forest Plot',
198
+ seriesName: 'Rate Series',
199
+ columnLabel: 'Rate Column',
200
+ expected: 'Rate Column: 22.0%'
201
+ }
202
+ ])('uses the $caseName', ({ visualizationType, seriesName, columnLabel, expected }) => {
203
+ const series = {
204
+ dataKey: 'Percentage',
205
+ ...(seriesName ? { name: seriesName } : {}),
206
+ type: 'Bar',
207
+ axis: 'Left',
208
+ tooltip: true
209
+ }
210
+ const tooltipConfig = createMockConfig({
211
+ ...config,
212
+ visualizationType: visualizationType as any,
213
+ series: [series] as any,
214
+ columns: {
215
+ ...config.columns,
216
+ Percentage: { name: 'Percentage', label: columnLabel }
217
+ } as any,
218
+ runtime: {
219
+ ...config.runtime,
220
+ series: [series],
221
+ seriesLabels: { Percentage: seriesName || 'Percentage' }
222
+ } as any
223
+ })
224
+ const tooltipWrapper = ({ children }: React.PropsWithChildren) => (
225
+ <ConfigContext.Provider value={createMockChartContext(tooltipConfig, { tableData: [row] })}>
226
+ {children}
227
+ </ConfigContext.Provider>
228
+ )
229
+ const { result } = renderHook(
230
+ () =>
231
+ useTooltip({
232
+ xScale,
233
+ yScale,
234
+ showTooltip,
235
+ hideTooltip,
236
+ yAxisWidth: 0
237
+ }),
238
+ { wrapper: tooltipWrapper }
239
+ )
240
+ const TooltipListItem = result.current.TooltipListItem
241
+
242
+ render(<TooltipListItem row={{ key: 'Percentage', value: '22.0%', kind: 'series' }} index={1} />)
243
+
244
+ expect(screen.getByText(expected)).toBeTruthy()
245
+ })
246
+
247
+ it.each([
248
+ { caseName: 'standard chart', visualizationType: 'Bar' },
249
+ { caseName: 'Forest Plot', visualizationType: 'Forest Plot' }
250
+ ])('preserves an additional column label that matches a series key for a $caseName', ({ visualizationType }) => {
251
+ const series = {
252
+ dataKey: 'Percentage',
253
+ name: 'Rate Series',
254
+ type: 'Bar',
255
+ axis: 'Left',
256
+ tooltip: true
257
+ }
258
+ const tooltipConfig = createMockConfig({
259
+ ...config,
260
+ visualizationType: visualizationType as any,
261
+ series: [series] as any,
262
+ runtime: {
263
+ ...config.runtime,
264
+ series: [series],
265
+ seriesLabels: { Percentage: 'Rate Series' }
266
+ } as any
267
+ })
268
+ const tooltipWrapper = ({ children }: React.PropsWithChildren) => (
269
+ <ConfigContext.Provider value={createMockChartContext(tooltipConfig, { tableData: [row] })}>
270
+ {children}
271
+ </ConfigContext.Provider>
272
+ )
273
+ const { result } = renderHook(
274
+ () =>
275
+ useTooltip({
276
+ xScale,
277
+ yScale,
278
+ showTooltip,
279
+ hideTooltip,
280
+ yAxisWidth: 0
281
+ }),
282
+ { wrapper: tooltipWrapper }
283
+ )
284
+ const TooltipListItem = result.current.TooltipListItem
285
+
286
+ render(<TooltipListItem row={{ key: 'Percentage', value: '146', kind: 'extra' }} index={2} />)
287
+
288
+ expect(screen.getByText('Percentage: 146')).toBeTruthy()
289
+ expect(screen.queryByText('Rate Series: 146')).toBeNull()
290
+ })
291
+
292
+ it('preserves standard x-axis heading rendering', () => {
293
+ renderTooltipListItem(config, {
294
+ key: 'Cause of death',
295
+ value: 'Hypertensive disorders of pregnancy',
296
+ kind: 'heading'
297
+ })
298
+
299
+ expect(screen.getByText(/Hypertensive disorders of pregnancy/)).toHaveClass('tooltip-heading')
300
+ })
301
+
302
+ it('preserves horizontal Bar heading rendering', () => {
303
+ const horizontalBarConfig = createMockConfig({
304
+ ...config,
305
+ orientation: 'horizontal',
306
+ runtime: {
307
+ ...config.runtime,
308
+ yAxis: { ...config.runtime.yAxis, label: 'Cause' }
309
+ } as any
310
+ })
311
+
312
+ renderTooltipListItem(horizontalBarConfig, {
313
+ key: 'Cause of death',
314
+ value: 'Hypertensive disorders of pregnancy',
315
+ kind: 'heading'
316
+ })
317
+
318
+ expect(screen.getByText(/Cause:.*Hypertensive disorders of pregnancy/)).toHaveClass('tooltip-heading')
319
+ })
320
+
321
+ it('preserves Pie calculated-area heading rendering', () => {
322
+ const pieConfig = createMockConfig({
323
+ ...config,
324
+ visualizationType: 'Pie',
325
+ dataFormat: { ...config.dataFormat, showPiePercent: true } as any
326
+ })
327
+
328
+ renderTooltipListItem(pieConfig, {
329
+ key: 'Percentage',
330
+ value: 'Calculated Area',
331
+ kind: 'heading'
332
+ })
333
+
334
+ expect(screen.getByText(/Calculated Area/)).toHaveClass('tooltip-heading')
335
+ })
336
+
337
+ it('preserves Forest Plot heading rendering', () => {
338
+ const forestPlotConfig = createMockConfig({
339
+ ...config,
340
+ visualizationType: 'Forest Plot'
341
+ })
342
+
343
+ renderTooltipListItem(forestPlotConfig, {
344
+ key: 'Cause of death',
345
+ value: 'Hypertensive disorders of pregnancy',
346
+ kind: 'heading'
347
+ })
348
+
349
+ expect(screen.getByText(/Cause of death:.*Hypertensive disorders of pregnancy/)).toHaveClass('tooltip-heading')
350
+ })
351
+
352
+ it.each([
353
+ { caseName: 'standard', orientation: 'vertical' as const },
354
+ { caseName: 'horizontal Bar', orientation: 'horizontal' as const }
355
+ ])('preserves custom date formatting for a $caseName heading', ({ orientation }) => {
356
+ const dateConfig = createMockConfig({
357
+ ...config,
358
+ orientation,
359
+ xAxis: { ...config.xAxis, type: 'date', dataKey: 'Date' },
360
+ tooltips: { ...config.tooltips, dateDisplayFormat: '%Y' },
361
+ runtime: {
362
+ ...config.runtime,
363
+ xAxis: { ...config.runtime.xAxis, type: 'date', dataKey: 'Date', label: 'Date' },
364
+ yAxis: { ...config.runtime.yAxis, label: 'Date' }
365
+ } as any
366
+ })
367
+
368
+ renderTooltipListItem(
369
+ dateConfig,
370
+ { key: 'Date', value: '2025-01-02', kind: 'heading' },
371
+ {
372
+ contextOverrides: {
373
+ parseDate: value => `parsed-${value}`,
374
+ formatDate: value => `date-${value}`,
375
+ formatTooltipsDate: value => `tooltip-${value}`
376
+ }
377
+ }
378
+ )
379
+
380
+ expect(screen.getByText('Date: tooltip-parsed-2025-01-02')).toHaveClass('tooltip-heading')
381
+ })
382
+
383
+ it('hides a matching suppression row when suppressed symbols are disabled', () => {
384
+ const suppressionConfig = createMockConfig({
385
+ ...config,
386
+ general: { ...config.general, showSuppressedSymbol: false } as any,
387
+ preliminaryData: [
388
+ {
389
+ label: 'Suppressed',
390
+ type: 'suppression',
391
+ displayTooltip: true,
392
+ value: '22.0%',
393
+ column: 'Percentage'
394
+ }
395
+ ] as any
396
+ })
397
+
398
+ const { container } = renderTooltipListItem(suppressionConfig, {
399
+ key: 'Percentage',
400
+ value: '22.0%',
401
+ kind: 'series'
402
+ })
403
+
404
+ expect(container.querySelector('li')).toBeNull()
405
+ })
406
+
407
+ it('preserves suppression replacement text and gray styling when symbols are shown', () => {
408
+ const suppressionConfig = createMockConfig({
409
+ ...config,
410
+ general: { ...config.general, showSuppressedSymbol: true } as any,
411
+ preliminaryData: [
412
+ {
413
+ label: 'Suppressed',
414
+ type: 'suppression',
415
+ displayTooltip: true,
416
+ value: '22.0%',
417
+ column: 'Percentage',
418
+ displayGray: true
419
+ }
420
+ ] as any
421
+ })
422
+
423
+ renderTooltipListItem(suppressionConfig, {
424
+ key: 'Percentage',
425
+ value: '22.0%',
426
+ kind: 'series'
427
+ })
428
+
429
+ expect(screen.getByText('Percentage: Suppressed')).toHaveStyle({ color: '#8b8b8a' })
430
+ })
431
+
432
+ it('leaves an unmatched suppression row unchanged', () => {
433
+ const suppressionConfig = createMockConfig({
434
+ ...config,
435
+ general: { ...config.general, showSuppressedSymbol: false } as any,
436
+ preliminaryData: [
437
+ {
438
+ label: 'Suppressed',
439
+ type: 'suppression',
440
+ displayTooltip: true,
441
+ value: 'Different value',
442
+ column: 'Percentage',
443
+ displayGray: true
444
+ }
445
+ ] as any
446
+ })
447
+
448
+ renderTooltipListItem(suppressionConfig, {
449
+ key: 'Percentage',
450
+ value: '22.0%',
451
+ kind: 'series'
452
+ })
453
+
454
+ expect(screen.getByText('Percentage: 22.0%')).not.toHaveStyle({ color: '#8b8b8a' })
455
+ })
456
+
457
+ it.each([
458
+ { markerColor: '#123456', markerShape: 'square' as const, expectedShape: 'square', expectedSwatches: 1 },
459
+ { markerColor: undefined, markerShape: 'square' as const, expectedShape: 'square', expectedSwatches: 0 },
460
+ { markerColor: '#654321', markerShape: undefined, expectedShape: 'circle', expectedSwatches: 1 }
461
+ ])(
462
+ 'preserves the marker column when markerColor is $markerColor and markerShape is $markerShape',
463
+ ({ markerColor, markerShape, expectedShape, expectedSwatches }) => {
464
+ const { container } = renderTooltipListItem(
465
+ config,
466
+ {
467
+ key: 'Percentage',
468
+ value: '22.0%',
469
+ kind: 'series',
470
+ markerColor,
471
+ markerShape
472
+ },
473
+ { useMarkerColumn: true }
474
+ )
475
+
476
+ expect(container.querySelector('.tooltip-body')).toHaveClass('tooltip-body--marker-layout')
477
+ expect(container.querySelector('.tooltip-marker-slot')).toBeTruthy()
478
+ const swatches = container.querySelectorAll(`.tooltip-marker-swatch--${expectedShape}`)
479
+ expect(swatches).toHaveLength(expectedSwatches)
480
+ if (markerColor) expect(swatches[0]).toHaveStyle({ backgroundColor: markerColor })
481
+ expect(container.querySelector('.tooltip-body-content')).toHaveTextContent('Percentage: 22.0%')
482
+ }
483
+ )
484
+ })
@@ -0,0 +1,22 @@
1
+ import { useEffect, useState } from 'react'
2
+
3
+ const REDUCED_MOTION_QUERY = '(prefers-reduced-motion: reduce)'
4
+
5
+ const usePrefersReducedMotion = () => {
6
+ const [prefersReducedMotion, setPrefersReducedMotion] = useState(
7
+ () => typeof window !== 'undefined' && Boolean(window.matchMedia?.(REDUCED_MOTION_QUERY).matches)
8
+ )
9
+
10
+ useEffect(() => {
11
+ if (typeof window === 'undefined' || !window.matchMedia) return
12
+ const mediaQuery = window.matchMedia(REDUCED_MOTION_QUERY)
13
+ const updatePreference = () => setPrefersReducedMotion(mediaQuery.matches)
14
+ updatePreference()
15
+ mediaQuery.addEventListener?.('change', updatePreference)
16
+ return () => mediaQuery.removeEventListener?.('change', updatePreference)
17
+ }, [])
18
+
19
+ return prefersReducedMotion
20
+ }
21
+
22
+ export default usePrefersReducedMotion
@@ -1,5 +1,6 @@
1
1
  import isNumber from '@cdc/core/helpers/isNumber'
2
2
  import { useMemo } from 'react'
3
+ import getStackedSeriesMax from '../helpers/getStackedSeriesMax'
3
4
 
4
5
  function useReduceData(config, data) {
5
6
  return useMemo(() => {
@@ -30,13 +31,11 @@ function useReduceData(config, data) {
30
31
  let minValue = Infinity
31
32
  let maxValue = -Infinity
32
33
  let existPositiveValue = false
33
- const stackedTotals = []
34
34
 
35
35
  for (let i = 0; i < data.length; i++) {
36
36
  const row = data[i]
37
37
  let rowMax = -Infinity
38
38
  let rowMin = Infinity
39
- let stackedSum = 0
40
39
 
41
40
  for (const key of config.runtime.seriesKeys) {
42
41
  const seriesKey = seriesKeysMap.get(key)
@@ -49,26 +48,22 @@ function useReduceData(config, data) {
49
48
  if (numValue < rowMin) rowMin = numValue
50
49
 
51
50
  if (numValue >= 0) existPositiveValue = true
52
-
53
- if (!isNaN(numValue)) stackedSum += numValue
54
51
  }
55
52
  }
56
53
 
57
54
  if (rowMax > maxValue) maxValue = rowMax
58
55
  if (rowMin < minValue) minValue = rowMin
59
-
60
- if (!isNaN(stackedSum)) stackedTotals.push(stackedSum)
61
56
  }
62
57
 
63
58
  if (
64
59
  (config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && isBar)) &&
65
60
  config.visualizationSubType === 'stacked'
66
61
  ) {
67
- maxValue = Math.max(...stackedTotals)
62
+ maxValue = getStackedSeriesMax(data, config.runtime.series)
68
63
  }
69
64
 
70
65
  if (config.visualizationSubType === 'stacked' && config.visualizationType === 'Area Chart') {
71
- maxValue = Math.max(...stackedTotals)
66
+ maxValue = getStackedSeriesMax(data, config.runtime.series)
72
67
  }
73
68
 
74
69
  if (
@@ -89,34 +84,7 @@ function useReduceData(config, data) {
89
84
 
90
85
  if (config.visualizationType === 'Combo' && config.visualizationSubType === 'stacked' && !isBar) {
91
86
  if (config.runtime.barSeriesKeys && config.runtime.lineSeriesKeys) {
92
- let barMax = -Infinity
93
- let lineMax = -Infinity
94
-
95
- for (const row of data) {
96
- let barSum = 0
97
- let rowLineMax = -Infinity
98
-
99
- for (const key of config.runtime.barSeriesKeys) {
100
- const cleanValue = cleanChars(row[key])
101
- if (isNumber(cleanValue)) {
102
- const numValue = Number(cleanValue)
103
- if (!isNaN(numValue)) barSum += numValue
104
- }
105
- }
106
-
107
- for (const key of config.runtime.lineSeriesKeys) {
108
- const cleanValue = cleanChars(row[key])
109
- if (isNumber(cleanValue)) {
110
- const numValue = Number(cleanValue)
111
- if (numValue > rowLineMax) rowLineMax = numValue
112
- }
113
- }
114
-
115
- if (barSum > barMax) barMax = barSum
116
- if (rowLineMax > lineMax) lineMax = rowLineMax
117
- }
118
-
119
- maxValue = Math.max(barMax, lineMax)
87
+ maxValue = Math.max(maxValue, getStackedSeriesMax(data, config.runtime.barSeriesKeys))
120
88
  }
121
89
  }
122
90
 
@@ -1,25 +1,24 @@
1
1
  import { scaleLinear } from '@visx/scale'
2
- import useReduceData from './useReduceData'
3
2
  import { TOP_PADDING } from './useScales'
4
3
  import { getCleanTopTickMax } from '../helpers/getCleanTopTickMax'
5
4
  import { getAxisMaxOverride } from '../helpers/getAxisMaxOverride'
6
5
 
6
+ const cleanRightAxisValue = value => (typeof value === 'string' ? value.replace(/[,$]/g, '').trim() : value)
7
+
7
8
  export default function useRightAxis({ config, yMax = 0, data = [] }) {
8
- const hasRightAxis = config.visualizationType === 'Combo' && config.orientation === 'vertical'
9
9
  const rightSeriesKeys =
10
10
  config.series && config.series.filter(series => series.axis === 'Right').map(key => key.dataKey)
11
- let { minValue } = useReduceData(config, data)
12
-
13
- const allRightAxisData = rightSeriesKeys => {
14
- if (!rightSeriesKeys) return [0]
15
- let rightAxisData = []
16
- rightSeriesKeys.map((key, index) => {
17
- return (rightAxisData = [...rightAxisData, ...data.map(item => Number(item[key]))])
18
- })
19
- return rightAxisData
20
- }
11
+ const hasRightAxis =
12
+ config.visualizationType === 'Combo' && config.orientation === 'vertical' && Boolean(rightSeriesKeys?.length)
21
13
 
22
- const rightAxisValues = allRightAxisData(rightSeriesKeys).map(Number).filter(Number.isFinite)
14
+ const rightAxisValues = (rightSeriesKeys ?? [])
15
+ .flatMap(key => data.map(item => item[key]))
16
+ .filter(value => value !== null && value !== undefined && String(value).trim() !== '')
17
+ .map(cleanRightAxisValue)
18
+ .filter(value => String(value).trim() !== '')
19
+ .map(Number)
20
+ .filter(Number.isFinite)
21
+ const rawRightMin = rightAxisValues.length ? Math.min(...rightAxisValues) : 0
23
22
  const rawRightMax = rightAxisValues.length ? Math.max(...rightAxisValues) : 0
24
23
  let max = rawRightMax
25
24
  const { hasValidMax: hasValidExplicitRightMax, maxNumber: rightMaxNumber } = getAxisMaxOverride({
@@ -28,24 +27,18 @@ export default function useRightAxis({ config, yMax = 0, data = [] }) {
28
27
  })
29
28
  const rightMinRaw = config.yAxis.rightMin
30
29
  const rightMinNumber = Number(rightMinRaw)
31
- const hasExplicitRightMin =
32
- rightMinRaw !== undefined && rightMinRaw !== null && rightMinRaw !== '' && Number.isFinite(rightMinNumber)
30
+ const hasValidExplicitRightMin =
31
+ rightMinRaw !== undefined &&
32
+ rightMinRaw !== null &&
33
+ rightMinRaw !== '' &&
34
+ Number.isFinite(rightMinNumber) &&
35
+ rightMinNumber <= rawRightMin
33
36
 
34
37
  if (hasValidExplicitRightMax && rightMaxNumber > max) {
35
38
  max = rightMaxNumber
36
39
  }
37
40
 
38
- if (hasExplicitRightMin && rightMinNumber < minValue) {
39
- minValue = rightMinNumber
40
- }
41
-
42
- // if there is a bar series & the right axis doesn't include a negative number, default to zero
43
- const hasBarSeries = config.runtime?.barSeriesKeys?.length > 0
44
- const hasLineSeries = config.runtime?.lineSeriesKeys?.length > 0
45
-
46
- if ((hasBarSeries || hasLineSeries) && minValue > 0) {
47
- minValue = 0
48
- }
41
+ const minValue = hasValidExplicitRightMin ? rightMinNumber : rawRightMin > 0 ? 0 : rawRightMin
49
42
 
50
43
  if (config.yAxis.autoMaxStrategy === 'clean-top-tick' && !hasValidExplicitRightMax) {
51
44
  max = getCleanTopTickMax(max)
@@ -18,6 +18,7 @@ import { countNumOfTicks } from '../helpers/countNumOfTicks'
18
18
  import { getFinalTopTickMax } from '../helpers/getCleanTopTickMax'
19
19
  import { getYAxisFinalizationEligibility } from '../helpers/getYAxisFinalizationEligibility'
20
20
  import { getAxisMaxOverride } from '../helpers/getAxisMaxOverride'
21
+ import { getDataDrivenYAxisCategories } from '../helpers/dataDrivenYAxisCategories'
21
22
 
22
23
  const scaleTypes = {
23
24
  TIME: 'time',
@@ -67,6 +68,20 @@ const useScales = (properties: useScaleProps) => {
67
68
  const context = useContext<ChartContext>(ConfigContext)
68
69
  const { convertLineToBarGraph = false } = context
69
70
 
71
+ const dataDrivenYAxisCategories = getDataDrivenYAxisCategories(config, data)
72
+ if (dataDrivenYAxisCategories?.axisMax !== null && dataDrivenYAxisCategories?.axisMax !== undefined) {
73
+ config = {
74
+ ...config,
75
+ runtime: {
76
+ ...config.runtime,
77
+ yAxis: {
78
+ ...config.runtime.yAxis,
79
+ max: String(dataDrivenYAxisCategories.axisMax)
80
+ }
81
+ }
82
+ }
83
+ }
84
+
70
85
  const isHorizontal = config.orientation === 'horizontal'
71
86
  const { visualizationType, xAxis, forestPlot, runtime } = config
72
87
  const isForestPlot = visualizationType === 'Forest Plot'