@cdc/chart 4.25.7 → 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 (95) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/dist/cdcchart.js +39551 -37016
  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 +10 -4
  17. package/src/CdcChartComponent.tsx +188 -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 +170 -25
  40. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +139 -6
  41. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +215 -73
  42. package/src/components/BarChart/components/BarChart.Vertical.tsx +172 -23
  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/Brush/BrushChart.tsx +65 -10
  48. package/src/components/Brush/BrushController.tsx +37 -5
  49. package/src/components/Brush/types.tsx +8 -0
  50. package/src/components/DeviationBar.jsx +9 -6
  51. package/src/components/EditorPanel/EditorPanel.tsx +364 -39
  52. package/src/components/EditorPanel/EditorPanelContext.ts +3 -0
  53. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +2 -2
  54. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +414 -0
  55. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +30 -54
  56. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +115 -120
  57. package/src/components/EditorPanel/components/Panels/index.tsx +3 -1
  58. package/src/components/EditorPanel/components/Panels/panelVisual.styles.css +0 -8
  59. package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +49 -48
  60. package/src/components/Forecasting/Forecasting.tsx +36 -6
  61. package/src/components/ForestPlot/ForestPlot.tsx +11 -7
  62. package/src/components/ForestPlot/ForestPlotProps.ts +1 -1
  63. package/src/components/Legend/Legend.Component.tsx +110 -2
  64. package/src/components/Legend/Legend.tsx +3 -1
  65. package/src/components/Legend/helpers/createFormatLabels.tsx +230 -171
  66. package/src/components/LegendWrapper.tsx +1 -1
  67. package/src/components/LineChart/components/LineChart.BumpCircle.tsx +27 -26
  68. package/src/components/LineChart/components/LineChart.Circle.tsx +2 -2
  69. package/src/components/LineChart/index.tsx +2 -2
  70. package/src/components/LinearChart.tsx +26 -9
  71. package/src/components/PairedBarChart.jsx +6 -4
  72. package/src/components/PieChart/PieChart.tsx +170 -54
  73. package/src/components/Sankey/components/Sankey.tsx +7 -1
  74. package/src/components/ScatterPlot/ScatterPlot.jsx +32 -4
  75. package/src/data/initial-state.js +315 -292
  76. package/src/helpers/buildForecastPaletteMappings.ts +112 -0
  77. package/src/helpers/buildForecastPaletteOptions.ts +109 -0
  78. package/src/helpers/getColorScale.ts +72 -8
  79. package/src/helpers/getNewRuntime.ts +1 -1
  80. package/src/helpers/getTransformedData.ts +1 -1
  81. package/src/hooks/useChartHoverAnalytics.tsx +44 -0
  82. package/src/hooks/useReduceData.ts +105 -70
  83. package/src/hooks/useTooltip.tsx +58 -16
  84. package/src/index.jsx +6 -3
  85. package/src/scss/main.scss +12 -0
  86. package/src/store/chart.reducer.ts +1 -1
  87. package/src/test/CdcChart.test.jsx +8 -3
  88. package/src/types/ChartConfig.ts +30 -6
  89. package/src/types/ChartContext.ts +1 -0
  90. package/vite.config.js +1 -1
  91. package/vitest.config.ts +16 -0
  92. package/src/coreStyles_chart.scss +0 -3
  93. package/src/helpers/configHelpers.ts +0 -28
  94. package/src/helpers/generateColorsArray.ts +0 -8
  95. 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
@@ -82,6 +83,9 @@ import { VizFilter } from '@cdc/core/types/VizFilter'
82
83
  import { getNewRuntime } from './helpers/getNewRuntime'
83
84
  import FootnotesStandAlone from '@cdc/core/components/Footnotes/FootnotesStandAlone'
84
85
  import { Datasets } from '@cdc/core/types/DataSet'
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'
85
89
 
86
90
  interface CdcChartProps {
87
91
  config?: ChartConfig
@@ -96,6 +100,7 @@ interface CdcChartProps {
96
100
  setSharedFilterValue?: (value: any) => void
97
101
  dashboardConfig?: DashboardConfig
98
102
  datasets?: Datasets
103
+ interactionLabel: string
99
104
  }
100
105
  const CdcChart: React.FC<CdcChartProps> = ({
101
106
  config: configObj,
@@ -108,7 +113,8 @@ const CdcChart: React.FC<CdcChartProps> = ({
108
113
  setSharedFilter,
109
114
  setSharedFilterValue,
110
115
  dashboardConfig,
111
- datasets
116
+ datasets,
117
+ interactionLabel
112
118
  }) => {
113
119
  const transform = new DataTransform()
114
120
  const initialState = getInitialState(configObj)
@@ -149,6 +155,73 @@ const CdcChart: React.FC<CdcChartProps> = ({
149
155
  // Destructure items from config for more readable JSX
150
156
  let { legend, title } = config
151
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
+
152
225
  // set defaults on titles if blank AND only in editor
153
226
  if (isEditor) {
154
227
  if (!title || title === '') title = 'Chart Title'
@@ -166,7 +239,22 @@ const CdcChart: React.FC<CdcChartProps> = ({
166
239
  const convertLineToBarGraph = isConvertLineToBarGraph(config, filteredData)
167
240
 
168
241
  const prepareConfig = (loadedConfig: ChartConfig) => {
169
- 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
+
170
258
  _.defaultsDeep(newConfig, {
171
259
  table: { showVertical: false }
172
260
  })
@@ -188,11 +276,30 @@ const CdcChart: React.FC<CdcChartProps> = ({
188
276
  }
189
277
 
190
278
  const updateConfig = (_config: AllChartsConfig, dataOverride?: any[]) => {
191
- const newConfig = _.cloneDeep(_config)
279
+ const newConfig = cloneConfig(_config)
192
280
  let data = dataOverride || stateData
193
281
 
194
282
  data = handleRankByValue(data, newConfig)
195
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
+
196
303
  // Deeper copy
197
304
  Object.keys(defaults).forEach(key => {
198
305
  if (newConfig[key] && 'object' === typeof newConfig[key] && !Array.isArray(newConfig[key])) {
@@ -223,7 +330,9 @@ const CdcChart: React.FC<CdcChartProps> = ({
223
330
  newConfig.runtime.originalXAxis = newConfig.xAxis
224
331
 
225
332
  if (newConfig.visualizationType === 'Pie') {
226
- 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]))
227
336
  newConfig.runtime.seriesLabelsAll = newConfig.runtime.seriesKeys
228
337
  } else {
229
338
  const finalData = dataOverride || newConfig.formattedData || newConfig.data
@@ -291,8 +400,15 @@ const CdcChart: React.FC<CdcChartProps> = ({
291
400
  newConfig.orientation === 'horizontal') ||
292
401
  ['Deviation Bar', 'Paired Bar', 'Forest Plot'].includes(newConfig.visualizationType)
293
402
  ) {
294
- newConfig.runtime.xAxis = _.cloneDeep(newConfig.yAxis.yAxis || newConfig.yAxis)
295
- 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
+ }
296
412
  newConfig.runtime.yAxis.labelOffset *= -1
297
413
 
298
414
  newConfig.runtime.horizontal = false
@@ -303,13 +419,13 @@ const CdcChart: React.FC<CdcChartProps> = ({
303
419
  ['Scatter Plot', 'Area Chart', 'Line', 'Forecasting'].includes(newConfig.visualizationType) &&
304
420
  !convertLineToBarGraph
305
421
  ) {
306
- newConfig.runtime.xAxis = newConfig.xAxis
307
- 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 }
308
424
  newConfig.runtime.horizontal = false
309
425
  newConfig.orientation = 'vertical'
310
426
  } else {
311
- newConfig.runtime.xAxis = newConfig.xAxis
312
- 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 }
313
429
  newConfig.runtime.horizontal = false
314
430
  }
315
431
 
@@ -426,8 +542,16 @@ const CdcChart: React.FC<CdcChartProps> = ({
426
542
  } else if (newConfig.formattedData) {
427
543
  newConfig.data = newConfig.formattedData
428
544
  } else if (newConfig.dataDescription) {
429
- newConfig.data = transform.autoStandardize(newConfig.data)
430
- 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
+ }
431
555
  }
432
556
  } catch (err) {
433
557
  console.error('Error on prepareData function ', err)
@@ -554,6 +678,17 @@ const CdcChart: React.FC<CdcChartProps> = ({
554
678
  } catch (e) {
555
679
  console.error('COVE:', e.message)
556
680
  }
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
+ })
557
692
  dispatch({ type: 'SET_SERIES_HIGHLIGHT', payload: [] })
558
693
  }
559
694
 
@@ -816,7 +951,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
816
951
  }
817
952
 
818
953
  const pivotDynamicSeries = (config: ChartConfig): TableConfig => {
819
- const tableConfig: TableConfig = _.cloneDeep(config)
954
+ const tableConfig: TableConfig = cloneConfig(config)
820
955
  const dynamicSeries = tableConfig.series.find(series => !!series.dynamicCategory)
821
956
  if (dynamicSeries) {
822
957
  const pivot: Pivot = { columnName: dynamicSeries.dynamicCategory, valueColumns: [dynamicSeries.dataKey] }
@@ -888,16 +1023,17 @@ const CdcChart: React.FC<CdcChartProps> = ({
888
1023
  showTitle={config.showTitle}
889
1024
  isDashboard={isDashboard}
890
1025
  title={title}
891
- superTitle={config.superTitle}
1026
+ superTitle={processedSuperTitle}
892
1027
  classes={['chart-title', `${config.theme}`, 'cove-component__header', 'mb-3']}
893
1028
  style={undefined}
1029
+ config={config}
894
1030
  />
895
1031
 
896
1032
  {/* Visualization Wrapper */}
897
1033
  <div className={getChartWrapperClasses().join(' ')}>
898
1034
  {/* Intro Text/Message */}
899
- {config?.introText && config.visualizationType !== 'Spark Line' && (
900
- <section className={`introText mb-4`}>{parse(config.introText)}</section>
1035
+ {processedIntroText && config.visualizationType !== 'Spark Line' && (
1036
+ <section className={`introText mb-4`}>{parse(processedIntroText)}</section>
901
1037
  )}
902
1038
 
903
1039
  {/* Filters */}
@@ -907,6 +1043,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
907
1043
  setFilters={setFilters}
908
1044
  excludedData={excludedData}
909
1045
  dimensions={dimensions}
1046
+ interactionLabel={interactionLabel}
910
1047
  />
911
1048
  )}
912
1049
  <SkipTo skipId={handleChartTabbing(config, legendId)} skipMessage='Skip Over Chart Container' />
@@ -943,7 +1080,14 @@ const CdcChart: React.FC<CdcChartProps> = ({
943
1080
 
944
1081
  {config.visualizationType === 'Pie' && (
945
1082
  <ParentSize className='justify-content-center d-flex' style={{ width: `100%` }}>
946
- {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
+ )}
947
1091
  </ParentSize>
948
1092
  )}
949
1093
  {/* Line Chart */}
@@ -985,10 +1129,11 @@ const CdcChart: React.FC<CdcChartProps> = ({
985
1129
  setFilters={setFilters}
986
1130
  excludedData={excludedData}
987
1131
  dimensions={dimensions}
1132
+ interactionLabel={interactionLabel}
988
1133
  />
989
- {config?.introText && (
1134
+ {processedIntroText && (
990
1135
  <section className='introText mb-4' style={{ padding: '0px 0 35px' }}>
991
- {parse(config.introText)}
1136
+ {parse(processedIntroText)}
992
1137
  </section>
993
1138
  )}
994
1139
  <div style={{ height: `100px`, width: `100%`, ...sparkLineStyles }}>
@@ -1012,7 +1157,11 @@ const CdcChart: React.FC<CdcChartProps> = ({
1012
1157
  {!config.legend.hide &&
1013
1158
  config.visualizationType !== 'Spark Line' &&
1014
1159
  config.visualizationType !== 'Sankey' && (
1015
- <Legend ref={legendRef} skipId={handleChartTabbing(config, legendId)} />
1160
+ <Legend
1161
+ ref={legendRef}
1162
+ skipId={handleChartTabbing(config, legendId)}
1163
+ interactionLabel={interactionLabel}
1164
+ />
1016
1165
  )}
1017
1166
  </LegendWrapper>
1018
1167
  {/* Link */}
@@ -1021,8 +1170,8 @@ const CdcChart: React.FC<CdcChartProps> = ({
1021
1170
  : link && link}
1022
1171
  {/* Description */}
1023
1172
 
1024
- {config.description && config.visualizationType !== 'Spark Line' && (
1025
- <div className={getChartSubTextClasses().join(' ')}>{parse(config.description)}</div>
1173
+ {processedDescription && config.visualizationType !== 'Spark Line' && (
1174
+ <div className={getChartSubTextClasses().join(' ')}>{parse(processedDescription)}</div>
1026
1175
  )}
1027
1176
 
1028
1177
  {/* buttons */}
@@ -1034,6 +1183,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
1034
1183
  type='image'
1035
1184
  state={config}
1036
1185
  elementToCapture={imageId}
1186
+ interactionLabel={interactionLabel}
1037
1187
  />
1038
1188
  )}
1039
1189
  {config.table.showDownloadPdfButton && (
@@ -1043,6 +1193,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
1043
1193
  type='pdf'
1044
1194
  state={config}
1045
1195
  elementToCapture={imageId}
1196
+ interactionLabel={interactionLabel}
1046
1197
  />
1047
1198
  )}
1048
1199
  </MediaControls.Section>
@@ -1054,7 +1205,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
1054
1205
  (config.visualizationType === 'Sankey' && config.table.show)) && (
1055
1206
  <DataTable
1056
1207
  /* changing the "key" will force the table to re-render
1057
- when the default sort changes while editing */
1208
+ when the default sort changes while editing */
1058
1209
  key={dataTableDefaultSortBy}
1059
1210
  config={pivotDynamicSeries(config)}
1060
1211
  rawData={
@@ -1076,12 +1227,13 @@ const CdcChart: React.FC<CdcChartProps> = ({
1076
1227
  viewport={currentViewport}
1077
1228
  tabbingId={handleChartTabbing(config, legendId)}
1078
1229
  colorScale={colorScale}
1230
+ interactionLabel={interactionLabel}
1079
1231
  />
1080
1232
  )}
1081
1233
  {config?.annotations?.length > 0 && <Annotation.Dropdown />}
1082
1234
  {/* show pdf or image button */}
1083
- {config?.legacyFootnotes && (
1084
- <section className='footnotes pt-2 mt-4'>{parse(config.legacyFootnotes)}</section>
1235
+ {processedLegacyFootnotes && (
1236
+ <section className='footnotes pt-2 mt-4'>{parse(processedLegacyFootnotes)}</section>
1085
1237
  )}
1086
1238
  </div>
1087
1239
  <FootnotesStandAlone
@@ -1105,6 +1257,9 @@ const CdcChart: React.FC<CdcChartProps> = ({
1105
1257
  return str.charAt(0).toUpperCase() + str.slice(1)
1106
1258
  }
1107
1259
 
1260
+ // Get version-specific color palettes based on current config
1261
+ const colorPalettes = filterChartColorPalettes(config)
1262
+
1108
1263
  const contextValues = {
1109
1264
  ...state,
1110
1265
  capitalize,
@@ -1123,6 +1278,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
1123
1278
  handleChartTabbing,
1124
1279
  highlight,
1125
1280
  handleShowAll,
1281
+ interactionLabel,
1126
1282
  isDashboard,
1127
1283
  isDebug,
1128
1284
  handleDragStateChange,
@@ -1136,7 +1292,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
1136
1292
  outerContainerRef,
1137
1293
  parentRef,
1138
1294
  parseDate,
1139
- rawData: _.cloneDeep(stateData) ?? {},
1295
+ rawData: stateData ?? {},
1140
1296
  setConfig,
1141
1297
  setEditing,
1142
1298
  setParentConfig,
@@ -1146,7 +1302,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
1146
1302
  tableData: filteredData || excludedData,
1147
1303
  transformedData: getTransformedData({ brushData: state.brushData, filteredData, excludedData, clean }),
1148
1304
  twoColorPalette,
1149
- unfilteredData: _.cloneDeep(stateData),
1305
+ unfilteredData: stateData,
1150
1306
  updateConfig
1151
1307
  }
1152
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> = {