@cdc/map 4.24.10 → 4.24.12

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 (50) hide show
  1. package/dist/cdcmap.js +27324 -27152
  2. package/examples/default-geocode.json +13 -4
  3. package/examples/default-usa-regions.json +267 -117
  4. package/examples/example-city-state.json +6 -3
  5. package/examples/pattern.json +861 -0
  6. package/examples/private/DEV-9644.json +184 -0
  7. package/examples/private/default-patterns.json +867 -0
  8. package/index.html +4 -5
  9. package/package.json +3 -3
  10. package/src/CdcMap.tsx +53 -52
  11. package/src/_stories/CdcMap.Legend.Gradient.stories.tsx +67 -0
  12. package/src/_stories/CdcMap.Legend.stories.tsx +40 -0
  13. package/src/_stories/CdcMap.Patterns.stories.tsx +29 -0
  14. package/src/_stories/CdcMap.stories.tsx +59 -0
  15. package/src/_stories/UsaMap.NoData.stories.tsx +19 -0
  16. package/src/_stories/_mock/custom-layer-map.json +1117 -0
  17. package/src/_stories/_mock/default-patterns.json +865 -0
  18. package/src/_stories/_mock/example-city-state.json +858 -0
  19. package/src/_stories/_mock/usa-state-gradient.json +238 -0
  20. package/src/_stories/_mock/wastewater-map.json +208 -0
  21. package/src/components/CityList.tsx +5 -2
  22. package/src/components/EditorPanel/components/EditorPanel.tsx +81 -61
  23. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +27 -23
  24. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +75 -16
  25. package/src/components/Legend/components/Legend.tsx +42 -20
  26. package/src/components/Legend/components/index.scss +24 -24
  27. package/src/components/UsaMap/components/HexIcon.tsx +7 -1
  28. package/src/components/UsaMap/components/SingleState/SingleState.CountyOutput.tsx +40 -6
  29. package/src/components/UsaMap/components/SingleState/SingleState.StateOutput.tsx +10 -2
  30. package/src/components/UsaMap/components/Territory/Territory.Hexagon.tsx +57 -12
  31. package/src/components/UsaMap/components/Territory/Territory.Rectangle.tsx +95 -21
  32. package/src/components/UsaMap/components/Territory/TerritoryShape.ts +13 -0
  33. package/src/components/UsaMap/components/UsaMap.County.tsx +11 -13
  34. package/src/components/UsaMap/components/UsaMap.Region.tsx +59 -16
  35. package/src/components/UsaMap/components/UsaMap.SingleState.tsx +2 -1
  36. package/src/components/UsaMap/components/UsaMap.State.tsx +60 -62
  37. package/src/components/UsaMap/helpers/shapes.ts +5 -4
  38. package/src/components/WorldMap/WorldMap.tsx +77 -16
  39. package/src/data/initial-state.js +2 -1
  40. package/src/helpers/applyColorToLegend.ts +80 -0
  41. package/src/helpers/colors.ts +23 -0
  42. package/src/hooks/useTooltip.ts +9 -6
  43. package/src/scss/editor-panel.scss +0 -3
  44. package/src/scss/filters.scss +1 -9
  45. package/src/scss/main.scss +0 -5
  46. package/src/scss/map.scss +11 -63
  47. package/src/types/MapConfig.ts +6 -1
  48. package/src/types/MapContext.ts +1 -0
  49. package/examples/default-patterns.json +0 -579
  50. package/src/scss/datatable.scss +0 -6
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect, useCallback, memo, useContext } from 'react'
1
+ import React, { useState, useEffect, useContext } from 'react'
2
2
 
3
3
  // Third Party
4
4
  import {
@@ -10,6 +10,7 @@ import {
10
10
  } from 'react-accessible-accordion'
11
11
  import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd'
12
12
  import { useDebounce } from 'use-debounce'
13
+ import _ from 'lodash'
13
14
  // import ReactTags from 'react-tag-autocomplete'
14
15
  import { Tooltip as ReactTooltip } from 'react-tooltip'
15
16
  import Panels from './Panels'
@@ -42,6 +43,7 @@ import HexSetting from './HexShapeSettings.jsx'
42
43
  import ConfigContext from '../../../context.ts'
43
44
  import { MapContext } from '../../../types/MapContext.js'
44
45
  import { TextField } from './Inputs'
46
+ import Alert from '@cdc/core/components/Alert'
45
47
 
46
48
  // Todo: move to useReducer, seperate files out.
47
49
  const EditorPanel = ({ columnsRequiredChecker }) => {
@@ -63,8 +65,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
63
65
  runtimeData,
64
66
  setRuntimeData,
65
67
  generateRuntimeData,
66
- position,
67
- topoData,
68
+
68
69
 
69
70
  } = useContext<MapContext>(ConfigContext)
70
71
 
@@ -109,12 +110,18 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
109
110
  } = useMapLayers(state, setState, false, tooltipId)
110
111
 
111
112
  const categoryMove = (idx1, idx2) => {
112
- let categoryValuesOrder = [...state.legend.categoryValuesOrder]
113
+ let categoryValuesOrder = getCategoryValuesOrder()
113
114
 
114
115
  let [movedItem] = categoryValuesOrder.splice(idx1, 1)
115
116
 
116
117
  categoryValuesOrder.splice(idx2, 0, movedItem)
117
118
 
119
+ state.legend.categoryValuesOrder?.forEach(value => {
120
+ if (categoryValuesOrder.indexOf(value) === -1) {
121
+ categoryValuesOrder.push(value)
122
+ }
123
+ })
124
+
118
125
  setState({
119
126
  ...state,
120
127
  legend: {
@@ -371,7 +378,8 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
371
378
  ...state,
372
379
  legend: {
373
380
  ...state.legend,
374
- position: value
381
+ position: value,
382
+ hideBorder: _.includes(['top', 'bottom'], value)
375
383
  }
376
384
  })
377
385
  break
@@ -1087,6 +1095,15 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1087
1095
  </option>
1088
1096
  </select>
1089
1097
  </label>
1098
+ <label>
1099
+ <TextField
1100
+ type='textarea'
1101
+ value={state.filterIntro}
1102
+ fieldName='filterIntro'
1103
+ label='Filter Intro text'
1104
+ updateField={updateField}
1105
+ />
1106
+ </label>
1090
1107
  {filtersJSX}
1091
1108
  </>
1092
1109
  )
@@ -1219,40 +1236,6 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1219
1236
  columnsRequiredChecker()
1220
1237
  }, [state]) // eslint-disable-line
1221
1238
 
1222
- useEffect(() => {
1223
- //If a categorical map is used and the order is either not defined or incorrect, fix it
1224
- if ('category' === state.legend.type && runtimeLegend && runtimeLegend.runtimeDataHash) {
1225
- let valid = true
1226
- if (state.legend.categoryValuesOrder) {
1227
- runtimeLegend.forEach(item => {
1228
- if (!item.special && state.legend.categoryValuesOrder.indexOf(item.value) === -1) {
1229
- valid = false
1230
- }
1231
- })
1232
- let runtimeLegendKeys = runtimeLegend.map(item => item.value)
1233
- state.legend.categoryValuesOrder.forEach(category => {
1234
- if (runtimeLegendKeys.indexOf(category) === -1) {
1235
- valid = false
1236
- }
1237
- })
1238
- } else {
1239
- valid = false
1240
- }
1241
-
1242
- if (!valid) {
1243
- let arr = runtimeLegend.filter(item => !item.special).map(({ value }) => value)
1244
-
1245
- setState({
1246
- ...state,
1247
- legend: {
1248
- ...state.legend,
1249
- categoryValuesOrder: arr
1250
- }
1251
- })
1252
- }
1253
- }
1254
- }, [runtimeLegend]) // eslint-disable-line
1255
-
1256
1239
  const columnsOptions = [
1257
1240
  <option value='' key={'Select Option'}>
1258
1241
  - Select Option -
@@ -1289,6 +1272,14 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1289
1272
  })
1290
1273
 
1291
1274
  const updateField = (section, subsection, fieldName, newValue) => {
1275
+ if (!section) {
1276
+ setState({
1277
+ ...state,
1278
+ [fieldName]: newValue
1279
+ })
1280
+ return
1281
+ }
1282
+
1292
1283
  const isArray = Array.isArray(state[section])
1293
1284
 
1294
1285
  let sectionValue = isArray ? [...state[section], newValue] : { ...state[section], [fieldName]: newValue }
@@ -1435,7 +1426,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1435
1426
  {filter.order === 'cust' && (
1436
1427
  <DragDropContext
1437
1428
  onDragEnd={({ source, destination }) =>
1438
- handleFilterOrder(source.index, destination.index, index, state.filters[index])
1429
+ handleFilterOrder(source.index, destination?.index, index, state.filters?.[index])
1439
1430
  }
1440
1431
  >
1441
1432
  <Droppable droppableId='filter_order'>
@@ -1530,9 +1521,29 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1530
1521
  ...draggableStyle
1531
1522
  })
1532
1523
 
1524
+ const getCategoryValuesOrder = () => {
1525
+ let values = runtimeLegend
1526
+ ? runtimeLegend.filter(item => !item.special).map(runtimeLegendItem => runtimeLegendItem.value)
1527
+ : []
1528
+
1529
+ if (state.legend.cateogryValuesOrder) {
1530
+ return values.sort((a, b) => {
1531
+ let aVal = state.legend.cateogryValuesOrder.indexOf(a)
1532
+ let bVal = state.legend.cateogryValuesOrder.indexOf(b)
1533
+ if (aVal === bVal) return 0
1534
+ if (aVal === -1) return 1
1535
+ if (bVal === -1) return -1
1536
+ return aVal - bVal
1537
+ })
1538
+ } else {
1539
+ return values
1540
+ }
1541
+ }
1542
+
1533
1543
  const CategoryList = () => {
1534
- return state.legend.categoryValuesOrder ? (
1535
- state.legend.categoryValuesOrder.map((value, index) => (
1544
+ return getCategoryValuesOrder()
1545
+ .filter(item => !item?.special)
1546
+ .map((value, index) => (
1536
1547
  <Draggable key={value} draggableId={`item-${value}`} index={index}>
1537
1548
  {(provided, snapshot) => (
1538
1549
  <li style={{ position: 'relative' }}>
@@ -1549,9 +1560,6 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1549
1560
  )}
1550
1561
  </Draggable>
1551
1562
  ))
1552
- ) : (
1553
- <></>
1554
- )
1555
1563
  }
1556
1564
 
1557
1565
  const isLoadedFromUrl = state?.dataKey?.includes('http://') || state?.dataKey?.includes('https://')
@@ -2205,6 +2213,13 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2205
2213
  </Tooltip>
2206
2214
  </span>
2207
2215
  </label>
2216
+ {state.legend.specialClasses.length === 2 && (
2217
+ <Alert
2218
+ type='info'
2219
+ message='If a third special class is needed you can apply a pattern to set it apart.'
2220
+ showCloseButton={false}
2221
+ />
2222
+ )}
2208
2223
  {specialClasses.map((specialClass, i) => (
2209
2224
  <div className='edit-block' key={`special-class-${i}`}>
2210
2225
  <button
@@ -2265,15 +2280,17 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2265
2280
  </label>
2266
2281
  </div>
2267
2282
  ))}
2268
- <button
2269
- className='btn full-width'
2270
- onClick={e => {
2271
- e.preventDefault()
2272
- editColumn('primary', 'specialClassAdd', {})
2273
- }}
2274
- >
2275
- Add Special Class
2276
- </button>
2283
+ {state.legend.specialClasses.length < 2 && (
2284
+ <button
2285
+ className='btn btn-primary full-width'
2286
+ onClick={e => {
2287
+ e.preventDefault()
2288
+ editColumn('primary', 'specialClassAdd', {})
2289
+ }}
2290
+ >
2291
+ Add Special Class
2292
+ </button>
2293
+ )}
2277
2294
  </fieldset>
2278
2295
  )}
2279
2296
 
@@ -2417,7 +2434,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2417
2434
  </fieldset>
2418
2435
  ))}
2419
2436
  <button
2420
- className={'btn full-width'}
2437
+ className={'btn btn-primary full-width'}
2421
2438
  onClick={event => {
2422
2439
  event.preventDefault()
2423
2440
  addAdditionalColumn(additionalColumns.length + 1)
@@ -2473,7 +2490,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2473
2490
  </fieldset>
2474
2491
  ))}
2475
2492
  <button
2476
- className={'btn full-width'}
2493
+ className={'btn btn-primary full-width'}
2477
2494
  onClick={event => {
2478
2495
  event.preventDefault()
2479
2496
  const updatedAdditionaCategories = [...(state.legend.additionalCategories || [])]
@@ -2784,7 +2801,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2784
2801
  )}
2785
2802
  </Droppable>
2786
2803
  </DragDropContext>
2787
- {state.legend.categoryValuesOrder && state.legend.categoryValuesOrder.length >= 10 && (
2804
+ {runtimeLegend && runtimeLegend.length >= 10 && (
2788
2805
  <section className='error-box my-2'>
2789
2806
  <div>
2790
2807
  <strong className='pt-1'>Warning</strong>
@@ -2911,7 +2928,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2911
2928
  <p style={{ textAlign: 'center' }}>There are currently no filters.</p>
2912
2929
  )}
2913
2930
  <button
2914
- className={'btn full-width'}
2931
+ className={'btn btn-primary full-width'}
2915
2932
  onClick={event => {
2916
2933
  event.preventDefault()
2917
2934
  changeFilter(null, 'addNew')
@@ -3243,7 +3260,6 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3243
3260
  <label>
3244
3261
  <span className='edit-label'>Map Color Palette</span>
3245
3262
  </label>
3246
- {/* <InputCheckbox section="general" subsection="palette" fieldName='isReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={isPaletteReversed} /> */}
3247
3263
  <InputToggle
3248
3264
  type='3d'
3249
3265
  section='general'
@@ -3527,7 +3543,11 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3527
3543
  )
3528
3544
  })}
3529
3545
 
3530
- <button type='button' onClick={() => editCityStyles('add', 0, '', '')} className='btn full-width'>
3546
+ <button
3547
+ type='button'
3548
+ onClick={() => editCityStyles('add', 0, '', '')}
3549
+ className='btn btn-primary full-width'
3550
+ >
3531
3551
  Add city style
3532
3552
  </button>
3533
3553
  </>
@@ -3629,7 +3649,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3629
3649
  </>
3630
3650
  )
3631
3651
  })}
3632
- <button className={'btn full-width'} onClick={handleAddLayer}>
3652
+ <button className={'btn btn-primary full-width'} onClick={handleAddLayer}>
3633
3653
  Add Map Layer
3634
3654
  </button>
3635
3655
  <p className='layer-purpose-details'>
@@ -11,7 +11,12 @@ import ConfigContext from '../../../../context'
11
11
  // styles
12
12
 
13
13
  const PanelAnnotate: React.FC = props => {
14
- const { state: config, setState: updateConfig, dimensions, isDraggingAnnotation } = useContext<MapContext>(ConfigContext)
14
+ const {
15
+ state: config,
16
+ setState: updateConfig,
17
+ dimensions,
18
+ isDraggingAnnotation
19
+ } = useContext<MapContext>(ConfigContext)
15
20
  const getColumns = (filter = true) => {
16
21
  const columns = {}
17
22
  config.data.forEach(row => {
@@ -20,7 +25,10 @@ const PanelAnnotate: React.FC = props => {
20
25
 
21
26
  if (filter) {
22
27
  Object.keys(columns).forEach(key => {
23
- if ((config.series && config.series.filter(series => series.dataKey === key).length > 0) || (config.confidenceKeys && Object.keys(config.confidenceKeys).includes(key))) {
28
+ if (
29
+ (config.series && config.series.filter(series => series.dataKey === key).length > 0) ||
30
+ (config.confidenceKeys && Object.keys(config.confidenceKeys).includes(key))
31
+ ) {
24
32
  delete columns[key]
25
33
  }
26
34
  })
@@ -41,7 +49,9 @@ const PanelAnnotate: React.FC = props => {
41
49
  }
42
50
 
43
51
  const handleAddAnnotation = () => {
44
- const svgContainer = document.querySelector('.map-container > section > svg, .map-container > section > canvas')?.getBoundingClientRect()
52
+ const svgContainer = document
53
+ .querySelector('.map-container > section > svg, .map-container > section > canvas')
54
+ ?.getBoundingClientRect()
45
55
  const newSvgDims = [svgContainer.width, svgContainer.height]
46
56
 
47
57
  const newAnnotation = {
@@ -139,11 +149,17 @@ const PanelAnnotate: React.FC = props => {
139
149
  {config?.annotations &&
140
150
  config?.annotations.map((annotation, index) => (
141
151
  <Accordion>
142
- <Accordion.Section title={annotation.text ? annotation.text.substring(0, 15) + '...' : `Annotation ${index + 1}`}>
152
+ <Accordion.Section
153
+ title={annotation.text ? annotation.text.substring(0, 15) + '...' : `Annotation ${index + 1}`}
154
+ >
143
155
  <div className='annotation-group'>
144
156
  <label>
145
157
  Annotation Text:
146
- <textarea rows={5} value={annotation.text} onChange={e => handleAnnotationUpdate(e.target.value, 'text', index)} />
158
+ <textarea
159
+ rows={5}
160
+ value={annotation.text}
161
+ onChange={e => handleAnnotationUpdate(e.target.value, 'text', index)}
162
+ />
147
163
  </label>
148
164
  {/* <label>
149
165
  Vertical Anchor
@@ -304,30 +320,18 @@ const PanelAnnotate: React.FC = props => {
304
320
  </select>
305
321
  </label>
306
322
 
307
- {/* <label>
308
- Snap to Nearest Point
309
- <input
310
- type='checkbox'
311
- checked={config?.annotations[index]?.snapToNearestPoint}
312
- onClick={e => {
313
- const updatedAnnotations = [...config?.annotations]
314
- updatedAnnotations[index].snapToNearestPoint = e.target.checked
315
- updateConfig({
316
- ...config,
317
- annotations: updatedAnnotations
318
- })
319
- }}
320
- />
321
- </label> */}
322
-
323
- <Button className='warn btn-warn btn btn-remove delete' onClick={() => handleRemoveAnnotation(index)}>
323
+ <Button className='btn btn-danger' onClick={() => handleRemoveAnnotation(index)}>
324
324
  Delete Annotation
325
325
  </Button>
326
326
  </div>
327
327
  </Accordion.Section>
328
328
  </Accordion>
329
329
  ))}
330
- {config?.annotations?.length < 3 && <Button onClick={handleAddAnnotation}>Add Annotation</Button>}
330
+ {config?.annotations?.length < 3 && (
331
+ <button className='btn btn-primary full-width' onClick={handleAddAnnotation}>
332
+ Add Annotation
333
+ </button>
334
+ )}
331
335
  </Accordion.Section>
332
336
  </Accordion>
333
337
  )
@@ -1,5 +1,11 @@
1
1
  import { useContext } from 'react'
2
- import { Accordion, AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
2
+ import {
3
+ Accordion,
4
+ AccordionItem,
5
+ AccordionItemHeading,
6
+ AccordionItemPanel,
7
+ AccordionItemButton
8
+ } from 'react-accessible-accordion'
3
9
  import ConfigContext from '../../../../context'
4
10
  import { type MapContext } from '../../../../types/MapContext'
5
11
  import Button from '@cdc/core/components/elements/Button'
@@ -41,7 +47,11 @@ const PatternSettings = ({ name }: PanelProps) => {
41
47
  }
42
48
 
43
49
  /** Updates the map pattern at a given index */
44
- const handleUpdateGeoPattern = (value: string, index: number, keyToUpdate: 'dataKey' | 'pattern' | 'dataValue' | 'size' | 'label' | 'color') => {
50
+ const handleUpdateGeoPattern = (
51
+ value: string,
52
+ index: number,
53
+ keyToUpdate: 'dataKey' | 'pattern' | 'dataValue' | 'size' | 'label' | 'color'
54
+ ) => {
45
55
  const { features: unitedStates } = feature(topoJSON, topoJSON.objects.states)
46
56
  const updatedPatterns = [...state.map.patterns]
47
57
 
@@ -68,7 +78,9 @@ const PatternSettings = ({ name }: PanelProps) => {
68
78
 
69
79
  // Log a warning if the contrast check fails
70
80
  if (!contrastCheck) {
71
- console.warn(`COVE: pattern contrast check failed on ${geoData?.[state.columns.geo.name]} for ${patternData.dataKey} with:
81
+ console.warn(`COVE: pattern contrast check failed on ${geoData?.[state.columns.geo.name]} for ${
82
+ patternData.dataKey
83
+ } with:
72
84
  pattern color: ${patternColor}
73
85
  contrast: ${getColorContrast(currentFill, patternColor)}
74
86
  `)
@@ -78,7 +90,9 @@ const PatternSettings = ({ name }: PanelProps) => {
78
90
  })
79
91
  })
80
92
 
81
- const editorErrorMessage = updatedPatterns.some(pattern => pattern.contrastCheck === false) ? 'One or more patterns do not pass the WCAG 2.1 contrast ratio of 3:1.' : ''
93
+ const editorErrorMessage = updatedPatterns.some(pattern => pattern.contrastCheck === false)
94
+ ? 'One or more patterns do not pass the WCAG 2.1 contrast ratio of 3:1.'
95
+ : ''
82
96
 
83
97
  // Update the state with the new patterns and error message
84
98
  setState(prevState => ({
@@ -116,7 +130,12 @@ const PatternSettings = ({ name }: PanelProps) => {
116
130
  <AccordionItemButton>{name}</AccordionItemButton>
117
131
  </AccordionItemHeading>
118
132
  <AccordionItemPanel>
119
- {patterns.length > 0 && <Alert type={checkPatternContrasts() ? 'success' : 'danger'} message='Pattern colors must comply with <br /> <a href="https://www.w3.org/TR/WCAG21/">WCAG 2.1</a> 3:1 contrast ratio.' />}
133
+ {patterns.length > 0 && (
134
+ <Alert
135
+ type={checkPatternContrasts() ? 'success' : 'danger'}
136
+ message='Pattern colors must comply with <br /> <a href="https://www.w3.org/TR/WCAG21/">WCAG 2.1</a> 3:1 contrast ratio.'
137
+ />
138
+ )}
120
139
  <br />
121
140
 
122
141
  {patterns &&
@@ -133,13 +152,26 @@ const PatternSettings = ({ name }: PanelProps) => {
133
152
  <Accordion allowZeroExpanded key={`accordion-pattern--${patternIndex}`}>
134
153
  <AccordionItem>
135
154
  <AccordionItemHeading>
136
- <AccordionItemButton>{pattern.dataKey ? `${pattern.dataKey}: ${pattern.dataValue ?? 'No Value'}` : 'Select Column'}</AccordionItemButton>
155
+ <AccordionItemButton>
156
+ {pattern.dataKey ? `${pattern.dataKey}: ${pattern.dataValue ?? 'No Value'}` : 'Select Column'}
157
+ </AccordionItemButton>
137
158
  </AccordionItemHeading>
138
159
  <AccordionItemPanel>
139
160
  <>
140
- {pattern.contrastCheck ?? true ? <Alert type='success' message='This pattern passes contrast checks' /> : <Alert type='danger' message='Error: <a href="https://webaim.org/resources/contrastchecker/" target="_blank"> Review Color Contrast</a>' />}{' '}
161
+ {pattern.contrastCheck ?? true ? (
162
+ <Alert type='success' message='This pattern passes contrast checks' />
163
+ ) : (
164
+ <Alert
165
+ type='danger'
166
+ message='Error: <a href="https://webaim.org/resources/contrastchecker/" target="_blank"> Review Color Contrast</a>'
167
+ />
168
+ )}{' '}
141
169
  <label htmlFor={`pattern-dataKey--${patternIndex}`}>Data Key:</label>
142
- <select id={`pattern-dataKey--${patternIndex}`} value={pattern.dataKey !== '' ? pattern.dataKey : 'Select'} onChange={e => handleUpdateGeoPattern(e.target.value, patternIndex, 'dataKey')}>
170
+ <select
171
+ id={`pattern-dataKey--${patternIndex}`}
172
+ value={pattern.dataKey !== '' ? pattern.dataKey : 'Select'}
173
+ onChange={e => handleUpdateGeoPattern(e.target.value, patternIndex, 'dataKey')}
174
+ >
143
175
  {/* TODO: sort these? */}
144
176
  {dataKeyOptions.map((d, index) => {
145
177
  return (
@@ -151,14 +183,28 @@ const PatternSettings = ({ name }: PanelProps) => {
151
183
  </select>
152
184
  <label htmlFor={`pattern-dataValue--${patternIndex}`}>
153
185
  Data Value:
154
- <input type='text' onChange={e => handleUpdateGeoPattern(e.target.value, patternIndex, 'dataValue')} id={`pattern-dataValue--${patternIndex}`} value={pattern.dataValue === '' ? '' : pattern.dataValue} />
186
+ <input
187
+ type='text'
188
+ onChange={e => handleUpdateGeoPattern(e.target.value, patternIndex, 'dataValue')}
189
+ id={`pattern-dataValue--${patternIndex}`}
190
+ value={pattern.dataValue === '' ? '' : pattern.dataValue}
191
+ />
155
192
  </label>
156
193
  <label htmlFor={`pattern-label--${patternIndex}`}>
157
194
  Label (optional):
158
- <input type='text' onChange={e => handleUpdateGeoPattern(e.target.value, patternIndex, 'label')} id={`pattern-dataValue--${patternIndex}`} value={pattern.label === '' ? '' : pattern.label} />
195
+ <input
196
+ type='text'
197
+ onChange={e => handleUpdateGeoPattern(e.target.value, patternIndex, 'label')}
198
+ id={`pattern-dataValue--${patternIndex}`}
199
+ value={pattern.label === '' ? '' : pattern.label}
200
+ />
159
201
  </label>
160
202
  <label htmlFor={`pattern-type--${patternIndex}`}>Pattern Type:</label>
161
- <select id={`pattern-type--${patternIndex}`} value={pattern?.pattern} onChange={e => handleUpdateGeoPattern(e.target.value, patternIndex, 'pattern')}>
203
+ <select
204
+ id={`pattern-type--${patternIndex}`}
205
+ value={pattern?.pattern}
206
+ onChange={e => handleUpdateGeoPattern(e.target.value, patternIndex, 'pattern')}
207
+ >
162
208
  {patternTypes.map((patternName, index) => (
163
209
  <option value={patternName} key={index}>
164
210
  {patternName}
@@ -166,7 +212,11 @@ const PatternSettings = ({ name }: PanelProps) => {
166
212
  ))}
167
213
  </select>
168
214
  <label htmlFor={`pattern-size--${patternIndex}`}>Pattern Size:</label>
169
- <select id={`pattern-size--${patternIndex}`} value={pattern?.size} onChange={e => handleUpdateGeoPattern(e.target.value, patternIndex, 'size')}>
215
+ <select
216
+ id={`pattern-size--${patternIndex}`}
217
+ value={pattern?.size}
218
+ onChange={e => handleUpdateGeoPattern(e.target.value, patternIndex, 'size')}
219
+ >
170
220
  {['small', 'medium', 'large'].map((size, index) => (
171
221
  <option value={size} key={index}>
172
222
  {size}
@@ -178,16 +228,25 @@ const PatternSettings = ({ name }: PanelProps) => {
178
228
  Pattern Color
179
229
  <Tooltip style={{ textTransform: 'none' }}>
180
230
  <Tooltip.Target>
181
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
231
+ <Icon
232
+ display='question'
233
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
234
+ />
182
235
  </Tooltip.Target>
183
236
  <Tooltip.Content>
184
237
  <p>{`If this setting is used, it is the reponsibility of the visualization author to verify the visualization colors meet WCAG 3:1 contrast ratios.`}</p>
185
238
  </Tooltip.Content>
186
239
  </Tooltip>
187
- <input type='text' value={pattern.color || ''} id='patternColor' name='patternColor' onChange={e => handleUpdateGeoPattern(e.target.value, patternIndex, 'color')} />
240
+ <input
241
+ type='text'
242
+ value={pattern.color || ''}
243
+ id='patternColor'
244
+ name='patternColor'
245
+ onChange={e => handleUpdateGeoPattern(e.target.value, patternIndex, 'color')}
246
+ />
188
247
  </label>
189
248
  </div>
190
- <Button onClick={e => handleRemovePattern(patternIndex)} className='btn btn--remove warn'>
249
+ <Button onClick={e => handleRemovePattern(patternIndex)} className='btn btn-danger'>
191
250
  Remove Pattern
192
251
  </Button>
193
252
  </>
@@ -196,7 +255,7 @@ const PatternSettings = ({ name }: PanelProps) => {
196
255
  </Accordion>
197
256
  )
198
257
  })}
199
- <button className='btn full-width' onClick={handleAddGeoPattern}>
258
+ <button className='btn btn-primary full-width mt-2' onClick={handleAddGeoPattern}>
200
259
  Add Geo Pattern
201
260
  </button>
202
261
  </AccordionItemPanel>