@cdc/chart 4.26.2 → 4.26.3

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 (70) hide show
  1. package/LICENSE +201 -0
  2. package/dist/cdcchart.js +35674 -32430
  3. package/examples/data/data-with-metadata.json +10 -0
  4. package/examples/feature/pie/planet-pie-example-config.json +2 -1
  5. package/examples/metadata-variables.json +58 -0
  6. package/package.json +3 -3
  7. package/src/CdcChart.tsx +8 -4
  8. package/src/CdcChartComponent.tsx +321 -288
  9. package/src/_stories/Chart.CustomColors.stories.tsx +74 -0
  10. package/src/_stories/Chart.Defaults.stories.tsx +95 -0
  11. package/src/_stories/Chart.SmallestLeftAxisMax.stories.tsx +64 -0
  12. package/src/_stories/Chart.stories.tsx +36 -2
  13. package/src/_stories/ChartBar.Editor.stories.tsx +97 -38
  14. package/src/_stories/ChartBrush.Editor.stories.tsx +11 -25
  15. package/src/_stories/ChartEditor.Editor.stories.tsx +1 -1
  16. package/src/_stories/_mock/paired-bar-abbr.json +421 -0
  17. package/src/_stories/_mock/pie_custom_colors.json +268 -0
  18. package/src/_stories/_mock/smallest_left_axis_max.json +104 -0
  19. package/src/components/Annotations/components/AnnotationDraggable.styles.css +10 -10
  20. package/src/components/Annotations/components/AnnotationDropdown.styles.css +1 -1
  21. package/src/components/Annotations/components/AnnotationList.styles.css +11 -11
  22. package/src/components/Axis/BottomAxis.tsx +10 -3
  23. package/src/components/Axis/PairedBarAxis.tsx +10 -4
  24. package/src/components/BarChart/components/BarChart.Horizontal.tsx +12 -28
  25. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +12 -30
  26. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +12 -31
  27. package/src/components/BarChart/components/BarChart.Vertical.tsx +12 -28
  28. package/src/components/BarChart/helpers/getPatternUrl.ts +94 -0
  29. package/src/components/BarChart/helpers/tests/getPatternUrl.test.ts +134 -0
  30. package/src/components/BarChart/helpers/useBarChart.ts +3 -0
  31. package/src/components/Brush/BrushSelector.tsx +2 -1
  32. package/src/components/Brush/MiniChartPreview.tsx +21 -26
  33. package/src/components/EditorPanel/EditorPanel.tsx +56 -43
  34. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +9 -9
  35. package/src/components/EditorPanel/components/Panels/Panel.ForestPlotSettings.tsx +0 -78
  36. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +39 -1
  37. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +24 -42
  38. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +83 -2
  39. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +45 -42
  40. package/src/components/EditorPanel/editor-panel.scss +1 -1
  41. package/src/components/ForestPlot/ForestPlot.tsx +26 -22
  42. package/src/components/Legend/LegendGroup/LegendGroup.styles.css +4 -4
  43. package/src/components/Legend/helpers/createFormatLabels.tsx +3 -2
  44. package/src/components/LinearChart/tests/LinearChart.test.tsx +77 -0
  45. package/src/components/LinearChart/tests/mockConfigContext.ts +2 -0
  46. package/src/components/LinearChart.tsx +26 -6
  47. package/src/components/PieChart/PieChart.tsx +19 -4
  48. package/src/components/RadarChart/RadarChart.tsx +1 -1
  49. package/src/components/Regions/components/Regions.tsx +6 -6
  50. package/src/components/Sankey/components/Sankey.tsx +3 -3
  51. package/src/components/Sankey/sankey.scss +1 -1
  52. package/src/components/SmallMultiples/SmallMultiples.css +5 -5
  53. package/src/components/Sparkline/index.scss +4 -2
  54. package/src/components/WarmingStripes/WarmingStripesGradientLegend.css +8 -8
  55. package/src/data/initial-state.js +23 -14
  56. package/src/data/legacy-defaults.ts +18 -0
  57. package/src/helpers/abbreviateNumber.ts +24 -17
  58. package/src/helpers/getChartPatternId.ts +17 -0
  59. package/src/helpers/getMinMax.ts +16 -2
  60. package/src/helpers/seriesColumnSettings.ts +114 -0
  61. package/src/helpers/tests/countNumOfTicks.test.ts +77 -0
  62. package/src/helpers/tests/seriesColumnSettings.test.ts +84 -0
  63. package/src/hooks/useRightAxis.ts +14 -0
  64. package/src/hooks/useScales.ts +92 -56
  65. package/src/hooks/useTooltip.tsx +20 -3
  66. package/src/scss/main.scss +152 -79
  67. package/src/test/CdcChart.test.jsx +2 -2
  68. package/src/types/ChartConfig.ts +4 -0
  69. package/tests/fixtures/chart-config-with-metadata.json +29 -0
  70. package/tests/fixtures/data-with-metadata.json +10 -0
@@ -6,7 +6,7 @@ import { useEditorPermissions } from '../../useEditorPermissions'
6
6
  import Accordion from '@cdc/core/components/ui/Accordion'
7
7
  import Button from '@cdc/core/components/elements/Button'
8
8
  import { CheckBox, Select } from '@cdc/core/components/EditorPanel/Inputs'
9
- import _ from 'lodash'
9
+ import cloneDeep from 'lodash/cloneDeep'
10
10
 
11
11
  // types
12
12
  import { type PanelProps } from './../PanelProps'
@@ -161,7 +161,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
161
161
  subsection={null}
162
162
  fieldName='anchorMode'
163
163
  updateField={(section, subsection, fieldName, value) => {
164
- const updatedAnnotations = _.cloneDeep(config?.annotations)
164
+ const updatedAnnotations = cloneDeep(config?.annotations)
165
165
  updatedAnnotations[index].anchorMode = value
166
166
 
167
167
  // When switching to data mode, ensure seriesKey and dataX are initialized
@@ -191,7 +191,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
191
191
  subsection={null}
192
192
  fieldName='seriesKey'
193
193
  updateField={(section, subsection, fieldName, value) => {
194
- const updatedAnnotations = _.cloneDeep(config?.annotations)
194
+ const updatedAnnotations = cloneDeep(config?.annotations)
195
195
  updatedAnnotations[index].seriesKey = value || config.series?.[0]?.dataKey
196
196
  updateConfig({
197
197
  ...config,
@@ -207,7 +207,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
207
207
  <input
208
208
  type='range'
209
209
  onChange={e => {
210
- const updatedAnnotations = _.cloneDeep(config?.annotations)
210
+ const updatedAnnotations = cloneDeep(config?.annotations)
211
211
  updatedAnnotations[index].opacity = e.target.value
212
212
  updateConfig({
213
213
  ...config,
@@ -225,7 +225,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
225
225
  fieldName={`${index}.edit.subject`}
226
226
  label='Edit Subject'
227
227
  updateField={(section, subsection, fieldName, value) => {
228
- const updatedAnnotations = _.cloneDeep(config?.annotations)
228
+ const updatedAnnotations = cloneDeep(config?.annotations)
229
229
  updatedAnnotations[index].edit.subject = value
230
230
  updateConfig({
231
231
  ...config,
@@ -240,7 +240,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
240
240
  fieldName={`${index}.edit.label`}
241
241
  label='Edit Label'
242
242
  updateField={(section, subsection, fieldName, value) => {
243
- const updatedAnnotations = _.cloneDeep(config?.annotations)
243
+ const updatedAnnotations = cloneDeep(config?.annotations)
244
244
  updatedAnnotations[index].edit.label = value
245
245
  updateConfig({
246
246
  ...config,
@@ -257,7 +257,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
257
257
  subsection={null}
258
258
  fieldName='connectionType'
259
259
  updateField={(section, subsection, fieldName, value) => {
260
- const updatedAnnotations = _.cloneDeep(config?.annotations)
260
+ const updatedAnnotations = cloneDeep(config?.annotations)
261
261
  updatedAnnotations[index].connectionType = value
262
262
  updateConfig({
263
263
  ...config,
@@ -277,7 +277,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
277
277
  max='20'
278
278
  value={config?.annotations[index]?.bezier || 0}
279
279
  onChange={e => {
280
- const updatedAnnotations = _.cloneDeep(config?.annotations)
280
+ const updatedAnnotations = cloneDeep(config?.annotations)
281
281
  updatedAnnotations[index].bezier = e.target.value
282
282
  updateConfig({
283
283
  ...config,
@@ -297,7 +297,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
297
297
  subsection={null}
298
298
  fieldName='marker'
299
299
  updateField={(section, subsection, fieldName, value) => {
300
- const updatedAnnotations = _.cloneDeep(config?.annotations)
300
+ const updatedAnnotations = cloneDeep(config?.annotations)
301
301
  updatedAnnotations[index].marker = value
302
302
  updateConfig({
303
303
  ...config,
@@ -320,84 +320,6 @@ const ForestPlotSettings: FC<PanelProps> = ({ name }) => {
320
320
  <br />
321
321
  <hr />
322
322
  <br />
323
- <h4>Width Settings</h4>
324
-
325
- <label>
326
- <span className='edit-label column-heading'>Chart Offset Left (%)</span>
327
- <input
328
- type='number'
329
- min={0}
330
- max={100}
331
- value={config.forestPlot.leftWidthOffset || 0}
332
- onChange={e => {
333
- updateConfig({
334
- ...config,
335
- forestPlot: {
336
- ...config.forestPlot,
337
- leftWidthOffset: e.target.value
338
- }
339
- })
340
- }}
341
- />
342
- </label>
343
-
344
- <label>
345
- <span className='edit-label column-heading'>Chart Offset Left Mobile(%)</span>
346
- <input
347
- type='number'
348
- min={0}
349
- max={100}
350
- value={config.forestPlot.leftWidthOffsetMobile || 0}
351
- onChange={e => {
352
- updateConfig({
353
- ...config,
354
- forestPlot: {
355
- ...config.forestPlot,
356
- leftWidthOffsetMobile: e.target.value
357
- }
358
- })
359
- }}
360
- />
361
- </label>
362
-
363
- <label>
364
- <span className='edit-label column-heading'>Chart Offset Right (%)</span>
365
- <input
366
- type='number'
367
- min={0}
368
- max={100}
369
- value={config.forestPlot.rightWidthOffset || 0}
370
- onChange={e => {
371
- updateConfig({
372
- ...config,
373
- forestPlot: {
374
- ...config.forestPlot,
375
- rightWidthOffset: e.target.value
376
- }
377
- })
378
- }}
379
- />
380
- </label>
381
-
382
- <label>
383
- <span className='edit-label column-heading'>Chart Offset Right Mobile(%)</span>
384
- <input
385
- type='number'
386
- min={0}
387
- max={100}
388
- value={config.forestPlot.rightWidthOffsetMobile || 0}
389
- onChange={e => {
390
- updateConfig({
391
- ...config,
392
- forestPlot: {
393
- ...config.forestPlot,
394
- rightWidthOffsetMobile: e.target.value
395
- }
396
- })
397
- }}
398
- />
399
- </label>
400
-
401
323
  <TextField
402
324
  type='number'
403
325
  min={20}
@@ -47,6 +47,22 @@ const PanelGeneral: FC<PanelProps> = props => {
47
47
  }
48
48
  }
49
49
 
50
+ const handleTitleStyleChange = (newTitleStyle: string) => {
51
+ updateConfig({
52
+ ...config,
53
+ titleStyle: newTitleStyle,
54
+ visual:
55
+ newTitleStyle === 'legacy'
56
+ ? config.visual
57
+ : {
58
+ ...config.visual,
59
+ border: undefined,
60
+ borderColorTheme: undefined,
61
+ accent: undefined
62
+ }
63
+ })
64
+ }
65
+
50
66
  return (
51
67
  <AccordionItem>
52
68
  {' '}
@@ -475,12 +491,12 @@ const PanelGeneral: FC<PanelProps> = props => {
475
491
  value={config.titleStyle}
476
492
  fieldName='titleStyle'
477
493
  label='Title Style'
478
- updateField={updateField}
479
494
  options={[
480
495
  { value: 'small', label: 'Small (h3)' },
481
496
  { value: 'large', label: 'Large (h2)' },
482
497
  { value: 'legacy', label: 'Legacy' }
483
498
  ]}
499
+ onChange={event => handleTitleStyleChange(event.target.value)}
484
500
  tooltip={
485
501
  <Tooltip style={{ textTransform: 'none' }}>
486
502
  <Tooltip.Target>
@@ -579,6 +595,28 @@ const PanelGeneral: FC<PanelProps> = props => {
579
595
  }
580
596
  />
581
597
  )}
598
+ <Select
599
+ value={config.locale}
600
+ fieldName='locale'
601
+ label='Language for dates and numbers'
602
+ updateField={updateField}
603
+ options={[
604
+ { value: 'en-US', label: 'English (en-US)' },
605
+ { value: 'es-MX', label: 'Spanish (es-MX)' }
606
+ ]}
607
+ tooltip={
608
+ <Tooltip style={{ textTransform: 'none' }}>
609
+ <Tooltip.Target>
610
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
611
+ </Tooltip.Target>
612
+ <Tooltip.Content>
613
+ <p>
614
+ Change the language (locale) for this visualization to alter the way dates and numbers are formatted.
615
+ </p>
616
+ </Tooltip.Content>
617
+ </Tooltip>
618
+ }
619
+ />
582
620
  </AccordionItemPanel>
583
621
  </AccordionItem>
584
622
  )
@@ -16,7 +16,7 @@ import { ChartContext } from '../../../../types/ChartContext'
16
16
  import { PanelProps } from '../PanelProps'
17
17
  import { checkColorContrast, getColorContrast } from '@cdc/core/helpers/cove/accessibility'
18
18
  import { getColorScale } from '../../../../helpers/getColorScale'
19
- import _ from 'lodash'
19
+ import { sanitizeToSvgId } from '@cdc/core/helpers/cove/string'
20
20
 
21
21
  const PanelPatternSettings: FC<PanelProps> = props => {
22
22
  const { config, updateConfig, transformedData } = useContext<ChartContext>(ConfigContext)
@@ -69,19 +69,6 @@ const PanelPatternSettings: FC<PanelProps> = props => {
69
69
  }
70
70
  }
71
71
 
72
- // Get unique values from a specific data field for dropdown options
73
- const getDataValueOptions = (dataKey: string) => {
74
- if (!dataKey || !Array.isArray(transformedData) || transformedData.length === 0) {
75
- return []
76
- }
77
-
78
- const uniqueValues = Array.from(new Set(transformedData.map(row => row[dataKey])))
79
- .filter(val => val !== undefined && val !== null && val !== '')
80
- .sort()
81
-
82
- return uniqueValues.map(value => ({ value: String(value), label: String(value) }))
83
- }
84
-
85
72
  const getFieldOptions = () => {
86
73
  if (!Array.isArray(transformedData) || transformedData.length === 0) return []
87
74
 
@@ -282,11 +269,6 @@ const PanelPatternSettings: FC<PanelProps> = props => {
282
269
  [field]: value
283
270
  }
284
271
 
285
- // Clear dataValue if dataKey is being cleared or set to 'Select'
286
- if (field === 'dataKey' && (value === 'Select' || value === '')) {
287
- updatedPattern.dataValue = ''
288
- }
289
-
290
272
  const newPatterns = {
291
273
  ...(legendCfg.patterns || {}),
292
274
  [patternKey]: updatedPattern
@@ -333,14 +315,18 @@ const PanelPatternSettings: FC<PanelProps> = props => {
333
315
  {/* Individual Pattern Configurations */}
334
316
  {Object.entries(currentPatterns).map(([patternKey, pattern], index) => {
335
317
  const p: LegendPattern = pattern || {}
336
- const dataValueOptions = p.dataKey ? getDataValueOptions(p.dataKey) : []
318
+ const domPatternKey = `${sanitizeToSvgId(patternKey)}-${index}`
337
319
 
338
320
  return (
339
321
  <Accordion allowZeroExpanded key={`pattern-accordion-${index}`}>
340
322
  <AccordionItem>
341
323
  <AccordionItemHeading>
342
324
  <AccordionItemButton>
343
- {p.dataKey && p.dataValue ? `${p.dataKey}: ${p.dataValue}` : `Pattern ${index + 1}`}
325
+ {p.dataKey && p.dataValue
326
+ ? `${p.dataKey}: ${p.dataValue}`
327
+ : p.dataValue
328
+ ? `All Series: ${p.dataValue}`
329
+ : `Pattern ${index + 1}`}
344
330
  </AccordionItemButton>
345
331
  </AccordionItemHeading>
346
332
  <AccordionItemPanel>
@@ -359,32 +345,28 @@ const PanelPatternSettings: FC<PanelProps> = props => {
359
345
  value={p.dataKey || ''}
360
346
  options={fieldOptions}
361
347
  initial='Select Data Key'
362
- fieldName={`pattern-datakey-${patternKey}`}
348
+ fieldName={`pattern-datakey-${domPatternKey}`}
363
349
  updateField={(section, subsection, fieldName, value) =>
364
350
  handlePatternUpdate(patternKey, 'dataKey', value)
365
351
  }
366
352
  />
367
353
 
368
- {p.dataKey && (
369
- <>
370
- <label htmlFor={`pattern-datavalue-${patternKey}`}>
371
- Data Value:
372
- <input
373
- type='text'
374
- id={`pattern-datavalue-${patternKey}`}
375
- value={p.dataValue || ''}
376
- onChange={e => handlePatternUpdate(patternKey, 'dataValue', e.target.value)}
377
- placeholder='Enter data value'
378
- />
379
- </label>
380
- </>
381
- )}
354
+ <label htmlFor={`pattern-datavalue-${domPatternKey}`}>
355
+ Data Value:
356
+ <input
357
+ type='text'
358
+ id={`pattern-datavalue-${domPatternKey}`}
359
+ value={p.dataValue || ''}
360
+ onChange={e => handlePatternUpdate(patternKey, 'dataValue', e.target.value)}
361
+ placeholder='Enter data value'
362
+ />
363
+ </label>
382
364
 
383
- <label htmlFor={`pattern-label-${patternKey}`}>
365
+ <label htmlFor={`pattern-label-${domPatternKey}`}>
384
366
  Label (optional):
385
367
  <input
386
368
  type='text'
387
- id={`pattern-label-${patternKey}`}
369
+ id={`pattern-label-${domPatternKey}`}
388
370
  value={p.label || ''}
389
371
  onChange={e => handlePatternUpdate(patternKey, 'label', e.target.value)}
390
372
  />
@@ -394,7 +376,7 @@ const PanelPatternSettings: FC<PanelProps> = props => {
394
376
  label='Pattern Type:'
395
377
  value={p.shape || 'circles'}
396
378
  options={patternTypes}
397
- fieldName={`pattern-type-${patternKey}`}
379
+ fieldName={`pattern-type-${domPatternKey}`}
398
380
  updateField={(section, subsection, fieldName, value) =>
399
381
  handlePatternUpdate(patternKey, 'shape', value)
400
382
  }
@@ -404,14 +386,14 @@ const PanelPatternSettings: FC<PanelProps> = props => {
404
386
  label='Pattern Size:'
405
387
  value={getPatternSizeText(p.patternSize || 8)}
406
388
  options={patternSizes}
407
- fieldName={`pattern-size-${patternKey}`}
389
+ fieldName={`pattern-size-${domPatternKey}`}
408
390
  updateField={(section, subsection, fieldName, value) =>
409
391
  handlePatternUpdate(patternKey, 'patternSize', getPatternSizeNumeric(value))
410
392
  }
411
393
  />
412
394
 
413
395
  <div className='mt-3'>
414
- <label htmlFor={`pattern-color-${patternKey}`}>
396
+ <label htmlFor={`pattern-color-${domPatternKey}`}>
415
397
  Pattern Color
416
398
  <Tooltip style={{ textTransform: 'none' }}>
417
399
  <Tooltip.Target>
@@ -430,7 +412,7 @@ const PanelPatternSettings: FC<PanelProps> = props => {
430
412
  <input
431
413
  type='text'
432
414
  value={p.color || ''}
433
- id={`pattern-color-${patternKey}`}
415
+ id={`pattern-color-${domPatternKey}`}
434
416
  onChange={e => handlePatternUpdate(patternKey, 'color', e.target.value)}
435
417
  placeholder='#666666'
436
418
  />
@@ -8,8 +8,9 @@ import { colorPalettesChartV1, colorPalettesChartV2, sequentialPalettes } from '
8
8
  import { updatePaletteNames } from '@cdc/core/helpers/updatePaletteNames'
9
9
  import { getColorPaletteVersion } from '@cdc/core/helpers/getColorPaletteVersion'
10
10
  import Icon from '@cdc/core/components/ui/Icon'
11
- import { Select } from '@cdc/core/components/EditorPanel/Inputs'
11
+ import { CheckBox, Select, TextField } from '@cdc/core/components/EditorPanel/Inputs'
12
12
  import { buildForecastPaletteOptions } from '../../../../helpers/buildForecastPaletteOptions'
13
+ import { getSeriesColumnConfig, upsertSeriesColumnConfig } from '../../../../helpers/seriesColumnSettings'
13
14
 
14
15
  // Third Party
15
16
  import {
@@ -538,6 +539,84 @@ const SeriesDisplayInTooltip = props => {
538
539
  )
539
540
  }
540
541
 
542
+ const SeriesColumnSettings = props => {
543
+ const { series } = props
544
+ const { config, updateConfig } = useContext(ConfigContext)
545
+ const { columnConfig } = getSeriesColumnConfig(config.columns || {}, series.dataKey)
546
+
547
+ const updateSeriesColumn = (fieldName, value) => {
548
+ const columns = upsertSeriesColumnConfig(config.columns || {}, series.dataKey, {
549
+ [fieldName]: value
550
+ })
551
+
552
+ updateConfig({
553
+ ...config,
554
+ columns
555
+ })
556
+ }
557
+
558
+ return (
559
+ <>
560
+ <span className='divider-heading'>Series Column Settings</span>
561
+ <TextField
562
+ value={columnConfig.label || ''}
563
+ section='seriesColumn'
564
+ subsection={series.dataKey}
565
+ fieldName='label'
566
+ label='Label'
567
+ updateField={(_section, _subsection, _fieldName, value) => updateSeriesColumn('label', value)}
568
+ />
569
+ <div className='three-col'>
570
+ <TextField
571
+ value={columnConfig.prefix || ''}
572
+ section='seriesColumn'
573
+ subsection={series.dataKey}
574
+ fieldName='prefix'
575
+ label='Prefix'
576
+ updateField={(_section, _subsection, _fieldName, value) => updateSeriesColumn('prefix', value)}
577
+ />
578
+ <TextField
579
+ value={columnConfig.suffix || ''}
580
+ section='seriesColumn'
581
+ subsection={series.dataKey}
582
+ fieldName='suffix'
583
+ label='Suffix'
584
+ updateField={(_section, _subsection, _fieldName, value) => updateSeriesColumn('suffix', value)}
585
+ />
586
+ <TextField
587
+ type='number'
588
+ value={columnConfig.roundToPlace ?? 0}
589
+ section='seriesColumn'
590
+ subsection={series.dataKey}
591
+ fieldName='roundToPlace'
592
+ label='Round'
593
+ updateField={(_section, _subsection, _fieldName, value) =>
594
+ updateSeriesColumn('roundToPlace', Number(value) || 0)
595
+ }
596
+ />
597
+ </div>
598
+ <CheckBox
599
+ value={columnConfig.commas || false}
600
+ section='seriesColumn'
601
+ subsection={series.dataKey}
602
+ fieldName='commas'
603
+ label='Add Commas to Numbers'
604
+ updateField={(_section, _subsection, _fieldName, value) => updateSeriesColumn('commas', value)}
605
+ />
606
+ {config.table.showVertical && (
607
+ <CheckBox
608
+ value={columnConfig.dataTable ?? true}
609
+ section='seriesColumn'
610
+ subsection={series.dataKey}
611
+ fieldName='dataTable'
612
+ label='Show in Data Table'
613
+ updateField={(_section, _subsection, _fieldName, value) => updateSeriesColumn('dataTable', value)}
614
+ />
615
+ )}
616
+ </>
617
+ )
618
+ }
619
+
541
620
  const SeriesButtonRemove = props => {
542
621
  const { config, updateConfig } = useContext(ConfigContext)
543
622
  const { series, index } = props
@@ -637,6 +716,7 @@ const SeriesItem = props => {
637
716
  {chartsWithOptions.includes(config.visualizationType) && (
638
717
  <AccordionItemPanel>
639
718
  <Series.Input.Name series={series} index={i} />
719
+ <Series.Input.ColumnSettings series={series} index={i} />
640
720
  {showDynamicCategory && (
641
721
  <>
642
722
  <Select
@@ -722,7 +802,8 @@ const Series = {
722
802
  },
723
803
  Input: {
724
804
  Name: SeriesInputName,
725
- Weight: SeriesInputWeight
805
+ Weight: SeriesInputWeight,
806
+ ColumnSettings: SeriesColumnSettings
726
807
  },
727
808
  Checkbox: {
728
809
  DisplayInTooltip: SeriesDisplayInTooltip
@@ -1,5 +1,4 @@
1
1
  import { useContext, FC, useMemo } from 'react'
2
- import _ from 'lodash'
3
2
  import cloneConfig from '@cdc/core/helpers/cloneConfig'
4
3
 
5
4
  // external libraries
@@ -31,13 +30,16 @@ import { LineChartConfig } from '../../../../types/ChartConfig'
31
30
  import { PaletteSelector, DeveloperPaletteRollback } from '@cdc/core/components/PaletteSelector'
32
31
  import { HeaderThemeSelector } from '@cdc/core/components/HeaderThemeSelector'
33
32
  import { CustomColorsEditor } from '@cdc/core/components/CustomColorsEditor'
33
+ import StyleTreatmentSection from '@cdc/core/components/EditorPanel/sections/StyleTreatmentSection'
34
34
  import { getColorScale } from '../../../../helpers/getColorScale'
35
- import '@cdc/core/styles/v2/components/editor.scss'
35
+ import { ENABLE_CHART_MAP_TP5_TREATMENT_SELECTION, ENABLE_CHART_VISUAL_SETTINGS } from '@cdc/core/helpers/constants'
36
+ import '@cdc/core/components/EditorPanel/editor.scss'
36
37
  import './panelVisual.styles.css'
37
38
 
38
39
  const PanelVisual: FC<PanelProps> = props => {
39
40
  const { config, updateConfig, colorPalettes, twoColorPalette } = useContext<ChartContext>(ConfigContext)
40
41
  const { visual } = config
42
+ const styleTreatment = config.titleStyle === 'legacy' && !visual?.tp5Treatment ? 'legacy' : 'tp5'
41
43
 
42
44
  const { setLollipopShape, updateField, handlePaletteSelection, handleTwoColorPaletteSelection } =
43
45
  useEditorPanelContext()
@@ -89,12 +91,44 @@ const PanelVisual: FC<PanelProps> = props => {
89
91
  }
90
92
  }
91
93
 
94
+ const handleStyleTreatmentChange = (value: string) => {
95
+ const useTp5Treatment = value === 'tp5'
96
+
97
+ updateConfig({
98
+ ...config,
99
+ titleStyle: useTp5Treatment ? 'small' : 'legacy',
100
+ visual: {
101
+ ...config.visual,
102
+ tp5Treatment: useTp5Treatment,
103
+ border: useTp5Treatment ? false : config.visual?.border,
104
+ borderColorTheme: useTp5Treatment ? false : config.visual?.borderColorTheme,
105
+ accent: useTp5Treatment ? false : config.visual?.accent
106
+ }
107
+ })
108
+ }
109
+
92
110
  return (
93
111
  <AccordionItem className='panel-visual'>
94
112
  <AccordionItemHeading>
95
113
  <AccordionItemButton>Visual</AccordionItemButton>
96
114
  </AccordionItemHeading>
97
115
  <AccordionItemPanel>
116
+ <HeaderThemeSelector selectedTheme={config.theme} onThemeSelect={theme => updateConfig({ ...config, theme })} />
117
+ {ENABLE_CHART_VISUAL_SETTINGS && (
118
+ <StyleTreatmentSection
119
+ styleTreatment={styleTreatment}
120
+ onStyleTreatmentChange={handleStyleTreatmentChange}
121
+ showStyleTreatment={ENABLE_CHART_MAP_TP5_TREATMENT_SELECTION}
122
+ border={visual?.border}
123
+ borderColorTheme={visual?.borderColorTheme}
124
+ accent={visual?.accent}
125
+ background={visual?.background}
126
+ hideBackgroundColor={visual?.hideBackgroundColor}
127
+ showBackground={config.visualizationType === 'Spark Line'}
128
+ showHideBackgroundColor={config.visualizationType === 'Spark Line'}
129
+ updateField={updateField}
130
+ />
131
+ )}
98
132
  {(config.barStyle === 'lollipop' || config.isLollipopChart) && (
99
133
  <>
100
134
  <fieldset className='header'>
@@ -272,7 +306,6 @@ const PanelVisual: FC<PanelProps> = props => {
272
306
  />
273
307
  </>
274
308
  )}
275
- <HeaderThemeSelector selectedTheme={config.theme} onThemeSelect={theme => updateConfig({ ...config, theme })} />
276
309
  {(visSupportsNonSequentialPallete() || visSupportsNonSequentialPallete()) && (
277
310
  <>
278
311
  <label>
@@ -573,45 +606,6 @@ const PanelVisual: FC<PanelProps> = props => {
573
606
  updateField={updateField}
574
607
  />
575
608
  )}
576
- {config.visualizationType === 'Spark Line' && (
577
- <div className='cove-accordion__panel-section checkbox-group'>
578
- <CheckBox
579
- value={visual?.border}
580
- section='visual'
581
- fieldName='border'
582
- label='Show Border'
583
- updateField={updateField}
584
- />
585
- <CheckBox
586
- value={visual?.borderColorTheme}
587
- section='visual'
588
- fieldName='borderColorTheme'
589
- label='Use Border Color Theme'
590
- updateField={updateField}
591
- />
592
- <CheckBox
593
- value={visual?.accent}
594
- section='visual'
595
- fieldName='accent'
596
- label='Use Accent Style'
597
- updateField={updateField}
598
- />
599
- <CheckBox
600
- value={visual?.background}
601
- section='visual'
602
- fieldName='background'
603
- label='Use Theme Background Color'
604
- updateField={updateField}
605
- />
606
- <CheckBox
607
- value={visual?.hideBackgroundColor}
608
- section='visual'
609
- fieldName='hideBackgroundColor'
610
- label='Hide Background Color'
611
- updateField={updateField}
612
- />
613
- </div>
614
- )}
615
609
  {(config.visualizationType === 'Line' || config.visualizationType === 'Combo') && (
616
610
  <CheckBox
617
611
  value={config.showLineSeriesLabels}
@@ -690,6 +684,15 @@ const PanelVisual: FC<PanelProps> = props => {
690
684
  }
691
685
  />
692
686
  </label>
687
+ {isCoveDeveloperMode() && (
688
+ <CheckBox
689
+ value={visual?.highlightWrappers}
690
+ section='visual'
691
+ fieldName='highlightWrappers'
692
+ label='Highlight Layout Wrappers'
693
+ updateField={updateField}
694
+ />
695
+ )}
693
696
  </AccordionItemPanel>
694
697
  </AccordionItem>
695
698
  )
@@ -1,4 +1,4 @@
1
- .cdc-open-viz-module.type-chart {
1
+ .cove-visualization.type-chart {
2
2
  .viewport-overrides {
3
3
  button {
4
4
  width: 100%;