@cdc/chart 4.25.8 → 4.25.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 (89) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/dist/cdcchart.js +37524 -35243
  3. package/examples/feature/__data__/planet-example-data.json +0 -30
  4. package/examples/grouped-bar-test.json +400 -0
  5. package/examples/private/d.json +382 -0
  6. package/examples/private/example-2.json +49784 -0
  7. package/examples/private/f2.json +1 -0
  8. package/examples/private/f4.json +1577 -0
  9. package/examples/private/forecast.json +1180 -0
  10. package/examples/private/lollipop.json +468 -0
  11. package/examples/private/new.json +48756 -0
  12. package/examples/private/pie-chart-legend.json +904 -0
  13. package/examples/suppressed_tooltip.json +480 -0
  14. package/index.html +10 -22
  15. package/package.json +25 -7
  16. package/src/CdcChart.tsx +1 -2
  17. package/src/CdcChartComponent.tsx +174 -32
  18. package/src/_stories/Chart.Anchors.stories.tsx +2 -2
  19. package/src/_stories/Chart.BoxPlot.stories.tsx +1 -1
  20. package/src/_stories/Chart.CI.stories.tsx +1 -1
  21. package/src/_stories/Chart.CustomColors.stories.tsx +1 -1
  22. package/src/_stories/Chart.DynamicSeries.stories.tsx +2 -2
  23. package/src/_stories/Chart.Filters.stories.tsx +2 -2
  24. package/src/_stories/Chart.Legend.Gradient.stories.tsx +2 -2
  25. package/src/_stories/Chart.Patterns.stories.tsx +19 -0
  26. package/src/_stories/Chart.ScatterPlot.stories.tsx +1 -1
  27. package/src/_stories/Chart.stories.tsx +8 -5
  28. package/src/_stories/Chart.tooltip.stories.tsx +1 -1
  29. package/src/_stories/ChartAnnotation.stories.tsx +1 -1
  30. package/src/_stories/ChartAxisLabels.stories.tsx +2 -2
  31. package/src/_stories/ChartAxisTitles.stories.tsx +2 -2
  32. package/src/_stories/ChartEditor.stories.tsx +60 -60
  33. package/src/_stories/ChartLine.Suppression.stories.tsx +1 -1
  34. package/src/_stories/ChartLine.Symbols.stories.tsx +1 -1
  35. package/src/_stories/ChartPrefixSuffix.stories.tsx +2 -2
  36. package/src/_stories/_mock/stacked-pattern-test.json +520 -0
  37. package/src/components/Annotations/components/AnnotationDraggable.tsx +1 -0
  38. package/src/components/Annotations/components/AnnotationDropdown.tsx +1 -1
  39. package/src/components/BarChart/components/BarChart.Horizontal.tsx +159 -20
  40. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +138 -5
  41. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +215 -73
  42. package/src/components/BarChart/components/BarChart.Vertical.tsx +153 -21
  43. package/src/components/BarChart/helpers/index.ts +43 -4
  44. package/src/components/BarChart/helpers/lollipopColors.ts +27 -0
  45. package/src/components/BarChart/helpers/useBarChart.ts +25 -3
  46. package/src/components/BoxPlot/BoxPlot.Vertical.tsx +2 -1
  47. package/src/components/DeviationBar.jsx +9 -6
  48. package/src/components/EditorPanel/EditorPanel.tsx +364 -39
  49. package/src/components/EditorPanel/EditorPanelContext.ts +3 -0
  50. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +414 -0
  51. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +28 -20
  52. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +115 -120
  53. package/src/components/EditorPanel/components/Panels/index.tsx +3 -1
  54. package/src/components/EditorPanel/components/Panels/panelVisual.styles.css +0 -8
  55. package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +49 -48
  56. package/src/components/Forecasting/Forecasting.tsx +36 -6
  57. package/src/components/ForestPlot/ForestPlot.tsx +11 -7
  58. package/src/components/ForestPlot/ForestPlotProps.ts +1 -1
  59. package/src/components/Legend/Legend.Component.tsx +106 -13
  60. package/src/components/Legend/helpers/createFormatLabels.tsx +230 -171
  61. package/src/components/LegendWrapper.tsx +1 -1
  62. package/src/components/LineChart/components/LineChart.Circle.tsx +2 -2
  63. package/src/components/LineChart/index.tsx +2 -2
  64. package/src/components/LinearChart.tsx +22 -5
  65. package/src/components/PairedBarChart.jsx +6 -4
  66. package/src/components/PieChart/PieChart.tsx +170 -54
  67. package/src/components/Sankey/components/Sankey.tsx +7 -1
  68. package/src/components/ScatterPlot/ScatterPlot.jsx +32 -4
  69. package/src/data/initial-state.js +315 -293
  70. package/src/helpers/buildForecastPaletteMappings.ts +112 -0
  71. package/src/helpers/buildForecastPaletteOptions.ts +109 -0
  72. package/src/helpers/getColorScale.ts +72 -8
  73. package/src/helpers/getNewRuntime.ts +1 -1
  74. package/src/helpers/getTransformedData.ts +1 -1
  75. package/src/hooks/useChartHoverAnalytics.tsx +44 -0
  76. package/src/hooks/useReduceData.ts +105 -70
  77. package/src/hooks/useTooltip.tsx +57 -15
  78. package/src/index.jsx +0 -2
  79. package/src/scss/main.scss +12 -0
  80. package/src/store/chart.reducer.ts +1 -1
  81. package/src/test/CdcChart.test.jsx +8 -3
  82. package/src/types/ChartConfig.ts +30 -6
  83. package/src/types/ChartContext.ts +1 -0
  84. package/vite.config.js +1 -1
  85. package/vitest.config.ts +16 -0
  86. package/src/coreStyles_chart.scss +0 -3
  87. package/src/helpers/configHelpers.ts +0 -28
  88. package/src/helpers/generateColorsArray.ts +0 -8
  89. 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
@@ -83,6 +84,8 @@ import { getNewRuntime } from './helpers/getNewRuntime'
83
84
  import FootnotesStandAlone from '@cdc/core/components/Footnotes/FootnotesStandAlone'
84
85
  import { Datasets } from '@cdc/core/types/DataSet'
85
86
  import { publishAnalyticsEvent } from '@cdc/core/helpers/metrics/helpers'
87
+ import cloneConfig from '@cdc/core/helpers/cloneConfig'
88
+ import { getVizTitle, getVizSubType } from '@cdc/core/helpers/metrics/utils'
86
89
 
87
90
  interface CdcChartProps {
88
91
  config?: ChartConfig
@@ -152,6 +155,73 @@ const CdcChart: React.FC<CdcChartProps> = ({
152
155
  // Destructure items from config for more readable JSX
153
156
  let { legend, title } = config
154
157
 
158
+ // Process markup variables for text fields (memoized to prevent re-processing on every render)
159
+ // Note: XSS Safety - The processed content is parsed using html-react-parser which sanitizes
160
+ // HTML input by default. The markup processor returns plain text with user data substituted.
161
+ const processedTextFields = useMemo(() => {
162
+ if (!config.enableMarkupVariables || !config.markupVariables?.length) {
163
+ return {
164
+ title,
165
+ superTitle: config.superTitle,
166
+ introText: config.introText,
167
+ legacyFootnotes: config.legacyFootnotes,
168
+ description: config.description
169
+ }
170
+ }
171
+
172
+ return {
173
+ title: title
174
+ ? processMarkupVariables(title, config.data || [], config.markupVariables, {
175
+ isEditor,
176
+ filters: config.filters || []
177
+ }).processedContent
178
+ : title,
179
+ superTitle: config.superTitle
180
+ ? processMarkupVariables(config.superTitle, config.data || [], config.markupVariables, {
181
+ isEditor,
182
+ filters: config.filters || []
183
+ }).processedContent
184
+ : config.superTitle,
185
+ introText: config.introText
186
+ ? processMarkupVariables(config.introText, config.data || [], config.markupVariables, {
187
+ isEditor,
188
+ filters: config.filters || []
189
+ }).processedContent
190
+ : config.introText,
191
+ legacyFootnotes: config.legacyFootnotes
192
+ ? processMarkupVariables(config.legacyFootnotes, config.data || [], config.markupVariables, {
193
+ isEditor,
194
+ filters: config.filters || []
195
+ }).processedContent
196
+ : config.legacyFootnotes,
197
+ description: config.description
198
+ ? processMarkupVariables(config.description, config.data || [], config.markupVariables, {
199
+ isEditor,
200
+ filters: config.filters || []
201
+ }).processedContent
202
+ : config.description
203
+ }
204
+ }, [
205
+ config.enableMarkupVariables,
206
+ config.markupVariables,
207
+ config.data,
208
+ config.filters,
209
+ title,
210
+ config.superTitle,
211
+ config.introText,
212
+ config.legacyFootnotes,
213
+ config.description,
214
+ isEditor
215
+ ])
216
+
217
+ // Destructure processed values
218
+ title = processedTextFields.title
219
+ const processedSuperTitle = processedTextFields.superTitle
220
+ const processedIntroText = processedTextFields.introText
221
+ const processedLegacyFootnotes = processedTextFields.legacyFootnotes
222
+ const processedDescription = processedTextFields.description
223
+ // Note: Axis labels are processed within updateConfig to ensure they use the correct data
224
+
155
225
  // set defaults on titles if blank AND only in editor
156
226
  if (isEditor) {
157
227
  if (!title || title === '') title = 'Chart Title'
@@ -169,7 +239,22 @@ const CdcChart: React.FC<CdcChartProps> = ({
169
239
  const convertLineToBarGraph = isConvertLineToBarGraph(config, filteredData)
170
240
 
171
241
  const prepareConfig = (loadedConfig: ChartConfig) => {
172
- let newConfig = _.defaultsDeep(loadedConfig, defaults)
242
+ // Create defaults without version to avoid overriding legacy configs
243
+ const defaultsWithoutPalette = { ...defaults }
244
+
245
+ // Only remove palette defaults for legacy (v1) configs
246
+ // New configs and v2 configs should get the v2 palette defaults
247
+ if (loadedConfig?.general?.palette || (!loadedConfig?.general && !loadedConfig?.color)) {
248
+ // Keep palette defaults for:
249
+ // 1. Configs that already have general.palette (v2 configs)
250
+ // 2. New configs (no general section and no legacy color property)
251
+ } else {
252
+ // Remove palette defaults for legacy configs that have color but no general.palette
253
+ delete defaultsWithoutPalette.general?.palette
254
+ }
255
+
256
+ let newConfig = { ...defaultsWithoutPalette, ...loadedConfig }
257
+
173
258
  _.defaultsDeep(newConfig, {
174
259
  table: { showVertical: false }
175
260
  })
@@ -191,11 +276,30 @@ const CdcChart: React.FC<CdcChartProps> = ({
191
276
  }
192
277
 
193
278
  const updateConfig = (_config: AllChartsConfig, dataOverride?: any[]) => {
194
- const newConfig = _.cloneDeep(_config)
279
+ const newConfig = cloneConfig(_config)
195
280
  let data = dataOverride || stateData
196
281
 
197
282
  data = handleRankByValue(data, newConfig)
198
283
 
284
+ // Process axis labels for markup variables if enabled
285
+ let processedXAxis = newConfig.xAxis?.label
286
+ let processedYAxis = newConfig.yAxis?.label
287
+
288
+ if (newConfig.enableMarkupVariables && newConfig.markupVariables?.length) {
289
+ if (newConfig.xAxis?.label) {
290
+ processedXAxis = processMarkupVariables(newConfig.xAxis.label, data || [], newConfig.markupVariables, {
291
+ isEditor,
292
+ filters: newConfig.filters || []
293
+ }).processedContent
294
+ }
295
+ if (newConfig.yAxis?.label) {
296
+ processedYAxis = processMarkupVariables(newConfig.yAxis.label, data || [], newConfig.markupVariables, {
297
+ isEditor,
298
+ filters: newConfig.filters || []
299
+ }).processedContent
300
+ }
301
+ }
302
+
199
303
  // Deeper copy
200
304
  Object.keys(defaults).forEach(key => {
201
305
  if (newConfig[key] && 'object' === typeof newConfig[key] && !Array.isArray(newConfig[key])) {
@@ -226,7 +330,9 @@ const CdcChart: React.FC<CdcChartProps> = ({
226
330
  newConfig.runtime.originalXAxis = newConfig.xAxis
227
331
 
228
332
  if (newConfig.visualizationType === 'Pie') {
229
- newConfig.runtime.seriesKeys = (dataOverride || data).map(d => d[newConfig.xAxis.dataKey])
333
+ // Use the same data that will be passed to PieChart (after exclusions and filters)
334
+ const pieData = currentData.length > 0 ? currentData : newExcludedData
335
+ newConfig.runtime.seriesKeys = _.uniq(pieData.map(d => d[newConfig.xAxis.dataKey]))
230
336
  newConfig.runtime.seriesLabelsAll = newConfig.runtime.seriesKeys
231
337
  } else {
232
338
  const finalData = dataOverride || newConfig.formattedData || newConfig.data
@@ -294,8 +400,15 @@ const CdcChart: React.FC<CdcChartProps> = ({
294
400
  newConfig.orientation === 'horizontal') ||
295
401
  ['Deviation Bar', 'Paired Bar', 'Forest Plot'].includes(newConfig.visualizationType)
296
402
  ) {
297
- newConfig.runtime.xAxis = _.cloneDeep(newConfig.yAxis.yAxis || newConfig.yAxis)
298
- newConfig.runtime.yAxis = _.cloneDeep(newConfig.xAxis.xAxis || newConfig.xAxis)
403
+ // For horizontal charts, axes are swapped, so processedYAxis goes to runtime.xAxis and vice versa
404
+ newConfig.runtime.xAxis = {
405
+ ..._.cloneDeep(newConfig.yAxis.yAxis || newConfig.yAxis),
406
+ label: processedYAxis || (newConfig.yAxis.yAxis || newConfig.yAxis).label
407
+ }
408
+ newConfig.runtime.yAxis = {
409
+ ..._.cloneDeep(newConfig.xAxis.xAxis || newConfig.xAxis),
410
+ label: processedXAxis || (newConfig.xAxis.xAxis || newConfig.xAxis).label
411
+ }
299
412
  newConfig.runtime.yAxis.labelOffset *= -1
300
413
 
301
414
  newConfig.runtime.horizontal = false
@@ -306,13 +419,13 @@ const CdcChart: React.FC<CdcChartProps> = ({
306
419
  ['Scatter Plot', 'Area Chart', 'Line', 'Forecasting'].includes(newConfig.visualizationType) &&
307
420
  !convertLineToBarGraph
308
421
  ) {
309
- newConfig.runtime.xAxis = newConfig.xAxis
310
- newConfig.runtime.yAxis = newConfig.yAxis
422
+ newConfig.runtime.xAxis = { ...newConfig.xAxis, label: processedXAxis || newConfig.xAxis.label }
423
+ newConfig.runtime.yAxis = { ...newConfig.yAxis, label: processedYAxis || newConfig.yAxis.label }
311
424
  newConfig.runtime.horizontal = false
312
425
  newConfig.orientation = 'vertical'
313
426
  } else {
314
- newConfig.runtime.xAxis = newConfig.xAxis
315
- newConfig.runtime.yAxis = newConfig.yAxis
427
+ newConfig.runtime.xAxis = { ...newConfig.xAxis, label: processedXAxis || newConfig.xAxis.label }
428
+ newConfig.runtime.yAxis = { ...newConfig.yAxis, label: processedYAxis || newConfig.yAxis.label }
316
429
  newConfig.runtime.horizontal = false
317
430
  }
318
431
 
@@ -429,8 +542,16 @@ const CdcChart: React.FC<CdcChartProps> = ({
429
542
  } else if (newConfig.formattedData) {
430
543
  newConfig.data = newConfig.formattedData
431
544
  } else if (newConfig.dataDescription) {
432
- newConfig.data = transform.autoStandardize(newConfig.data)
433
- newConfig.data = transform.developerStandardize(newConfig.data, newConfig.dataDescription)
545
+ // For dashboard contexts, get data from datasets if config.data is undefined
546
+ let dataToProcess = newConfig.data
547
+ if (!dataToProcess && isDashboard && datasets && newConfig.dataKey) {
548
+ dataToProcess = datasets[newConfig.dataKey]?.data
549
+ }
550
+
551
+ if (dataToProcess) {
552
+ newConfig.data = transform.autoStandardize(dataToProcess)
553
+ newConfig.data = transform.developerStandardize(newConfig.data, newConfig.dataDescription)
554
+ }
434
555
  }
435
556
  } catch (err) {
436
557
  console.error('Error on prepareData function ', err)
@@ -468,7 +589,6 @@ const CdcChart: React.FC<CdcChartProps> = ({
468
589
  if (container && !isLoading && !_.isEmpty(config) && !coveLoadedEventRan) {
469
590
  publish('cove_loaded', { config: config })
470
591
  dispatch({ type: 'SET_LOADED_EVENT', payload: true })
471
- publishAnalyticsEvent('chart_loaded', 'load', interactionLabel, 'chart')
472
592
  }
473
593
  }, [container, config, isLoading]) // eslint-disable-line
474
594
 
@@ -558,7 +678,17 @@ const CdcChart: React.FC<CdcChartProps> = ({
558
678
  } catch (e) {
559
679
  console.error('COVE:', e.message)
560
680
  }
561
- publishAnalyticsEvent('chart_legend_reset', 'click', interactionLabel, 'chart')
681
+ publishAnalyticsEvent({
682
+ vizType: config?.type,
683
+ vizSubType: getVizSubType(config),
684
+ eventType: 'chart_legend_reset',
685
+ eventAction: 'click',
686
+ eventLabel: interactionLabel,
687
+ vizTitle: getVizTitle(config),
688
+ ...(config.visualizationType === 'Bar' && {
689
+ specifics: `orientation: ${config.orientation === 'horizontal' ? 'horizontal' : 'vertical'}`
690
+ })
691
+ })
562
692
  dispatch({ type: 'SET_SERIES_HIGHLIGHT', payload: [] })
563
693
  }
564
694
 
@@ -821,7 +951,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
821
951
  }
822
952
 
823
953
  const pivotDynamicSeries = (config: ChartConfig): TableConfig => {
824
- const tableConfig: TableConfig = _.cloneDeep(config)
954
+ const tableConfig: TableConfig = cloneConfig(config)
825
955
  const dynamicSeries = tableConfig.series.find(series => !!series.dynamicCategory)
826
956
  if (dynamicSeries) {
827
957
  const pivot: Pivot = { columnName: dynamicSeries.dynamicCategory, valueColumns: [dynamicSeries.dataKey] }
@@ -893,16 +1023,17 @@ const CdcChart: React.FC<CdcChartProps> = ({
893
1023
  showTitle={config.showTitle}
894
1024
  isDashboard={isDashboard}
895
1025
  title={title}
896
- superTitle={config.superTitle}
1026
+ superTitle={processedSuperTitle}
897
1027
  classes={['chart-title', `${config.theme}`, 'cove-component__header', 'mb-3']}
898
1028
  style={undefined}
1029
+ config={config}
899
1030
  />
900
1031
 
901
1032
  {/* Visualization Wrapper */}
902
1033
  <div className={getChartWrapperClasses().join(' ')}>
903
1034
  {/* Intro Text/Message */}
904
- {config?.introText && config.visualizationType !== 'Spark Line' && (
905
- <section className={`introText mb-4`}>{parse(config.introText)}</section>
1035
+ {processedIntroText && config.visualizationType !== 'Spark Line' && (
1036
+ <section className={`introText mb-4`}>{parse(processedIntroText)}</section>
906
1037
  )}
907
1038
 
908
1039
  {/* Filters */}
@@ -949,7 +1080,14 @@ const CdcChart: React.FC<CdcChartProps> = ({
949
1080
 
950
1081
  {config.visualizationType === 'Pie' && (
951
1082
  <ParentSize className='justify-content-center d-flex' style={{ width: `100%` }}>
952
- {parent => <PieChart ref={svgRef} parentWidth={parent.width} parentHeight={parent.height} />}
1083
+ {parent => (
1084
+ <PieChart
1085
+ ref={svgRef}
1086
+ parentWidth={parent.width}
1087
+ parentHeight={parent.height}
1088
+ interactionLabel={interactionLabel}
1089
+ />
1090
+ )}
953
1091
  </ParentSize>
954
1092
  )}
955
1093
  {/* Line Chart */}
@@ -993,9 +1131,9 @@ const CdcChart: React.FC<CdcChartProps> = ({
993
1131
  dimensions={dimensions}
994
1132
  interactionLabel={interactionLabel}
995
1133
  />
996
- {config?.introText && (
1134
+ {processedIntroText && (
997
1135
  <section className='introText mb-4' style={{ padding: '0px 0 35px' }}>
998
- {parse(config.introText)}
1136
+ {parse(processedIntroText)}
999
1137
  </section>
1000
1138
  )}
1001
1139
  <div style={{ height: `100px`, width: `100%`, ...sparkLineStyles }}>
@@ -1032,8 +1170,8 @@ const CdcChart: React.FC<CdcChartProps> = ({
1032
1170
  : link && link}
1033
1171
  {/* Description */}
1034
1172
 
1035
- {config.description && config.visualizationType !== 'Spark Line' && (
1036
- <div className={getChartSubTextClasses().join(' ')}>{parse(config.description)}</div>
1173
+ {processedDescription && config.visualizationType !== 'Spark Line' && (
1174
+ <div className={getChartSubTextClasses().join(' ')}>{parse(processedDescription)}</div>
1037
1175
  )}
1038
1176
 
1039
1177
  {/* buttons */}
@@ -1067,7 +1205,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
1067
1205
  (config.visualizationType === 'Sankey' && config.table.show)) && (
1068
1206
  <DataTable
1069
1207
  /* changing the "key" will force the table to re-render
1070
- when the default sort changes while editing */
1208
+ when the default sort changes while editing */
1071
1209
  key={dataTableDefaultSortBy}
1072
1210
  config={pivotDynamicSeries(config)}
1073
1211
  rawData={
@@ -1094,8 +1232,8 @@ const CdcChart: React.FC<CdcChartProps> = ({
1094
1232
  )}
1095
1233
  {config?.annotations?.length > 0 && <Annotation.Dropdown />}
1096
1234
  {/* show pdf or image button */}
1097
- {config?.legacyFootnotes && (
1098
- <section className='footnotes pt-2 mt-4'>{parse(config.legacyFootnotes)}</section>
1235
+ {processedLegacyFootnotes && (
1236
+ <section className='footnotes pt-2 mt-4'>{parse(processedLegacyFootnotes)}</section>
1099
1237
  )}
1100
1238
  </div>
1101
1239
  <FootnotesStandAlone
@@ -1119,6 +1257,9 @@ const CdcChart: React.FC<CdcChartProps> = ({
1119
1257
  return str.charAt(0).toUpperCase() + str.slice(1)
1120
1258
  }
1121
1259
 
1260
+ // Get version-specific color palettes based on current config
1261
+ const colorPalettes = filterChartColorPalettes(config)
1262
+
1122
1263
  const contextValues = {
1123
1264
  ...state,
1124
1265
  capitalize,
@@ -1137,6 +1278,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
1137
1278
  handleChartTabbing,
1138
1279
  highlight,
1139
1280
  handleShowAll,
1281
+ interactionLabel,
1140
1282
  isDashboard,
1141
1283
  isDebug,
1142
1284
  handleDragStateChange,
@@ -1150,7 +1292,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
1150
1292
  outerContainerRef,
1151
1293
  parentRef,
1152
1294
  parseDate,
1153
- rawData: _.cloneDeep(stateData) ?? {},
1295
+ rawData: stateData ?? {},
1154
1296
  setConfig,
1155
1297
  setEditing,
1156
1298
  setParentConfig,
@@ -1160,7 +1302,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
1160
1302
  tableData: filteredData || excludedData,
1161
1303
  transformedData: getTransformedData({ brushData: state.brushData, filteredData, excludedData, clean }),
1162
1304
  twoColorPalette,
1163
- unfilteredData: _.cloneDeep(stateData),
1305
+ unfilteredData: stateData,
1164
1306
  updateConfig
1165
1307
  }
1166
1308
 
@@ -1,8 +1,8 @@
1
1
  import React from 'react'
2
- import { Meta, Story } from '@storybook/react'
2
+ import { Meta, Story } from '@storybook/react-vite'
3
3
  import Chart from '../CdcChartComponent'
4
4
  import exampleComboBarNonNumeric from './../../examples/feature/tests-date-exclusions/date-exclusions-config.json'
5
- import { editConfigKeys } from '../helpers/configHelpers'
5
+ import { editConfigKeys } from '@cdc/core/helpers/configHelpers'
6
6
 
7
7
  export default {
8
8
  title: 'Components/Templates/Chart/Anchors',
@@ -1,4 +1,4 @@
1
- import type { Meta, StoryObj } from '@storybook/react'
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
2
  import boxPlotConfig from './_mock/boxplot_multiseries.json'
3
3
  import Chart from '../CdcChartComponent'
4
4
 
@@ -1,4 +1,4 @@
1
- import type { Meta, StoryObj } from '@storybook/react'
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
2
  import barChartCiLabels from './_mock/bar_chart_ci_labels.json'
3
3
  import lineChartDynamicCI from './_mock/line_chart_dynamic_ci.json'
4
4
  import lineChartNonDynamicCI from './_mock/line_chart_non_dynamic_ci.json'
@@ -1,4 +1,4 @@
1
- import type { Meta, StoryObj } from '@storybook/react'
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
2
  import Chart from '../CdcChartComponent'
3
3
  import scatterPlotCustomColorConfig from './_mock/scatterplot_mock.json'
4
4
 
@@ -1,7 +1,7 @@
1
1
  import DynamicSeriesConfig from './_mock/dynamic_series_config.json'
2
2
  import DynamicSeriesBarConfig from './_mock/dynamic_series_bar_config.json'
3
3
  import DynamicSeriesSuppression from './_mock/dynamic_series_suppression_mock.json'
4
- import { Meta, StoryObj } from '@storybook/react'
4
+ import { Meta, StoryObj } from '@storybook/react-vite'
5
5
  import Chart from '../CdcChartComponent'
6
6
 
7
7
  const meta: Meta<typeof Chart> = {
@@ -43,7 +43,7 @@ export const LineHoverPoints: Story = {
43
43
  export const Bar_Vertical: Story = {
44
44
  args: {
45
45
  config: DynamicSeriesBarConfig,
46
- isEditor: false
46
+ isEditor: true
47
47
  }
48
48
  }
49
49
 
@@ -1,6 +1,6 @@
1
- import type { Meta, StoryObj } from '@storybook/react'
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
2
  import Chart from '../CdcChartComponent'
3
- import { editConfigKeys } from '../helpers/configHelpers'
3
+ import { editConfigKeys } from '@cdc/core/helpers/configHelpers'
4
4
  import scatterPlotDownloadImage from './_mock/scatterplot-image-download.json'
5
5
 
6
6
  const meta: Meta<typeof Chart> = {
@@ -1,10 +1,10 @@
1
- import type { Meta, StoryObj } from '@storybook/react'
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
2
  import chartGradientConfig from './_mock/legend.gradient_mock.json'
3
3
  import chartGroupedLagend from './_mock/legend_groupBy_mock.json'
4
4
  import SimplifiedLineConfig from './_mock/simplified_line.json'
5
5
 
6
6
  import Chart from '../CdcChartComponent'
7
- import { editConfigKeys } from '../helpers/configHelpers'
7
+ import { editConfigKeys } from '@cdc/core/helpers/configHelpers'
8
8
 
9
9
  const meta: Meta<typeof Chart> = {
10
10
  title: 'Components/Templates/Chart/Legend',
@@ -0,0 +1,19 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import StackedPattern from './_mock/stacked-pattern-test.json'
3
+
4
+ import Chart from '../CdcChartComponent'
5
+
6
+ const meta: Meta<typeof Chart> = {
7
+ title: 'Components/Templates/Chart/Patterns',
8
+ component: Chart
9
+ }
10
+
11
+ type Story = StoryObj<typeof Chart>
12
+
13
+ export const Stacked_Bar_Pattern: Story = {
14
+ args: {
15
+ config: StackedPattern
16
+ }
17
+ }
18
+
19
+ export default meta
@@ -1,4 +1,4 @@
1
- import type { Meta, StoryObj } from '@storybook/react'
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
2
  import Chart from '../CdcChartComponent'
3
3
  import scatterPlotDownloadImage from './_mock/scatterplot-image-download.json'
4
4
 
@@ -1,4 +1,4 @@
1
- import type { Meta, StoryObj } from '@storybook/react'
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
2
 
3
3
  import Chart from '../CdcChart'
4
4
  import lineChartTwoPointsRegressionTest from './_mock/line_chart_two_points_regression_test.json'
@@ -12,7 +12,7 @@ import pieConfig from './_mock/pie_with_data.json'
12
12
  import pieCalculatedArea from './_mock/pie_calculated_area.json'
13
13
  import areaChartStacked from './_mock/area_chart_stacked.json'
14
14
  import multipleLines from './_mock/short_dates.json'
15
- import { editConfigKeys } from '../helpers/configHelpers'
15
+ import { editConfigKeys } from '@cdc/core/helpers/configHelpers'
16
16
 
17
17
  const meta: Meta<typeof Chart> = {
18
18
  title: 'Components/Templates/Chart',
@@ -67,18 +67,21 @@ export const BarChart_Labels: Story = {
67
67
 
68
68
  export const Pie: Story = {
69
69
  args: {
70
- config: pieConfig
70
+ config: pieConfig,
71
+ isEditor: true
71
72
  }
72
73
  }
73
74
  export const Pie_Calculated_Area: Story = {
74
75
  args: {
75
- config: pieCalculatedArea
76
+ config: pieCalculatedArea,
77
+ isEditor: true
76
78
  }
77
79
  }
78
80
 
79
81
  export const Paired_Bar: Story = {
80
82
  args: {
81
- config: pairedBar
83
+ config: pairedBar,
84
+ isEditor: true
82
85
  }
83
86
  }
84
87
 
@@ -1,4 +1,4 @@
1
- import type { Meta, StoryObj } from '@storybook/react'
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
2
 
3
3
  import Chart from '../CdcChartComponent'
4
4
  import barChartStacked from './_mock/barchart_labels.mock.json'
@@ -1,4 +1,4 @@
1
- import type { Meta, StoryObj } from '@storybook/react'
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
2
  import annotationConfig from './_mock/annotation_category_mock.json'
3
3
  import annotationConfigDateLinear from './_mock/annotation_date-linear_mock.json'
4
4
  import annotationConfigDateTime from './_mock/annotation_date-time_mock.json'
@@ -1,8 +1,8 @@
1
- import type { Meta, StoryObj } from '@storybook/react'
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
2
  import SimplifiedLineConfig from './_mock/simplified_line.json'
3
3
 
4
4
  import Chart from '../CdcChartComponent'
5
- import { editConfigKeys } from '../helpers/configHelpers'
5
+ import { editConfigKeys } from '@cdc/core/helpers/configHelpers'
6
6
 
7
7
  const meta: Meta<typeof Chart> = {
8
8
  title: 'Components/Templates/Chart/Axis Labels',
@@ -1,8 +1,8 @@
1
- import type { Meta, StoryObj } from '@storybook/react'
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
2
  import Chart from '../CdcChartComponent'
3
3
  import longXLabelsConfig from './_mock/large_x_axis_labels.json'
4
4
  import pairedBarConfig from './_mock/paired-bar.json'
5
- import { editConfigKeys } from '../helpers/configHelpers'
5
+ import { editConfigKeys } from '@cdc/core/helpers/configHelpers'
6
6
  import { ChartConfig } from '../types/ChartConfig'
7
7
 
8
8
  const meta: Meta<typeof Chart> = {