@cdc/chart 4.25.10 → 4.26.1

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 (135) hide show
  1. package/dist/{cdcchart-1a1724a1.es.js → cdcchart-dgT_1dIT.es.js} +136 -151
  2. package/dist/cdcchart.js +44003 -43518
  3. package/examples/feature/__data__/planet-example-data.json +1 -1
  4. package/examples/feature/boxplot/valid-boxplot.csv +38 -17
  5. package/examples/feature/pie/planet-pie-example-config.json +48 -2
  6. package/examples/private/DEV-11825.json +573 -0
  7. package/examples/private/DEV-12100.json +1303 -0
  8. package/examples/private/cat-y.json +1235 -0
  9. package/examples/private/data-points.json +228 -0
  10. package/examples/private/height.json +3915 -0
  11. package/examples/private/links.json +569 -0
  12. package/examples/private/na.json +913 -0
  13. package/examples/private/quadrant.txt +30 -0
  14. package/examples/private/test-data.csv +28 -0
  15. package/examples/private/test-forecast.json +5510 -0
  16. package/examples/private/warming-stripe-test.json +2578 -0
  17. package/examples/private/warming-stripes.json +4763 -0
  18. package/examples/tech-adoption-with-links.json +560 -0
  19. package/index.html +16 -140
  20. package/package.json +6 -5
  21. package/preview.html +1616 -0
  22. package/src/CdcChart.tsx +8 -11
  23. package/src/CdcChartComponent.tsx +329 -124
  24. package/src/_stories/Chart.Combo.stories.tsx +18 -0
  25. package/src/_stories/Chart.Forecast.stories.tsx +36 -0
  26. package/src/_stories/Chart.HTMLInDataTable.stories.tsx +520 -0
  27. package/src/_stories/Chart.Patterns.stories.tsx +2 -1
  28. package/src/_stories/Chart.PreserveDecimals.stories.tsx +220 -0
  29. package/src/_stories/Chart.Regions.Categorical.stories.tsx +148 -0
  30. package/src/_stories/Chart.Regions.DateScale.stories.tsx +197 -0
  31. package/src/_stories/Chart.Regions.DateTimeScale.stories.tsx +297 -0
  32. package/src/_stories/Chart.SmallMultiples.stories.tsx +47 -0
  33. package/src/_stories/Chart.stories.tsx +8 -0
  34. package/src/_stories/ChartAnnotation.stories.tsx +6 -3
  35. package/src/_stories/ChartBar.Editor.stories.tsx +3585 -0
  36. package/src/_stories/ChartBrush.Editor.stories.tsx +295 -0
  37. package/src/_stories/ChartBrush.stories.tsx +50 -0
  38. package/src/_stories/ChartEditor.Editor.stories.tsx +656 -0
  39. package/src/_stories/ChartEditor.stories.tsx +1 -2
  40. package/src/_stories/TechAdoptionWithLinks.stories.tsx +27 -0
  41. package/src/_stories/_mock/brush_enabled.json +326 -0
  42. package/src/_stories/_mock/brush_mock.json +2 -69
  43. package/src/_stories/_mock/combo.json +451 -0
  44. package/src/_stories/_mock/editor-test-configs.json +376 -0
  45. package/src/_stories/_mock/editor-test-datasets.json +477 -0
  46. package/src/_stories/_mock/editor-tests/bar-chart-editor-test.json +255 -0
  47. package/src/_stories/_mock/editor-tests/bar-chart-general-test.json +267 -0
  48. package/src/_stories/_mock/editor-tests/bar-chart-test.json +237 -0
  49. package/src/_stories/_mock/forecast_combo_with_gaps.json +913 -0
  50. package/src/_stories/_mock/horizontal-bars-dynamic-y-axis.json +413 -0
  51. package/src/_stories/_mock/pie_config.json +257 -62
  52. package/src/_stories/_mock/small_multiples/small_multiples_bars.json +1944 -0
  53. package/src/_stories/_mock/small_multiples/small_multiples_big_data_bars.json +1114 -0
  54. package/src/_stories/_mock/small_multiples/small_multiples_lines.json +2646 -0
  55. package/src/_stories/_mock/small_multiples/small_multiples_lines_colors.json +1305 -0
  56. package/src/_stories/_mock/small_multiples/small_multiples_stacked_bars.json +1936 -0
  57. package/src/components/Annotations/components/findNearestDatum.ts +6 -41
  58. package/src/components/AreaChart/components/AreaChart.Stacked.jsx +10 -7
  59. package/src/components/AreaChart/index.tsx +1 -2
  60. package/src/components/Axis/Categorical.Axis.tsx +6 -7
  61. package/src/components/BarChart/components/BarChart.Horizontal.tsx +181 -27
  62. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +3 -1
  63. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +1 -0
  64. package/src/components/BarChart/components/BarChart.Vertical.tsx +8 -9
  65. package/src/components/BarChart/components/context.tsx +1 -0
  66. package/src/components/BarChart/helpers/useBarChart.ts +14 -2
  67. package/src/components/BoxPlot/helpers/index.ts +3 -3
  68. package/src/components/Brush/BrushSelector.tsx +1258 -0
  69. package/src/components/Brush/MiniChartPreview.tsx +283 -0
  70. package/src/components/DeviationBar.jsx +9 -7
  71. package/src/components/EditorPanel/EditorPanel.tsx +2720 -2586
  72. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +96 -111
  73. package/src/components/EditorPanel/components/Panels/Panel.ForestPlotSettings.tsx +56 -34
  74. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +76 -31
  75. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +104 -55
  76. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +54 -49
  77. package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +427 -0
  78. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +96 -48
  79. package/src/components/EditorPanel/components/Panels/index.tsx +3 -1
  80. package/src/components/EditorPanel/editor-panel.scss +0 -20
  81. package/src/components/EditorPanel/useEditorPermissions.ts +36 -31
  82. package/src/components/Forecasting/Forecasting.tsx +139 -21
  83. package/src/components/Legend/Legend.Component.tsx +16 -9
  84. package/src/components/Legend/Legend.tsx +3 -2
  85. package/src/components/Legend/helpers/createFormatLabels.tsx +325 -176
  86. package/src/components/Legend/helpers/getLegendClasses.ts +0 -1
  87. package/src/components/Legend/helpers/index.ts +10 -6
  88. package/src/components/LineChart/LineChartProps.ts +0 -3
  89. package/src/components/LineChart/helpers.ts +1 -1
  90. package/src/components/LineChart/index.tsx +36 -13
  91. package/src/components/LinearChart.tsx +559 -499
  92. package/src/components/PairedBarChart.jsx +20 -3
  93. package/src/components/Regions/components/Regions.tsx +366 -144
  94. package/src/components/Sankey/types/index.ts +1 -1
  95. package/src/components/ScatterPlot/ScatterPlot.jsx +2 -2
  96. package/src/components/SmallMultiples/SmallMultipleTile.tsx +202 -0
  97. package/src/components/SmallMultiples/SmallMultiples.css +32 -0
  98. package/src/components/SmallMultiples/SmallMultiples.tsx +271 -0
  99. package/src/components/SmallMultiples/index.ts +2 -0
  100. package/src/components/WarmingStripes/WarmingStripes.tsx +160 -0
  101. package/src/components/WarmingStripes/WarmingStripesGradientLegend.css +35 -0
  102. package/src/components/WarmingStripes/WarmingStripesGradientLegend.tsx +104 -0
  103. package/src/components/WarmingStripes/index.tsx +3 -0
  104. package/src/data/initial-state.js +16 -2
  105. package/src/helpers/buildForecastPaletteOptions.ts +0 -38
  106. package/src/helpers/calculateHorizontalBarCategoryLabelWidth.ts +57 -0
  107. package/src/helpers/getColorScale.ts +10 -0
  108. package/src/{hooks/useMinMax.ts → helpers/getMinMax.ts} +26 -14
  109. package/src/helpers/getYAxisAutoPadding.ts +53 -0
  110. package/src/helpers/sizeHelpers.ts +0 -20
  111. package/src/helpers/smallMultiplesHelpers.ts +529 -0
  112. package/src/hooks/useChartHoverAnalytics.tsx +10 -9
  113. package/src/hooks/useProgrammaticTooltip.ts +96 -0
  114. package/src/hooks/useScales.ts +98 -34
  115. package/src/hooks/useSmallMultipleSynchronization.ts +59 -0
  116. package/src/hooks/useTooltip.tsx +91 -25
  117. package/src/scss/DataTable.scss +0 -4
  118. package/src/scss/main.scss +18 -83
  119. package/src/store/chart.actions.ts +2 -0
  120. package/src/store/chart.reducer.ts +4 -0
  121. package/src/test/CdcChart.test.jsx +1 -1
  122. package/src/types/ChartConfig.ts +27 -6
  123. package/src/types/ChartContext.ts +3 -0
  124. package/src/types/Label.ts +1 -0
  125. package/src/utils/analyticsTracking.ts +19 -0
  126. package/LICENSE +0 -201
  127. package/src/_stories/_mock/pie_data.json +0 -218
  128. package/src/components/AreaChart/components/AreaChart.jsx +0 -109
  129. package/src/components/Brush/BrushChart.tsx +0 -128
  130. package/src/components/Brush/BrushController.tsx +0 -71
  131. package/src/components/Brush/types.tsx +0 -8
  132. package/src/components/BrushChart.tsx +0 -223
  133. package/src/helpers/sort.ts +0 -7
  134. package/src/hooks/useActiveElement.js +0 -19
  135. package/src/hooks/useChartClasses.js +0 -41
@@ -4,6 +4,7 @@ import ConfigContext from '../../../../ConfigContext.js'
4
4
  // CDC Core
5
5
  import Accordion from '@cdc/core/components/ui/Accordion'
6
6
  import Button from '@cdc/core/components/elements/Button'
7
+ import { CheckBox, Select } from '@cdc/core/components/EditorPanel/Inputs'
7
8
  import _ from 'lodash'
8
9
 
9
10
  // types
@@ -14,6 +15,29 @@ import './../panels.scss'
14
15
  const PanelAnnotate: React.FC<PanelProps> = props => {
15
16
  const { updateConfig, config, svgRef } = useContext(ConfigContext)
16
17
 
18
+ const updateField = (section, subsection, fieldName, value) => {
19
+ if (subsection) {
20
+ updateConfig({
21
+ ...config,
22
+ [section]: {
23
+ ...config[section],
24
+ [subsection]: {
25
+ ...config[section][subsection],
26
+ [fieldName]: value
27
+ }
28
+ }
29
+ })
30
+ } else {
31
+ updateConfig({
32
+ ...config,
33
+ [section]: {
34
+ ...config[section],
35
+ [fieldName]: value
36
+ }
37
+ })
38
+ }
39
+ }
40
+
17
41
  const handleAnnotationUpdate = (value, property, index) => {
18
42
  const svgContainer = document.querySelector('.chart-container > svg')?.getBoundingClientRect()
19
43
  const newSvgDims = [svgContainer?.width, svgContainer?.height]
@@ -67,8 +91,8 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
67
91
  config.xAxis.type === 'date'
68
92
  ? new Date(config?.data?.[0]?.[config.xAxis.dataKey]).getTime()
69
93
  : config.xAxis.type === 'categorical'
70
- ? '1/15/2016'
71
- : '',
94
+ ? '1/15/2016'
95
+ : '',
72
96
  yKey: '',
73
97
  dx: 20,
74
98
  dy: -20,
@@ -96,22 +120,14 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
96
120
  return (
97
121
  <Accordion key={props.name}>
98
122
  <Accordion.Section title={props.name} key={props.name}>
99
- <label key={`key-1`}>
100
- Show Annotation Dropdown
101
- <input
102
- type='checkbox'
103
- checked={config?.general?.showAnnotationDropdown || false}
104
- onChange={e => {
105
- updateConfig({
106
- ...config,
107
- general: {
108
- ...config.general,
109
- showAnnotationDropdown: e.target.checked
110
- }
111
- })
112
- }}
113
- />
114
- </label>
123
+ <CheckBox
124
+ value={config?.general?.showAnnotationDropdown || false}
125
+ section='general'
126
+ subsection={null}
127
+ fieldName='showAnnotationDropdown'
128
+ label='Show Annotation Dropdown'
129
+ updateField={updateField}
130
+ />
115
131
 
116
132
  {config.general.showAnnotationDropdown && (
117
133
  <label key={`key-2`}>
@@ -164,61 +180,53 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
164
180
  />
165
181
  </label>
166
182
 
167
- <label>
168
- Edit Subject
169
- <input
170
- type='checkbox'
171
- checked={config?.annotations[index]?.edit?.subject || false}
172
- onChange={e => {
173
- const updatedAnnotations = _.cloneDeep(config?.annotations)
174
- updatedAnnotations[index].edit.subject = e.target.checked
175
- updateConfig({
176
- ...config,
177
- annotations: updatedAnnotations
178
- })
179
- }}
180
- />
181
- </label>
182
- <label>
183
- Edit Label
184
- <input
185
- type='checkbox'
186
- checked={config?.annotations[index]?.edit?.label || false}
187
- onChange={e => {
188
- const updatedAnnotations = _.cloneDeep(config?.annotations)
189
- updatedAnnotations[index].edit.label = e.target.checked
190
- updateConfig({
191
- ...config,
192
- annotations: updatedAnnotations
193
- })
194
- }}
195
- />
196
- </label>
183
+ <CheckBox
184
+ value={config?.annotations[index]?.edit?.subject || false}
185
+ section='annotations'
186
+ subsection={null}
187
+ fieldName={`${index}.edit.subject`}
188
+ label='Edit Subject'
189
+ updateField={(section, subsection, fieldName, value) => {
190
+ const updatedAnnotations = _.cloneDeep(config?.annotations)
191
+ updatedAnnotations[index].edit.subject = value
192
+ updateConfig({
193
+ ...config,
194
+ annotations: updatedAnnotations
195
+ })
196
+ }}
197
+ />
198
+ <CheckBox
199
+ value={config?.annotations[index]?.edit?.label || false}
200
+ section='annotations'
201
+ subsection={null}
202
+ fieldName={`${index}.edit.label`}
203
+ label='Edit Label'
204
+ updateField={(section, subsection, fieldName, value) => {
205
+ const updatedAnnotations = _.cloneDeep(config?.annotations)
206
+ updatedAnnotations[index].edit.label = value
207
+ updateConfig({
208
+ ...config,
209
+ annotations: updatedAnnotations
210
+ })
211
+ }}
212
+ />
197
213
 
198
- <label>
199
- Connection Type:
200
- <select
201
- key='annotation-connection-type'
202
- onChange={e => {
203
- const updatedAnnotations = _.cloneDeep(config?.annotations)
204
- updatedAnnotations[index].connectionType = e.target.value
205
- updateConfig({
206
- ...config,
207
- annotations: updatedAnnotations
208
- })
209
- }}
210
- value={config?.annotations[index]?.connectionType}
211
- >
212
- <option key='select' value='select'>
213
- Select
214
- </option>
215
- {['curve', 'line', 'elbow', 'none'].map((side, index) => (
216
- <option key={side} value={side}>
217
- {side}
218
- </option>
219
- ))}
220
- </select>
221
- </label>
214
+ <Select
215
+ label='Connection Type:'
216
+ value={config?.annotations[index]?.connectionType}
217
+ options={['Select', 'curve', 'line', 'elbow', 'none']}
218
+ section='annotations'
219
+ subsection={null}
220
+ fieldName='connectionType'
221
+ updateField={(section, subsection, fieldName, value) => {
222
+ const updatedAnnotations = _.cloneDeep(config?.annotations)
223
+ updatedAnnotations[index].connectionType = value
224
+ updateConfig({
225
+ ...config,
226
+ annotations: updatedAnnotations
227
+ })
228
+ }}
229
+ />
222
230
 
223
231
  {annotation.connectionType === 'curve' && (
224
232
  <>
@@ -243,45 +251,22 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
243
251
  </>
244
252
  )}
245
253
 
246
- {/* <label>
247
- Connection Location:
248
- <select
249
- onChange={e => {
250
- const updatedAnnotations = _.cloneDeep(config?.annotations)
251
- updatedAnnotations[index].connectionLocation = e.target.value
252
- updateConfig({
253
- ...config,
254
- annotations: updatedAnnotations
255
- })
256
- }}
257
- >
258
- {['auto', 'left', 'top', 'bottom', 'right'].map((side, index) => (
259
- <option key={side} value={side}>
260
- {side}
261
- </option>
262
- ))}
263
- </select>
264
- </label> */}
265
-
266
- <label>
267
- Marker
268
- <select
269
- key='annotation-marker'
270
- value={annotation.marker}
271
- onChange={e => {
272
- const updatedAnnotations = _.cloneDeep(config?.annotations)
273
- updatedAnnotations[index].marker = e.target.value
274
- updateConfig({
275
- ...config,
276
- annotations: updatedAnnotations
277
- })
278
- }}
279
- >
280
- {['arrow', 'circle'].map((column, columnIndex) => {
281
- return <option key={`col-${columnIndex}`}>{column}</option>
282
- })}
283
- </select>
284
- </label>
254
+ <Select
255
+ label='Marker'
256
+ value={annotation.marker}
257
+ options={['arrow', 'circle']}
258
+ section='annotations'
259
+ subsection={null}
260
+ fieldName='marker'
261
+ updateField={(section, subsection, fieldName, value) => {
262
+ const updatedAnnotations = _.cloneDeep(config?.annotations)
263
+ updatedAnnotations[index].marker = value
264
+ updateConfig({
265
+ ...config,
266
+ annotations: updatedAnnotations
267
+ })
268
+ }}
269
+ />
285
270
 
286
271
  <Button className='btn btn-danger full-width' onClick={() => handleRemoveAnnotation(index)}>
287
272
  Delete Annotation
@@ -8,18 +8,24 @@ import WarningImage from '../../../../images/warning.svg'
8
8
 
9
9
  // contexts
10
10
  import ConfigContext from '../../../../ConfigContext'
11
+ import { useEditorPanelContext } from '../../EditorPanelContext'
11
12
 
12
13
  // types
13
14
  import { type ChartContext } from '../../../../types/ChartContext'
14
15
  import { type PanelProps } from '../PanelProps'
15
16
 
16
- import { AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
17
+ import {
18
+ AccordionItem,
19
+ AccordionItemHeading,
20
+ AccordionItemPanel,
21
+ AccordionItemButton
22
+ } from 'react-accessible-accordion'
17
23
 
18
24
  const ForestPlotSettings: FC<PanelProps> = ({ name }) => {
19
25
  const { config, rawData: unfilteredData, updateConfig } = useContext<ChartContext>(ConfigContext)
26
+ const { getColumns } = useEditorPanelContext()
20
27
  if (config.visualizationType !== 'Forest Plot') return
21
28
 
22
- // todo: get from editor context?
23
29
  const enforceRestrictions = updatedConfig => {
24
30
  if (updatedConfig.orientation === 'horizontal') {
25
31
  updatedConfig.labels = false
@@ -33,31 +39,6 @@ const ForestPlotSettings: FC<PanelProps> = ({ name }) => {
33
39
  }
34
40
  }
35
41
 
36
- // todo: get from editor context?
37
- const getColumns = (filter = true) => {
38
- let columns = {}
39
- unfilteredData.forEach(row => {
40
- Object.keys(row).forEach(columnName => (columns[columnName] = true))
41
- })
42
-
43
- if (filter) {
44
- Object.keys(columns).forEach(key => {
45
- if (
46
- (config.series && config.series.filter(series => series.dataKey === key).length > 0) ||
47
- (config.confidenceKeys && Object.keys(config.confidenceKeys).includes(key))
48
- /*
49
- TODO: Resolve errors when config keys exist, but have no value
50
- Proposal: (((confidenceUpper && confidenceLower) || confidenceUpper || confidenceLower) && Object.keys(config.confidenceKeys).includes(key))
51
- */
52
- ) {
53
- delete columns[key]
54
- }
55
- })
56
- }
57
-
58
- return Object.keys(columns)
59
- }
60
-
61
42
  // todo: editor context?
62
43
  const updateField = (section, subsection, fieldName, newValue) => {
63
44
  if (section === 'boxplot' && subsection === 'legend') {
@@ -151,7 +132,9 @@ const ForestPlotSettings: FC<PanelProps> = ({ name }) => {
151
132
  <AccordionItemHeading>
152
133
  <AccordionItemButton>
153
134
  {name}
154
- {(!config.forestPlot.estimateField || !config.forestPlot.upper || !config.forestPlot.lower) && <WarningImage width='25' className='warning-icon' />}
135
+ {(!config.forestPlot.estimateField || !config.forestPlot.upper || !config.forestPlot.lower) && (
136
+ <WarningImage width='25' className='warning-icon' />
137
+ )}
155
138
  </AccordionItemButton>
156
139
  </AccordionItemHeading>
157
140
  <AccordionItemPanel>
@@ -201,14 +184,22 @@ const ForestPlotSettings: FC<PanelProps> = ({ name }) => {
201
184
  <Tooltip.Content>
202
185
  <p>
203
186
  Linear - Typically used for continuous outcomes. Line of no effect is positioned on 0 (zero) <br />
204
- <br /> Logarithmic - Typically used for binary outcomes such as risk ratios and odds ratios. Line of no effect is positioned on 1.
187
+ <br /> Logarithmic - Typically used for binary outcomes such as risk ratios and odds ratios. Line of
188
+ no effect is positioned on 1.
205
189
  </p>
206
190
  </Tooltip.Content>
207
191
  </Tooltip>
208
192
  }
209
193
  />
210
194
 
211
- <TextField type='text' value={config.forestPlot?.title || ''} updateField={updateField} section='forestPlot' fieldName='title' label='Plot Title' />
195
+ <TextField
196
+ type='text'
197
+ value={config.forestPlot?.title || ''}
198
+ updateField={updateField}
199
+ section='forestPlot'
200
+ fieldName='title'
201
+ label='Plot Title'
202
+ />
212
203
 
213
204
  <br />
214
205
  <hr />
@@ -317,7 +308,14 @@ const ForestPlotSettings: FC<PanelProps> = ({ name }) => {
317
308
  </span>
318
309
  </label>
319
310
 
320
- <CheckBox value={config.forestPlot?.lineOfNoEffect?.show || false} section='forestPlot' subsection='lineOfNoEffect' fieldName='show' label='Show Line of No Effect' updateField={updateField} />
311
+ <CheckBox
312
+ value={config.forestPlot?.lineOfNoEffect?.show || false}
313
+ section='forestPlot'
314
+ subsection='lineOfNoEffect'
315
+ fieldName='show'
316
+ label='Show Line of No Effect'
317
+ updateField={updateField}
318
+ />
321
319
 
322
320
  <br />
323
321
  <hr />
@@ -400,13 +398,37 @@ const ForestPlotSettings: FC<PanelProps> = ({ name }) => {
400
398
  />
401
399
  </label>
402
400
 
403
- <TextField type='number' min={20} max={45} value={config.forestPlot.rowHeight ? config.forestPlot.rowHeight : 10} updateField={updateField} section='forestPlot' fieldName='rowHeight' label='Row Height' placeholder='10' />
401
+ <TextField
402
+ type='number'
403
+ min={20}
404
+ max={45}
405
+ value={config.forestPlot.rowHeight ? config.forestPlot.rowHeight : 10}
406
+ updateField={updateField}
407
+ section='forestPlot'
408
+ fieldName='rowHeight'
409
+ label='Row Height'
410
+ placeholder='10'
411
+ />
404
412
  <br />
405
413
  <hr />
406
414
  <br />
407
415
  <h4>Labels Settings</h4>
408
- <TextField type='text' value={config.forestPlot?.leftLabel || ''} updateField={updateField} section='forestPlot' fieldName='leftLabel' label='Left Label' />
409
- <TextField type='text' value={config.forestPlot?.rightLabel || ''} updateField={updateField} section='forestPlot' fieldName='rightLabel' label='Right Label' />
416
+ <TextField
417
+ type='text'
418
+ value={config.forestPlot?.leftLabel || ''}
419
+ updateField={updateField}
420
+ section='forestPlot'
421
+ fieldName='leftLabel'
422
+ label='Left Label'
423
+ />
424
+ <TextField
425
+ type='text'
426
+ value={config.forestPlot?.rightLabel || ''}
427
+ updateField={updateField}
428
+ section='forestPlot'
429
+ fieldName='rightLabel'
430
+ label='Right Label'
431
+ />
410
432
 
411
433
  <br />
412
434
  <hr />
@@ -21,7 +21,7 @@ import ConfigContext from '../../../../ConfigContext.js'
21
21
  import { PanelProps } from '../PanelProps'
22
22
 
23
23
  const PanelGeneral: FC<PanelProps> = props => {
24
- const { config } = useContext(ConfigContext)
24
+ const { config, updateConfig } = useContext(ConfigContext)
25
25
  const { updateField } = useEditorPanelContext()
26
26
  const {
27
27
  enabledChartTypes,
@@ -62,6 +62,24 @@ const PanelGeneral: FC<PanelProps> = props => {
62
62
  label='Chart Type'
63
63
  updateField={updateField}
64
64
  options={enabledChartTypes}
65
+ onChange={event => {
66
+ const newVisType = event.target.value
67
+
68
+ updateField(null, null, 'visualizationType', newVisType)
69
+
70
+ if (newVisType === 'Forecasting' && config.xAxis.type === 'categorical') {
71
+ updateConfig({
72
+ ...config,
73
+ visualizationType: newVisType,
74
+ xAxis: {
75
+ ...config.xAxis,
76
+ type: 'date',
77
+ dateParseFormat: config.xAxis.dateParseFormat || '%Y-%m-%d',
78
+ dateDisplayFormat: config.xAxis.dateDisplayFormat || '%Y-%m-%d'
79
+ }
80
+ })
81
+ }
82
+ }}
65
83
  />
66
84
  )}
67
85
  {visSupportsChartHeight() && config.orientation === 'vertical' && (
@@ -298,36 +316,37 @@ const PanelGeneral: FC<PanelProps> = props => {
298
316
  />
299
317
  </>
300
318
  )}
301
-
302
- <CheckBox
303
- tooltip={
304
- <Tooltip style={{ textTransform: 'none' }}>
305
- <Tooltip.Target>
306
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
307
- </Tooltip.Target>
308
- <Tooltip.Content>
309
- {config.visualizationSubType === 'stacked' && (
310
- <p>
311
- We do not recommend using stacked vertical/horizontal bar charts for missing data. If you choose to
312
- proceed, selecting this option will display 'N/A' in the tooltip hover and data table (e.g. nothing
313
- will display in chart).
314
- </p>
315
- )}
316
- {config.visualizationSubType !== 'stacked' && (
317
- <p>
318
- Selecting this option will display 'N/A' on the Date/Category Axis, in the tooltip hover, and in the
319
- data table to indicate missing or undefined data values.
320
- </p>
321
- )}
322
- </Tooltip.Content>
323
- </Tooltip>
324
- }
325
- value={config.general.showMissingDataLabel}
326
- section='general'
327
- fieldName='showMissingDataLabel'
328
- label='Display "Missing Data" Label'
329
- updateField={updateField}
330
- />
319
+ {config.visualizationType !== 'Warming Stripes' && (
320
+ <CheckBox
321
+ tooltip={
322
+ <Tooltip style={{ textTransform: 'none' }}>
323
+ <Tooltip.Target>
324
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
325
+ </Tooltip.Target>
326
+ <Tooltip.Content>
327
+ {config.visualizationSubType === 'stacked' && (
328
+ <p>
329
+ We do not recommend using stacked vertical/horizontal bar charts for missing data. If you choose
330
+ to proceed, selecting this option will display 'N/A' in the tooltip hover and data table (e.g.
331
+ nothing will display in chart).
332
+ </p>
333
+ )}
334
+ {config.visualizationSubType !== 'stacked' && (
335
+ <p>
336
+ Selecting this option will display 'N/A' on the Date/Category Axis, in the tooltip hover, and in
337
+ the data table to indicate missing or undefined data values.
338
+ </p>
339
+ )}
340
+ </Tooltip.Content>
341
+ </Tooltip>
342
+ }
343
+ value={config.general.showMissingDataLabel}
344
+ section='general'
345
+ fieldName='showMissingDataLabel'
346
+ label='Display "Missing Data" Label'
347
+ updateField={updateField}
348
+ />
349
+ )}
331
350
 
332
351
  {visualizationType === 'Pie' && (
333
352
  <Select fieldName='pieType' label='Pie Chart Type' updateField={updateField} options={['Regular', 'Donut']} />
@@ -371,6 +390,32 @@ const PanelGeneral: FC<PanelProps> = props => {
371
390
  </Tooltip>
372
391
  }
373
392
  />
393
+
394
+ <Select
395
+ value={config.titleStyle}
396
+ fieldName='titleStyle'
397
+ label='Title Style'
398
+ updateField={updateField}
399
+ options={[
400
+ { value: 'small', label: 'Small (h3)' },
401
+ { value: 'large', label: 'Large (h2)' },
402
+ { value: 'legacy', label: 'Legacy' }
403
+ ]}
404
+ tooltip={
405
+ <Tooltip style={{ textTransform: 'none' }}>
406
+ <Tooltip.Target>
407
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
408
+ </Tooltip.Target>
409
+ <Tooltip.Content>
410
+ <p>
411
+ Choose the visual style for the title. Consider heading order on your page when selecting the title
412
+ style. For 508 reasons, ensure your page follows a proper heading order.
413
+ </p>
414
+ </Tooltip.Content>
415
+ </Tooltip>
416
+ }
417
+ />
418
+
374
419
  <CheckBox value={config.showTitle} fieldName='showTitle' label='Show Title' updateField={updateField} />
375
420
 
376
421
  {visSupportsSuperTitle() && (