@cdc/chart 4.26.4 → 4.26.6

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 (141) hide show
  1. package/CONFIG.md +353 -29
  2. package/LICENSE +201 -0
  3. package/dist/{cdcchart-DQ00cQCm.es.js → cdcchart-BWVIUcAF.es.js} +5 -55
  4. package/dist/cdcchart.js +37885 -35117
  5. package/examples/feature/heatmap/average-age-categorical.json +313 -0
  6. package/examples/feature/heatmap/calendar-heatmap.json +134 -0
  7. package/examples/feature/heatmap/cell-values-bottom-axis.json +181 -0
  8. package/examples/feature/heatmap/sparse-aggregation.json +158 -0
  9. package/examples/private/bad-y-axis.json +543 -0
  10. package/examples/private/bar-chart-negative-value.json +455 -0
  11. package/examples/private/bump-chart.json +1116 -0
  12. package/examples/private/test-123.json +624 -0
  13. package/package.json +4 -3
  14. package/src/CdcChart.tsx +5 -4
  15. package/src/CdcChartComponent.tsx +166 -62
  16. package/src/_stories/Chart.AltText.stories.tsx +136 -0
  17. package/src/_stories/Chart.HeatMap.stories.tsx +187 -0
  18. package/src/_stories/Chart.Sankey.smoke.stories.tsx +62 -0
  19. package/src/_stories/Chart.SeriesColorAssignments.stories.tsx +183 -0
  20. package/src/_stories/Chart.SmallMultiples.smoke.stories.tsx +29 -0
  21. package/src/_stories/Chart.YAxisAutoMaxStrategy.stories.tsx +52 -0
  22. package/src/_stories/Chart.YAxisFilterDomain.stories.tsx +90 -0
  23. package/src/_stories/ChartAnnotation.smoke.stories.tsx +10 -0
  24. package/src/_stories/ChartAxisTitles.smoke.stories.tsx +13 -0
  25. package/src/_stories/ChartBar.Editor.stories.tsx +63 -0
  26. package/src/_stories/ChartBrush.Interaction.stories.tsx +112 -0
  27. package/src/_stories/ChartBrush.smoke.stories.tsx +13 -4
  28. package/src/_stories/_mock/alt_text_metadata.json +38 -0
  29. package/src/_stories/_mock/annotation_event-line_mock.json +1064 -0
  30. package/src/_stories/_mock/heatmap-average-age-categorical.json +315 -0
  31. package/src/_stories/_mock/heatmap.json +156 -0
  32. package/src/_stories/_mock/reported_pertussis_cases.json +1643 -0
  33. package/src/_stories/_mock/sankey_mock.json +78 -0
  34. package/src/_stories/_mock/small_multiples/small_multiples_lines.json +1 -1
  35. package/src/components/Annotations/components/AnnotationDraggable.styles.css +22 -1
  36. package/src/components/Annotations/components/AnnotationDraggable.tsx +220 -120
  37. package/src/components/Annotations/components/AnnotationDropdown.tsx +5 -2
  38. package/src/components/Annotations/tests/AnnotationDraggable.test.tsx +198 -0
  39. package/src/components/Axis/LeftAxis.tsx +17 -11
  40. package/src/components/Axis/LeftAxisGridlines.tsx +22 -12
  41. package/src/components/Axis/RightAxis.tsx +3 -0
  42. package/src/components/Axis/tests/AxisTickValues.test.tsx +86 -0
  43. package/src/components/Brush/BrushSelector.tsx +88 -187
  44. package/src/components/Brush/brushInteraction.ts +22 -0
  45. package/src/components/Brush/tests/brushInteraction.test.ts +38 -0
  46. package/src/components/EditorPanel/EditorPanel.tsx +677 -185
  47. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +114 -52
  48. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +105 -13
  49. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +1 -0
  50. package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +5 -0
  51. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +2 -2
  52. package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.test.tsx +98 -0
  53. package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +10 -0
  54. package/src/components/EditorPanel/components/Panels/Panel.Visual.test.tsx +484 -0
  55. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +4 -1
  56. package/src/components/EditorPanel/components/Panels/SeriesColorAssignments.tsx +262 -0
  57. package/src/components/EditorPanel/components/Panels/panelVisual.styles.css +32 -0
  58. package/src/components/EditorPanel/components/panels.scss +10 -0
  59. package/src/components/EditorPanel/editor-panel.scss +47 -0
  60. package/src/components/EditorPanel/helpers/getVisualizationTypeConfigUpdate.ts +61 -0
  61. package/src/components/EditorPanel/helpers/tests/getVisualizationTypeConfigUpdate.test.ts +74 -0
  62. package/src/components/EditorPanel/useEditorPermissions.test.tsx +315 -0
  63. package/src/components/EditorPanel/useEditorPermissions.ts +77 -21
  64. package/src/components/HeatMap/components/HeatMap.tsx +767 -0
  65. package/src/components/HeatMap/components/HeatMapGradientLegend.tsx +128 -0
  66. package/src/components/HeatMap/heatmap.constants.ts +13 -0
  67. package/src/components/HeatMap/heatmap.css +85 -0
  68. package/src/components/HeatMap/helpers/index.ts +261 -0
  69. package/src/components/HeatMap/index.tsx +5 -0
  70. package/src/components/HeatMap/tests/HeatMap.test.tsx +1072 -0
  71. package/src/components/HeatMap/tests/helpers.test.ts +167 -0
  72. package/src/components/Legend/Legend.Component.tsx +2 -2
  73. package/src/components/Legend/helpers/createFormatLabels.test.ts +88 -0
  74. package/src/components/Legend/helpers/createFormatLabels.tsx +6 -1
  75. package/src/components/LineChart/components/LineChart.BumpCircle.tsx +19 -22
  76. package/src/components/LineChart/helpers.test.ts +574 -0
  77. package/src/components/LineChart/helpers.ts +39 -16
  78. package/src/components/LineChart/index.tsx +28 -5
  79. package/src/components/LinearChart/tests/LinearChart.test.tsx +137 -33
  80. package/src/components/LinearChart/tests/mockConfigContext.ts +1 -0
  81. package/src/components/LinearChart.tsx +103 -47
  82. package/src/components/PieChart/PieChart.tsx +4 -1
  83. package/src/components/RadarChart/RadarChart.tsx +3 -1
  84. package/src/components/Regions/components/Regions.tsx +195 -41
  85. package/src/components/Sankey/components/Sankey.tsx +7 -3
  86. package/src/components/Sankey/helpers/getSankeyTooltip.tsx +7 -6
  87. package/src/components/ScatterPlot/ScatterPlot.jsx +3 -3
  88. package/src/components/SmallMultiples/SmallMultipleTile.tsx +33 -3
  89. package/src/components/SmallMultiples/SmallMultiples.css +12 -0
  90. package/src/components/SmallMultiples/SmallMultiples.tsx +50 -15
  91. package/src/components/SmallMultiples/tests/SmallMultipleTile.test.tsx +152 -0
  92. package/src/components/SmallMultiples/tests/SmallMultiples.test.tsx +170 -0
  93. package/src/components/Sparkline/components/SparkLine.tsx +4 -9
  94. package/src/components/WarmingStripes/WarmingStripesGradientLegend.css +1 -1
  95. package/src/components/WarmingStripes/WarmingStripesGradientLegend.tsx +2 -2
  96. package/src/data/initial-state.js +12 -0
  97. package/src/helpers/axisLabelFontSize.ts +8 -0
  98. package/src/helpers/bumpChartTooltip.ts +54 -0
  99. package/src/helpers/calculateLeftYAxisWidth.ts +13 -3
  100. package/src/helpers/colorAssignmentHelpers.ts +102 -0
  101. package/src/helpers/dataHelpers.ts +11 -1
  102. package/src/helpers/ensureSpecialChartAxisTypes.ts +11 -0
  103. package/src/helpers/getAxisMaxOverride.ts +16 -0
  104. package/src/helpers/getCleanTopTickMax.ts +64 -0
  105. package/src/helpers/getColorScale.ts +18 -9
  106. package/src/helpers/getHasBoundarySuppression.ts +26 -0
  107. package/src/helpers/getMinMax.ts +26 -25
  108. package/src/helpers/getYAxisDomainData.ts +38 -0
  109. package/src/helpers/getYAxisFinalizationEligibility.ts +40 -0
  110. package/src/helpers/handleChartAriaLabels.ts +23 -10
  111. package/src/helpers/hasSpacedInlineLabel.ts +10 -0
  112. package/src/helpers/seriesColumnSettings.ts +5 -4
  113. package/src/helpers/seriesHighlight.ts +26 -0
  114. package/src/helpers/smallMultiplesHelpers.ts +5 -0
  115. package/src/helpers/tests/axisLabelFontSize.test.ts +15 -0
  116. package/src/helpers/tests/bumpChartTooltip.test.ts +75 -0
  117. package/src/helpers/tests/calculateLeftYAxisWidth.test.ts +38 -0
  118. package/src/helpers/tests/dataHelpers.test.ts +135 -0
  119. package/src/helpers/tests/ensureSpecialChartAxisTypes.test.ts +30 -0
  120. package/src/helpers/tests/getAxisMaxOverride.test.ts +36 -0
  121. package/src/helpers/tests/getCleanTopTickMax.test.ts +165 -0
  122. package/src/helpers/tests/getColorScale.test.ts +197 -0
  123. package/src/helpers/tests/getMinMax.test.ts +211 -0
  124. package/src/helpers/tests/getYAxisDomainData.test.ts +119 -0
  125. package/src/helpers/tests/getYAxisFinalizationEligibility.test.ts +185 -0
  126. package/src/helpers/tests/handleChartAriaLabels.test.ts +71 -0
  127. package/src/helpers/tests/hasSpacedInlineLabel.test.ts +75 -0
  128. package/src/helpers/tests/seriesColumnSettings.test.ts +16 -2
  129. package/src/helpers/tests/seriesHighlight.test.ts +61 -0
  130. package/src/helpers/tests/smallMultiplesHelpers.test.ts +99 -0
  131. package/src/hooks/tests/useRightAxis.test.tsx +127 -0
  132. package/src/hooks/tests/useScales.test.tsx +383 -0
  133. package/src/hooks/useRightAxis.ts +30 -13
  134. package/src/hooks/useScales.ts +48 -21
  135. package/src/hooks/useTooltip.tsx +3 -1
  136. package/src/index.jsx +5 -2
  137. package/src/scss/main.scss +32 -49
  138. package/src/test/CdcChart.dataTable.test.tsx +122 -0
  139. package/src/types/ChartConfig.ts +24 -1
  140. package/src/types/ChartContext.ts +5 -0
  141. package/src/helpers/getYAxisAutoPadding.ts +0 -53
@@ -0,0 +1,315 @@
1
+ import React from 'react'
2
+ import { renderHook } from '@testing-library/react'
3
+ import { describe, expect, it } from 'vitest'
4
+ import ConfigContext from '../../ConfigContext'
5
+ import { useEditorPermissions } from './useEditorPermissions'
6
+ import { createMockChartContext, createMockConfig } from '../LinearChart/tests/mockConfigContext'
7
+ import { ChartConfig } from '../../types/ChartConfig'
8
+
9
+ const renderUseEditorPermissions = (
10
+ configOverrides: Partial<ChartConfig>,
11
+ contextOverrides: Partial<ReturnType<typeof createMockChartContext>> = {}
12
+ ) => {
13
+ const config = createMockConfig(configOverrides)
14
+ const context = createMockChartContext(config, contextOverrides)
15
+ const wrapper = ({ children }: React.PropsWithChildren) => (
16
+ <ConfigContext.Provider value={context}>{children}</ConfigContext.Provider>
17
+ )
18
+
19
+ return renderHook(() => useEditorPermissions(), { wrapper })
20
+ }
21
+
22
+ describe('useEditorPermissions', () => {
23
+ it('shows manual y-axis padding controls when there is no spaced inline label', () => {
24
+ const { result } = renderUseEditorPermissions({
25
+ yAxis: {
26
+ ...createMockConfig().yAxis,
27
+ titlePlacement: 'side',
28
+ inlineLabel: 'Rate'
29
+ }
30
+ })
31
+
32
+ expect(result.current.visSupportsYPadding()).toBe(true)
33
+ })
34
+
35
+ it('hides manual y-axis padding controls for spaced inline labels when renderer headroom applies', () => {
36
+ const { result } = renderUseEditorPermissions({
37
+ yAxis: {
38
+ ...createMockConfig().yAxis,
39
+ titlePlacement: 'side',
40
+ inlineLabel: 'per 100k'
41
+ }
42
+ })
43
+
44
+ expect(result.current.visSupportsYPadding()).toBe(false)
45
+ })
46
+
47
+ it('shows manual y-axis padding controls for horizontal charts with spaced inline labels', () => {
48
+ const { result } = renderUseEditorPermissions({
49
+ orientation: 'horizontal',
50
+ yAxis: {
51
+ ...createMockConfig().yAxis,
52
+ titlePlacement: 'side',
53
+ inlineLabel: 'per 100k'
54
+ }
55
+ })
56
+
57
+ expect(result.current.visSupportsYPadding()).toBe(true)
58
+ })
59
+
60
+ it('shows manual y-axis padding controls for Combo charts with spaced inline labels', () => {
61
+ const { result } = renderUseEditorPermissions({
62
+ visualizationType: 'Combo',
63
+ yAxis: {
64
+ ...createMockConfig().yAxis,
65
+ titlePlacement: 'side',
66
+ inlineLabel: 'per 100k'
67
+ }
68
+ })
69
+
70
+ expect(result.current.visSupportsYPadding()).toBe(true)
71
+ })
72
+
73
+ it('shows manual y-axis padding controls for top y-axis titles', () => {
74
+ const { result } = renderUseEditorPermissions({
75
+ yAxis: {
76
+ ...createMockConfig().yAxis,
77
+ titlePlacement: 'top',
78
+ label: 'Y-Axis',
79
+ inlineLabel: ''
80
+ }
81
+ })
82
+
83
+ expect(result.current.visSupportsYPadding()).toBe(true)
84
+ })
85
+
86
+ it('supports series color assignments only for eligible authored-series charts', () => {
87
+ const supported = renderUseEditorPermissions({
88
+ visualizationType: 'Line',
89
+ series: [{ dataKey: 'cases', type: 'Line' }] as any
90
+ })
91
+
92
+ expect(supported.result.current.visSupportsSeriesColorAssignments()).toBe(true)
93
+
94
+ const unsupported = renderUseEditorPermissions({
95
+ visualizationType: 'Pie',
96
+ series: [{ dataKey: 'cases', type: 'Pie' }] as any
97
+ })
98
+
99
+ expect(unsupported.result.current.visSupportsSeriesColorAssignments()).toBe(false)
100
+ })
101
+
102
+ it('shows filter-domain behavior when a standalone chart has visible filters and automatic max', () => {
103
+ const { result } = renderUseEditorPermissions({
104
+ filters: [{ columnName: 'Region', showDropdown: true } as any],
105
+ yAxis: {
106
+ ...createMockConfig().yAxis,
107
+ max: '',
108
+ type: 'linear'
109
+ }
110
+ })
111
+
112
+ expect(result.current.visSupportsFilterDomainBehavior()).toBe(true)
113
+ })
114
+
115
+ it('shows filter-domain behavior for horizontal bar charts when automatic max can respond to filters', () => {
116
+ const { result } = renderUseEditorPermissions({
117
+ visualizationType: 'Bar',
118
+ orientation: 'horizontal',
119
+ filters: [{ columnName: 'Region', showDropdown: true } as any],
120
+ yAxis: {
121
+ ...createMockConfig().yAxis,
122
+ max: '',
123
+ type: 'linear'
124
+ }
125
+ })
126
+
127
+ expect(result.current.visSupportsFilterDomainBehavior()).toBe(true)
128
+ })
129
+
130
+ it('shows filter-domain behavior for dashboard charts without local filters', () => {
131
+ const { result } = renderUseEditorPermissions(
132
+ {
133
+ filters: [],
134
+ yAxis: {
135
+ ...createMockConfig().yAxis,
136
+ max: '',
137
+ type: 'linear'
138
+ }
139
+ },
140
+ { isDashboard: true }
141
+ )
142
+
143
+ expect(result.current.visSupportsFilterDomainBehavior()).toBe(true)
144
+ })
145
+
146
+ it('hides filter-domain behavior when vertical value-axis max is explicit', () => {
147
+ const { result } = renderUseEditorPermissions(
148
+ {
149
+ filters: [{ columnName: 'Region', showDropdown: true } as any],
150
+ yAxis: {
151
+ ...createMockConfig().yAxis,
152
+ max: '100',
153
+ type: 'linear'
154
+ }
155
+ },
156
+ { isDashboard: true }
157
+ )
158
+
159
+ expect(result.current.visSupportsFilterDomainBehavior()).toBe(false)
160
+ })
161
+
162
+ it('hides filter-domain behavior for horizontal charts when value-axis max is explicit', () => {
163
+ const { result } = renderUseEditorPermissions(
164
+ {
165
+ visualizationType: 'Bar',
166
+ orientation: 'horizontal',
167
+ filters: [{ columnName: 'Region', showDropdown: true } as any],
168
+ xAxis: {
169
+ ...createMockConfig().xAxis,
170
+ max: '100'
171
+ },
172
+ yAxis: {
173
+ ...createMockConfig().yAxis,
174
+ max: '',
175
+ type: 'linear'
176
+ }
177
+ },
178
+ { isDashboard: true }
179
+ )
180
+
181
+ expect(result.current.visSupportsFilterDomainBehavior()).toBe(false)
182
+ })
183
+
184
+ it('hides filter-domain behavior for unfiltered standalone charts', () => {
185
+ const { result } = renderUseEditorPermissions({
186
+ filters: [],
187
+ yAxis: {
188
+ ...createMockConfig().yAxis,
189
+ max: '',
190
+ type: 'linear'
191
+ }
192
+ })
193
+
194
+ expect(result.current.visSupportsFilterDomainBehavior()).toBe(false)
195
+ })
196
+
197
+ it('hides filter-domain behavior for charts outside the value-axis allowlist', () => {
198
+ const { result } = renderUseEditorPermissions(
199
+ {
200
+ visualizationType: 'Bump Chart',
201
+ filters: [{ columnName: 'Region', showDropdown: true } as any],
202
+ yAxis: {
203
+ ...createMockConfig().yAxis,
204
+ max: '',
205
+ type: 'linear'
206
+ }
207
+ },
208
+ { isDashboard: true }
209
+ )
210
+
211
+ expect(result.current.visSupportsFilterDomainBehavior()).toBe(false)
212
+ })
213
+
214
+ it('hides filter-domain behavior for chart types with specialized value scales', () => {
215
+ const { result } = renderUseEditorPermissions(
216
+ {
217
+ visualizationType: 'Paired Bar',
218
+ filters: [{ columnName: 'Region', showDropdown: true } as any],
219
+ yAxis: {
220
+ ...createMockConfig().yAxis,
221
+ max: '',
222
+ type: 'linear'
223
+ }
224
+ },
225
+ { isDashboard: true }
226
+ )
227
+
228
+ expect(result.current.visSupportsFilterDomainBehavior()).toBe(false)
229
+ })
230
+
231
+ it('shows automatic max strategy for automatic numeric value axes', () => {
232
+ const { result } = renderUseEditorPermissions({
233
+ yAxis: {
234
+ ...createMockConfig().yAxis,
235
+ max: '',
236
+ type: 'linear'
237
+ }
238
+ })
239
+
240
+ expect(result.current.visSupportsAutoMaxStrategy()).toBe(true)
241
+ })
242
+
243
+ it('shows automatic max strategy for horizontal charts with automatic value axes', () => {
244
+ const { result } = renderUseEditorPermissions({
245
+ visualizationType: 'Bar',
246
+ orientation: 'horizontal',
247
+ xAxis: {
248
+ ...createMockConfig().xAxis,
249
+ max: ''
250
+ },
251
+ yAxis: {
252
+ ...createMockConfig().yAxis,
253
+ max: '',
254
+ type: 'linear'
255
+ }
256
+ })
257
+
258
+ expect(result.current.visSupportsAutoMaxStrategy()).toBe(true)
259
+ })
260
+
261
+ it('hides automatic max strategy when vertical value-axis max is explicit', () => {
262
+ const { result } = renderUseEditorPermissions({
263
+ yAxis: {
264
+ ...createMockConfig().yAxis,
265
+ max: '100',
266
+ type: 'linear'
267
+ }
268
+ })
269
+
270
+ expect(result.current.visSupportsAutoMaxStrategy()).toBe(false)
271
+ })
272
+
273
+ it('hides automatic max strategy for horizontal charts when value-axis max is explicit', () => {
274
+ const { result } = renderUseEditorPermissions({
275
+ visualizationType: 'Bar',
276
+ orientation: 'horizontal',
277
+ xAxis: {
278
+ ...createMockConfig().xAxis,
279
+ max: '100'
280
+ },
281
+ yAxis: {
282
+ ...createMockConfig().yAxis,
283
+ max: '',
284
+ type: 'linear'
285
+ }
286
+ })
287
+
288
+ expect(result.current.visSupportsAutoMaxStrategy()).toBe(false)
289
+ })
290
+
291
+ it('hides automatic max strategy for categorical value axes', () => {
292
+ const { result } = renderUseEditorPermissions({
293
+ yAxis: {
294
+ ...createMockConfig().yAxis,
295
+ max: '',
296
+ type: 'categorical'
297
+ }
298
+ })
299
+
300
+ expect(result.current.visSupportsAutoMaxStrategy()).toBe(false)
301
+ })
302
+
303
+ it('hides automatic max strategy for chart types with specialized value scales', () => {
304
+ const { result } = renderUseEditorPermissions({
305
+ visualizationType: 'Paired Bar',
306
+ yAxis: {
307
+ ...createMockConfig().yAxis,
308
+ max: '',
309
+ type: 'linear'
310
+ }
311
+ })
312
+
313
+ expect(result.current.visSupportsAutoMaxStrategy()).toBe(false)
314
+ })
315
+ })
@@ -1,8 +1,12 @@
1
1
  import React, { useContext } from 'react'
2
2
  import ConfigContext from '../../ConfigContext'
3
+ import { getYAxisFinalizationEligibility } from '../../helpers/getYAxisFinalizationEligibility'
4
+ import { hasSpacedInlineLabel } from '../../helpers/hasSpacedInlineLabel'
5
+ import { supportsSeriesColorAssignments } from '../../helpers/colorAssignmentHelpers'
6
+ import { hasVisibleVizFilters } from '@cdc/core/helpers/filterVisibility'
3
7
 
4
8
  export const useEditorPermissions = () => {
5
- const { config } = useContext(ConfigContext)
9
+ const { config, isDashboard } = useContext(ConfigContext)
6
10
  const { visualizationType, series, orientation, visualizationSubType } = config
7
11
 
8
12
  // Overall support for the chart types
@@ -16,6 +20,7 @@ export const useEditorPermissions = () => {
16
20
  'Deviation Bar',
17
21
  'Forecasting',
18
22
  // 'Forest Plot',
23
+ 'HeatMap',
19
24
  'Horizon Chart',
20
25
  'Line',
21
26
  'Paired Bar',
@@ -58,7 +63,7 @@ export const useEditorPermissions = () => {
58
63
  }
59
64
 
60
65
  const visSupportsClickingLegend = () => {
61
- const disabledCharts = ['Horizon Chart']
66
+ const disabledCharts = ['HeatMap', 'Horizon Chart']
62
67
  if (disabledCharts.includes(visualizationType)) return false
63
68
  return true
64
69
  }
@@ -75,6 +80,7 @@ export const useEditorPermissions = () => {
75
80
  'Box Plot',
76
81
  'Bump Chart',
77
82
  'Forest Plot',
83
+ 'HeatMap',
78
84
  'Horizon Chart',
79
85
  'Pie',
80
86
  'Radar',
@@ -93,6 +99,7 @@ export const useEditorPermissions = () => {
93
99
  'Box Plot',
94
100
  'Bump Chart',
95
101
  'Forest Plot',
102
+ 'HeatMap',
96
103
  'Radar',
97
104
  'Sankey',
98
105
  'Scatter Plot',
@@ -109,6 +116,8 @@ export const useEditorPermissions = () => {
109
116
  return true
110
117
  case 'Forest Plot':
111
118
  return false
119
+ case 'HeatMap':
120
+ return true
112
121
  case 'Spark Line':
113
122
  return false
114
123
  case 'Sankey':
@@ -197,9 +206,13 @@ export const useEditorPermissions = () => {
197
206
  }
198
207
  }
199
208
 
200
- const visHasSelectableLegendValues = !['Box Plot', 'Forest Plot', 'Spark Line', 'Warming Stripes'].includes(
201
- visualizationType
202
- )
209
+ const visHasSelectableLegendValues = ![
210
+ 'Box Plot',
211
+ 'Forest Plot',
212
+ 'HeatMap',
213
+ 'Spark Line',
214
+ 'Warming Stripes'
215
+ ].includes(visualizationType)
203
216
  const visHasLegendAxisAlign = () => {
204
217
  return visualizationType === 'Bar' && visualizationSubType === 'stacked' && config.legend.behavior === 'isolate'
205
218
  }
@@ -208,7 +221,7 @@ export const useEditorPermissions = () => {
208
221
  }
209
222
 
210
223
  const visSupportsTooltipOpacity = () => {
211
- const disabledCharts = ['Spark Line', 'Sankey', 'Warming Stripes']
224
+ const disabledCharts = ['HeatMap', 'Spark Line', 'Sankey', 'Warming Stripes']
212
225
  if (disabledCharts.includes(visualizationType)) return false
213
226
  return true
214
227
  }
@@ -226,7 +239,7 @@ export const useEditorPermissions = () => {
226
239
  }
227
240
 
228
241
  const visSupportsNonSequentialPallete = () => {
229
- const disabledCharts = ['Paired Bar', 'Deviation Bar', 'Forest Plot', 'Forecasting', 'Sankey']
242
+ const disabledCharts = ['HeatMap', 'Paired Bar', 'Deviation Bar', 'Forest Plot', 'Forecasting', 'Sankey']
230
243
  if (disabledCharts.includes(visualizationType)) return false
231
244
  return true
232
245
  }
@@ -238,7 +251,7 @@ export const useEditorPermissions = () => {
238
251
  }
239
252
 
240
253
  const visSupportsDateCategoryAxisLabel = () => {
241
- const disabledCharts = ['Forest Plot', 'Spark Line', 'Bump Chart', 'Warming Stripes']
254
+ const disabledCharts = ['Forest Plot', 'HeatMap', 'Spark Line', 'Bump Chart', 'Warming Stripes']
242
255
  if (disabledCharts.includes(visualizationType)) return false
243
256
  return true
244
257
  }
@@ -262,31 +275,41 @@ export const useEditorPermissions = () => {
262
275
  }
263
276
 
264
277
  const visSupportsDateCategoryNumTicks = () => {
265
- const disabledCharts = ['Spark Line']
278
+ const disabledCharts = ['HeatMap', 'Spark Line']
266
279
  if (disabledCharts.includes(visualizationType)) return false
267
280
  return true
268
281
  }
269
282
 
270
283
  const visSupportsResponsiveTicks = () => {
271
- const disabledCharts = ['Spark Line']
284
+ const disabledCharts = ['HeatMap', 'Spark Line']
272
285
  if (disabledCharts.includes(visualizationType)) return false
273
286
  return true
274
287
  }
275
288
 
276
289
  const visSupportsRegions = () => {
277
- const disabledCharts = ['Forest Plot', 'Pie', 'Paired Bar', 'Radar', 'Spark Line', 'Sankey', 'Warming Stripes']
290
+ const disabledCharts = [
291
+ 'Forest Plot',
292
+ 'Horizon Chart',
293
+ 'HeatMap',
294
+ 'Pie',
295
+ 'Paired Bar',
296
+ 'Radar',
297
+ 'Spark Line',
298
+ 'Sankey',
299
+ 'Warming Stripes'
300
+ ]
278
301
  if (disabledCharts.includes(visualizationType)) return false
279
302
  return true
280
303
  }
281
304
 
282
305
  const visSupportsValueAxisMax = () => {
283
- const disabledCharts = ['Forest Plot']
306
+ const disabledCharts = ['Forest Plot', 'HeatMap']
284
307
  if (disabledCharts.includes(visualizationType)) return false
285
308
  return true
286
309
  }
287
310
 
288
311
  const visSupportsValueAxisMin = () => {
289
- const disabledCharts = ['Forest Plot']
312
+ const disabledCharts = ['Forest Plot', 'HeatMap']
290
313
  if (disabledCharts.includes(visualizationType)) return false
291
314
  return true
292
315
  }
@@ -297,15 +320,36 @@ export const useEditorPermissions = () => {
297
320
  return true
298
321
  }
299
322
 
323
+ const hasExplicitValueAxisMax = () => {
324
+ const valueAxisMax = orientation === 'horizontal' ? config.xAxis?.max : config.yAxis?.max
325
+ return valueAxisMax !== undefined && valueAxisMax !== null && valueAxisMax !== ''
326
+ }
327
+
328
+ const visSupportsAutomaticValueDomain = () => {
329
+ const enabledCharts = ['Area Chart', 'Bar', 'Combo', 'Deviation Bar', 'Forecasting', 'Line', 'Scatter Plot']
330
+ if (!enabledCharts.includes(visualizationType)) return false
331
+ if (config.yAxis?.type === 'categorical') return false
332
+ if (hasExplicitValueAxisMax()) return false
333
+ return true
334
+ }
335
+
336
+ const visSupportsAutoMaxStrategy = () => {
337
+ return visSupportsAutomaticValueDomain()
338
+ }
339
+
340
+ const visSupportsFilterDomainBehavior = () => {
341
+ return visSupportsAutomaticValueDomain() && Boolean(isDashboard || hasVisibleVizFilters(config.filters))
342
+ }
343
+
300
344
  const visSupportsValueAxisGridLines = () => {
301
- const disabledCharts = ['Forest Plot']
345
+ const disabledCharts = ['Forest Plot', 'HeatMap']
302
346
  if (disabledCharts.includes(visualizationType)) return false
303
347
  return true
304
348
  }
305
349
 
306
350
  // implement later
307
351
  const visSupportsValueAxisTicks = () => {
308
- const disabledCharts = ['Forest Plot']
352
+ const disabledCharts = ['Forest Plot', 'HeatMap']
309
353
  if (disabledCharts.includes(visualizationType)) return false
310
354
  return true
311
355
  }
@@ -319,7 +363,7 @@ export const useEditorPermissions = () => {
319
363
 
320
364
  // implement later
321
365
  const visSupportsValueAxisLabels = () => {
322
- const disabledCharts = ['Forest Plot', 'Bump Chart']
366
+ const disabledCharts = ['Forest Plot', 'HeatMap', 'Bump Chart']
323
367
  if (disabledCharts.includes(visualizationType)) return false
324
368
  return true
325
369
  }
@@ -332,7 +376,7 @@ export const useEditorPermissions = () => {
332
376
  }
333
377
 
334
378
  const visSupportsBarThickness = () => {
335
- const disabledCharts = ['Forest Plot', 'Warming Stripes']
379
+ const disabledCharts = ['Forest Plot', 'HeatMap', 'Warming Stripes']
336
380
  if (disabledCharts.includes(visualizationType)) return false
337
381
  return true
338
382
  }
@@ -344,7 +388,7 @@ export const useEditorPermissions = () => {
344
388
  }
345
389
  const visSupportsMobileChartHeight = () => {
346
390
  // TODO: this is a soft release. Support should eventually match visSupportsChartHeight
347
- const enabledCharts = ['Bar', 'Line', 'Combo', 'Area Chart', 'Radar']
391
+ const enabledCharts = ['Bar', 'Line', 'Combo', 'Area Chart', 'HeatMap', 'Radar']
348
392
  if (enabledCharts.includes(visualizationType)) return true
349
393
  return false
350
394
  }
@@ -356,13 +400,13 @@ export const useEditorPermissions = () => {
356
400
  }
357
401
 
358
402
  const visSupportsRankByValue = () => {
359
- const disabledCharts = ['Spark Line']
403
+ const disabledCharts = ['HeatMap', 'Spark Line']
360
404
  if (disabledCharts.includes(visualizationType)) return false
361
405
  return true
362
406
  }
363
407
 
364
408
  const visSupportsDateCategoryHeight = () => {
365
- const disabledCharts = ['Spark Line', 'Sankey', 'Bump Chart']
409
+ const disabledCharts = ['HeatMap', 'Spark Line', 'Sankey', 'Bump Chart']
366
410
  if (disabledCharts.includes(visualizationType)) return false
367
411
  if (config.orientation !== 'horizontal') return false
368
412
  if (config.orientation === 'horizontal' && visualizationType === 'Bar' && !config.isLollipopChart) return false
@@ -406,8 +450,17 @@ export const useEditorPermissions = () => {
406
450
  return false
407
451
  }
408
452
 
453
+ const visSupportsSeriesColorAssignments = () => supportsSeriesColorAssignments(config)
454
+
409
455
  const visSupportsYPadding = () => {
410
- return !config.yAxis.inlineLabel || !config.yAxis.inlineLabel?.includes(' ')
456
+ const { shouldUseInlineLabelHeadroom } = getYAxisFinalizationEligibility({
457
+ config,
458
+ hasSpacedInlineLabel: hasSpacedInlineLabel(config),
459
+ hasValidExplicitLeftMax: false,
460
+ isHorizontal: orientation === 'horizontal'
461
+ })
462
+
463
+ return !shouldUseInlineLabelHeadroom
411
464
  }
412
465
 
413
466
  const visHasSingleSeriesTooltip = () => {
@@ -466,6 +519,8 @@ export const useEditorPermissions = () => {
466
519
  visSupportsDateCategoryTickRotation,
467
520
  visSupportsDynamicSeries,
468
521
  visSupportsFilters,
522
+ visSupportsAutoMaxStrategy,
523
+ visSupportsFilterDomainBehavior,
469
524
  visSupportsFootnotes,
470
525
  visSupportsLeftValueAxis,
471
526
  visSupportsMobileChartHeight,
@@ -477,6 +532,7 @@ export const useEditorPermissions = () => {
477
532
  visSupportsResponsiveTicks,
478
533
  visSupportsReverseColorPalette,
479
534
  visSupportsSequentialPallete,
535
+ visSupportsSeriesColorAssignments,
480
536
  visSupportsSmallMultiples,
481
537
  visSupportsSuperTitle,
482
538
  visSupportsTooltipLines,