@cdc/chart 4.26.4 → 4.26.6
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.
- package/CONFIG.md +353 -29
- package/LICENSE +201 -0
- package/dist/{cdcchart-DQ00cQCm.es.js → cdcchart-BWVIUcAF.es.js} +5 -55
- package/dist/cdcchart.js +37885 -35117
- package/examples/feature/heatmap/average-age-categorical.json +313 -0
- package/examples/feature/heatmap/calendar-heatmap.json +134 -0
- package/examples/feature/heatmap/cell-values-bottom-axis.json +181 -0
- package/examples/feature/heatmap/sparse-aggregation.json +158 -0
- package/examples/private/bad-y-axis.json +543 -0
- package/examples/private/bar-chart-negative-value.json +455 -0
- package/examples/private/bump-chart.json +1116 -0
- package/examples/private/test-123.json +624 -0
- package/package.json +4 -3
- package/src/CdcChart.tsx +5 -4
- package/src/CdcChartComponent.tsx +166 -62
- package/src/_stories/Chart.AltText.stories.tsx +136 -0
- package/src/_stories/Chart.HeatMap.stories.tsx +187 -0
- package/src/_stories/Chart.Sankey.smoke.stories.tsx +62 -0
- package/src/_stories/Chart.SeriesColorAssignments.stories.tsx +183 -0
- package/src/_stories/Chart.SmallMultiples.smoke.stories.tsx +29 -0
- package/src/_stories/Chart.YAxisAutoMaxStrategy.stories.tsx +52 -0
- package/src/_stories/Chart.YAxisFilterDomain.stories.tsx +90 -0
- package/src/_stories/ChartAnnotation.smoke.stories.tsx +10 -0
- package/src/_stories/ChartAxisTitles.smoke.stories.tsx +13 -0
- package/src/_stories/ChartBar.Editor.stories.tsx +63 -0
- package/src/_stories/ChartBrush.Interaction.stories.tsx +112 -0
- package/src/_stories/ChartBrush.smoke.stories.tsx +13 -4
- package/src/_stories/_mock/alt_text_metadata.json +38 -0
- package/src/_stories/_mock/annotation_event-line_mock.json +1064 -0
- package/src/_stories/_mock/heatmap-average-age-categorical.json +315 -0
- package/src/_stories/_mock/heatmap.json +156 -0
- package/src/_stories/_mock/reported_pertussis_cases.json +1643 -0
- package/src/_stories/_mock/sankey_mock.json +78 -0
- package/src/_stories/_mock/small_multiples/small_multiples_lines.json +1 -1
- package/src/components/Annotations/components/AnnotationDraggable.styles.css +22 -1
- package/src/components/Annotations/components/AnnotationDraggable.tsx +220 -120
- package/src/components/Annotations/components/AnnotationDropdown.tsx +5 -2
- package/src/components/Annotations/tests/AnnotationDraggable.test.tsx +198 -0
- package/src/components/Axis/LeftAxis.tsx +17 -11
- package/src/components/Axis/LeftAxisGridlines.tsx +22 -12
- package/src/components/Axis/RightAxis.tsx +3 -0
- package/src/components/Axis/tests/AxisTickValues.test.tsx +86 -0
- package/src/components/Brush/BrushSelector.tsx +88 -187
- package/src/components/Brush/brushInteraction.ts +22 -0
- package/src/components/Brush/tests/brushInteraction.test.ts +38 -0
- package/src/components/EditorPanel/EditorPanel.tsx +677 -185
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +114 -52
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +105 -13
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +1 -0
- package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +5 -0
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +2 -2
- package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.test.tsx +98 -0
- package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +10 -0
- package/src/components/EditorPanel/components/Panels/Panel.Visual.test.tsx +484 -0
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +4 -1
- package/src/components/EditorPanel/components/Panels/SeriesColorAssignments.tsx +262 -0
- package/src/components/EditorPanel/components/Panels/panelVisual.styles.css +32 -0
- package/src/components/EditorPanel/components/panels.scss +10 -0
- package/src/components/EditorPanel/editor-panel.scss +47 -0
- package/src/components/EditorPanel/helpers/getVisualizationTypeConfigUpdate.ts +61 -0
- package/src/components/EditorPanel/helpers/tests/getVisualizationTypeConfigUpdate.test.ts +74 -0
- package/src/components/EditorPanel/useEditorPermissions.test.tsx +315 -0
- package/src/components/EditorPanel/useEditorPermissions.ts +77 -21
- package/src/components/HeatMap/components/HeatMap.tsx +767 -0
- package/src/components/HeatMap/components/HeatMapGradientLegend.tsx +128 -0
- package/src/components/HeatMap/heatmap.constants.ts +13 -0
- package/src/components/HeatMap/heatmap.css +85 -0
- package/src/components/HeatMap/helpers/index.ts +261 -0
- package/src/components/HeatMap/index.tsx +5 -0
- package/src/components/HeatMap/tests/HeatMap.test.tsx +1072 -0
- package/src/components/HeatMap/tests/helpers.test.ts +167 -0
- package/src/components/Legend/Legend.Component.tsx +2 -2
- package/src/components/Legend/helpers/createFormatLabels.test.ts +88 -0
- package/src/components/Legend/helpers/createFormatLabels.tsx +6 -1
- package/src/components/LineChart/components/LineChart.BumpCircle.tsx +19 -22
- package/src/components/LineChart/helpers.test.ts +574 -0
- package/src/components/LineChart/helpers.ts +39 -16
- package/src/components/LineChart/index.tsx +28 -5
- package/src/components/LinearChart/tests/LinearChart.test.tsx +137 -33
- package/src/components/LinearChart/tests/mockConfigContext.ts +1 -0
- package/src/components/LinearChart.tsx +103 -47
- package/src/components/PieChart/PieChart.tsx +4 -1
- package/src/components/RadarChart/RadarChart.tsx +3 -1
- package/src/components/Regions/components/Regions.tsx +195 -41
- package/src/components/Sankey/components/Sankey.tsx +7 -3
- package/src/components/Sankey/helpers/getSankeyTooltip.tsx +7 -6
- package/src/components/ScatterPlot/ScatterPlot.jsx +3 -3
- package/src/components/SmallMultiples/SmallMultipleTile.tsx +33 -3
- package/src/components/SmallMultiples/SmallMultiples.css +12 -0
- package/src/components/SmallMultiples/SmallMultiples.tsx +50 -15
- package/src/components/SmallMultiples/tests/SmallMultipleTile.test.tsx +152 -0
- package/src/components/SmallMultiples/tests/SmallMultiples.test.tsx +170 -0
- package/src/components/Sparkline/components/SparkLine.tsx +4 -9
- package/src/components/WarmingStripes/WarmingStripesGradientLegend.css +1 -1
- package/src/components/WarmingStripes/WarmingStripesGradientLegend.tsx +2 -2
- package/src/data/initial-state.js +12 -0
- package/src/helpers/axisLabelFontSize.ts +8 -0
- package/src/helpers/bumpChartTooltip.ts +54 -0
- package/src/helpers/calculateLeftYAxisWidth.ts +13 -3
- package/src/helpers/colorAssignmentHelpers.ts +102 -0
- package/src/helpers/dataHelpers.ts +11 -1
- package/src/helpers/ensureSpecialChartAxisTypes.ts +11 -0
- package/src/helpers/getAxisMaxOverride.ts +16 -0
- package/src/helpers/getCleanTopTickMax.ts +64 -0
- package/src/helpers/getColorScale.ts +18 -9
- package/src/helpers/getHasBoundarySuppression.ts +26 -0
- package/src/helpers/getMinMax.ts +26 -25
- package/src/helpers/getYAxisDomainData.ts +38 -0
- package/src/helpers/getYAxisFinalizationEligibility.ts +40 -0
- package/src/helpers/handleChartAriaLabels.ts +23 -10
- package/src/helpers/hasSpacedInlineLabel.ts +10 -0
- package/src/helpers/seriesColumnSettings.ts +5 -4
- package/src/helpers/seriesHighlight.ts +26 -0
- package/src/helpers/smallMultiplesHelpers.ts +5 -0
- package/src/helpers/tests/axisLabelFontSize.test.ts +15 -0
- package/src/helpers/tests/bumpChartTooltip.test.ts +75 -0
- package/src/helpers/tests/calculateLeftYAxisWidth.test.ts +38 -0
- package/src/helpers/tests/dataHelpers.test.ts +135 -0
- package/src/helpers/tests/ensureSpecialChartAxisTypes.test.ts +30 -0
- package/src/helpers/tests/getAxisMaxOverride.test.ts +36 -0
- package/src/helpers/tests/getCleanTopTickMax.test.ts +165 -0
- package/src/helpers/tests/getColorScale.test.ts +197 -0
- package/src/helpers/tests/getMinMax.test.ts +211 -0
- package/src/helpers/tests/getYAxisDomainData.test.ts +119 -0
- package/src/helpers/tests/getYAxisFinalizationEligibility.test.ts +185 -0
- package/src/helpers/tests/handleChartAriaLabels.test.ts +71 -0
- package/src/helpers/tests/hasSpacedInlineLabel.test.ts +75 -0
- package/src/helpers/tests/seriesColumnSettings.test.ts +16 -2
- package/src/helpers/tests/seriesHighlight.test.ts +61 -0
- package/src/helpers/tests/smallMultiplesHelpers.test.ts +99 -0
- package/src/hooks/tests/useRightAxis.test.tsx +127 -0
- package/src/hooks/tests/useScales.test.tsx +383 -0
- package/src/hooks/useRightAxis.ts +30 -13
- package/src/hooks/useScales.ts +48 -21
- package/src/hooks/useTooltip.tsx +3 -1
- package/src/index.jsx +5 -2
- package/src/scss/main.scss +32 -49
- package/src/test/CdcChart.dataTable.test.tsx +122 -0
- package/src/types/ChartConfig.ts +24 -1
- package/src/types/ChartContext.ts +5 -0
- package/src/helpers/getYAxisAutoPadding.ts +0 -53
|
@@ -2,6 +2,7 @@ import React, { useContext } from 'react'
|
|
|
2
2
|
import { Draggable } from '@hello-pangea/dnd'
|
|
3
3
|
import ConfigContext from '../../../../ConfigContext.js'
|
|
4
4
|
import { useEditorPermissions } from '../../useEditorPermissions'
|
|
5
|
+
import { EVENT_LINE_LABEL_OFFSET } from '../../../Annotations/components/AnnotationDraggable'
|
|
5
6
|
|
|
6
7
|
// CDC Core
|
|
7
8
|
import Accordion from '@cdc/core/components/ui/Accordion'
|
|
@@ -63,6 +64,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
|
|
|
63
64
|
const handleAddAnnotation = () => {
|
|
64
65
|
const newAnnotation = {
|
|
65
66
|
text: 'New annotation',
|
|
67
|
+
style: 'callout',
|
|
66
68
|
anchorMode: 'fixed',
|
|
67
69
|
fontSize: 16,
|
|
68
70
|
bezier: 10,
|
|
@@ -134,6 +136,19 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
|
|
|
134
136
|
updateField={updateField}
|
|
135
137
|
/>
|
|
136
138
|
|
|
139
|
+
<Select
|
|
140
|
+
label='Mobile Annotations'
|
|
141
|
+
value={config?.general?.mobileAnnotationDisplay || 'symbol'}
|
|
142
|
+
options={[
|
|
143
|
+
{ value: 'symbol', label: 'Show Symbol' },
|
|
144
|
+
{ value: 'text', label: 'Show Text' }
|
|
145
|
+
]}
|
|
146
|
+
section='general'
|
|
147
|
+
subsection={null}
|
|
148
|
+
fieldName='mobileAnnotationDisplay'
|
|
149
|
+
updateField={updateField}
|
|
150
|
+
/>
|
|
151
|
+
|
|
137
152
|
{config.general.showAnnotationDropdown && (
|
|
138
153
|
<label key={`key-2`}>
|
|
139
154
|
Annotation Dropdown Title:
|
|
@@ -200,7 +215,48 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
|
|
|
200
215
|
/>
|
|
201
216
|
</label>
|
|
202
217
|
|
|
203
|
-
|
|
218
|
+
<Select
|
|
219
|
+
label='Annotation Style:'
|
|
220
|
+
value={annotation.style || 'callout'}
|
|
221
|
+
options={[
|
|
222
|
+
{ value: 'callout', label: 'Callout' },
|
|
223
|
+
{
|
|
224
|
+
value: 'event-line',
|
|
225
|
+
label: visSupportsDataAnnotations()
|
|
226
|
+
? 'Event Line'
|
|
227
|
+
: 'Event Line (requires Line/Bar/Combo/Area/Forecasting, vertical)'
|
|
228
|
+
}
|
|
229
|
+
]}
|
|
230
|
+
section='annotations'
|
|
231
|
+
subsection={null}
|
|
232
|
+
fieldName='style'
|
|
233
|
+
updateField={(section, subsection, fieldName, value) => {
|
|
234
|
+
const updatedAnnotations = cloneDeep(config?.annotations)
|
|
235
|
+
const target = updatedAnnotations[index]
|
|
236
|
+
target.style = value
|
|
237
|
+
|
|
238
|
+
if (value === 'event-line') {
|
|
239
|
+
target.anchorMode = 'data'
|
|
240
|
+
if (!target.dataX) {
|
|
241
|
+
target.dataX = transformedData?.[0]?.[config.xAxis.dataKey] || ''
|
|
242
|
+
}
|
|
243
|
+
target.seriesKey = ''
|
|
244
|
+
target.edit = { subject: false, label: true }
|
|
245
|
+
target.dx =
|
|
246
|
+
typeof target.dx === 'number' && target.dx < 0
|
|
247
|
+
? -EVENT_LINE_LABEL_OFFSET
|
|
248
|
+
: EVENT_LINE_LABEL_OFFSET
|
|
249
|
+
if (target.dy === undefined || target.dy === null) target.dy = -120
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
updateConfig({
|
|
253
|
+
...config,
|
|
254
|
+
annotations: updatedAnnotations
|
|
255
|
+
})
|
|
256
|
+
}}
|
|
257
|
+
/>
|
|
258
|
+
|
|
259
|
+
{visSupportsDataAnnotations() && annotation.style !== 'event-line' && (
|
|
204
260
|
<Select
|
|
205
261
|
label='Position Mode:'
|
|
206
262
|
value={annotation.anchorMode || 'fixed'}
|
|
@@ -233,24 +289,26 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
|
|
|
233
289
|
/>
|
|
234
290
|
)}
|
|
235
291
|
|
|
236
|
-
{visSupportsDataAnnotations() &&
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
292
|
+
{visSupportsDataAnnotations() &&
|
|
293
|
+
annotation.style !== 'event-line' &&
|
|
294
|
+
annotation.anchorMode === 'data' && (
|
|
295
|
+
<Select
|
|
296
|
+
label='Series:'
|
|
297
|
+
value={annotation.seriesKey || config.series?.[0]?.dataKey || ''}
|
|
298
|
+
options={config.series.map(s => s.dataKey)}
|
|
299
|
+
section='annotations'
|
|
300
|
+
subsection={null}
|
|
301
|
+
fieldName='seriesKey'
|
|
302
|
+
updateField={(section, subsection, fieldName, value) => {
|
|
303
|
+
const updatedAnnotations = cloneDeep(config?.annotations)
|
|
304
|
+
updatedAnnotations[index].seriesKey = value || config.series?.[0]?.dataKey
|
|
305
|
+
updateConfig({
|
|
306
|
+
...config,
|
|
307
|
+
annotations: updatedAnnotations
|
|
308
|
+
})
|
|
309
|
+
}}
|
|
310
|
+
/>
|
|
311
|
+
)}
|
|
254
312
|
|
|
255
313
|
<label>
|
|
256
314
|
Opacity
|
|
@@ -300,24 +358,26 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
|
|
|
300
358
|
}}
|
|
301
359
|
/>
|
|
302
360
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
361
|
+
{annotation.style !== 'event-line' && (
|
|
362
|
+
<Select
|
|
363
|
+
label='Connection Type:'
|
|
364
|
+
value={config?.annotations[index]?.connectionType}
|
|
365
|
+
options={['Select', 'curve', 'line', 'elbow', 'none']}
|
|
366
|
+
section='annotations'
|
|
367
|
+
subsection={null}
|
|
368
|
+
fieldName='connectionType'
|
|
369
|
+
updateField={(section, subsection, fieldName, value) => {
|
|
370
|
+
const updatedAnnotations = cloneDeep(config?.annotations)
|
|
371
|
+
updatedAnnotations[index].connectionType = value
|
|
372
|
+
updateConfig({
|
|
373
|
+
...config,
|
|
374
|
+
annotations: updatedAnnotations
|
|
375
|
+
})
|
|
376
|
+
}}
|
|
377
|
+
/>
|
|
378
|
+
)}
|
|
319
379
|
|
|
320
|
-
{annotation.connectionType === 'curve' && (
|
|
380
|
+
{annotation.style !== 'event-line' && annotation.connectionType === 'curve' && (
|
|
321
381
|
<>
|
|
322
382
|
<label>
|
|
323
383
|
Curve Control
|
|
@@ -340,22 +400,24 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
|
|
|
340
400
|
</>
|
|
341
401
|
)}
|
|
342
402
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
403
|
+
{annotation.style !== 'event-line' && (
|
|
404
|
+
<Select
|
|
405
|
+
label='Marker'
|
|
406
|
+
value={annotation.marker}
|
|
407
|
+
options={['arrow', 'circle']}
|
|
408
|
+
section='annotations'
|
|
409
|
+
subsection={null}
|
|
410
|
+
fieldName='marker'
|
|
411
|
+
updateField={(section, subsection, fieldName, value) => {
|
|
412
|
+
const updatedAnnotations = cloneDeep(config?.annotations)
|
|
413
|
+
updatedAnnotations[index].marker = value
|
|
414
|
+
updateConfig({
|
|
415
|
+
...config,
|
|
416
|
+
annotations: updatedAnnotations
|
|
417
|
+
})
|
|
418
|
+
}}
|
|
419
|
+
/>
|
|
420
|
+
)}
|
|
359
421
|
</AccordionItemPanel>
|
|
360
422
|
</AccordionItem>
|
|
361
423
|
</AccessibleAccordion>
|
|
@@ -13,12 +13,15 @@ import { approvedCurveTypes } from '@cdc/core/helpers/lineChartHelpers'
|
|
|
13
13
|
import { TextField, Select, CheckBox } from '@cdc/core/components/EditorPanel/Inputs'
|
|
14
14
|
import Tooltip from '@cdc/core/components/ui/Tooltip'
|
|
15
15
|
import Icon from '@cdc/core/components/ui/Icon'
|
|
16
|
+
import { resolveAltTextDescription } from '@cdc/core/helpers/resolveAltTextDescription'
|
|
16
17
|
|
|
17
18
|
// contexts
|
|
18
19
|
import { useEditorPermissions } from '../../useEditorPermissions.js'
|
|
19
20
|
import { useEditorPanelContext } from '../../EditorPanelContext.js'
|
|
20
21
|
import ConfigContext from '../../../../ConfigContext.js'
|
|
21
22
|
import { PanelProps } from '../PanelProps'
|
|
23
|
+
import { getVisualizationTypeConfigUpdate } from '../../helpers/getVisualizationTypeConfigUpdate'
|
|
24
|
+
import { type VisualizationType } from '../../../../types/ChartConfig'
|
|
22
25
|
|
|
23
26
|
const PanelGeneral: FC<PanelProps> = props => {
|
|
24
27
|
const { config, updateConfig } = useContext(ConfigContext)
|
|
@@ -79,22 +82,12 @@ const PanelGeneral: FC<PanelProps> = props => {
|
|
|
79
82
|
updateField={updateField}
|
|
80
83
|
options={enabledChartTypes}
|
|
81
84
|
onChange={event => {
|
|
82
|
-
const newVisType = event.target.value
|
|
85
|
+
const newVisType = event.target.value as VisualizationType
|
|
83
86
|
|
|
84
87
|
updateField(null, null, 'visualizationType', newVisType)
|
|
85
88
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
...config,
|
|
89
|
-
visualizationType: newVisType,
|
|
90
|
-
xAxis: {
|
|
91
|
-
...config.xAxis,
|
|
92
|
-
type: 'date',
|
|
93
|
-
dateParseFormat: config.xAxis.dateParseFormat || '%Y-%m-%d',
|
|
94
|
-
dateDisplayFormat: config.xAxis.dateDisplayFormat || '%Y-%m-%d'
|
|
95
|
-
}
|
|
96
|
-
})
|
|
97
|
-
}
|
|
89
|
+
const updatedConfig = getVisualizationTypeConfigUpdate(config, newVisType)
|
|
90
|
+
if (updatedConfig) updateConfig(updatedConfig)
|
|
98
91
|
}}
|
|
99
92
|
/>
|
|
100
93
|
)}
|
|
@@ -617,6 +610,105 @@ const PanelGeneral: FC<PanelProps> = props => {
|
|
|
617
610
|
</Tooltip>
|
|
618
611
|
}
|
|
619
612
|
/>
|
|
613
|
+
|
|
614
|
+
{/* Accessible Alt Text Description */}
|
|
615
|
+
{(() => {
|
|
616
|
+
const metadataKeys = Object.keys(config.dataMetadata || {})
|
|
617
|
+
const hasMetadata = metadataKeys.length > 0
|
|
618
|
+
const descType = config.altText?.type || ''
|
|
619
|
+
const resolvedDescription = resolveAltTextDescription(config.altText, config.dataMetadata)
|
|
620
|
+
return (
|
|
621
|
+
<>
|
|
622
|
+
<Select
|
|
623
|
+
value={descType}
|
|
624
|
+
fieldName='altTextType'
|
|
625
|
+
label='Alt Text Description'
|
|
626
|
+
options={[
|
|
627
|
+
{ value: '', label: 'None' },
|
|
628
|
+
{ value: 'static', label: 'Static (manual text)' },
|
|
629
|
+
{ value: 'metadata', label: 'Data File Metadata' }
|
|
630
|
+
]}
|
|
631
|
+
updateField={(_section, _subsection, _fieldName, value) => {
|
|
632
|
+
if (value === '') {
|
|
633
|
+
updateField(null, null, 'altText', undefined)
|
|
634
|
+
} else {
|
|
635
|
+
updateField(null, null, 'altText', { type: value as 'static' | 'metadata' })
|
|
636
|
+
}
|
|
637
|
+
}}
|
|
638
|
+
tooltip={
|
|
639
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
640
|
+
<Tooltip.Target>
|
|
641
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
642
|
+
</Tooltip.Target>
|
|
643
|
+
<Tooltip.Content>
|
|
644
|
+
<p>
|
|
645
|
+
Add a longer description for screen readers. The chart title is always auto-generated. Use
|
|
646
|
+
"Static" for manually written text, or "Data File Metadata" to pull it from a key in your data
|
|
647
|
+
file.
|
|
648
|
+
</p>
|
|
649
|
+
</Tooltip.Content>
|
|
650
|
+
</Tooltip>
|
|
651
|
+
}
|
|
652
|
+
/>
|
|
653
|
+
{descType === 'static' && (
|
|
654
|
+
<TextField
|
|
655
|
+
value={config.altText?.value || ''}
|
|
656
|
+
fieldName='altTextValue'
|
|
657
|
+
type='textarea'
|
|
658
|
+
label='Description Text'
|
|
659
|
+
placeholder='Longer interpretive description of chart insights...'
|
|
660
|
+
updateField={(_section, _subsection, _fieldName, value) => {
|
|
661
|
+
updateField(null, null, 'altText', { ...config.altText, value })
|
|
662
|
+
}}
|
|
663
|
+
/>
|
|
664
|
+
)}
|
|
665
|
+
{descType === 'metadata' && (
|
|
666
|
+
<>
|
|
667
|
+
{hasMetadata ? (
|
|
668
|
+
<Select
|
|
669
|
+
value={config.altText?.metadataKey || ''}
|
|
670
|
+
fieldName='altTextMetadataKey'
|
|
671
|
+
label='Description Metadata Field'
|
|
672
|
+
options={[
|
|
673
|
+
{ value: '', label: 'Select Metadata Field...' },
|
|
674
|
+
...metadataKeys.map(key => ({
|
|
675
|
+
value: key,
|
|
676
|
+
label: `${key}: ${config.dataMetadata[key]}`
|
|
677
|
+
}))
|
|
678
|
+
]}
|
|
679
|
+
updateField={(_section, _subsection, _fieldName, value) => {
|
|
680
|
+
updateField(null, null, 'altText', { ...config.altText, metadataKey: value })
|
|
681
|
+
}}
|
|
682
|
+
/>
|
|
683
|
+
) : (
|
|
684
|
+
<span className='subtext'>
|
|
685
|
+
No metadata fields are available. Your data file must be a JSON object with a <code>data</code>{' '}
|
|
686
|
+
array and sibling key-value pairs, for example:{' '}
|
|
687
|
+
<code>{`{ "altDescription": "...", "data": [...] }`}</code>
|
|
688
|
+
</span>
|
|
689
|
+
)}
|
|
690
|
+
</>
|
|
691
|
+
)}
|
|
692
|
+
{resolvedDescription && (
|
|
693
|
+
<div
|
|
694
|
+
style={{
|
|
695
|
+
marginTop: '1em',
|
|
696
|
+
padding: '0.75em',
|
|
697
|
+
background: '#f5f5f5',
|
|
698
|
+
borderRadius: '4px',
|
|
699
|
+
fontSize: '0.8em',
|
|
700
|
+
textTransform: 'none'
|
|
701
|
+
}}
|
|
702
|
+
>
|
|
703
|
+
<strong style={{ display: 'block', marginBottom: '0.25em' }}>Preview:</strong>
|
|
704
|
+
<p data-testid='alt-text-desc-preview' style={{ margin: 0, fontStyle: 'italic' }}>
|
|
705
|
+
{resolvedDescription}
|
|
706
|
+
</p>
|
|
707
|
+
</div>
|
|
708
|
+
)}
|
|
709
|
+
</>
|
|
710
|
+
)
|
|
711
|
+
})()}
|
|
620
712
|
</AccordionItemPanel>
|
|
621
713
|
</AccordionItem>
|
|
622
714
|
)
|
|
@@ -22,6 +22,7 @@ import { sanitizeToSvgId } from '@cdc/core/helpers/cove/string'
|
|
|
22
22
|
|
|
23
23
|
const PanelPatternSettings: FC<PanelProps> = props => {
|
|
24
24
|
const { config, updateConfig, transformedData } = useContext<ChartContext>(ConfigContext)
|
|
25
|
+
if (config.visualizationType === 'HeatMap') return null
|
|
25
26
|
|
|
26
27
|
type LegendPattern = {
|
|
27
28
|
label?: string
|
|
@@ -14,10 +14,13 @@ import { TextField, Select } from '@cdc/core/components/EditorPanel/Inputs'
|
|
|
14
14
|
import Tooltip from '@cdc/core/components/ui/Tooltip'
|
|
15
15
|
import Icon from '@cdc/core/components/ui/Icon'
|
|
16
16
|
import Button from '@cdc/core/components/elements/Button'
|
|
17
|
+
import { APP_FONT_COLOR } from '@cdc/core/helpers/constants'
|
|
17
18
|
import { type ChartContext } from '../../../../types/ChartContext.js'
|
|
18
19
|
import { type PanelProps } from '../PanelProps.js'
|
|
19
20
|
import ConfigContext from '../../../../ConfigContext.js'
|
|
20
21
|
|
|
22
|
+
const DEFAULT_REGION_BACKGROUND = getComputedStyle(document.documentElement).getPropertyValue('--cool-gray-50').trim()
|
|
23
|
+
|
|
21
24
|
const RegionSettings = memo(({ config, updateConfig }: { config: ChartConfig; updateConfig: Function }) => {
|
|
22
25
|
let regionUpdate = (fieldName, value, i) => {
|
|
23
26
|
let regions = []
|
|
@@ -116,12 +119,14 @@ const RegionSettings = memo(({ config, updateConfig }: { config: ChartConfig; up
|
|
|
116
119
|
value={color}
|
|
117
120
|
label='Text Color'
|
|
118
121
|
fieldName='color'
|
|
122
|
+
placeholder={APP_FONT_COLOR}
|
|
119
123
|
updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)}
|
|
120
124
|
/>
|
|
121
125
|
<TextField
|
|
122
126
|
value={background}
|
|
123
127
|
label='Background'
|
|
124
128
|
fieldName='background'
|
|
129
|
+
placeholder={DEFAULT_REGION_BACKGROUND}
|
|
125
130
|
updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)}
|
|
126
131
|
/>
|
|
127
132
|
</div>
|
|
@@ -660,7 +660,7 @@ const SeriesButtonRemove = props => {
|
|
|
660
660
|
|
|
661
661
|
return (
|
|
662
662
|
config.series &&
|
|
663
|
-
config.series.length > 1 && (
|
|
663
|
+
(config.series.length > 1 || config.visualizationType === 'HeatMap') && (
|
|
664
664
|
<Button variant='danger' size='sm' className='grouped-list__remove' onClick={e => handleRemoveSeries(e, series)}>
|
|
665
665
|
Remove
|
|
666
666
|
</Button>
|
|
@@ -710,7 +710,7 @@ const SeriesItem = props => {
|
|
|
710
710
|
}
|
|
711
711
|
>
|
|
712
712
|
<Icon display='move' size={15} style={{ cursor: 'default' }} />
|
|
713
|
-
{series.dataKey}
|
|
713
|
+
{config.visualizationType === 'HeatMap' ? series.name || series.dataKey : series.dataKey}
|
|
714
714
|
</AccordionItemButton>
|
|
715
715
|
</AccordionItemHeading>
|
|
716
716
|
{chartsWithOptions.includes(config.visualizationType) && (
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Accordion } from 'react-accessible-accordion'
|
|
3
|
+
import { render, screen, fireEvent } from '@testing-library/react'
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
5
|
+
import ConfigContext from '../../../../ConfigContext'
|
|
6
|
+
import EditorPanelContext from '../../EditorPanelContext'
|
|
7
|
+
import PanelSmallMultiples from './Panel.SmallMultiples'
|
|
8
|
+
import { createMockChartContext, createMockConfig } from '../../../LinearChart/tests/mockConfigContext'
|
|
9
|
+
|
|
10
|
+
vi.mock('@cdc/core/components/ui/Icon', () => ({
|
|
11
|
+
default: () => <span data-testid='icon' />
|
|
12
|
+
}))
|
|
13
|
+
|
|
14
|
+
const renderPanel = config => {
|
|
15
|
+
const context = createMockChartContext(config, {
|
|
16
|
+
rawData: [{ Date: '2024-01-01', series_a: 1, series_b: 2 }]
|
|
17
|
+
} as any)
|
|
18
|
+
|
|
19
|
+
render(
|
|
20
|
+
<ConfigContext.Provider value={context}>
|
|
21
|
+
<EditorPanelContext.Provider value={{ updateField: vi.fn() }}>
|
|
22
|
+
<Accordion allowZeroExpanded>
|
|
23
|
+
<PanelSmallMultiples name='Small Multiples' />
|
|
24
|
+
</Accordion>
|
|
25
|
+
</EditorPanelContext.Provider>
|
|
26
|
+
</ConfigContext.Provider>
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
fireEvent.click(screen.getByRole('button', { name: 'Small Multiples' }))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
describe('PanelSmallMultiples color assignments warning', () => {
|
|
33
|
+
it('shows the by-series same-color override warning only when assignments are active', () => {
|
|
34
|
+
const config = createMockConfig({
|
|
35
|
+
visualizationType: 'Line',
|
|
36
|
+
general: {
|
|
37
|
+
palette: {
|
|
38
|
+
colorAssignmentMode: 'by-value',
|
|
39
|
+
colorAssignments: [{ key: 'series_a', color: '#123456' }]
|
|
40
|
+
}
|
|
41
|
+
} as any,
|
|
42
|
+
smallMultiples: {
|
|
43
|
+
mode: 'by-series',
|
|
44
|
+
colorMode: 'same'
|
|
45
|
+
},
|
|
46
|
+
series: [
|
|
47
|
+
{ dataKey: 'series_a', name: 'Alpha', type: 'Line' },
|
|
48
|
+
{ dataKey: 'series_b', name: 'Beta', type: 'Line' }
|
|
49
|
+
] as any
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
renderPanel(config)
|
|
53
|
+
|
|
54
|
+
expect(screen.queryByText(/Color assignments are enabled/)).toBeInTheDocument()
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('does not show the override warning when assignment mode is ordered', () => {
|
|
58
|
+
const config = createMockConfig({
|
|
59
|
+
visualizationType: 'Line',
|
|
60
|
+
general: {
|
|
61
|
+
palette: {
|
|
62
|
+
colorAssignmentMode: 'ordered',
|
|
63
|
+
colorAssignments: [{ key: 'series_a', color: '#123456' }]
|
|
64
|
+
}
|
|
65
|
+
} as any,
|
|
66
|
+
smallMultiples: {
|
|
67
|
+
mode: 'by-series',
|
|
68
|
+
colorMode: 'same'
|
|
69
|
+
},
|
|
70
|
+
series: [{ dataKey: 'series_a', name: 'Alpha', type: 'Line' }] as any
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
renderPanel(config)
|
|
74
|
+
|
|
75
|
+
expect(screen.queryByText(/Color assignments are enabled/)).not.toBeInTheDocument()
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('does not show the override warning when assignments only contain stale keys', () => {
|
|
79
|
+
const config = createMockConfig({
|
|
80
|
+
visualizationType: 'Line',
|
|
81
|
+
general: {
|
|
82
|
+
palette: {
|
|
83
|
+
colorAssignmentMode: 'by-value',
|
|
84
|
+
colorAssignments: [{ key: 'removed_series', color: '#123456' }]
|
|
85
|
+
}
|
|
86
|
+
} as any,
|
|
87
|
+
smallMultiples: {
|
|
88
|
+
mode: 'by-series',
|
|
89
|
+
colorMode: 'same'
|
|
90
|
+
},
|
|
91
|
+
series: [{ dataKey: 'series_a', name: 'Alpha', type: 'Line' }] as any
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
renderPanel(config)
|
|
95
|
+
|
|
96
|
+
expect(screen.queryByText(/Color assignments are enabled/)).not.toBeInTheDocument()
|
|
97
|
+
})
|
|
98
|
+
})
|
|
@@ -20,6 +20,7 @@ import { useEditorPanelContext } from '../../EditorPanelContext.js'
|
|
|
20
20
|
import ConfigContext from '../../../../ConfigContext.js'
|
|
21
21
|
import { PanelProps } from '../PanelProps'
|
|
22
22
|
import { getTileKeys } from '../../../../helpers/smallMultiplesHelpers'
|
|
23
|
+
import { hasSeriesColorAssignmentOverrides } from '../../../../helpers/colorAssignmentHelpers'
|
|
23
24
|
|
|
24
25
|
const PanelSmallMultiples: FC<PanelProps> = props => {
|
|
25
26
|
const { config, rawData, updateConfig } = useContext<ChartContext>(ConfigContext)
|
|
@@ -273,6 +274,15 @@ const PanelSmallMultiples: FC<PanelProps> = props => {
|
|
|
273
274
|
}
|
|
274
275
|
/>
|
|
275
276
|
|
|
277
|
+
{config.smallMultiples?.mode === 'by-series' &&
|
|
278
|
+
config.smallMultiples?.colorMode === 'same' &&
|
|
279
|
+
hasSeriesColorAssignmentOverrides(config) && (
|
|
280
|
+
<p className='small-multiples-color-assignment-warning mt-1'>
|
|
281
|
+
Color assignments are enabled in the Visual section, so tiles will use their assigned series
|
|
282
|
+
colors instead of the ‘Same Color’ setting.
|
|
283
|
+
</p>
|
|
284
|
+
)}
|
|
285
|
+
|
|
276
286
|
{/* Custom Tile Titles - only show for by-column mode */}
|
|
277
287
|
{config.smallMultiples?.mode === 'by-column' && (
|
|
278
288
|
<div>
|