@cdc/chart 4.25.10 → 4.25.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.
- package/dist/{cdcchart-1a1724a1.es.js → cdcchart-dgT_1dIT.es.js} +136 -151
- package/dist/cdcchart.js +36258 -34658
- package/examples/feature/__data__/planet-example-data.json +1 -1
- package/examples/feature/boxplot/valid-boxplot.csv +38 -17
- package/examples/private/DEV-11825.json +573 -0
- package/examples/private/na.json +913 -0
- package/examples/private/test-data.csv +28 -0
- package/index.html +2 -121
- package/package.json +4 -4
- package/src/CdcChart.tsx +8 -11
- package/src/CdcChartComponent.tsx +256 -87
- package/src/_stories/Chart.Combo.stories.tsx +18 -0
- package/src/_stories/Chart.Forecast.stories.tsx +36 -0
- package/src/_stories/Chart.HTMLInDataTable.stories.tsx +520 -0
- package/src/_stories/Chart.Patterns.stories.tsx +2 -1
- package/src/_stories/Chart.PreserveDecimals.stories.tsx +220 -0
- package/src/_stories/Chart.SmallMultiples.stories.tsx +47 -0
- package/src/_stories/ChartAnnotation.stories.tsx +6 -3
- package/src/_stories/ChartBar.Editor.stories.tsx +3580 -0
- package/src/_stories/ChartEditor.Editor.stories.tsx +658 -0
- package/src/_stories/ChartEditor.stories.tsx +1 -2
- package/src/_stories/_mock/combo.json +451 -0
- package/src/_stories/_mock/editor-test-configs.json +376 -0
- package/src/_stories/_mock/editor-test-datasets.json +477 -0
- package/src/_stories/_mock/editor-tests/bar-chart-editor-test.json +255 -0
- package/src/_stories/_mock/editor-tests/bar-chart-general-test.json +267 -0
- package/src/_stories/_mock/editor-tests/bar-chart-test.json +237 -0
- package/src/_stories/_mock/forecast_combo_with_gaps.json +913 -0
- package/src/_stories/_mock/pie_config.json +257 -62
- package/src/_stories/_mock/small_multiples/small_multiples_bars.json +1944 -0
- package/src/_stories/_mock/small_multiples/small_multiples_big_data_bars.json +1114 -0
- package/src/_stories/_mock/small_multiples/small_multiples_lines.json +2646 -0
- package/src/_stories/_mock/small_multiples/small_multiples_lines_colors.json +1305 -0
- package/src/_stories/_mock/small_multiples/small_multiples_stacked_bars.json +1936 -0
- package/src/components/Annotations/components/findNearestDatum.ts +6 -41
- package/src/components/AreaChart/components/AreaChart.Stacked.jsx +10 -6
- package/src/components/AreaChart/index.tsx +1 -2
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +4 -4
- package/src/components/BarChart/components/BarChart.Vertical.tsx +3 -2
- package/src/components/BoxPlot/helpers/index.ts +3 -3
- package/src/components/Brush/BrushChart.tsx +1 -1
- package/src/components/EditorPanel/EditorPanel.tsx +199 -190
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +96 -111
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +19 -1
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +102 -55
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +54 -49
- package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +422 -0
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +75 -21
- package/src/components/EditorPanel/components/Panels/index.tsx +3 -1
- package/src/components/EditorPanel/editor-panel.scss +0 -20
- package/src/components/EditorPanel/useEditorPermissions.ts +7 -15
- package/src/components/Forecasting/Forecasting.tsx +139 -21
- package/src/components/Legend/Legend.Component.tsx +16 -9
- package/src/components/Legend/helpers/createFormatLabels.tsx +181 -181
- package/src/components/Legend/helpers/getLegendClasses.ts +0 -1
- package/src/components/LineChart/LineChartProps.ts +0 -3
- package/src/components/LineChart/helpers.ts +1 -1
- package/src/components/LineChart/index.tsx +36 -13
- package/src/components/LinearChart.tsx +75 -80
- package/src/components/Regions/components/Regions.tsx +3 -24
- package/src/components/Sankey/types/index.ts +1 -1
- package/src/components/SmallMultiples/SmallMultipleTile.tsx +198 -0
- package/src/components/SmallMultiples/SmallMultiples.css +32 -0
- package/src/components/SmallMultiples/SmallMultiples.tsx +271 -0
- package/src/components/SmallMultiples/index.ts +2 -0
- package/src/data/initial-state.js +13 -1
- package/src/helpers/buildForecastPaletteOptions.ts +0 -38
- package/src/helpers/getColorScale.ts +10 -0
- package/src/{hooks/useMinMax.ts → helpers/getMinMax.ts} +14 -7
- package/src/helpers/getYAxisAutoPadding.ts +53 -0
- package/src/helpers/smallMultiplesHelpers.ts +529 -0
- package/src/hooks/useProgrammaticTooltip.ts +96 -0
- package/src/hooks/useScales.ts +88 -34
- package/src/hooks/useSmallMultipleSynchronization.ts +59 -0
- package/src/hooks/useTooltip.tsx +60 -15
- package/src/scss/main.scss +1 -80
- package/src/store/chart.actions.ts +2 -0
- package/src/store/chart.reducer.ts +4 -0
- package/src/types/ChartConfig.ts +24 -6
- package/src/types/ChartContext.ts +3 -0
- package/src/_stories/_mock/pie_data.json +0 -218
- package/src/components/AreaChart/components/AreaChart.jsx +0 -109
- package/src/helpers/sort.ts +0 -7
- package/src/hooks/useActiveElement.js +0 -19
- 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
|
-
|
|
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
|
-
<
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
<
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
<
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
|
|
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
|
-
<
|
|
199
|
-
Connection Type:
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
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
|
|
@@ -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' && (
|
|
@@ -10,6 +10,7 @@ import Tooltip from '@cdc/core/components/ui/Tooltip'
|
|
|
10
10
|
import Icon from '@cdc/core/components/ui/Icon'
|
|
11
11
|
import Button from '@cdc/core/components/elements/Button'
|
|
12
12
|
import Alert from '@cdc/core/components/Alert'
|
|
13
|
+
import { Select } from '@cdc/core/components/EditorPanel/Inputs'
|
|
13
14
|
import ConfigContext from '../../../../ConfigContext'
|
|
14
15
|
import { ChartContext } from '../../../../types/ChartContext'
|
|
15
16
|
import { PanelProps } from '../PanelProps'
|
|
@@ -89,17 +90,22 @@ const PanelPatternSettings: FC<PanelProps> = props => {
|
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
// Checks contrast and logs warning if needed
|
|
92
|
-
const checkAndLogContrast = (
|
|
93
|
-
|
|
93
|
+
const checkAndLogContrast = (
|
|
94
|
+
patternColor: string,
|
|
95
|
+
backgroundColor: string,
|
|
96
|
+
dataValue: string,
|
|
97
|
+
dataKey: string
|
|
98
|
+
): boolean => {
|
|
99
|
+
if (!backgroundColor || !patternColor) return true // Default to true if colors are missing
|
|
94
100
|
|
|
95
|
-
const contrastCheck = checkColorContrast(
|
|
101
|
+
const contrastCheck = checkColorContrast(patternColor, backgroundColor)
|
|
96
102
|
|
|
97
103
|
if (!contrastCheck) {
|
|
98
104
|
console.error(
|
|
99
105
|
`COVE: pattern contrast check failed for ${dataValue} in ${dataKey} with:
|
|
100
106
|
pattern color: ${patternColor}
|
|
101
|
-
background color: ${
|
|
102
|
-
contrast: ${getColorContrast(
|
|
107
|
+
background color: ${backgroundColor}
|
|
108
|
+
contrast: ${getColorContrast(patternColor, backgroundColor)}`
|
|
103
109
|
)
|
|
104
110
|
}
|
|
105
111
|
|
|
@@ -108,7 +114,9 @@ const PanelPatternSettings: FC<PanelProps> = props => {
|
|
|
108
114
|
|
|
109
115
|
// Perform contrast check for a specific pattern against actual bar colors
|
|
110
116
|
const performContrastCheck = (patternKey: string, patternColor: string) => {
|
|
111
|
-
if (!patternColor || patternColor === '')
|
|
117
|
+
if (!patternColor || patternColor === '') {
|
|
118
|
+
return true
|
|
119
|
+
}
|
|
112
120
|
|
|
113
121
|
// Get the actual bar colors that the pattern will be overlaid on
|
|
114
122
|
let seriesColors: string[] = []
|
|
@@ -138,8 +146,8 @@ const PanelPatternSettings: FC<PanelProps> = props => {
|
|
|
138
146
|
const contrastResults: Array<{ color: string; passes: boolean; ratio: number | false }> = []
|
|
139
147
|
|
|
140
148
|
seriesColors.forEach((barColor, index) => {
|
|
141
|
-
const contrastPasses = checkAndLogContrast(
|
|
142
|
-
const contrastRatio = getColorContrast(
|
|
149
|
+
const contrastPasses = checkAndLogContrast(patternColor, barColor, patternKey, `series-${index}`)
|
|
150
|
+
const contrastRatio = getColorContrast(patternColor, barColor)
|
|
143
151
|
|
|
144
152
|
contrastResults.push({
|
|
145
153
|
color: barColor,
|
|
@@ -184,26 +192,48 @@ const PanelPatternSettings: FC<PanelProps> = props => {
|
|
|
184
192
|
}
|
|
185
193
|
}
|
|
186
194
|
|
|
187
|
-
|
|
195
|
+
const updatedConfig = {
|
|
188
196
|
...config,
|
|
189
197
|
legend: {
|
|
190
198
|
...(config.legend || {}),
|
|
191
199
|
patterns: newPatterns
|
|
200
|
+
},
|
|
201
|
+
runtime: {
|
|
202
|
+
...config.runtime
|
|
192
203
|
}
|
|
193
|
-
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Check if all patterns pass and set error message
|
|
207
|
+
const allPatternsPass = Object.values(newPatterns).every((p: any) => p.contrastCheck !== false)
|
|
208
|
+
updatedConfig.runtime.editorErrorMessage = allPatternsPass
|
|
209
|
+
? ''
|
|
210
|
+
: 'One or more patterns do not pass the WCAG 2.1 contrast ratio of 3:1.'
|
|
211
|
+
|
|
212
|
+
updateConfig(updatedConfig)
|
|
194
213
|
}
|
|
195
214
|
|
|
196
215
|
const handleRemovePattern = (patternKey: string) => {
|
|
197
216
|
const newPatterns = { ...(legendCfg.patterns || {}) }
|
|
198
217
|
delete newPatterns[patternKey]
|
|
199
218
|
|
|
200
|
-
|
|
219
|
+
const updatedConfig = {
|
|
201
220
|
...config,
|
|
202
221
|
legend: {
|
|
203
222
|
...(config.legend || {}),
|
|
204
223
|
patterns: newPatterns
|
|
224
|
+
},
|
|
225
|
+
runtime: {
|
|
226
|
+
...config.runtime
|
|
205
227
|
}
|
|
206
|
-
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Check if all remaining patterns pass and clear error message if needed
|
|
231
|
+
const allPatternsPass = Object.values(newPatterns).every((p: any) => p.contrastCheck !== false)
|
|
232
|
+
if (allPatternsPass || Object.keys(newPatterns).length === 0) {
|
|
233
|
+
updatedConfig.runtime.editorErrorMessage = ''
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
updateConfig(updatedConfig)
|
|
207
237
|
}
|
|
208
238
|
|
|
209
239
|
const handlePatternKeyChange = (oldKey: string, newKey: string) => {
|
|
@@ -228,15 +258,33 @@ const PanelPatternSettings: FC<PanelProps> = props => {
|
|
|
228
258
|
})
|
|
229
259
|
}
|
|
230
260
|
|
|
261
|
+
const reviewColorContrast = (updatedConfig: any, patternKey: string) => {
|
|
262
|
+
// Re-check the contrast for the updated pattern
|
|
263
|
+
const pattern = updatedConfig.legend.patterns[patternKey]
|
|
264
|
+
|
|
265
|
+
if (pattern?.color) {
|
|
266
|
+
pattern.contrastCheck = performContrastCheck(patternKey, pattern.color)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Update error message based on whether all patterns pass contrast checks
|
|
270
|
+
const allPatterns = Object.values(updatedConfig.legend.patterns || {})
|
|
271
|
+
|
|
272
|
+
const allPatternsPass = allPatterns.every((p: any) => p.contrastCheck !== false)
|
|
273
|
+
|
|
274
|
+
const errorMsg = allPatternsPass ? '' : 'One or more patterns do not pass the WCAG 2.1 contrast ratio of 3:1.'
|
|
275
|
+
// Set error message AFTER spreading runtime to avoid it being overwritten
|
|
276
|
+
updatedConfig.runtime.editorErrorMessage = errorMsg
|
|
277
|
+
}
|
|
278
|
+
|
|
231
279
|
const handlePatternUpdate = (patternKey: string, field: string, value: any) => {
|
|
232
280
|
const updatedPattern = {
|
|
233
281
|
...(legendCfg.patterns?.[patternKey] || {}),
|
|
234
282
|
[field]: value
|
|
235
283
|
}
|
|
236
284
|
|
|
237
|
-
//
|
|
238
|
-
if (field === '
|
|
239
|
-
updatedPattern.
|
|
285
|
+
// Clear dataValue if dataKey is being cleared or set to 'Select'
|
|
286
|
+
if (field === 'dataKey' && (value === 'Select' || value === '')) {
|
|
287
|
+
updatedPattern.dataValue = ''
|
|
240
288
|
}
|
|
241
289
|
|
|
242
290
|
const newPatterns = {
|
|
@@ -244,13 +292,23 @@ const PanelPatternSettings: FC<PanelProps> = props => {
|
|
|
244
292
|
[patternKey]: updatedPattern
|
|
245
293
|
}
|
|
246
294
|
|
|
247
|
-
|
|
295
|
+
const updatedConfig = {
|
|
248
296
|
...config,
|
|
249
297
|
legend: {
|
|
250
298
|
...(config.legend || {}),
|
|
251
299
|
patterns: newPatterns
|
|
300
|
+
},
|
|
301
|
+
runtime: {
|
|
302
|
+
...config.runtime
|
|
252
303
|
}
|
|
253
|
-
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Perform contrast check whenever color changes (even if cleared)
|
|
307
|
+
if (field === 'color') {
|
|
308
|
+
reviewColorContrast(updatedConfig, patternKey)
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
updateConfig(updatedConfig)
|
|
254
312
|
}
|
|
255
313
|
|
|
256
314
|
return (
|
|
@@ -294,19 +352,16 @@ const PanelPatternSettings: FC<PanelProps> = props => {
|
|
|
294
352
|
/>
|
|
295
353
|
)}
|
|
296
354
|
|
|
297
|
-
<
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
</option>
|
|
308
|
-
))}
|
|
309
|
-
</select>
|
|
355
|
+
<Select
|
|
356
|
+
label='Data Key:'
|
|
357
|
+
value={p.dataKey || ''}
|
|
358
|
+
options={fieldOptions}
|
|
359
|
+
initial='Select Data Key'
|
|
360
|
+
fieldName={`pattern-datakey-${patternKey}`}
|
|
361
|
+
updateField={(section, subsection, fieldName, value) =>
|
|
362
|
+
handlePatternUpdate(patternKey, 'dataKey', value)
|
|
363
|
+
}
|
|
364
|
+
/>
|
|
310
365
|
|
|
311
366
|
{p.dataKey && (
|
|
312
367
|
<>
|
|
@@ -333,33 +388,25 @@ const PanelPatternSettings: FC<PanelProps> = props => {
|
|
|
333
388
|
/>
|
|
334
389
|
</label>
|
|
335
390
|
|
|
336
|
-
<
|
|
337
|
-
|
|
338
|
-
id={`pattern-type-${patternKey}`}
|
|
391
|
+
<Select
|
|
392
|
+
label='Pattern Type:'
|
|
339
393
|
value={p.shape || 'circles'}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
{
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
<label htmlFor={`pattern-size-${patternKey}`}>Pattern Size:</label>
|
|
350
|
-
<select
|
|
351
|
-
id={`pattern-size-${patternKey}`}
|
|
394
|
+
options={patternTypes}
|
|
395
|
+
fieldName={`pattern-type-${patternKey}`}
|
|
396
|
+
updateField={(section, subsection, fieldName, value) =>
|
|
397
|
+
handlePatternUpdate(patternKey, 'shape', value)
|
|
398
|
+
}
|
|
399
|
+
/>
|
|
400
|
+
|
|
401
|
+
<Select
|
|
402
|
+
label='Pattern Size:'
|
|
352
403
|
value={getPatternSizeText(p.patternSize || 8)}
|
|
353
|
-
|
|
354
|
-
|
|
404
|
+
options={patternSizes}
|
|
405
|
+
fieldName={`pattern-size-${patternKey}`}
|
|
406
|
+
updateField={(section, subsection, fieldName, value) =>
|
|
407
|
+
handlePatternUpdate(patternKey, 'patternSize', getPatternSizeNumeric(value))
|
|
355
408
|
}
|
|
356
|
-
|
|
357
|
-
{patternSizes.map((size, index) => (
|
|
358
|
-
<option value={size.value} key={index}>
|
|
359
|
-
{size.label}
|
|
360
|
-
</option>
|
|
361
|
-
))}
|
|
362
|
-
</select>
|
|
409
|
+
/>
|
|
363
410
|
|
|
364
411
|
<div className='mt-3'>
|
|
365
412
|
<label htmlFor={`pattern-color-${patternKey}`}>
|
|
@@ -380,7 +427,7 @@ const PanelPatternSettings: FC<PanelProps> = props => {
|
|
|
380
427
|
</Tooltip>
|
|
381
428
|
<input
|
|
382
429
|
type='text'
|
|
383
|
-
value={p.color || '
|
|
430
|
+
value={p.color || ''}
|
|
384
431
|
id={`pattern-color-${patternKey}`}
|
|
385
432
|
onChange={e => handlePatternUpdate(patternKey, 'color', e.target.value)}
|
|
386
433
|
placeholder='#666666'
|