@cdc/chart 4.24.9 → 4.24.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/LICENSE +201 -0
  2. package/dist/cdcchart.js +45911 -41739
  3. package/examples/feature/boxplot/boxplot-data.json +88 -22
  4. package/examples/feature/boxplot/boxplot.json +540 -16
  5. package/examples/feature/boxplot/testing.csv +7 -7
  6. package/examples/feature/sankey/sankey-example-data.json +0 -1
  7. package/examples/private/test.json +20092 -0
  8. package/index.html +4 -4
  9. package/package.json +2 -2
  10. package/src/CdcChart.tsx +209 -188
  11. package/src/_stories/Chart.CustomColors.stories.tsx +19 -0
  12. package/src/_stories/Chart.DynamicSeries.stories.tsx +27 -0
  13. package/src/_stories/Chart.Legend.Gradient.stories.tsx +74 -0
  14. package/src/_stories/Chart.stories.tsx +30 -3
  15. package/src/_stories/ChartAxisLabels.stories.tsx +20 -0
  16. package/src/_stories/ChartAxisTitles.stories.tsx +53 -0
  17. package/src/_stories/ChartEditor.stories.tsx +27 -0
  18. package/src/_stories/ChartLine.Suppression.stories.tsx +25 -0
  19. package/src/_stories/ChartPrefixSuffix.stories.tsx +159 -0
  20. package/src/_stories/_mock/boxplot_multiseries.json +647 -0
  21. package/src/_stories/_mock/dynamic_series_bar_config.json +723 -0
  22. package/src/_stories/_mock/dynamic_series_config.json +979 -0
  23. package/src/_stories/_mock/horizontal_bar.json +257 -0
  24. package/src/_stories/_mock/large_x_axis_labels.json +261 -0
  25. package/src/_stories/_mock/paired-bar.json +262 -0
  26. package/src/_stories/_mock/pie_with_data.json +255 -0
  27. package/{examples/feature/scatterplot/scatterplot.json → src/_stories/_mock/scatterplot_mock.json} +62 -92
  28. package/src/_stories/_mock/simplified_line.json +1510 -0
  29. package/src/_stories/_mock/suppression_mock.json +1549 -0
  30. package/src/components/Annotations/components/AnnotationDraggable.tsx +0 -3
  31. package/src/components/Annotations/components/AnnotationDropdown.tsx +1 -1
  32. package/src/components/Axis/Categorical.Axis.tsx +22 -4
  33. package/src/components/BarChart/components/BarChart.Horizontal.tsx +95 -16
  34. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +41 -17
  35. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +43 -9
  36. package/src/components/BarChart/components/BarChart.Vertical.tsx +123 -47
  37. package/src/components/BarChart/helpers/index.ts +23 -5
  38. package/src/components/BoxPlot/BoxPlot.tsx +189 -0
  39. package/src/components/BrushChart.tsx +3 -2
  40. package/src/components/DeviationBar.jsx +58 -8
  41. package/src/components/EditorPanel/EditorPanel.tsx +127 -102
  42. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +11 -28
  43. package/src/components/EditorPanel/components/Panels/Panel.BoxPlot.tsx +51 -6
  44. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +21 -4
  45. package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +40 -9
  46. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +3 -3
  47. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +121 -56
  48. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +296 -35
  49. package/src/components/EditorPanel/components/panels.scss +4 -6
  50. package/src/components/EditorPanel/editor-panel.scss +0 -8
  51. package/src/components/EditorPanel/helpers/tests/updateFieldRankByValue.test.ts +38 -0
  52. package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +42 -0
  53. package/src/components/EditorPanel/useEditorPermissions.ts +16 -1
  54. package/src/components/ForestPlot/ForestPlot.tsx +2 -3
  55. package/src/components/ForestPlot/ForestPlotProps.ts +2 -0
  56. package/src/components/Legend/Legend.Component.tsx +23 -24
  57. package/src/components/Legend/Legend.Suppression.tsx +25 -20
  58. package/src/components/Legend/Legend.tsx +16 -18
  59. package/src/components/Legend/helpers/index.ts +16 -19
  60. package/src/components/LegendWrapper.tsx +3 -1
  61. package/src/components/LineChart/components/LineChart.Circle.tsx +10 -0
  62. package/src/components/LineChart/helpers.ts +48 -43
  63. package/src/components/LineChart/index.tsx +88 -82
  64. package/src/components/LinearChart.tsx +747 -562
  65. package/src/components/PairedBarChart.jsx +50 -10
  66. package/src/components/PieChart/PieChart.tsx +1 -6
  67. package/src/components/Regions/components/Regions.tsx +33 -19
  68. package/src/components/Sankey/index.tsx +50 -32
  69. package/src/components/Sankey/sankey.scss +6 -5
  70. package/src/components/Sankey/useSankeyAlert.tsx +60 -0
  71. package/src/components/ScatterPlot/ScatterPlot.jsx +20 -4
  72. package/src/components/ZoomBrush.tsx +25 -6
  73. package/src/coreStyles_chart.scss +3 -0
  74. package/src/data/initial-state.js +8 -10
  75. package/src/helpers/configHelpers.ts +28 -0
  76. package/src/helpers/handleRankByValue.ts +15 -0
  77. package/src/helpers/sizeHelpers.ts +25 -0
  78. package/src/helpers/tests/handleRankByValue.test.ts +37 -0
  79. package/src/helpers/tests/sizeHelpers.test.ts +80 -0
  80. package/src/hooks/useColorPalette.js +10 -2
  81. package/src/hooks/useLegendClasses.ts +13 -22
  82. package/src/hooks/useMinMax.ts +27 -13
  83. package/src/hooks/useReduceData.ts +43 -10
  84. package/src/hooks/useScales.ts +87 -38
  85. package/src/hooks/useTooltip.tsx +62 -53
  86. package/src/index.jsx +1 -0
  87. package/src/scss/DataTable.scss +5 -4
  88. package/src/scss/main.scss +57 -70
  89. package/src/types/ChartConfig.ts +43 -34
  90. package/src/types/ChartContext.ts +22 -15
  91. package/src/types/ForestPlot.ts +8 -0
  92. package/src/_stories/Chart.Legend.Gradient.tsx +0 -19
  93. package/src/_stories/ChartBrush.stories.tsx +0 -19
  94. package/src/components/BoxPlot/BoxPlot.jsx +0 -111
  95. package/src/components/LinearChart.jsx +0 -817
@@ -1,5 +1,10 @@
1
1
  import { useContext, FC } from 'react'
2
- import { AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
2
+ import {
3
+ AccordionItem,
4
+ AccordionItemHeading,
5
+ AccordionItemPanel,
6
+ AccordionItemButton
7
+ } from 'react-accessible-accordion'
3
8
  import { TextField } from '@cdc/core/components/EditorPanel/Inputs'
4
9
  import Tooltip from '@cdc/core/components/ui/Tooltip'
5
10
  import Icon from '@cdc/core/components/ui/Icon'
@@ -131,15 +136,55 @@ const PanelBoxPlot: FC<PanelProps> = props => {
131
136
  <h4 style={{ fontSize: '18px' }}>Labels for Additional Measures</h4>
132
137
 
133
138
  {/* iqr */}
134
- <TextField type='text' value={boxplot.labels.iqr} fieldName='iqr' section='boxplot' subsection='labels' label='Interquartile Range' updateField={updateField} />
139
+ <TextField
140
+ type='text'
141
+ value={boxplot.labels.iqr}
142
+ fieldName='iqr'
143
+ section='boxplot'
144
+ subsection='labels'
145
+ label='Interquartile Range'
146
+ updateField={updateField}
147
+ />
135
148
  {/* count */}
136
- <TextField type='text' value={boxplot.labels.total} fieldName='total' section='boxplot' subsection='labels' label='Total' updateField={updateField} />
149
+ <TextField
150
+ type='text'
151
+ value={boxplot.labels.count}
152
+ fieldName='count'
153
+ section='boxplot'
154
+ subsection='labels'
155
+ label='Count'
156
+ updateField={updateField}
157
+ />
137
158
  {/* mean */}
138
- <TextField type='text' value={boxplot.labels.mean} fieldName='mean' section='boxplot' subsection='labels' label='Mean' updateField={updateField} />
159
+ <TextField
160
+ type='text'
161
+ value={boxplot.labels.mean}
162
+ fieldName='mean'
163
+ section='boxplot'
164
+ subsection='labels'
165
+ label='Mean'
166
+ updateField={updateField}
167
+ />
139
168
  {/* outliers */}
140
- <TextField type='text' value={boxplot.labels.outliers} fieldName='outliers' section='boxplot' subsection='labels' label='Outliers' updateField={updateField} />
169
+ <TextField
170
+ type='text'
171
+ value={boxplot.labels.outliers}
172
+ fieldName='outliers'
173
+ section='boxplot'
174
+ subsection='labels'
175
+ label='Outliers'
176
+ updateField={updateField}
177
+ />
141
178
  {/* values */}
142
- <TextField type='text' value={boxplot.labels.values} fieldName='values' section='boxplot' subsection='labels' label='Values' updateField={updateField} />
179
+ <TextField
180
+ type='text'
181
+ value={boxplot.labels.values}
182
+ fieldName='values'
183
+ section='boxplot'
184
+ subsection='labels'
185
+ label='Values'
186
+ updateField={updateField}
187
+ />
143
188
  </AccordionItemPanel>
144
189
  </AccordionItem>
145
190
  )
@@ -221,6 +221,26 @@ const PanelGeneral: FC<PanelProps> = props => {
221
221
  )}
222
222
  {visHasaAdditionalLabelsOnBars() && (
223
223
  <>
224
+ <CheckBox
225
+ tooltip={
226
+ <Tooltip style={{ textTransform: 'none' }}>
227
+ <Tooltip.Target>
228
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
229
+ </Tooltip.Target>
230
+ <Tooltip.Content>
231
+ <p>
232
+ Selecting this option will display a thin line slightly above the Date/Category Axis to indicate
233
+ "zero value" where zero values are indicated in the Data Series.
234
+ </p>
235
+ </Tooltip.Content>
236
+ </Tooltip>
237
+ }
238
+ value={config.general.showZeroValueData}
239
+ section='general'
240
+ fieldName='showZeroValueData'
241
+ label='Display "Zero Data" Label'
242
+ updateField={updateField}
243
+ />
224
244
  <CheckBox
225
245
  tooltip={
226
246
  <Tooltip style={{ textTransform: 'none' }}>
@@ -251,10 +271,7 @@ const PanelGeneral: FC<PanelProps> = props => {
251
271
  updateField={updateField}
252
272
  />
253
273
  <CheckBox
254
- display={
255
- config.visualizationSubType === 'stacked' &&
256
- (config.visualizationType === 'Bar' || config.visualizationType === 'Combo')
257
- }
274
+ display={config.visualizationType === 'Bar' || config.visualizationType === 'Combo'}
258
275
  tooltip={
259
276
  <Tooltip style={{ textTransform: 'none' }}>
260
277
  <Tooltip.Target>
@@ -1,6 +1,11 @@
1
1
  import { memo, useContext } from 'react'
2
2
  import { useEditorPermissions } from '../../useEditorPermissions.js'
3
- import { AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
3
+ import {
4
+ AccordionItem,
5
+ AccordionItemHeading,
6
+ AccordionItemPanel,
7
+ AccordionItemButton
8
+ } from 'react-accessible-accordion'
4
9
  import { type ChartConfig } from '../../../../types/ChartConfig.js'
5
10
  import { TextField, Select } from '@cdc/core/components/EditorPanel/Inputs'
6
11
  import Tooltip from '@cdc/core/components/ui/Tooltip'
@@ -58,7 +63,7 @@ const RegionSettings = memo(({ config, updateConfig }: { config: ChartConfig; up
58
63
  <div className='edit-block' key={`region-${i}`}>
59
64
  <button
60
65
  type='button'
61
- className='remove-column'
66
+ className='btn btn-danger remove-column'
62
67
  onClick={event => {
63
68
  event.preventDefault()
64
69
  removeColumn(i)
@@ -68,8 +73,18 @@ const RegionSettings = memo(({ config, updateConfig }: { config: ChartConfig; up
68
73
  </button>
69
74
  <TextField value={label} label='Region Label' fieldName='label' i={i} updateField={updateField} />
70
75
  <div className='two-col-inputs'>
71
- <TextField value={color} label='Text Color' fieldName='color' updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)} />
72
- <TextField value={background} label='Background' fieldName='background' updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)} />
76
+ <TextField
77
+ value={color}
78
+ label='Text Color'
79
+ fieldName='color'
80
+ updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)}
81
+ />
82
+ <TextField
83
+ value={background}
84
+ label='Background'
85
+ fieldName='background'
86
+ updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)}
87
+ />
73
88
  </div>
74
89
 
75
90
  <Select
@@ -91,11 +106,17 @@ const RegionSettings = memo(({ config, updateConfig }: { config: ChartConfig; up
91
106
  options={fromOptions}
92
107
  />
93
108
 
94
- {(config.regions[i].fromType === 'Fixed' || config.regions[i].fromType === 'Previous Days' || !config.regions[i].fromType) && (
109
+ {(config.regions[i].fromType === 'Fixed' ||
110
+ config.regions[i].fromType === 'Previous Days' ||
111
+ !config.regions[i].fromType) && (
95
112
  <>
96
113
  <TextField
97
114
  value={from}
98
- label={config.regions[i].fromType === 'Fixed' || !config.regions[i]?.fromType ? 'From Value' : 'Previous Number of Days'}
115
+ label={
116
+ config.regions[i].fromType === 'Fixed' || !config.regions[i]?.fromType
117
+ ? 'From Value'
118
+ : 'Previous Number of Days'
119
+ }
99
120
  fieldName='from'
100
121
  updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)}
101
122
  tooltip={
@@ -104,7 +125,10 @@ const RegionSettings = memo(({ config, updateConfig }: { config: ChartConfig; up
104
125
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
105
126
  </Tooltip.Target>
106
127
  <Tooltip.Content>
107
- <p>When using categorical (linear scale) match the data set value. When using date (linear / date time scale) match the x-axis value.</p>
128
+ <p>
129
+ When using categorical (linear scale) match the data set value. When using date (linear / date
130
+ time scale) match the x-axis value.
131
+ </p>
108
132
  </Tooltip.Content>
109
133
  </Tooltip>
110
134
  }
@@ -131,13 +155,20 @@ const RegionSettings = memo(({ config, updateConfig }: { config: ChartConfig; up
131
155
  options={toOptions}
132
156
  />
133
157
 
134
- {(config.regions[i].toType === 'Fixed' || !config.regions[i].toType) && <TextField value={to} label='To Value' fieldName='to' updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)} />}
158
+ {(config.regions[i].toType === 'Fixed' || !config.regions[i].toType) && (
159
+ <TextField
160
+ value={to}
161
+ label='To Value'
162
+ fieldName='to'
163
+ updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)}
164
+ />
165
+ )}
135
166
  </div>
136
167
  ))}
137
168
  {!config.regions && <p style={{ textAlign: 'center' }}>There are currently no regions.</p>}
138
169
  <button
139
170
  type='button'
140
- className='btn full-width'
171
+ className='btn btn-primary full-width'
141
172
  onClick={e => {
142
173
  e.preventDefault()
143
174
  addColumn()
@@ -11,7 +11,7 @@ import {
11
11
  } from 'react-accessible-accordion'
12
12
  import EditorPanelContext, { type EditorPanelContext as EPContext } from '../../EditorPanelContext'
13
13
 
14
- const SankeySettings = () => {
14
+ const SankeySettings: React.FC<PanelProps> = props => {
15
15
  const { config, updateConfig } = useContext(ConfigContext)
16
16
  const data = config.data?.[0]
17
17
  const { updateField } = useContext<EPContext>(EditorPanelContext)
@@ -109,7 +109,7 @@ const SankeySettings = () => {
109
109
  onChange={e => updateStoryNode('segmentTextAfter', e.target.value, i)}
110
110
  />
111
111
  </label>
112
- <Button onClick={e => removeStoryNode(i)} className='btn' style={{ background: 'tomato' }}>
112
+ <Button onClick={e => removeStoryNode(i)} className='btn btn-danger full-width'>
113
113
  Remove Story Node
114
114
  </Button>
115
115
  </div>
@@ -117,7 +117,7 @@ const SankeySettings = () => {
117
117
  {data?.storyNodeText?.length < 3 && (
118
118
  <button
119
119
  type='button'
120
- className='btn full-width'
120
+ className='btn btn-primary full-width'
121
121
  onClick={e => {
122
122
  e.preventDefault()
123
123
  addStoryNode()
@@ -1,4 +1,4 @@
1
- import React, { useContext } from 'react'
1
+ import React, { useContext, useMemo } from 'react'
2
2
  import ConfigContext from '../../../../ConfigContext'
3
3
 
4
4
  // Core
@@ -7,10 +7,18 @@ import Check from '@cdc/core/assets/icon-check.svg'
7
7
  import { approvedCurveTypes } from '@cdc/core/helpers/lineChartHelpers'
8
8
  import { sequentialPalettes } from '@cdc/core/data/colorPalettes'
9
9
  import Icon from '@cdc/core/components/ui/Icon'
10
+ import { Select } from '@cdc/core/components/EditorPanel/Inputs'
10
11
 
11
12
  // Third Party
12
- import { Accordion, AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
13
+ import {
14
+ Accordion,
15
+ AccordionItem,
16
+ AccordionItemHeading,
17
+ AccordionItemPanel,
18
+ AccordionItemButton
19
+ } from 'react-accessible-accordion'
13
20
  import { Draggable } from '@hello-pangea/dnd'
21
+ import Tooltip from '@cdc/core/components/ui/Tooltip'
14
22
 
15
23
  const SeriesContext = React.createContext({})
16
24
 
@@ -48,7 +56,11 @@ const SeriesWrapper = props => {
48
56
  updateConfig({ ...config, series })
49
57
  }
50
58
 
51
- return <SeriesContext.Provider value={{ updateSeries, supportedRightAxisTypes, getColumns, selectComponent }}>{props.children}</SeriesContext.Provider>
59
+ return (
60
+ <SeriesContext.Provider value={{ updateSeries, supportedRightAxisTypes, getColumns, selectComponent }}>
61
+ {props.children}
62
+ </SeriesContext.Provider>
63
+ )
52
64
  }
53
65
 
54
66
  const SeriesDropdownLineType = props => {
@@ -245,7 +257,9 @@ const SeriesDropdownForecastColor = props => {
245
257
  <InputSelect
246
258
  key={`${stage}--${stageIndex}`}
247
259
  initial='Select an option'
248
- value={config.series?.[index].stages?.[stageIndex].color ? config.series?.[index].stages?.[stageIndex].color : 'Select'}
260
+ value={
261
+ config.series?.[index].stages?.[stageIndex].color ? config.series?.[index].stages?.[stageIndex].color : 'Select'
262
+ }
249
263
  label={`${stage.key} Series Color`}
250
264
  onChange={event => {
251
265
  const copyOfSeries = [...config.series] // copy the entire series array
@@ -315,55 +329,33 @@ const SeriesDropdownConfidenceInterval = props => {
315
329
  <AccordionItemPanel>
316
330
  <div className='input-group'>
317
331
  <label htmlFor='showInTooltip'>Show In Tooltip</label>
318
- <div className={'cove-input__checkbox--small'} onClick={e => updateShowInTooltip(e, index, ciIndex)}>
319
- <div className={`cove-input__checkbox-box${'blue' ? ' custom-color' : ''}`} style={{ backgroundColor: '' }}>
332
+ <div
333
+ className={'cove-input__checkbox--small'}
334
+ onClick={e => updateShowInTooltip(e, index, ciIndex)}
335
+ >
336
+ <div
337
+ className={`cove-input__checkbox-box${'blue' ? ' custom-color' : ''}`}
338
+ style={{ backgroundColor: '' }}
339
+ >
320
340
  {showInTooltip && <Check className='' style={{ fill: '#025eaa' }} />}
321
341
  </div>
322
- <input className='cove-input--hidden' type='checkbox' name={'showInTooltip'} checked={showInTooltip ? showInTooltip : false} readOnly />
342
+ <input
343
+ className='cove-input--hidden'
344
+ type='checkbox'
345
+ name={'showInTooltip'}
346
+ checked={showInTooltip ? showInTooltip : false}
347
+ readOnly
348
+ />
323
349
  </div>
324
350
  </div>
325
351
 
326
- {/* <label>
327
- High Label
328
- <input
329
- type='text'
330
- key={`series-ci-high-label-${index}`}
331
- value={series.confidenceIntervals[index]?.highLabel ? series.confidenceIntervals[index]?.highLabel : ''}
332
- onChange={e => {
333
- const copiedConfidenceArray = [...config.series[index].confidenceIntervals]
334
- copiedConfidenceArray[ciIndex].highLabel = e.target.value
335
- const copyOfSeries = [...config.series] // copy the entire series array
336
- copyOfSeries[index] = { ...copyOfSeries[index], confidenceIntervals: copiedConfidenceArray }
337
- updateConfig({
338
- ...config,
339
- series: copyOfSeries
340
- })
341
- }}
342
- />
343
- </label> */}
344
-
345
- {/* <label>
346
- Low label
347
- <input
348
- type='text'
349
- key={`series-ci-high-label-${index}`}
350
- value={series.confidenceIntervals[index]?.lowLabel ? series.confidenceIntervals[index]?.lowLabel : ''}
351
- onChange={e => {
352
- const copiedConfidenceArray = [...config.series[index].confidenceIntervals]
353
- copiedConfidenceArray[ciIndex].lowLabel = e.target.value
354
- const copyOfSeries = [...config.series] // copy the entire series array
355
- copyOfSeries[index] = { ...copyOfSeries[index], confidenceIntervals: copiedConfidenceArray }
356
- updateConfig({
357
- ...config,
358
- series: copyOfSeries
359
- })
360
- }}
361
- />
362
- </label> */}
363
-
364
352
  <InputSelect
365
353
  initial='Select an option'
366
- value={config.series[index].confidenceIntervals[ciIndex].low ? config.series[index].confidenceIntervals[ciIndex].low : 'Select'}
354
+ value={
355
+ config.series[index].confidenceIntervals[ciIndex].low
356
+ ? config.series[index].confidenceIntervals[ciIndex].low
357
+ : 'Select'
358
+ }
367
359
  label='Low Confidence Interval'
368
360
  onChange={e => {
369
361
  const copiedConfidenceArray = [...config.series[index].confidenceIntervals]
@@ -379,7 +371,11 @@ const SeriesDropdownConfidenceInterval = props => {
379
371
  />
380
372
  <InputSelect
381
373
  initial='Select an option'
382
- value={config.series[index].confidenceIntervals[ciIndex].high ? config.series[index].confidenceIntervals[ciIndex].high : 'Select'}
374
+ value={
375
+ config.series[index].confidenceIntervals[ciIndex].high
376
+ ? config.series[index].confidenceIntervals[ciIndex].high
377
+ : 'Select'
378
+ }
383
379
  label='High Confidence Interval'
384
380
  onChange={e => {
385
381
  const copiedConfidenceArray = [...config.series[index].confidenceIntervals]
@@ -399,7 +395,7 @@ const SeriesDropdownConfidenceInterval = props => {
399
395
  })}
400
396
  </Accordion>
401
397
  <button
402
- className='btn full-width'
398
+ className='btn btn-primary full-width'
403
399
  onClick={e => {
404
400
  e.preventDefault()
405
401
  let copiedIndex = null
@@ -409,7 +405,10 @@ const SeriesDropdownConfidenceInterval = props => {
409
405
  copiedIndex = []
410
406
  }
411
407
  const copyOfSeries = [...config.series] // copy the entire series array
412
- copyOfSeries[index] = { ...copyOfSeries[index], confidenceIntervals: [...copiedIndex, { high: '', low: '' }] } // update the nested array
408
+ copyOfSeries[index] = {
409
+ ...copyOfSeries[index],
410
+ confidenceIntervals: [...copiedIndex, { high: '', low: '' }]
411
+ } // update the nested array
413
412
  updateConfig({
414
413
  ...config,
415
414
  series: copyOfSeries
@@ -468,7 +467,19 @@ const SeriesInputWeight = props => {
468
467
  const SeriesInputName = props => {
469
468
  const { series, index: i } = props
470
469
  const { config, updateConfig } = useContext(ConfigContext)
471
- const adjustableNameSeriesTypes = ['Bump Chart', 'Bar', 'Line', 'Area Chart', 'Combo', 'Deviation', 'Paired', 'Scatter', 'dashed-sm', 'dashed-md', 'dashed-lg']
470
+ const adjustableNameSeriesTypes = [
471
+ 'Bump Chart',
472
+ 'Bar',
473
+ 'Line',
474
+ 'Area Chart',
475
+ 'Combo',
476
+ 'Deviation',
477
+ 'Paired',
478
+ 'Scatter',
479
+ 'dashed-sm',
480
+ 'dashed-md',
481
+ 'dashed-lg'
482
+ ]
472
483
 
473
484
  if (!adjustableNameSeriesTypes.includes(series.type)) return
474
485
 
@@ -532,7 +543,13 @@ const SeriesDisplayInTooltip = props => {
532
543
  <div className={`cove-input__checkbox-box${'blue' ? ' custom-color' : ''}`} style={{ backgroundColor: '' }}>
533
544
  {series.tooltip && <Check className='' style={{ fill: '#025eaa' }} />}
534
545
  </div>
535
- <input className='cove-input--hidden' type='checkbox' name={`series-tooltip--${index}`} checked={series.tooltip ? series.tooltip : false} readOnly />
546
+ <input
547
+ className='cove-input--hidden'
548
+ type='checkbox'
549
+ name={`series-tooltip--${index}`}
550
+ checked={series.tooltip ? series.tooltip : false}
551
+ readOnly
552
+ />
536
553
  </div>
537
554
  </div>
538
555
  </>
@@ -591,17 +608,32 @@ const SeriesButtonRemove = props => {
591
608
 
592
609
  const SeriesItem = props => {
593
610
  const { config } = useContext(ConfigContext)
594
-
611
+ const { updateSeries, getColumns } = useContext(SeriesContext)
595
612
  const { series, getItemStyle, sortableItemStyles, chartsWithOptions, index: i } = props
596
-
613
+ const showDynamicCategory =
614
+ ['Bar', 'Line'].includes(config.visualizationType) &&
615
+ !config.series.find(s => s.dynamicCategory && s.dataKey !== series.dataKey)
597
616
  return (
598
617
  <Draggable key={series.dataKey} draggableId={`draggableFilter-${series.dataKey}`} index={i}>
599
618
  {(provided, snapshot) => (
600
- <div key={i} className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
619
+ <div
620
+ key={i}
621
+ className={snapshot.isDragging ? 'currently-dragging' : ''}
622
+ style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)}
623
+ ref={provided.innerRef}
624
+ {...provided.draggableProps}
625
+ {...provided.dragHandleProps}
626
+ >
601
627
  <Accordion allowZeroExpanded>
602
628
  <AccordionItem className='series-item series-item--chart'>
603
629
  <AccordionItemHeading className='series-item__title'>
604
- <AccordionItemButton className={chartsWithOptions.includes(config.visualizationType) ? 'accordion__button' : 'accordion__button hide-arrow'}>
630
+ <AccordionItemButton
631
+ className={
632
+ chartsWithOptions.includes(config.visualizationType)
633
+ ? 'accordion__button'
634
+ : 'accordion__button hide-arrow'
635
+ }
636
+ >
605
637
  <Icon display='move' size={15} style={{ cursor: 'default' }} />
606
638
  {series.dataKey}
607
639
  <Series.Button.Remove series={series} index={i} />
@@ -610,6 +642,30 @@ const SeriesItem = props => {
610
642
  {chartsWithOptions.includes(config.visualizationType) && (
611
643
  <AccordionItemPanel>
612
644
  <Series.Input.Name series={series} index={i} />
645
+ {showDynamicCategory && (
646
+ <Select
647
+ label='Dynamic Category'
648
+ value={series.dynamicCategory}
649
+ options={['- Select - ', ...getColumns().filter(col => series.dataKey !== col)]}
650
+ updateField={(_section, _subsection, _fieldName, value) => {
651
+ if (value === '- Select -') value = ''
652
+ updateSeries(i, value, 'dynamicCategory')
653
+ }}
654
+ tooltip={
655
+ <Tooltip style={{ textTransform: 'none' }}>
656
+ <Tooltip.Target>
657
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
658
+ </Tooltip.Target>
659
+ <Tooltip.Content>
660
+ <p>
661
+ This field is Optional. If you have a dynamic data series you can select the category
662
+ field here. You can only add one dynamic category per visualization.
663
+ </p>
664
+ </Tooltip.Content>
665
+ </Tooltip>
666
+ }
667
+ />
668
+ )}
613
669
  <Series.Input.Weight series={series} index={i} />
614
670
  <Series.Dropdown.SeriesType series={series} index={i} />
615
671
  <Series.Dropdown.AxisPosition series={series} index={i} />
@@ -630,7 +686,16 @@ const SeriesItem = props => {
630
686
  const SeriesList = props => {
631
687
  const { series, getItemStyle, sortableItemStyles, chartsWithOptions } = props
632
688
  return series.map((series, i) => {
633
- return <SeriesItem getItemStyle={getItemStyle} sortableItemStyles={sortableItemStyles} chartsWithOptions={chartsWithOptions} series={series} index={i} key={`series-list-${i}`} />
689
+ return (
690
+ <SeriesItem
691
+ getItemStyle={getItemStyle}
692
+ sortableItemStyles={sortableItemStyles}
693
+ chartsWithOptions={chartsWithOptions}
694
+ series={series}
695
+ index={i}
696
+ key={`series-list-${i}`}
697
+ />
698
+ )
634
699
  })
635
700
  }
636
701