@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,6 +1,7 @@
1
1
  import parse from 'html-react-parser'
2
2
  import React from 'react'
3
3
  import { LegendOrdinal, LegendItem, LegendLabel } from '@visx/legend'
4
+ import { PatternLines, PatternCircles, PatternWaves } from '@visx/pattern'
4
5
  import LegendShape from '@cdc/core/components/LegendShape'
5
6
  import Button from '@cdc/core/components/elements/Button'
6
7
  import { getLegendClasses } from './helpers/getLegendClasses'
@@ -17,6 +18,8 @@ import { isLegendWrapViewport } from '@cdc/core/helpers/viewports'
17
18
  import LegendLineShape from './LegendLine.Shape'
18
19
  import LegendGroup from './LegendGroup'
19
20
  import { getSeriesWithData } from '../../helpers/dataHelpers'
21
+ import { publishAnalyticsEvent } from '@cdc/core/helpers/metrics/helpers'
22
+ import { getVizTitle, getVizSubType } from '@cdc/core/helpers/metrics/utils'
20
23
 
21
24
  const LEGEND_PADDING = 36
22
25
 
@@ -32,9 +35,9 @@ export interface LegendProps {
32
35
  skipId: string
33
36
  dimensions: DimensionsType // for responsive width legend
34
37
  transformedData: any
38
+ interactionLabel: string
35
39
  }
36
40
 
37
- /* eslint-disable jsx-a11y/no-noninteractive-tabindex, jsx-a11y/no-static-element-interactions */
38
41
  const Legend: React.FC<LegendProps> = forwardRef(
39
42
  (
40
43
  {
@@ -47,7 +50,8 @@ const Legend: React.FC<LegendProps> = forwardRef(
47
50
  formatLabels,
48
51
  skipId = 'legend',
49
52
  dimensions,
50
- transformedData: data
53
+ transformedData: data,
54
+ interactionLabel = ''
51
55
  },
52
56
  ref
53
57
  ) => {
@@ -69,6 +73,7 @@ const Legend: React.FC<LegendProps> = forwardRef(
69
73
 
70
74
  const { HighLightedBarUtils } = useHighlightedBars(config)
71
75
  let highLightedLegendItems = HighLightedBarUtils.findDuplicates(config.highlightedBarValues)
76
+
72
77
  if (!legend) return null
73
78
  return (
74
79
  <aside
@@ -137,11 +142,34 @@ const Legend: React.FC<LegendProps> = forwardRef(
137
142
  onKeyDown={e => {
138
143
  if (e.key === 'Enter') {
139
144
  e.preventDefault()
145
+ publishAnalyticsEvent({
146
+ vizType: config?.type,
147
+ vizSubType: getVizSubType(config),
148
+ vizTitle: getVizTitle(config),
149
+ eventType: `chart_legend_item_toggled` as any,
150
+ eventAction: 'keydown',
151
+ eventLabel: interactionLabel,
152
+ specifics: config.visualizationType === 'Bar'
153
+ ? `label: ${label.text}, orientation: ${config.orientation === 'horizontal' ? 'horizontal' : 'vertical'}, mode: ${legend.behavior}`
154
+ : `label: ${label.text}, mode: ${legend.behavior}`,
155
+ })
140
156
  highlight(label)
141
157
  }
142
158
  }}
143
159
  onClick={e => {
144
160
  e.preventDefault()
161
+ publishAnalyticsEvent({
162
+ vizType: config?.type,
163
+ vizSubType: getVizSubType(config),
164
+ eventType: `chart_legend_item_toggled` as any,
165
+ eventAction: 'click',
166
+ eventLabel: interactionLabel,
167
+ specifics: config.visualizationType === 'Bar'
168
+ ? `label: ${label.text}, orientation: ${config.orientation === 'horizontal' ? 'horizontal' : 'vertical'}, mode: ${legend.behavior}`
169
+ : `label: ${label.text}, mode: ${legend.behavior}`,
170
+
171
+ vizTitle: getVizTitle(config)
172
+ })
145
173
  highlight(label)
146
174
  }}
147
175
  role='button'
@@ -206,6 +234,86 @@ const Legend: React.FC<LegendProps> = forwardRef(
206
234
  </div>
207
235
 
208
236
  <LegendSuppression config={config} isLegendBottom={isLegendBottom} />
237
+
238
+ {/* Pattern Legend Items */}
239
+ {config.legend.patterns && Object.keys(config.legend.patterns).length > 0 && (
240
+ <div
241
+ className={`legend-patterns d-flex ${['top', 'bottom'].includes(config.legend.position) ? 'flex-row flex-wrap' : 'flex-column'
242
+ }`}
243
+ >
244
+ {Object.entries(config.legend.patterns).map(([key, pattern]) => {
245
+ const patternId = `legend-pattern-${key}`
246
+ const size = config.legend.patternSize || 8
247
+ const legendSize = 16
248
+ const pColor = (pattern as any)?.color || '#666666'
249
+
250
+ return (
251
+ <LegendItem
252
+ key={patternId}
253
+ className='legend-item legend-item--pattern d-flex align-items-center'
254
+ tabIndex={0}
255
+ role='button'
256
+ >
257
+ <span className='me-2'>
258
+ <svg width={legendSize} height={legendSize}>
259
+ <defs>
260
+ {pattern.shape === 'circles' && (
261
+ <PatternCircles
262
+ id={patternId}
263
+ height={size}
264
+ width={size}
265
+ fill={pColor}
266
+ radius={1.25}
267
+ />
268
+ )}
269
+ {pattern.shape === 'lines' && (
270
+ <PatternLines
271
+ id={patternId}
272
+ height={size}
273
+ width={size}
274
+ stroke={pColor}
275
+ strokeWidth={0.75}
276
+ orientation={['horizontal']}
277
+ />
278
+ )}
279
+ {pattern.shape === 'diagonalLines' && (
280
+ <PatternLines
281
+ id={patternId}
282
+ height={size}
283
+ width={size}
284
+ stroke={pColor}
285
+ strokeWidth={0.75}
286
+ orientation={['diagonalRightToLeft']}
287
+ />
288
+ )}
289
+ {pattern.shape === 'waves' && (
290
+ <PatternWaves
291
+ id={patternId}
292
+ height={size}
293
+ width={size}
294
+ fill={pColor}
295
+ strokeWidth={0.25}
296
+ />
297
+ )}
298
+ </defs>
299
+ <circle
300
+ fill={`url(#${patternId})`}
301
+ r={legendSize / 2}
302
+ cx={legendSize / 2}
303
+ cy={legendSize / 2}
304
+ stroke='#0000004d'
305
+ strokeWidth={1}
306
+ />
307
+ </svg>
308
+ </span>
309
+ <LegendLabel align='left' className='m-0'>
310
+ {parse(String((pattern as any)?.label || key))}
311
+ </LegendLabel>
312
+ </LegendItem>
313
+ )
314
+ })}
315
+ </div>
316
+ )}
209
317
  </>
210
318
  )
211
319
  }}
@@ -21,7 +21,8 @@ const Legend = forwardRef((props, ref) => {
21
21
  transformedData
22
22
  } = useContext(ConfigContext)
23
23
  if (!config.legend) return null
24
- // create fn to reverse labels while legend is Bottom. Legend-right , legend-left works by default.
24
+ // create fn to reverse labels while legend is Bottom. Legend-right , legend-left works by default
25
+ const { interactionLabel } = props
25
26
 
26
27
  const createLegendLabels = createFormatLabels(config, tableData, data, colorScale)
27
28
 
@@ -40,6 +41,7 @@ const Legend = forwardRef((props, ref) => {
40
41
  handleShowAll={handleShowAll}
41
42
  currentViewport={currentViewport}
42
43
  formatLabels={createLegendLabels}
44
+ interactionLabel={interactionLabel}
43
45
  />
44
46
  </Fragment>
45
47
  )
@@ -1,171 +1,230 @@
1
- import { colorPalettesChart as colorPalettes, sequentialPalettes, twoColorPalette } from '@cdc/core/data/colorPalettes'
2
- import { FaStar } from 'react-icons/fa'
3
- import { Label } from '../../../types/Label'
4
- import { ColorScale, TransformedData } from '../../../types/ChartContext'
5
- import { ChartConfig } from '../../../types/ChartConfig'
6
- import _ from 'lodash'
7
-
8
- export const createFormatLabels =
9
- (config: ChartConfig, tableData: Object[], data: TransformedData[], colorScale: ColorScale) =>
10
- (defaultLabels: Label[]): Label[] => {
11
- const { visualizationType, visualizationSubType, series, runtime, legend } = config
12
- const sortVertical = labels =>
13
- legend.verticalSorted
14
- ? _.sortBy(_.cloneDeep(labels), label => {
15
- const match = label.datum?.match(/-?\d+(\.\d+)?/)
16
- return match ? parseFloat(match[0]) : Number.MAX_SAFE_INTEGER
17
- })
18
- : labels
19
- const reverseLabels = labels => {
20
- if (config.series.some(series => series.dynamicCategory)) {
21
- return orderDynamicLabels(labels)
22
- }
23
-
24
- return config.legend.reverseLabelOrder ? sortVertical(labels).reverse() : sortVertical(labels)
25
- }
26
-
27
- const orderDynamicLabels = labels => {
28
- // Handle different ordering configurations
29
- switch (config.legend.order) {
30
- case 'dataColumn':
31
- return labels
32
- case 'asc':
33
- case 'desc':
34
- return labels.sort((a, b) => {
35
- const valA = a.datum || a.text
36
- const valB = b.datum || b.text
37
- const numA = parseFloat(valA)
38
- const numB = parseFloat(valB)
39
- if (!isNaN(numA) && !isNaN(numB)) {
40
- return config.legend.order === 'asc' ? numA - numB : numB - numA
41
- } else {
42
- return config.legend.order === 'asc' ? valA.localeCompare(valB) : valB.localeCompare(valA)
43
- }
44
- })
45
-
46
- default:
47
- return labels // Default case to handle any unexpected config.legend.order values
48
- }
49
- }
50
- const colorCode = config.legend?.colorCode
51
- if (visualizationType === 'Deviation Bar') {
52
- const [belowColor, aboveColor] = twoColorPalette[config.twoColor.palette]
53
- const labelBelow = {
54
- datum: 'X',
55
- index: 0,
56
- text: `Below ${config.xAxis.targetLabel}`,
57
- value: belowColor
58
- }
59
- const labelAbove = {
60
- datum: 'X',
61
- index: 1,
62
- text: `Above ${config.xAxis.targetLabel}`,
63
- value: aboveColor
64
- }
65
-
66
- return reverseLabels([labelBelow, labelAbove])
67
- }
68
- if (visualizationType === 'Bar' && visualizationSubType === 'regular' && colorCode && series?.length === 1) {
69
- let palette = colorPalettes[config.palette]
70
-
71
- while (tableData.length > palette.length) {
72
- palette = palette.concat(palette)
73
- }
74
- palette = palette.slice(0, data.length)
75
- //store unique values to Set by colorCode
76
- const set = new Set()
77
-
78
- tableData.forEach(d => set.add(d[colorCode]))
79
-
80
- // create labels with unique values
81
- const uniqueLabels = Array.from(set).map((val, i) => {
82
- const newLabel = {
83
- datum: val,
84
- index: i,
85
- text: val,
86
- value: palette[i]
87
- }
88
- return newLabel
89
- })
90
-
91
- return reverseLabels(uniqueLabels)
92
- }
93
-
94
- // get forecasting items inside of combo
95
- if (runtime?.forecastingSeriesKeys?.length > 0) {
96
- let seriesLabels = []
97
-
98
- //store unique values to Set by colorCode
99
- // loop through each stage/group/area on the chart and create a label
100
- config.runtime?.forecastingSeriesKeys?.map((outerGroup, index) => {
101
- return outerGroup?.stages?.map((stage, index) => {
102
- let colorValue = sequentialPalettes[stage.color]?.[2]
103
- ? sequentialPalettes[stage.color]?.[2]
104
- : colorPalettes[stage.color]?.[2]
105
- ? colorPalettes[stage.color]?.[2]
106
- : '#ccc'
107
-
108
- const newLabel = {
109
- datum: stage.key,
110
- index: index,
111
- text: stage.key,
112
- value: colorValue
113
- }
114
-
115
- seriesLabels.push(newLabel)
116
- })
117
- })
118
-
119
- // loop through bars for now to meet requirements.
120
- config.runtime.barSeriesKeys &&
121
- config.runtime.barSeriesKeys.forEach((bar, index) => {
122
- let colorValue = colorPalettes[config.palette][index] ? colorPalettes[config.palette][index] : '#ccc'
123
-
124
- const newLabel = {
125
- datum: bar,
126
- index: index,
127
- text: bar,
128
- value: colorValue
129
- }
130
-
131
- seriesLabels.push(newLabel)
132
- })
133
-
134
- return reverseLabels(seriesLabels)
135
- }
136
-
137
- if (config.series.some(item => item.name)) {
138
- const uniqueLabels = Array.from(new Set(config.series.map(d => d.name || d.dataKey))).map((val, i) => ({
139
- datum: val,
140
- index: i,
141
- text: val,
142
- value: colorScale(val)
143
- }))
144
- return reverseLabels(uniqueLabels)
145
- }
146
-
147
- if (
148
- (config.visualizationType === 'Bar' || config.visualizationType === 'Combo') &&
149
- config.visualizationSubType === 'regular' &&
150
- config.suppressedData
151
- ) {
152
- const lastIndex = defaultLabels.length - 1
153
- let newLabels = []
154
-
155
- config.suppressedData?.forEach(({ label, icon }, index) => {
156
- if (label && icon) {
157
- const newLabel = {
158
- datum: label,
159
- index: lastIndex + index,
160
- text: label,
161
- icon: <FaStar color='#000' size={15} />
162
- }
163
- newLabels.push(newLabel)
164
- }
165
- })
166
-
167
- return [...defaultLabels, ...newLabels]
168
- }
169
-
170
- return reverseLabels(defaultLabels)
171
- }
1
+ import {
2
+ colorPalettesChart as colorPalettes,
3
+ colorPalettesChartV2,
4
+ sequentialPalettes,
5
+ twoColorPalette
6
+ } from '@cdc/core/data/colorPalettes'
7
+ import { getCurrentPaletteName, getFallbackColorPalette, migratePaletteWithMap } from '@cdc/core/helpers/palettes/utils'
8
+ import { chartPaletteMigrationMap } from '@cdc/core/helpers/palettes/migratePaletteName'
9
+ import { getPaletteAccessor } from '@cdc/core/helpers/getPaletteAccessor'
10
+ import { getColorPaletteVersion } from '@cdc/core/helpers/getColorPaletteVersion'
11
+ import { isV1Palette } from '@cdc/core/helpers/palettes/utils'
12
+ import { v2ColorDistribution } from '@cdc/core/helpers/palettes/colorDistributions'
13
+ import { updatePaletteNames } from '@cdc/core/helpers/updatePaletteNames'
14
+ import { buildForecastPaletteMappings } from '../../../helpers/buildForecastPaletteMappings'
15
+ import { FaStar } from 'react-icons/fa'
16
+ import { Label } from '../../../types/Label'
17
+ import { ColorScale, TransformedData } from '../../../types/ChartContext'
18
+ import { ChartConfig } from '../../../types/ChartConfig'
19
+ import _ from 'lodash'
20
+
21
+ export const createFormatLabels =
22
+ (config: ChartConfig, tableData: Object[], data: TransformedData[], colorScale: ColorScale) =>
23
+ (defaultLabels: Label[]): Label[] => {
24
+ const { visualizationType, visualizationSubType, series, runtime, legend } = config
25
+ const sortVertical = labels =>
26
+ legend.verticalSorted
27
+ ? _.sortBy(_.cloneDeep(labels), label => {
28
+ const match = label.datum?.match(/-?\d+(\.\d+)?/)
29
+ return match ? parseFloat(match[0]) : Number.MAX_SAFE_INTEGER
30
+ })
31
+ : labels
32
+ const reverseLabels = labels => {
33
+ if (config.series.some(series => series.dynamicCategory)) {
34
+ return orderDynamicLabels(labels)
35
+ }
36
+
37
+ return config.legend.reverseLabelOrder ? sortVertical(labels).reverse() : sortVertical(labels)
38
+ }
39
+
40
+ const orderDynamicLabels = labels => {
41
+ // Handle different ordering configurations
42
+ switch (config.legend.order) {
43
+ case 'dataColumn':
44
+ return labels
45
+ case 'asc':
46
+ case 'desc':
47
+ return labels.sort((a, b) => {
48
+ const valA = a.datum || a.text
49
+ const valB = b.datum || b.text
50
+ const numA = parseFloat(valA)
51
+ const numB = parseFloat(valB)
52
+ if (!isNaN(numA) && !isNaN(numB)) {
53
+ return config.legend.order === 'asc' ? numA - numB : numB - numA
54
+ } else {
55
+ return config.legend.order === 'asc' ? valA.localeCompare(valB) : valB.localeCompare(valA)
56
+ }
57
+ })
58
+
59
+ default:
60
+ return labels // Default case to handle any unexpected config.legend.order values
61
+ }
62
+ }
63
+ const colorCode = config.legend?.colorCode
64
+ if (visualizationType === 'Deviation Bar') {
65
+ let versionName = isV1Palette(config) ? 'v1' : 'v2'
66
+ const [belowColor, aboveColor] = twoColorPalette?.[versionName]?.[config.twoColor.palette] || [
67
+ '#1D6ABF',
68
+ '#935586'
69
+ ]
70
+
71
+ const labelBelow = {
72
+ datum: 'X',
73
+ index: 0,
74
+ text: `Below ${config.xAxis.targetLabel}`,
75
+ value: belowColor
76
+ }
77
+ const labelAbove = {
78
+ datum: 'X',
79
+ index: 1,
80
+ text: `Above ${config.xAxis.targetLabel}`,
81
+ value: aboveColor
82
+ }
83
+
84
+ return reverseLabels([labelBelow, labelAbove])
85
+ }
86
+ if (visualizationType === 'Bar' && visualizationSubType === 'regular' && colorCode && series?.length === 1) {
87
+ const currentPaletteName = getCurrentPaletteName(config) || getFallbackColorPalette(config)
88
+ const paletteName = migratePaletteWithMap(currentPaletteName, chartPaletteMigrationMap, true)
89
+ let palette = getPaletteAccessor(colorPalettes, config, paletteName)
90
+
91
+ const numberOfKeys = data.length
92
+
93
+ // Check if we should use v2 distribution logic for better contrast
94
+ const version = getColorPaletteVersion(config)
95
+ const isSequentialOrDivergent =
96
+ paletteName && (paletteName.includes('sequential') || paletteName.includes('divergent'))
97
+ const isPairedBarOrDeviation = ['Paired Bar', 'Deviation Bar'].includes(config.visualizationType)
98
+ const useV2Distribution =
99
+ version === 2 && isSequentialOrDivergent && palette.length === 9 && numberOfKeys <= 9 && !isPairedBarOrDeviation
100
+
101
+ if (useV2Distribution && v2ColorDistribution[numberOfKeys]) {
102
+ // Use strategic color distribution for v2 sequential palettes
103
+ const distributionIndices = v2ColorDistribution[numberOfKeys]
104
+ palette = distributionIndices.map(index => palette[index])
105
+ } else {
106
+ // Use existing logic for v1 palettes and other cases
107
+ while (tableData.length > palette?.length) {
108
+ palette = palette.concat(palette)
109
+ }
110
+ palette = palette?.slice(0, data.length)
111
+ }
112
+ //store unique values to Set by colorCode
113
+ const set = new Set()
114
+
115
+ tableData.forEach(d => set.add(d[colorCode]))
116
+
117
+ // create labels with unique values
118
+ const uniqueLabels = Array.from(set).map((val, i) => {
119
+ const newLabel = {
120
+ datum: val,
121
+ index: i,
122
+ text: val,
123
+ value: palette?.[i]
124
+ }
125
+ return newLabel
126
+ })
127
+
128
+ return reverseLabels(uniqueLabels)
129
+ }
130
+
131
+ // get forecasting items inside of combo
132
+ if (runtime?.forecastingSeriesKeys?.length > 0) {
133
+ let seriesLabels = []
134
+
135
+ // Create palette lookup map - use version-specific palettes
136
+ // Forecasting charts use sequentialPalettes for v1, sequential-only palettes for v2
137
+ const paletteVersion = getColorPaletteVersion(config)
138
+
139
+ let forecastPalettes
140
+ if (paletteVersion === 1) {
141
+ // V1: Use original sequential palettes
142
+ forecastPalettes = sequentialPalettes
143
+ } else {
144
+ // V2: Only use sequential palettes (filter out divergent and qualitative)
145
+ const allV2Palettes = colorPalettesChartV2
146
+ forecastPalettes = {}
147
+ Object.keys(allV2Palettes).forEach(key => {
148
+ if (key.startsWith('sequential')) {
149
+ forecastPalettes[key] = allV2Palettes[key]
150
+ }
151
+ })
152
+ }
153
+
154
+ const processedPalettes = updatePaletteNames(forecastPalettes)
155
+ const forecastingPalettes = buildForecastPaletteMappings(processedPalettes, paletteVersion)
156
+
157
+ //store unique values to Set by colorCode
158
+ // loop through each stage/group/area on the chart and create a label
159
+ config.runtime?.forecastingSeriesKeys?.map((outerGroup, index) => {
160
+ return outerGroup?.stages?.map((stage, index) => {
161
+ const palette = forecastingPalettes[stage.color] || false
162
+ let colorValue = palette?.[2] || '#ccc'
163
+
164
+ const newLabel = {
165
+ datum: stage.key,
166
+ index: index,
167
+ text: stage.key,
168
+ value: colorValue
169
+ }
170
+
171
+ seriesLabels.push(newLabel)
172
+ })
173
+ })
174
+
175
+ // loop through bars for now to meet requirements.
176
+ config.runtime.barSeriesKeys &&
177
+ config.runtime.barSeriesKeys.forEach((bar, index) => {
178
+ const currentPaletteName = getCurrentPaletteName(config) || getFallbackColorPalette(config)
179
+ const migratedPaletteName = migratePaletteWithMap(currentPaletteName, chartPaletteMigrationMap, true)
180
+ const palette = getPaletteAccessor(colorPalettes, config, migratedPaletteName)
181
+ let colorValue = palette?.[index] || '#ccc'
182
+
183
+ const newLabel = {
184
+ datum: bar,
185
+ index: index,
186
+ text: bar,
187
+ value: colorValue
188
+ }
189
+
190
+ seriesLabels.push(newLabel)
191
+ })
192
+
193
+ return reverseLabels(seriesLabels)
194
+ }
195
+
196
+ if (config.series.some(item => item.name)) {
197
+ const uniqueLabels = Array.from(new Set(config.series.map(d => d.name || d.dataKey))).map((val, i) => ({
198
+ datum: val,
199
+ index: i,
200
+ text: val,
201
+ value: colorScale(val)
202
+ }))
203
+ return reverseLabels(uniqueLabels)
204
+ }
205
+
206
+ if (
207
+ (config.visualizationType === 'Bar' || config.visualizationType === 'Combo') &&
208
+ config.visualizationSubType === 'regular' &&
209
+ config.suppressedData
210
+ ) {
211
+ const lastIndex = defaultLabels.length - 1
212
+ let newLabels = []
213
+
214
+ config.suppressedData?.forEach(({ label, icon }, index) => {
215
+ if (label && icon) {
216
+ const newLabel = {
217
+ datum: label,
218
+ index: lastIndex + index,
219
+ text: label,
220
+ icon: <FaStar color='#000' size={15} />
221
+ }
222
+ newLabels.push(newLabel)
223
+ }
224
+ })
225
+
226
+ return [...defaultLabels, ...newLabels]
227
+ }
228
+
229
+ return reverseLabels(defaultLabels)
230
+ }
@@ -22,7 +22,7 @@ const LegendWrapper: React.FC<LegendWrapperProps> = props => {
22
22
  return classes.join(' ')
23
23
  }
24
24
 
25
- return <div className={getLegendWrappingClasses()}>{...children}</div>
25
+ return <div className={getLegendWrappingClasses()}>{children}</div>
26
26
  }
27
27
 
28
28
  export default LegendWrapper