@cdc/chart 4.25.8 → 4.25.11

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 (145) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/dist/{cdcchart-1a1724a1.es.js → cdcchart-dgT_1dIT.es.js} +136 -151
  3. package/dist/cdcchart.js +44236 -40355
  4. package/examples/feature/__data__/planet-example-data.json +0 -30
  5. package/examples/feature/boxplot/valid-boxplot.csv +38 -17
  6. package/examples/grouped-bar-test.json +400 -0
  7. package/examples/private/DEV-11825.json +573 -0
  8. package/examples/private/d.json +382 -0
  9. package/examples/private/example-2.json +49784 -0
  10. package/examples/private/f2.json +1 -0
  11. package/examples/private/f4.json +1577 -0
  12. package/examples/private/forecast.json +1180 -0
  13. package/examples/private/lollipop.json +468 -0
  14. package/examples/private/na.json +913 -0
  15. package/examples/private/new.json +48756 -0
  16. package/examples/private/pie-chart-legend.json +904 -0
  17. package/examples/private/test-data.csv +28 -0
  18. package/examples/suppressed_tooltip.json +480 -0
  19. package/index.html +2 -133
  20. package/package.json +25 -7
  21. package/src/CdcChart.tsx +9 -13
  22. package/src/CdcChartComponent.tsx +403 -92
  23. package/src/_stories/Chart.Anchors.stories.tsx +2 -2
  24. package/src/_stories/Chart.BoxPlot.stories.tsx +1 -1
  25. package/src/_stories/Chart.CI.stories.tsx +1 -1
  26. package/src/_stories/Chart.Combo.stories.tsx +18 -0
  27. package/src/_stories/Chart.CustomColors.stories.tsx +1 -1
  28. package/src/_stories/Chart.DynamicSeries.stories.tsx +2 -2
  29. package/src/_stories/Chart.Filters.stories.tsx +2 -2
  30. package/src/_stories/Chart.Forecast.stories.tsx +36 -0
  31. package/src/_stories/Chart.HTMLInDataTable.stories.tsx +520 -0
  32. package/src/_stories/Chart.Legend.Gradient.stories.tsx +2 -2
  33. package/src/_stories/Chart.Patterns.stories.tsx +20 -0
  34. package/src/_stories/Chart.PreserveDecimals.stories.tsx +220 -0
  35. package/src/_stories/Chart.ScatterPlot.stories.tsx +1 -1
  36. package/src/_stories/Chart.SmallMultiples.stories.tsx +47 -0
  37. package/src/_stories/Chart.stories.tsx +8 -5
  38. package/src/_stories/Chart.tooltip.stories.tsx +1 -1
  39. package/src/_stories/ChartAnnotation.stories.tsx +7 -4
  40. package/src/_stories/ChartAxisLabels.stories.tsx +2 -2
  41. package/src/_stories/ChartAxisTitles.stories.tsx +2 -2
  42. package/src/_stories/ChartBar.Editor.stories.tsx +3580 -0
  43. package/src/_stories/ChartEditor.Editor.stories.tsx +658 -0
  44. package/src/_stories/ChartEditor.stories.tsx +59 -60
  45. package/src/_stories/ChartLine.Suppression.stories.tsx +1 -1
  46. package/src/_stories/ChartLine.Symbols.stories.tsx +1 -1
  47. package/src/_stories/ChartPrefixSuffix.stories.tsx +2 -2
  48. package/src/_stories/_mock/combo.json +451 -0
  49. package/src/_stories/_mock/editor-test-configs.json +376 -0
  50. package/src/_stories/_mock/editor-test-datasets.json +477 -0
  51. package/src/_stories/_mock/editor-tests/bar-chart-editor-test.json +255 -0
  52. package/src/_stories/_mock/editor-tests/bar-chart-general-test.json +267 -0
  53. package/src/_stories/_mock/editor-tests/bar-chart-test.json +237 -0
  54. package/src/_stories/_mock/forecast_combo_with_gaps.json +913 -0
  55. package/src/_stories/_mock/pie_config.json +257 -62
  56. package/src/_stories/_mock/small_multiples/small_multiples_bars.json +1944 -0
  57. package/src/_stories/_mock/small_multiples/small_multiples_big_data_bars.json +1114 -0
  58. package/src/_stories/_mock/small_multiples/small_multiples_lines.json +2646 -0
  59. package/src/_stories/_mock/small_multiples/small_multiples_lines_colors.json +1305 -0
  60. package/src/_stories/_mock/small_multiples/small_multiples_stacked_bars.json +1936 -0
  61. package/src/_stories/_mock/stacked-pattern-test.json +520 -0
  62. package/src/components/Annotations/components/AnnotationDraggable.tsx +1 -0
  63. package/src/components/Annotations/components/AnnotationDropdown.tsx +1 -1
  64. package/src/components/Annotations/components/findNearestDatum.ts +6 -41
  65. package/src/components/AreaChart/components/AreaChart.Stacked.jsx +10 -6
  66. package/src/components/AreaChart/index.tsx +1 -2
  67. package/src/components/BarChart/components/BarChart.Horizontal.tsx +161 -22
  68. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +138 -5
  69. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +215 -73
  70. package/src/components/BarChart/components/BarChart.Vertical.tsx +155 -22
  71. package/src/components/BarChart/helpers/index.ts +43 -4
  72. package/src/components/BarChart/helpers/lollipopColors.ts +27 -0
  73. package/src/components/BarChart/helpers/useBarChart.ts +25 -3
  74. package/src/components/BoxPlot/BoxPlot.Vertical.tsx +2 -1
  75. package/src/components/BoxPlot/helpers/index.ts +3 -3
  76. package/src/components/Brush/BrushChart.tsx +1 -1
  77. package/src/components/DeviationBar.jsx +9 -6
  78. package/src/components/EditorPanel/EditorPanel.tsx +563 -229
  79. package/src/components/EditorPanel/EditorPanelContext.ts +3 -0
  80. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +96 -111
  81. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +19 -1
  82. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +461 -0
  83. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +80 -67
  84. package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +422 -0
  85. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +188 -139
  86. package/src/components/EditorPanel/components/Panels/index.tsx +5 -1
  87. package/src/components/EditorPanel/components/Panels/panelVisual.styles.css +0 -8
  88. package/src/components/EditorPanel/editor-panel.scss +0 -20
  89. package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +49 -48
  90. package/src/components/EditorPanel/useEditorPermissions.ts +7 -15
  91. package/src/components/Forecasting/Forecasting.tsx +175 -27
  92. package/src/components/ForestPlot/ForestPlot.tsx +11 -7
  93. package/src/components/ForestPlot/ForestPlotProps.ts +1 -1
  94. package/src/components/Legend/Legend.Component.tsx +114 -14
  95. package/src/components/Legend/helpers/createFormatLabels.tsx +230 -171
  96. package/src/components/Legend/helpers/getLegendClasses.ts +0 -1
  97. package/src/components/LegendWrapper.tsx +1 -1
  98. package/src/components/LineChart/LineChartProps.ts +0 -3
  99. package/src/components/LineChart/components/LineChart.Circle.tsx +2 -2
  100. package/src/components/LineChart/helpers.ts +1 -1
  101. package/src/components/LineChart/index.tsx +38 -15
  102. package/src/components/LinearChart.tsx +96 -84
  103. package/src/components/PairedBarChart.jsx +6 -4
  104. package/src/components/PieChart/PieChart.tsx +170 -54
  105. package/src/components/Regions/components/Regions.tsx +3 -24
  106. package/src/components/Sankey/components/Sankey.tsx +7 -1
  107. package/src/components/Sankey/types/index.ts +1 -1
  108. package/src/components/ScatterPlot/ScatterPlot.jsx +32 -4
  109. package/src/components/SmallMultiples/SmallMultipleTile.tsx +198 -0
  110. package/src/components/SmallMultiples/SmallMultiples.css +32 -0
  111. package/src/components/SmallMultiples/SmallMultiples.tsx +271 -0
  112. package/src/components/SmallMultiples/index.ts +2 -0
  113. package/src/data/initial-state.js +327 -293
  114. package/src/helpers/buildForecastPaletteMappings.ts +112 -0
  115. package/src/helpers/buildForecastPaletteOptions.ts +71 -0
  116. package/src/helpers/getColorScale.ts +82 -8
  117. package/src/{hooks/useMinMax.ts → helpers/getMinMax.ts} +14 -7
  118. package/src/helpers/getNewRuntime.ts +1 -1
  119. package/src/helpers/getTransformedData.ts +1 -1
  120. package/src/helpers/getYAxisAutoPadding.ts +53 -0
  121. package/src/helpers/smallMultiplesHelpers.ts +529 -0
  122. package/src/hooks/useChartHoverAnalytics.tsx +44 -0
  123. package/src/hooks/useProgrammaticTooltip.ts +96 -0
  124. package/src/hooks/useReduceData.ts +105 -70
  125. package/src/hooks/useScales.ts +88 -34
  126. package/src/hooks/useSmallMultipleSynchronization.ts +59 -0
  127. package/src/hooks/useTooltip.tsx +116 -29
  128. package/src/index.jsx +0 -2
  129. package/src/scss/main.scss +13 -80
  130. package/src/store/chart.actions.ts +2 -0
  131. package/src/store/chart.reducer.ts +5 -1
  132. package/src/test/CdcChart.test.jsx +8 -3
  133. package/src/types/ChartConfig.ts +53 -11
  134. package/src/types/ChartContext.ts +4 -0
  135. package/vite.config.js +1 -1
  136. package/vitest.config.ts +16 -0
  137. package/src/_stories/_mock/pie_data.json +0 -218
  138. package/src/components/AreaChart/components/AreaChart.jsx +0 -109
  139. package/src/coreStyles_chart.scss +0 -3
  140. package/src/helpers/configHelpers.ts +0 -28
  141. package/src/helpers/generateColorsArray.ts +0 -8
  142. package/src/helpers/sort.ts +0 -7
  143. package/src/hooks/useActiveElement.js +0 -19
  144. package/src/hooks/useChartClasses.js +0 -41
  145. package/src/hooks/useColorPalette.js +0 -76
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect, useCallback, useRef, useId, useContext, useReducer } from 'react'
1
+ import React, { useState, useEffect, useCallback, useRef, useId, useContext, useReducer, useMemo } from 'react'
2
2
 
3
3
  // IE11
4
4
  import ResizeObserver from 'resize-observer-polyfill'
@@ -24,7 +24,6 @@ import { Label } from './types/Label'
24
24
  import ParentSize from '@visx/responsive/lib/components/ParentSize'
25
25
  import { timeParse, timeFormat } from 'd3-time-format'
26
26
  import parse from 'html-react-parser'
27
- import 'react-tooltip/dist/react-tooltip.css'
28
27
  import _ from 'lodash'
29
28
  // Primary Components
30
29
  import ConfigContext, { ChartDispatchContext } from './ConfigContext'
@@ -33,7 +32,8 @@ import SankeyChart from './components/Sankey'
33
32
  import LinearChart from './components/LinearChart'
34
33
  import { isDateScale } from '@cdc/core/helpers/cove/date'
35
34
 
36
- import { colorPalettesChart as colorPalettes, twoColorPalette } from '@cdc/core/data/colorPalettes'
35
+ import { twoColorPalette } from '@cdc/core/data/colorPalettes'
36
+ import { filterChartColorPalettes } from '@cdc/core/helpers/filterColorPalettes'
37
37
 
38
38
  import SparkLine from './components/Sparkline'
39
39
  import Legend from './components/Legend'
@@ -46,7 +46,8 @@ import { handleChartAriaLabels } from './helpers/handleChartAriaLabels'
46
46
  import { lineOptions } from './helpers/lineOptions'
47
47
  import { handleLineType } from './helpers/handleLineType'
48
48
  import { handleRankByValue } from './helpers/handleRankByValue'
49
- import { generateColorsArray } from './helpers/generateColorsArray'
49
+ import { generateColorsArray } from '@cdc/core/helpers/generateColorsArray'
50
+ import { processMarkupVariables } from '@cdc/core/helpers/markupProcessor'
50
51
  import Loading from '@cdc/core/components/Loading'
51
52
  import Filters from '@cdc/core/components/Filters'
52
53
  import MediaControls from '@cdc/core/components/MediaControls'
@@ -63,7 +64,7 @@ import numberFromString from '@cdc/core/helpers/numberFromString'
63
64
  import getViewport from '@cdc/core/helpers/getViewport'
64
65
  import isNumber from '@cdc/core/helpers/isNumber'
65
66
  import coveUpdateWorker from '@cdc/core/helpers/coveUpdateWorker'
66
- import EditorContext from '../../editor/src/ConfigContext'
67
+ import EditorContext from '@cdc/core/contexts/EditorContext'
67
68
  import { EDITOR_WIDTH } from '@cdc/core/helpers/constants'
68
69
  import { extractCoveData, updateVegaData } from '@cdc/core/helpers/vegaConfig'
69
70
  // Local helpers
@@ -74,6 +75,7 @@ import { getExcludedData } from './helpers/getExcludedData'
74
75
  import { getColorScale } from './helpers/getColorScale'
75
76
  import { getTransformedData } from './helpers/getTransformedData'
76
77
  import { getPiePercent } from './helpers/getPiePercent'
78
+ import { prepareSmallMultiplesDataTable } from './helpers/smallMultiplesHelpers'
77
79
 
78
80
  // styles
79
81
  import './scss/main.scss'
@@ -83,6 +85,8 @@ import { getNewRuntime } from './helpers/getNewRuntime'
83
85
  import FootnotesStandAlone from '@cdc/core/components/Footnotes/FootnotesStandAlone'
84
86
  import { Datasets } from '@cdc/core/types/DataSet'
85
87
  import { publishAnalyticsEvent } from '@cdc/core/helpers/metrics/helpers'
88
+ import cloneConfig from '@cdc/core/helpers/cloneConfig'
89
+ import { getVizTitle, getVizSubType } from '@cdc/core/helpers/metrics/utils'
86
90
 
87
91
  interface CdcChartProps {
88
92
  config?: ChartConfig
@@ -152,6 +156,73 @@ const CdcChart: React.FC<CdcChartProps> = ({
152
156
  // Destructure items from config for more readable JSX
153
157
  let { legend, title } = config
154
158
 
159
+ // Process markup variables for text fields (memoized to prevent re-processing on every render)
160
+ // Note: XSS Safety - The processed content is parsed using html-react-parser which sanitizes
161
+ // HTML input by default. The markup processor returns plain text with user data substituted.
162
+ const processedTextFields = useMemo(() => {
163
+ if (!config.enableMarkupVariables || !config.markupVariables?.length) {
164
+ return {
165
+ title,
166
+ superTitle: config.superTitle,
167
+ introText: config.introText,
168
+ legacyFootnotes: config.legacyFootnotes,
169
+ description: config.description
170
+ }
171
+ }
172
+
173
+ return {
174
+ title: title
175
+ ? processMarkupVariables(title, config.data || [], config.markupVariables, {
176
+ isEditor,
177
+ filters: config.filters || []
178
+ }).processedContent
179
+ : title,
180
+ superTitle: config.superTitle
181
+ ? processMarkupVariables(config.superTitle, config.data || [], config.markupVariables, {
182
+ isEditor,
183
+ filters: config.filters || []
184
+ }).processedContent
185
+ : config.superTitle,
186
+ introText: config.introText
187
+ ? processMarkupVariables(config.introText, config.data || [], config.markupVariables, {
188
+ isEditor,
189
+ filters: config.filters || []
190
+ }).processedContent
191
+ : config.introText,
192
+ legacyFootnotes: config.legacyFootnotes
193
+ ? processMarkupVariables(config.legacyFootnotes, config.data || [], config.markupVariables, {
194
+ isEditor,
195
+ filters: config.filters || []
196
+ }).processedContent
197
+ : config.legacyFootnotes,
198
+ description: config.description
199
+ ? processMarkupVariables(config.description, config.data || [], config.markupVariables, {
200
+ isEditor,
201
+ filters: config.filters || []
202
+ }).processedContent
203
+ : config.description
204
+ }
205
+ }, [
206
+ config.enableMarkupVariables,
207
+ config.markupVariables,
208
+ config.data,
209
+ config.filters,
210
+ title,
211
+ config.superTitle,
212
+ config.introText,
213
+ config.legacyFootnotes,
214
+ config.description,
215
+ isEditor
216
+ ])
217
+
218
+ // Destructure processed values
219
+ title = processedTextFields.title
220
+ const processedSuperTitle = processedTextFields.superTitle
221
+ const processedIntroText = processedTextFields.introText
222
+ const processedLegacyFootnotes = processedTextFields.legacyFootnotes
223
+ const processedDescription = processedTextFields.description
224
+ // Note: Axis labels are processed within updateConfig to ensure they use the correct data
225
+
155
226
  // set defaults on titles if blank AND only in editor
156
227
  if (isEditor) {
157
228
  if (!title || title === '') title = 'Chart Title'
@@ -169,7 +240,22 @@ const CdcChart: React.FC<CdcChartProps> = ({
169
240
  const convertLineToBarGraph = isConvertLineToBarGraph(config, filteredData)
170
241
 
171
242
  const prepareConfig = (loadedConfig: ChartConfig) => {
172
- let newConfig = _.defaultsDeep(loadedConfig, defaults)
243
+ // Create defaults without version to avoid overriding legacy configs
244
+ const defaultsWithoutPalette = { ...defaults }
245
+
246
+ // Only remove palette defaults for legacy (v1) configs
247
+ // New configs and v2 configs should get the v2 palette defaults
248
+ if (loadedConfig?.general?.palette || (!loadedConfig?.general && !loadedConfig?.color)) {
249
+ // Keep palette defaults for:
250
+ // 1. Configs that already have general.palette (v2 configs)
251
+ // 2. New configs (no general section and no legacy color property)
252
+ } else {
253
+ // Remove palette defaults for legacy configs that have color but no general.palette
254
+ delete defaultsWithoutPalette.general?.palette
255
+ }
256
+
257
+ let newConfig = { ...defaultsWithoutPalette, ...loadedConfig }
258
+
173
259
  _.defaultsDeep(newConfig, {
174
260
  table: { showVertical: false }
175
261
  })
@@ -190,12 +276,63 @@ const CdcChart: React.FC<CdcChartProps> = ({
190
276
  return newConfig
191
277
  }
192
278
 
279
+ const getProcessedAxisLabels = useCallback(
280
+ (targetConfig: AllChartsConfig, dataSource: any[] = []) => {
281
+ let processedXAxis = targetConfig.xAxis?.label
282
+ let processedYAxis = targetConfig.yAxis?.label
283
+
284
+ if (targetConfig.enableMarkupVariables && targetConfig.markupVariables?.length) {
285
+ if (targetConfig.xAxis?.label) {
286
+ processedXAxis = processMarkupVariables(
287
+ targetConfig.xAxis.label,
288
+ dataSource || [],
289
+ targetConfig.markupVariables,
290
+ {
291
+ isEditor,
292
+ filters: targetConfig.filters || []
293
+ }
294
+ ).processedContent
295
+ }
296
+ if (targetConfig.yAxis?.label) {
297
+ processedYAxis = processMarkupVariables(
298
+ targetConfig.yAxis.label,
299
+ dataSource || [],
300
+ targetConfig.markupVariables,
301
+ {
302
+ isEditor,
303
+ filters: targetConfig.filters || []
304
+ }
305
+ ).processedContent
306
+ }
307
+ }
308
+
309
+ const isHorizontalVariant =
310
+ ((targetConfig.visualizationType === 'Bar' || targetConfig.visualizationType === 'Box Plot') &&
311
+ targetConfig.orientation === 'horizontal') ||
312
+ ['Deviation Bar', 'Paired Bar', 'Forest Plot'].includes(targetConfig.visualizationType)
313
+
314
+ const runtimeXAxisLabel = isHorizontalVariant
315
+ ? processedYAxis ?? (targetConfig.yAxis as any)?.yAxis?.label ?? targetConfig.yAxis?.label
316
+ : processedXAxis ?? targetConfig.xAxis?.label
317
+
318
+ const runtimeYAxisLabel = isHorizontalVariant
319
+ ? processedXAxis ?? (targetConfig.xAxis as any)?.xAxis?.label ?? targetConfig.xAxis?.label
320
+ : processedYAxis ?? targetConfig.yAxis?.label
321
+
322
+ return { processedXAxis, processedYAxis, runtimeXAxisLabel, runtimeYAxisLabel, isHorizontalVariant }
323
+ },
324
+ [isEditor]
325
+ )
326
+
193
327
  const updateConfig = (_config: AllChartsConfig, dataOverride?: any[]) => {
194
- const newConfig = _.cloneDeep(_config)
328
+ const newConfig = cloneConfig(_config)
195
329
  let data = dataOverride || stateData
196
330
 
197
331
  data = handleRankByValue(data, newConfig)
198
332
 
333
+ const { processedXAxis, processedYAxis, runtimeXAxisLabel, runtimeYAxisLabel, isHorizontalVariant } =
334
+ getProcessedAxisLabels(newConfig, data || [])
335
+
199
336
  // Deeper copy
200
337
  Object.keys(defaults).forEach(key => {
201
338
  if (newConfig[key] && 'object' === typeof newConfig[key] && !Array.isArray(newConfig[key])) {
@@ -219,6 +356,14 @@ const CdcChart: React.FC<CdcChartProps> = ({
219
356
  }
220
357
 
221
358
  //Enforce default values that need to be calculated at runtime
359
+ // Preserve error messages that were set outside of updateConfig (e.g., from pattern settings)
360
+ const existingErrorMessage = _config.runtime?.editorErrorMessage || ''
361
+ const isPieChartValidationError =
362
+ existingErrorMessage === 'Data column section must be set for pie charts.' ||
363
+ existingErrorMessage === 'Segment labels section must be set for pie charts.' ||
364
+ existingErrorMessage === 'Data column and Segment labels sections must be set for pie charts.'
365
+ const shouldPreserveError = existingErrorMessage && !isPieChartValidationError
366
+
222
367
  newConfig.runtime = {} as Runtime
223
368
  newConfig.runtime.series = _.cloneDeep(newConfig.series)
224
369
  newConfig.runtime.seriesLabels = {}
@@ -226,7 +371,9 @@ const CdcChart: React.FC<CdcChartProps> = ({
226
371
  newConfig.runtime.originalXAxis = newConfig.xAxis
227
372
 
228
373
  if (newConfig.visualizationType === 'Pie') {
229
- newConfig.runtime.seriesKeys = (dataOverride || data).map(d => d[newConfig.xAxis.dataKey])
374
+ // Use the same data that will be passed to PieChart (after exclusions and filters)
375
+ const pieData = currentData.length > 0 ? currentData : newExcludedData
376
+ newConfig.runtime.seriesKeys = _.uniq(pieData.map(d => d[newConfig.xAxis.dataKey]))
230
377
  newConfig.runtime.seriesLabelsAll = newConfig.runtime.seriesKeys
231
378
  } else {
232
379
  const finalData = dataOverride || newConfig.formattedData || newConfig.data
@@ -278,6 +425,18 @@ const CdcChart: React.FC<CdcChartProps> = ({
278
425
  newConfig.runtime.forecastingSeriesKeys.push(series)
279
426
  }
280
427
  })
428
+
429
+ // Default to date scaling type for Forecasting charts
430
+ if (newConfig.xAxis.type === 'categorical') {
431
+ newConfig.xAxis.type = 'date'
432
+ // Initialize date parsing formats if they don't exist
433
+ if (!newConfig.xAxis.dateParseFormat) {
434
+ newConfig.xAxis.dateParseFormat = '%Y-%m-%d'
435
+ }
436
+ if (!newConfig.xAxis.dateDisplayFormat) {
437
+ newConfig.xAxis.dateDisplayFormat = '%Y-%m-%d'
438
+ }
439
+ }
281
440
  }
282
441
 
283
442
  if (newConfig.visualizationType === 'Area Chart' && newConfig.series) {
@@ -289,13 +448,18 @@ const CdcChart: React.FC<CdcChartProps> = ({
289
448
  newConfig.visualizationSubType = 'stacked'
290
449
  }
291
450
 
292
- if (
293
- ((newConfig.visualizationType === 'Bar' || newConfig.visualizationType === 'Box Plot') &&
294
- newConfig.orientation === 'horizontal') ||
295
- ['Deviation Bar', 'Paired Bar', 'Forest Plot'].includes(newConfig.visualizationType)
296
- ) {
297
- newConfig.runtime.xAxis = _.cloneDeep(newConfig.yAxis.yAxis || newConfig.yAxis)
298
- newConfig.runtime.yAxis = _.cloneDeep(newConfig.xAxis.xAxis || newConfig.xAxis)
451
+ if (isHorizontalVariant) {
452
+ // For horizontal charts, axes are swapped, so processedYAxis goes to runtime.xAxis and vice versa
453
+ const horizontalXAxisSource = _.cloneDeep((newConfig.yAxis as any)?.yAxis || newConfig.yAxis)
454
+ const horizontalYAxisSource = _.cloneDeep((newConfig.xAxis as any)?.xAxis || newConfig.xAxis)
455
+ newConfig.runtime.xAxis = {
456
+ ...horizontalXAxisSource,
457
+ label: runtimeXAxisLabel ?? horizontalXAxisSource?.label
458
+ }
459
+ newConfig.runtime.yAxis = {
460
+ ...horizontalYAxisSource,
461
+ label: runtimeYAxisLabel ?? horizontalYAxisSource?.label
462
+ }
299
463
  newConfig.runtime.yAxis.labelOffset *= -1
300
464
 
301
465
  newConfig.runtime.horizontal = false
@@ -306,24 +470,40 @@ const CdcChart: React.FC<CdcChartProps> = ({
306
470
  ['Scatter Plot', 'Area Chart', 'Line', 'Forecasting'].includes(newConfig.visualizationType) &&
307
471
  !convertLineToBarGraph
308
472
  ) {
309
- newConfig.runtime.xAxis = newConfig.xAxis
310
- newConfig.runtime.yAxis = newConfig.yAxis
473
+ newConfig.runtime.xAxis = { ...newConfig.xAxis, label: runtimeXAxisLabel ?? newConfig.xAxis.label }
474
+ newConfig.runtime.yAxis = { ...newConfig.yAxis, label: runtimeYAxisLabel ?? newConfig.yAxis.label }
311
475
  newConfig.runtime.horizontal = false
312
476
  newConfig.orientation = 'vertical'
313
477
  } else {
314
- newConfig.runtime.xAxis = newConfig.xAxis
315
- newConfig.runtime.yAxis = newConfig.yAxis
478
+ newConfig.runtime.xAxis = { ...newConfig.xAxis, label: runtimeXAxisLabel ?? newConfig.xAxis.label }
479
+ newConfig.runtime.yAxis = { ...newConfig.yAxis, label: runtimeYAxisLabel ?? newConfig.yAxis.label }
316
480
  newConfig.runtime.horizontal = false
317
481
  }
318
482
 
319
483
  newConfig.runtime.uniqueId = Date.now()
320
- newConfig.runtime.editorErrorMessage =
321
- newConfig.visualizationType === 'Pie' && !newConfig.yAxis.dataKey
322
- ? 'Data Key property in Y Axis section must be set for pie charts.'
323
- : ''
324
484
 
325
- // Sankey Description box error message
326
- newConfig.runtime.editorErrorMessage = ''
485
+ // Set error messages: preserve external errors (from pattern settings, etc.) or set validation errors
486
+ if (shouldPreserveError) {
487
+ // Preserve error messages set by editor panels (e.g., pattern contrast errors)
488
+ newConfig.runtime.editorErrorMessage = existingErrorMessage
489
+ } else if (newConfig.visualizationType === 'Pie') {
490
+ // Check for Pie chart validation errors
491
+ const missingDataColumn = !newConfig.yAxis.dataKey || newConfig.yAxis.dataKey === ''
492
+ const missingSegmentLabels = !newConfig.xAxis.dataKey || newConfig.xAxis.dataKey === ''
493
+
494
+ if (missingDataColumn && missingSegmentLabels) {
495
+ newConfig.runtime.editorErrorMessage = 'Data column and Segment labels sections must be set for pie charts.'
496
+ } else if (missingDataColumn) {
497
+ newConfig.runtime.editorErrorMessage = 'Data column section must be set for pie charts.'
498
+ } else if (missingSegmentLabels) {
499
+ newConfig.runtime.editorErrorMessage = 'Segment labels section must be set for pie charts.'
500
+ } else {
501
+ newConfig.runtime.editorErrorMessage = ''
502
+ }
503
+ } else {
504
+ // No errors
505
+ newConfig.runtime.editorErrorMessage = ''
506
+ }
327
507
 
328
508
  if (newConfig.legend.seriesHighlight?.length) {
329
509
  dispatch({ type: 'SET_SERIES_HIGHLIGHT', payload: newConfig.legend?.seriesHighlight })
@@ -379,11 +559,13 @@ const CdcChart: React.FC<CdcChartProps> = ({
379
559
  for (let entry of entries) {
380
560
  let { width, height } = entry.contentRect
381
561
 
382
- width = isEditor ? width - EDITOR_WIDTH : width
562
+ const editorIsOpen = isEditor && !!document.querySelector('.editor-panel:not(.hidden)')
563
+ width = editorIsOpen ? width - EDITOR_WIDTH : width
383
564
 
384
565
  const newViewport = getViewport(width)
385
566
 
386
567
  dispatch({ type: 'SET_VIEWPORT', payload: newViewport })
568
+ dispatch({ type: 'SET_VIZ_VIEWPORT', payload: newViewport })
387
569
 
388
570
  if (entry.target.dataset.lollipop === 'true') {
389
571
  width = width - 2.5
@@ -429,8 +611,16 @@ const CdcChart: React.FC<CdcChartProps> = ({
429
611
  } else if (newConfig.formattedData) {
430
612
  newConfig.data = newConfig.formattedData
431
613
  } else if (newConfig.dataDescription) {
432
- newConfig.data = transform.autoStandardize(newConfig.data)
433
- newConfig.data = transform.developerStandardize(newConfig.data, newConfig.dataDescription)
614
+ // For dashboard contexts, get data from datasets if config.data is undefined
615
+ let dataToProcess = newConfig.data
616
+ if (!dataToProcess && isDashboard && datasets && newConfig.dataKey) {
617
+ dataToProcess = datasets[newConfig.dataKey]?.data
618
+ }
619
+
620
+ if (dataToProcess) {
621
+ newConfig.data = transform.autoStandardize(dataToProcess)
622
+ newConfig.data = transform.developerStandardize(newConfig.data, newConfig.dataDescription)
623
+ }
434
624
  }
435
625
  } catch (err) {
436
626
  console.error('Error on prepareData function ', err)
@@ -468,7 +658,6 @@ const CdcChart: React.FC<CdcChartProps> = ({
468
658
  if (container && !isLoading && !_.isEmpty(config) && !coveLoadedEventRan) {
469
659
  publish('cove_loaded', { config: config })
470
660
  dispatch({ type: 'SET_LOADED_EVENT', payload: true })
471
- publishAnalyticsEvent('chart_loaded', 'load', interactionLabel, 'chart')
472
661
  }
473
662
  }, [container, config, isLoading]) // eslint-disable-line
474
663
 
@@ -534,6 +723,49 @@ const CdcChart: React.FC<CdcChartProps> = ({
534
723
  }
535
724
  }, [config, stateData]) // eslint-disable-line
536
725
 
726
+ // Updates runtime axis labels when config or data changes when using markup variables
727
+ useEffect(() => {
728
+ if (
729
+ !config?.runtime ||
730
+ _.isEmpty(config.runtime) ||
731
+ (!config.runtime.xAxis && !config.runtime.yAxis) ||
732
+ !config.markupVariables?.length
733
+ ) {
734
+ return
735
+ }
736
+
737
+ const dataSource = (stateData && stateData.length ? stateData : config.data) || []
738
+ const { runtimeXAxisLabel, runtimeYAxisLabel, isHorizontalVariant } = getProcessedAxisLabels(config, dataSource)
739
+
740
+ const runtimeClone = _.cloneDeep(config.runtime)
741
+
742
+ if (!runtimeClone?.xAxis || !runtimeClone?.yAxis) {
743
+ return
744
+ }
745
+
746
+ let shouldUpdateLabels = false
747
+
748
+ if (typeof runtimeXAxisLabel !== 'undefined' && runtimeClone.xAxis.label !== runtimeXAxisLabel) {
749
+ runtimeClone.xAxis = { ...runtimeClone.xAxis, label: runtimeXAxisLabel }
750
+ shouldUpdateLabels = true
751
+ }
752
+
753
+ if (typeof runtimeYAxisLabel !== 'undefined' && runtimeClone.yAxis.label !== runtimeYAxisLabel) {
754
+ runtimeClone.yAxis = { ...runtimeClone.yAxis, label: runtimeYAxisLabel }
755
+ shouldUpdateLabels = true
756
+ }
757
+
758
+ if (shouldUpdateLabels) {
759
+ runtimeClone.uniqueId = Date.now()
760
+ const updatedConfig = { ...config, runtime: runtimeClone } as ChartConfig
761
+ dispatch({ type: 'SET_CONFIG', payload: updatedConfig })
762
+
763
+ if (isEditor && !isDashboard) {
764
+ editorContext.setTempConfig(updatedConfig)
765
+ }
766
+ }
767
+ }, [config, stateData, getProcessedAxisLabels, dispatch, editorContext, isEditor, isDashboard])
768
+
537
769
  // Called on legend click, highlights/unhighlights the data series with the given label
538
770
  const highlight = (label: Label): void => {
539
771
  if (
@@ -558,7 +790,17 @@ const CdcChart: React.FC<CdcChartProps> = ({
558
790
  } catch (e) {
559
791
  console.error('COVE:', e.message)
560
792
  }
561
- publishAnalyticsEvent('chart_legend_reset', 'click', interactionLabel, 'chart')
793
+ publishAnalyticsEvent({
794
+ vizType: config?.type,
795
+ vizSubType: getVizSubType(config),
796
+ eventType: 'chart_legend_reset',
797
+ eventAction: 'click',
798
+ eventLabel: interactionLabel,
799
+ vizTitle: getVizTitle(config),
800
+ ...(config.visualizationType === 'Bar' && {
801
+ specifics: `orientation: ${config.orientation === 'horizontal' ? 'horizontal' : 'vertical'}`
802
+ })
803
+ })
562
804
  dispatch({ type: 'SET_SERIES_HIGHLIGHT', payload: [] })
563
805
  }
564
806
 
@@ -639,7 +881,8 @@ const CdcChart: React.FC<CdcChartProps> = ({
639
881
  rightSuffix,
640
882
  bottomPrefix,
641
883
  bottomSuffix,
642
- bottomAbbreviated
884
+ bottomAbbreviated,
885
+ preserveOriginalDecimals
643
886
  }
644
887
  } = config
645
888
 
@@ -658,32 +901,52 @@ const CdcChart: React.FC<CdcChartProps> = ({
658
901
  } else {
659
902
  roundToPlace = roundTo ? Number(roundTo) : 0
660
903
  }
661
- stringFormattingOptions = {
662
- useGrouping: addColRoundTo ? true : config.dataFormat.commas ? true : false,
663
- minimumFractionDigits: roundToPlace,
664
- maximumFractionDigits: roundToPlace
904
+
905
+ // If preserveOriginalDecimals is enabled, don't force decimal places
906
+ if (preserveOriginalDecimals) {
907
+ stringFormattingOptions = {
908
+ useGrouping: addColRoundTo ? true : config.dataFormat.commas ? true : false
909
+ }
910
+ } else {
911
+ stringFormattingOptions = {
912
+ useGrouping: addColRoundTo ? true : config.dataFormat.commas ? true : false,
913
+ minimumFractionDigits: roundToPlace,
914
+ maximumFractionDigits: roundToPlace
915
+ }
665
916
  }
666
917
  }
667
918
 
668
919
  if (axis === 'right') {
669
- stringFormattingOptions = {
670
- useGrouping: config.dataFormat.rightCommas ? true : false,
671
- minimumFractionDigits: rightRoundTo ? Number(rightRoundTo) : 0,
672
- maximumFractionDigits: rightRoundTo ? Number(rightRoundTo) : 0
920
+ if (preserveOriginalDecimals) {
921
+ stringFormattingOptions = {
922
+ useGrouping: config.dataFormat.rightCommas ? true : false
923
+ }
924
+ } else {
925
+ stringFormattingOptions = {
926
+ useGrouping: config.dataFormat.rightCommas ? true : false,
927
+ minimumFractionDigits: rightRoundTo ? Number(rightRoundTo) : 0,
928
+ maximumFractionDigits: rightRoundTo ? Number(rightRoundTo) : 0
929
+ }
673
930
  }
674
931
  }
675
932
 
676
933
  const resolveBottomTickRounding = () => {
677
- if (config.forestPlot.type === 'Logarithmic' && !bottomRoundTo) return 2
934
+ if (config.forestPlot?.type === 'Logarithmic' && !bottomRoundTo) return 2
678
935
  if (Number(bottomRoundTo)) return Number(bottomRoundTo)
679
936
  return 0
680
937
  }
681
938
 
682
939
  if (axis === 'bottom') {
683
- stringFormattingOptions = {
684
- useGrouping: config.dataFormat.bottomCommas ? true : false,
685
- minimumFractionDigits: resolveBottomTickRounding(),
686
- maximumFractionDigits: resolveBottomTickRounding()
940
+ if (preserveOriginalDecimals) {
941
+ stringFormattingOptions = {
942
+ useGrouping: config.dataFormat.bottomCommas ? true : false
943
+ }
944
+ } else {
945
+ stringFormattingOptions = {
946
+ useGrouping: config.dataFormat.bottomCommas ? true : false,
947
+ minimumFractionDigits: resolveBottomTickRounding(),
948
+ maximumFractionDigits: resolveBottomTickRounding()
949
+ }
687
950
  }
688
951
  }
689
952
 
@@ -821,7 +1084,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
821
1084
  }
822
1085
 
823
1086
  const pivotDynamicSeries = (config: ChartConfig): TableConfig => {
824
- const tableConfig: TableConfig = _.cloneDeep(config)
1087
+ const tableConfig: TableConfig = cloneConfig(config)
825
1088
  const dynamicSeries = tableConfig.series.find(series => !!series.dynamicCategory)
826
1089
  if (dynamicSeries) {
827
1090
  const pivot: Pivot = { columnName: dynamicSeries.dynamicCategory, valueColumns: [dynamicSeries.dataKey] }
@@ -878,9 +1141,6 @@ const CdcChart: React.FC<CdcChartProps> = ({
878
1141
  {isEditor && <EditorPanel datasets={datasets} />}
879
1142
  <Layout.Responsive isEditor={isEditor}>
880
1143
  {config.newViz && <Confirm updateConfig={updateConfig} config={config} />}
881
- {undefined === config.newViz && isEditor && config.runtime && config.runtime?.editorErrorMessage && (
882
- <Error errorMessage={config.runtime.editorErrorMessage} />
883
- )}
884
1144
  {!missingRequiredSections(config) && !config.newViz && (
885
1145
  <div
886
1146
  className={`cdc-chart-inner-container cove-component__content type-${makeClassName(
@@ -893,16 +1153,25 @@ const CdcChart: React.FC<CdcChartProps> = ({
893
1153
  showTitle={config.showTitle}
894
1154
  isDashboard={isDashboard}
895
1155
  title={title}
896
- superTitle={config.superTitle}
1156
+ superTitle={processedSuperTitle}
897
1157
  classes={['chart-title', `${config.theme}`, 'cove-component__header', 'mb-3']}
898
1158
  style={undefined}
1159
+ config={config}
899
1160
  />
900
1161
 
1162
+ {/* Error Message Display - Show at top before visualization wrapper */}
1163
+ {/* {(() => {
1164
+ const errorMessage = config.runtime?.editorErrorMessage
1165
+ const hasError = errorMessage && typeof errorMessage === 'string' && errorMessage.trim() !== ''
1166
+ const shouldShow = undefined === config.newViz && isEditor && config.runtime && hasError
1167
+ return shouldShow ? <Error errorMessage={errorMessage} /> : null
1168
+ })()} */}
1169
+
901
1170
  {/* Visualization Wrapper */}
902
1171
  <div className={getChartWrapperClasses().join(' ')}>
903
1172
  {/* Intro Text/Message */}
904
- {config?.introText && config.visualizationType !== 'Spark Line' && (
905
- <section className={`introText mb-4`}>{parse(config.introText)}</section>
1173
+ {processedIntroText && config.visualizationType !== 'Spark Line' && (
1174
+ <section className={`introText mb-4`}>{parse(processedIntroText)}</section>
906
1175
  )}
907
1176
 
908
1177
  {/* Filters */}
@@ -936,24 +1205,42 @@ const CdcChart: React.FC<CdcChartProps> = ({
936
1205
  : 'w-75'
937
1206
  }
938
1207
  >
939
- {/* All charts with LinearChart */}
940
- {!['Spark Line', 'Line', 'Sankey', 'Pie', 'Sankey'].includes(config.visualizationType) && (
941
- <div ref={parentRef} style={{ width: `100%` }}>
942
- <ParentSize>
943
- {parent => (
944
- <LinearChart ref={svgRef} parentWidth={parent.width} parentHeight={parent.height} />
945
- )}
946
- </ParentSize>
1208
+ {/* Check if there is data to display */}
1209
+ {(!filteredData || filteredData.length === 0) && (
1210
+ <div className='no-data-message' style={{ padding: '2rem', textAlign: 'center', color: '#666' }}>
1211
+ {config.chartMessage?.noData || 'No Data Available'}
947
1212
  </div>
948
1213
  )}
949
1214
 
950
- {config.visualizationType === 'Pie' && (
1215
+ {/* All charts with LinearChart */}
1216
+ {filteredData &&
1217
+ filteredData.length > 0 &&
1218
+ !['Spark Line', 'Line', 'Sankey', 'Pie', 'Sankey'].includes(config.visualizationType) && (
1219
+ <div ref={parentRef} style={{ width: `100%` }}>
1220
+ <ParentSize>
1221
+ {parent => (
1222
+ <LinearChart ref={svgRef} parentWidth={parent.width} parentHeight={parent.height} />
1223
+ )}
1224
+ </ParentSize>
1225
+ </div>
1226
+ )}
1227
+
1228
+ {filteredData && filteredData.length > 0 && config.visualizationType === 'Pie' && (
951
1229
  <ParentSize className='justify-content-center d-flex' style={{ width: `100%` }}>
952
- {parent => <PieChart ref={svgRef} parentWidth={parent.width} parentHeight={parent.height} />}
1230
+ {parent => (
1231
+ <PieChart
1232
+ ref={svgRef}
1233
+ parentWidth={parent.width}
1234
+ parentHeight={parent.height}
1235
+ interactionLabel={interactionLabel}
1236
+ />
1237
+ )}
953
1238
  </ParentSize>
954
1239
  )}
955
1240
  {/* Line Chart */}
956
- {config.visualizationType === 'Line' &&
1241
+ {filteredData &&
1242
+ filteredData.length > 0 &&
1243
+ config.visualizationType === 'Line' &&
957
1244
  (convertLineToBarGraph ? (
958
1245
  <div ref={parentRef} style={{ width: `100%` }}>
959
1246
  <ParentSize>
@@ -993,9 +1280,9 @@ const CdcChart: React.FC<CdcChartProps> = ({
993
1280
  dimensions={dimensions}
994
1281
  interactionLabel={interactionLabel}
995
1282
  />
996
- {config?.introText && (
1283
+ {processedIntroText && (
997
1284
  <section className='introText mb-4' style={{ padding: '0px 0 35px' }}>
998
- {parse(config.introText)}
1285
+ {parse(processedIntroText)}
999
1286
  </section>
1000
1287
  )}
1001
1288
  <div style={{ height: `100px`, width: `100%`, ...sparkLineStyles }}>
@@ -1032,8 +1319,8 @@ const CdcChart: React.FC<CdcChartProps> = ({
1032
1319
  : link && link}
1033
1320
  {/* Description */}
1034
1321
 
1035
- {config.description && config.visualizationType !== 'Spark Line' && (
1036
- <div className={getChartSubTextClasses().join(' ')}>{parse(config.description)}</div>
1322
+ {processedDescription && config.visualizationType !== 'Spark Line' && (
1323
+ <div className={getChartSubTextClasses().join(' ')}>{parse(processedDescription)}</div>
1037
1324
  )}
1038
1325
 
1039
1326
  {/* buttons */}
@@ -1064,43 +1351,63 @@ const CdcChart: React.FC<CdcChartProps> = ({
1064
1351
  config.table.show &&
1065
1352
  config.visualizationType !== 'Spark Line' &&
1066
1353
  config.visualizationType !== 'Sankey') ||
1067
- (config.visualizationType === 'Sankey' && config.table.show)) && (
1068
- <DataTable
1069
- /* changing the "key" will force the table to re-render
1070
- when the default sort changes while editing */
1071
- key={dataTableDefaultSortBy}
1072
- config={pivotDynamicSeries(config)}
1073
- rawData={
1354
+ (config.visualizationType === 'Sankey' && config.table.show)) &&
1355
+ (() => {
1356
+ let dataTableConfig = pivotDynamicSeries(config)
1357
+ let dataTableColumns = config.columns
1358
+ let dataTableRuntimeData = getTableRuntimeData()
1359
+ let dataTableRawData =
1074
1360
  config.visualizationType === 'Sankey'
1075
1361
  ? config?.data?.[0]?.tableData
1076
1362
  : config.table.customTableConfig
1077
1363
  ? filterVizData(config.filters, config.data)
1078
1364
  : config.data
1365
+
1366
+ if (config.smallMultiples?.mode) {
1367
+ const prepared = prepareSmallMultiplesDataTable(config, config.columns, dataTableRuntimeData)
1368
+ dataTableConfig = prepared.config
1369
+ dataTableColumns = prepared.columns
1370
+ dataTableRuntimeData = prepared.runtimeData
1371
+ if (config.smallMultiples.mode === 'by-column') {
1372
+ dataTableRawData = prepared.config.data
1373
+ }
1079
1374
  }
1080
- runtimeData={getTableRuntimeData()}
1081
- expandDataTable={config.table.expanded}
1082
- columns={config.columns}
1083
- defaultSortBy={dataTableDefaultSortBy}
1084
- displayGeoName={name => name}
1085
- applyLegendToRow={applyLegendToRow}
1086
- tableTitle={config.table.label}
1087
- indexTitle={config.table.indexLabel}
1088
- vizTitle={title}
1089
- viewport={currentViewport}
1090
- tabbingId={handleChartTabbing(config, legendId)}
1091
- colorScale={colorScale}
1092
- interactionLabel={interactionLabel}
1093
- />
1094
- )}
1375
+
1376
+ return (
1377
+ <DataTable
1378
+ /* changing the "key" will force the table to re-render
1379
+ when the default sort changes while editing */
1380
+ key={dataTableDefaultSortBy}
1381
+ config={dataTableConfig}
1382
+ rawData={dataTableRawData}
1383
+ runtimeData={dataTableRuntimeData}
1384
+ expandDataTable={config.table.expanded}
1385
+ columns={dataTableColumns}
1386
+ defaultSortBy={dataTableDefaultSortBy}
1387
+ displayGeoName={name => name}
1388
+ applyLegendToRow={applyLegendToRow}
1389
+ tableTitle={config.table.label}
1390
+ indexTitle={config.table.indexLabel}
1391
+ vizTitle={title}
1392
+ viewport={currentViewport}
1393
+ tabbingId={handleChartTabbing(config, legendId)}
1394
+ colorScale={colorScale}
1395
+ interactionLabel={interactionLabel}
1396
+ />
1397
+ )
1398
+ })()}
1095
1399
  {config?.annotations?.length > 0 && <Annotation.Dropdown />}
1096
1400
  {/* show pdf or image button */}
1097
- {config?.legacyFootnotes && (
1098
- <section className='footnotes pt-2 mt-4'>{parse(config.legacyFootnotes)}</section>
1401
+ {processedLegacyFootnotes && (
1402
+ <section className='footnotes pt-2 mt-4'>{parse(processedLegacyFootnotes)}</section>
1099
1403
  )}
1100
1404
  </div>
1101
1405
  <FootnotesStandAlone
1102
1406
  config={configObj.footnotes}
1103
1407
  filters={config.filters?.filter(f => f.filterFootnotes)}
1408
+ markupVariables={config.markupVariables}
1409
+ enableMarkupVariables={config.enableMarkupVariables}
1410
+ data={config.data}
1104
1411
  />
1105
1412
  </div>
1106
1413
  )}
@@ -1119,6 +1426,9 @@ const CdcChart: React.FC<CdcChartProps> = ({
1119
1426
  return str.charAt(0).toUpperCase() + str.slice(1)
1120
1427
  }
1121
1428
 
1429
+ // Get version-specific color palettes based on current config
1430
+ const colorPalettes = filterChartColorPalettes(config)
1431
+
1122
1432
  const contextValues = {
1123
1433
  ...state,
1124
1434
  capitalize,
@@ -1137,6 +1447,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
1137
1447
  handleChartTabbing,
1138
1448
  highlight,
1139
1449
  handleShowAll,
1450
+ interactionLabel,
1140
1451
  isDashboard,
1141
1452
  isDebug,
1142
1453
  handleDragStateChange,
@@ -1150,7 +1461,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
1150
1461
  outerContainerRef,
1151
1462
  parentRef,
1152
1463
  parseDate,
1153
- rawData: _.cloneDeep(stateData) ?? {},
1464
+ rawData: stateData ?? {},
1154
1465
  setConfig,
1155
1466
  setEditing,
1156
1467
  setParentConfig,
@@ -1160,7 +1471,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
1160
1471
  tableData: filteredData || excludedData,
1161
1472
  transformedData: getTransformedData({ brushData: state.brushData, filteredData, excludedData, clean }),
1162
1473
  twoColorPalette,
1163
- unfilteredData: _.cloneDeep(stateData),
1474
+ unfilteredData: stateData,
1164
1475
  updateConfig
1165
1476
  }
1166
1477