@cdc/map 4.24.11 → 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 (42) hide show
  1. package/dist/cdcmap.js +28291 -28264
  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/default-patterns.json +867 -0
  7. package/index.html +4 -5
  8. package/package.json +3 -3
  9. package/src/CdcMap.tsx +42 -48
  10. package/src/_stories/{CdcMapLegend.stories.tsx → CdcMap.Legend.Gradient.stories.tsx} +1 -20
  11. package/src/_stories/CdcMap.Legend.stories.tsx +40 -0
  12. package/src/_stories/CdcMap.Patterns.stories.tsx +29 -0
  13. package/src/_stories/CdcMap.stories.tsx +59 -0
  14. package/src/_stories/UsaMap.NoData.stories.tsx +19 -0
  15. package/src/_stories/_mock/custom-layer-map.json +1117 -0
  16. package/src/_stories/_mock/default-patterns.json +865 -0
  17. package/src/_stories/_mock/example-city-state.json +858 -0
  18. package/src/components/CityList.tsx +5 -2
  19. package/src/components/EditorPanel/components/EditorPanel.tsx +51 -21
  20. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +1 -1
  21. package/src/components/Legend/components/Legend.tsx +22 -6
  22. package/src/components/Legend/components/index.scss +16 -23
  23. package/src/components/UsaMap/components/SingleState/SingleState.CountyOutput.tsx +40 -6
  24. package/src/components/UsaMap/components/SingleState/SingleState.StateOutput.tsx +10 -2
  25. package/src/components/UsaMap/components/Territory/Territory.Hexagon.tsx +1 -1
  26. package/src/components/UsaMap/components/Territory/Territory.Rectangle.tsx +12 -11
  27. package/src/components/UsaMap/components/UsaMap.County.tsx +11 -13
  28. package/src/components/UsaMap/components/UsaMap.Region.tsx +59 -16
  29. package/src/components/UsaMap/components/UsaMap.SingleState.tsx +2 -1
  30. package/src/components/UsaMap/components/UsaMap.State.tsx +57 -59
  31. package/src/components/WorldMap/WorldMap.tsx +77 -16
  32. package/src/data/initial-state.js +2 -1
  33. package/src/helpers/applyColorToLegend.ts +80 -0
  34. package/src/helpers/colors.ts +23 -0
  35. package/src/hooks/useTooltip.ts +9 -6
  36. package/src/scss/filters.scss +0 -3
  37. package/src/scss/main.scss +0 -1
  38. package/src/scss/map.scss +11 -59
  39. package/src/types/MapConfig.ts +5 -0
  40. package/src/types/MapContext.ts +1 -0
  41. package/examples/default-patterns.json +0 -579
  42. package/src/scss/datatable.scss +0 -6
@@ -7,6 +7,7 @@ import { GlyphStar, GlyphTriangle, GlyphDiamond, GlyphSquare, GlyphCircle } from
7
7
  import { getFilterControllingStatePicked } from './UsaMap/helpers/map'
8
8
 
9
9
  import ConfigContext from '../context'
10
+ import { getGeoStrokeColor } from '../helpers/colors'
10
11
 
11
12
  const CityList = ({
12
13
  data,
@@ -79,6 +80,8 @@ const CityList = ({
79
80
  fillOpacity: state.general.type === 'bubble' ? 0.4 : 1
80
81
  }
81
82
 
83
+ const geoStrokeColor = getGeoStrokeColor(state)
84
+
82
85
  const pin = (
83
86
  <path
84
87
  className='marker'
@@ -88,7 +91,7 @@ const CityList = ({
88
91
  data-tooltip-id={`tooltip__${tooltipId}`}
89
92
  data-tooltip-html={toolTip}
90
93
  transform={`scale(${radius / 9})`}
91
- stroke={state.general.geoBorderColor === 'sameAsBackground' ? '#ffffff' : '#000000'}
94
+ stroke={geoStrokeColor}
92
95
  strokeWidth={'2px'}
93
96
  tabIndex='-1'
94
97
  {...additionalProps}
@@ -185,7 +188,7 @@ const CityList = ({
185
188
  title: 'Select for more information',
186
189
  'data-tooltip-id': `tooltip__${tooltipId}`,
187
190
  'data-tooltip-html': toolTip,
188
- stroke: state.general.geoBorderColor === 'sameAsBackground' ? '#ffffff' : '#000000',
191
+ stroke: geoStrokeColor,
189
192
  strokeWidth: '2px',
190
193
  tabIndex: -1,
191
194
  ...additionalProps
@@ -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
 
@@ -116,7 +117,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
116
117
  categoryValuesOrder.splice(idx2, 0, movedItem)
117
118
 
118
119
  state.legend.categoryValuesOrder?.forEach(value => {
119
- if(categoryValuesOrder.indexOf(value) === -1){
120
+ if (categoryValuesOrder.indexOf(value) === -1) {
120
121
  categoryValuesOrder.push(value)
121
122
  }
122
123
  })
@@ -377,7 +378,8 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
377
378
  ...state,
378
379
  legend: {
379
380
  ...state.legend,
380
- position: value
381
+ position: value,
382
+ hideBorder: _.includes(['top', 'bottom'], value)
381
383
  }
382
384
  })
383
385
  break
@@ -1093,6 +1095,15 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1093
1095
  </option>
1094
1096
  </select>
1095
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>
1096
1107
  {filtersJSX}
1097
1108
  </>
1098
1109
  )
@@ -1261,6 +1272,14 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1261
1272
  })
1262
1273
 
1263
1274
  const updateField = (section, subsection, fieldName, newValue) => {
1275
+ if (!section) {
1276
+ setState({
1277
+ ...state,
1278
+ [fieldName]: newValue
1279
+ })
1280
+ return
1281
+ }
1282
+
1264
1283
  const isArray = Array.isArray(state[section])
1265
1284
 
1266
1285
  let sectionValue = isArray ? [...state[section], newValue] : { ...state[section], [fieldName]: newValue }
@@ -1407,7 +1426,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1407
1426
  {filter.order === 'cust' && (
1408
1427
  <DragDropContext
1409
1428
  onDragEnd={({ source, destination }) =>
1410
- handleFilterOrder(source.index, destination.index, index, state.filters[index])
1429
+ handleFilterOrder(source.index, destination?.index, index, state.filters?.[index])
1411
1430
  }
1412
1431
  >
1413
1432
  <Droppable droppableId='filter_order'>
@@ -1503,9 +1522,11 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1503
1522
  })
1504
1523
 
1505
1524
  const getCategoryValuesOrder = () => {
1506
- let values = runtimeLegend ? runtimeLegend.filter(item => !item.special).map(runtimeLegendItem => runtimeLegendItem.value) : []
1525
+ let values = runtimeLegend
1526
+ ? runtimeLegend.filter(item => !item.special).map(runtimeLegendItem => runtimeLegendItem.value)
1527
+ : []
1507
1528
 
1508
- if(state.legend.cateogryValuesOrder){
1529
+ if (state.legend.cateogryValuesOrder) {
1509
1530
  return values.sort((a, b) => {
1510
1531
  let aVal = state.legend.cateogryValuesOrder.indexOf(a)
1511
1532
  let bVal = state.legend.cateogryValuesOrder.indexOf(b)
@@ -1517,11 +1538,12 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1517
1538
  } else {
1518
1539
  return values
1519
1540
  }
1520
-
1521
1541
  }
1522
1542
 
1523
1543
  const CategoryList = () => {
1524
- return getCategoryValuesOrder().filter(item => !item.special).map((value, index) => (
1544
+ return getCategoryValuesOrder()
1545
+ .filter(item => !item?.special)
1546
+ .map((value, index) => (
1525
1547
  <Draggable key={value} draggableId={`item-${value}`} index={index}>
1526
1548
  {(provided, snapshot) => (
1527
1549
  <li style={{ position: 'relative' }}>
@@ -1537,7 +1559,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1537
1559
  </li>
1538
1560
  )}
1539
1561
  </Draggable>
1540
- ))
1562
+ ))
1541
1563
  }
1542
1564
 
1543
1565
  const isLoadedFromUrl = state?.dataKey?.includes('http://') || state?.dataKey?.includes('https://')
@@ -2191,6 +2213,13 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2191
2213
  </Tooltip>
2192
2214
  </span>
2193
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
+ )}
2194
2223
  {specialClasses.map((specialClass, i) => (
2195
2224
  <div className='edit-block' key={`special-class-${i}`}>
2196
2225
  <button
@@ -2251,15 +2280,17 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2251
2280
  </label>
2252
2281
  </div>
2253
2282
  ))}
2254
- <button
2255
- className='btn btn-primary full-width'
2256
- onClick={e => {
2257
- e.preventDefault()
2258
- editColumn('primary', 'specialClassAdd', {})
2259
- }}
2260
- >
2261
- Add Special Class
2262
- </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
+ )}
2263
2294
  </fieldset>
2264
2295
  )}
2265
2296
 
@@ -3229,7 +3260,6 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3229
3260
  <label>
3230
3261
  <span className='edit-label'>Map Color Palette</span>
3231
3262
  </label>
3232
- {/* <InputCheckbox section="general" subsection="palette" fieldName='isReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={isPaletteReversed} /> */}
3233
3263
  <InputToggle
3234
3264
  type='3d'
3235
3265
  section='general'
@@ -255,7 +255,7 @@ const PatternSettings = ({ name }: PanelProps) => {
255
255
  </Accordion>
256
256
  )
257
257
  })}
258
- <button className='btn btn-primary full-width' onClick={handleAddGeoPattern}>
258
+ <button className='btn btn-primary full-width mt-2' onClick={handleAddGeoPattern}>
259
259
  Add Geo Pattern
260
260
  </button>
261
261
  </AccordionItemPanel>
@@ -18,7 +18,7 @@ import { GlyphStar, GlyphTriangle, GlyphDiamond, GlyphSquare, GlyphCircle } from
18
18
  import { Group } from '@visx/group'
19
19
  import './index.scss'
20
20
  import { ViewportSize } from '@cdc/chart/src/types/ChartConfig'
21
- import { isMobileHeightViewport } from '@cdc/core/helpers/viewports'
21
+ import { isBelowBreakpoint, isMobileHeightViewport } from '@cdc/core/helpers/viewports'
22
22
 
23
23
  const LEGEND_PADDING = 30
24
24
 
@@ -46,6 +46,12 @@ const Legend = forwardRef<HTMLDivElement, LegendProps>((props, ref) => {
46
46
  } = useContext(ConfigContext)
47
47
 
48
48
  const { legend } = state
49
+ const isLegendGradient = legend.style === 'gradient'
50
+ const boxDynamicallyHidden = isBelowBreakpoint('md', currentViewport)
51
+ const legendWrapping =
52
+ (legend.position === 'left' || legend.position === 'right') && isBelowBreakpoint('md', currentViewport)
53
+ const legendOnBottom = legend.position === 'bottom' || legendWrapping
54
+ const needsTopMargin = legend.hideBorder && legendOnBottom
49
55
 
50
56
  // Toggles if a legend is active and being applied to the map and data table.
51
57
  const toggleLegendActive = (i, legendLabel) => {
@@ -87,6 +93,10 @@ const Legend = forwardRef<HTMLDivElement, LegendProps>((props, ref) => {
87
93
  formattedText = '0'
88
94
  }
89
95
 
96
+ if (entry.max === null && entry.min === null) {
97
+ formattedText = 'No data'
98
+ }
99
+
90
100
  let legendLabel = formattedText
91
101
 
92
102
  if (entry.hasOwnProperty('special')) {
@@ -207,7 +217,7 @@ const Legend = forwardRef<HTMLDivElement, LegendProps>((props, ref) => {
207
217
 
208
218
  return legendItems
209
219
  }
210
- const legendListItems = legendList(state.legend.style === 'gradient')
220
+ const legendListItems = legendList(isLegendGradient)
211
221
 
212
222
  const { legendClasses } = useDataVizClasses(state, viewport)
213
223
 
@@ -244,13 +254,13 @@ const Legend = forwardRef<HTMLDivElement, LegendProps>((props, ref) => {
244
254
 
245
255
  return (
246
256
  <ErrorBoundary component='Sidebar'>
247
- <div className='legends'>
257
+ <div className={`legends ${needsTopMargin ? 'mt-1' : ''}`}>
248
258
  <aside
249
259
  id={skipId || 'legend'}
250
260
  className={legendClasses.aside.join(' ') || ''}
251
261
  role='region'
252
262
  aria-label='Legend'
253
- tabIndex={0}
263
+ tabIndex={isLegendGradient ? -1 : 0}
254
264
  ref={ref}
255
265
  >
256
266
  <section className={legendClasses.section.join(' ') || ''} aria-label='Map Legend'>
@@ -279,7 +289,9 @@ const Legend = forwardRef<HTMLDivElement, LegendProps>((props, ref) => {
279
289
  labels={getFormattedLegendItems().map(item => item?.label) ?? []}
280
290
  colors={getFormattedLegendItems().map(item => item?.color) ?? []}
281
291
  dimensions={dimensions}
282
- parentPaddingToSubtract={containerWidthPadding + (legend.hideBorder ? 0 : LEGEND_PADDING)}
292
+ parentPaddingToSubtract={
293
+ containerWidthPadding + (legend.hideBorder || boxDynamicallyHidden ? 0 : LEGEND_PADDING)
294
+ }
283
295
  config={state}
284
296
  />
285
297
  {!!legendListItems.length && (
@@ -321,7 +333,11 @@ const Legend = forwardRef<HTMLDivElement, LegendProps>((props, ref) => {
321
333
  </div>
322
334
  </>
323
335
  )}
324
- {runtimeLegend.disabledAmt > 0 && <Button onClick={handleReset}>Reset</Button>}
336
+ {runtimeLegend.disabledAmt > 0 && (
337
+ <Button className={legendClasses.resetButton.join(' ')} onClick={handleReset}>
338
+ Reset
339
+ </Button>
340
+ )}
325
341
  </section>
326
342
  </aside>
327
343
  {state.hexMap.shapeGroups?.length > 0 && state.hexMap.type === 'shapes' && state.general.displayAsHex && (
@@ -6,7 +6,7 @@
6
6
  }
7
7
  @include breakpointClass(md) {
8
8
  .map-container.world aside.side {
9
- border-top: var(--lightGray) 1px solid;
9
+ border-top: var(--cool-gray-10) 1px solid;
10
10
  position: absolute;
11
11
  box-shadow: rgba(0, 0, 0, 0.2) 0 10px 18px;
12
12
  }
@@ -15,12 +15,15 @@
15
15
  aside {
16
16
  background-color: #fff;
17
17
  z-index: 6;
18
- border-top: var(--lightGray) 1px solid;
18
+ border-top: var(--cool-gray-10) 1px solid;
19
19
 
20
20
  @include breakpointClass(md) {
21
+ .legend-container.legend-padding {
22
+ padding: 15px;
23
+ }
21
24
  &.bottom,
22
25
  &.top {
23
- border: var(--lightGray) 1px solid;
26
+ border: var(--cool-gray-10) 1px solid;
24
27
  }
25
28
  &.side {
26
29
  z-index: 1;
@@ -31,7 +34,7 @@
31
34
  align-self: flex-start;
32
35
  z-index: 4;
33
36
  right: 1em;
34
- border: var(--lightGray) 1px solid;
37
+ border: var(--cool-gray-10) 1px solid;
35
38
  top: 2em;
36
39
  right: 1em;
37
40
 
@@ -67,9 +70,10 @@
67
70
  }
68
71
 
69
72
  .legend-container {
73
+ --space-between-legend-items: 0.6em;
70
74
  position: relative;
71
75
  &.legend-padding {
72
- padding: 15px;
76
+ padding-top: 15px;
73
77
  }
74
78
  .legend-container__title {
75
79
  font-size: 1.3em;
@@ -83,17 +87,7 @@
83
87
  padding-top: 1em;
84
88
  }
85
89
  .legend-container__reset-button {
86
- font-size: 0.75em;
87
- right: 1em;
88
- text-transform: uppercase;
89
- transition: 0.2s all;
90
- padding: 0.2em 0.5em;
91
- border: rgba(0, 0, 0, 0.2) 1px solid;
92
- padding: 0.375rem;
93
- &:hover {
94
- text-decoration: none;
95
- transition: 0.2s all;
96
- }
90
+ margin-top: 1em;
97
91
  }
98
92
  p {
99
93
  line-height: 1.4em;
@@ -118,23 +112,21 @@
118
112
 
119
113
  &:not(.vertical-sorted, .legend-container__ul--single-column, .single-row) {
120
114
  width: 100%;
121
- @include breakpoint(sm) {
122
- .legend-container__li {
123
- width: 50%;
124
- }
125
- }
126
115
  }
127
116
  .legend-container__li {
128
117
  flex-shrink: 0;
129
118
  display: inline-block;
130
119
  padding-right: 1em;
131
- padding-bottom: 1em;
120
+ margin-bottom: var(--space-between-legend-items);
132
121
  vertical-align: middle;
133
122
  transition: 0.1s opacity;
134
123
  display: flex;
135
124
  cursor: pointer;
136
125
  white-space: wrap;
137
126
  flex-grow: 1;
127
+ &:last-child {
128
+ margin-bottom: 0;
129
+ }
138
130
  @include breakpoint(md) {
139
131
  white-space: nowrap;
140
132
  }
@@ -146,16 +138,17 @@
146
138
  }
147
139
  .legend-container__ul.single-row {
148
140
  width: 100%;
141
+ cursor: pointer;
149
142
  list-style: none;
150
143
  display: flex;
151
144
  flex-direction: row;
152
145
  align-items: center;
153
146
  justify-content: flex-start;
154
147
  flex-wrap: wrap;
148
+ row-gap: var(--space-between-legend-items);
155
149
 
156
150
  & > li {
157
151
  margin-right: 1em;
158
- margin-bottom: 1em;
159
152
  white-space: wrap;
160
153
  display: flex;
161
154
  justify-content: center;
@@ -1,6 +1,7 @@
1
1
  import React, { useContext } from 'react'
2
2
  import ConfigContext from '../../../../context'
3
3
  import { MapContext } from '../../../../types/MapContext'
4
+ import { getGeoFillColor } from '../../../../helpers/colors'
4
5
 
5
6
  interface CountyOutputProps {
6
7
  counties: any[]
@@ -11,7 +12,10 @@ interface CountyOutputProps {
11
12
  }
12
13
 
13
14
  const CountyOutput: React.FC<CountyOutputProps> = ({ path, counties, scale, geoStrokeColor, tooltipId }) => {
14
- const { applyTooltipsToGeo, applyLegendToRow, displayGeoName, state, data, geoClickHandler } = useContext<MapContext>(ConfigContext)
15
+ const { applyTooltipsToGeo, applyLegendToRow, displayGeoName, state, data, geoClickHandler } =
16
+ useContext<MapContext>(ConfigContext)
17
+
18
+ const geoFillColor = getGeoFillColor(state)
15
19
  return (
16
20
  <>
17
21
  {counties.map(county => {
@@ -50,19 +54,49 @@ const CountyOutput: React.FC<CountyOutputProps> = ({ path, counties, scale, geoS
50
54
  }
51
55
 
52
56
  // When to add pointer cursor
53
- if ((state.columns.navigate && geoData[state.columns.navigate.name]) || state.tooltips.appearanceType === 'hover') {
57
+ if (
58
+ (state.columns.navigate && geoData[state.columns.navigate.name]) ||
59
+ state.tooltips.appearanceType === 'hover'
60
+ ) {
54
61
  styles.cursor = 'pointer'
55
62
  }
56
63
 
57
64
  return (
58
- <g key={`key--${county.id}`} className={`county county--${geoDisplayName.split(' ').join('')} county--${geoData[state.columns.geo.name]}`} style={styles} onClick={() => geoClickHandler(geoDisplayName, geoData)} data-tooltip-id={`tooltip__${tooltipId}`} data-tooltip-html={toolTip}>
59
- <path tabIndex={-1} className={`county`} stroke={geoStrokeColor} d={countyPath} strokeWidth={0.75 / scale} />
65
+ <g
66
+ key={`key--${county.id}`}
67
+ className={`county county--${geoDisplayName.split(' ').join('')} county--${
68
+ geoData[state.columns.geo.name]
69
+ }`}
70
+ style={styles}
71
+ onClick={() => geoClickHandler(geoDisplayName, geoData)}
72
+ data-tooltip-id={`tooltip__${tooltipId}`}
73
+ data-tooltip-html={toolTip}
74
+ >
75
+ <path
76
+ tabIndex={-1}
77
+ className={`county`}
78
+ stroke={geoStrokeColor}
79
+ d={countyPath}
80
+ strokeWidth={0.75 / scale}
81
+ />
60
82
  </g>
61
83
  )
62
84
  } else {
63
85
  return (
64
- <g key={`key--${county.id}`} className={`county county--${geoDisplayName.split(' ').join('')}`} style={{ fill: '#e6e6e6' }} data-tooltip-id={`tooltip__${tooltipId}`} data-tooltip-html={toolTip}>
65
- <path tabIndex={-1} className={`county`} stroke={geoStrokeColor} d={countyPath} strokeWidth={0.75 / scale} />
86
+ <g
87
+ key={`key--${county.id}`}
88
+ className={`county county--${geoDisplayName.split(' ').join('')}`}
89
+ style={{ fill: geoFillColor }}
90
+ data-tooltip-id={`tooltip__${tooltipId}`}
91
+ data-tooltip-html={toolTip}
92
+ >
93
+ <path
94
+ tabIndex={-1}
95
+ className={`county`}
96
+ stroke={geoStrokeColor}
97
+ d={countyPath}
98
+ strokeWidth={0.75 / scale}
99
+ />
66
100
  </g>
67
101
  )
68
102
  }
@@ -1,6 +1,7 @@
1
1
  import { useContext } from 'react'
2
2
  import { mesh, Topology } from 'topojson-client'
3
3
  import ConfigContext from '../../../../context'
4
+ import { getGeoFillColor, getGeoStrokeColor } from '../../../../helpers/colors'
4
5
 
5
6
  type StateOutputProps = {
6
7
  topoData: Topology
@@ -15,12 +16,19 @@ const StateOutput: React.FC<StateOutputProps> = ({ topoData, path, scale, stateT
15
16
  return s.properties.name === state.general.statePicked.stateName
16
17
  })
17
18
 
18
- const geoStrokeColor = state.general.geoBorderColor === 'darkGray' ? 'rgba(0, 0, 0, 0.2)' : 'rgba(255,255,255,0.7)'
19
+ const geoStrokeColor = getGeoStrokeColor(state)
20
+ const geoFillColor = getGeoFillColor(state)
19
21
 
20
22
  let stateLines = path(mesh(topoData, geo[0]))
21
23
 
22
24
  return (
23
- <g key={'single-state'} className='single-state' style={{ fill: '#E6E6E6' }} stroke={geoStrokeColor} strokeWidth={0.95 / scale}>
25
+ <g
26
+ key={'single-state'}
27
+ className='single-state'
28
+ style={{ fill: geoFillColor }}
29
+ stroke={geoStrokeColor}
30
+ strokeWidth={0.95 / scale}
31
+ >
24
32
  <path tabIndex={-1} className='state-path' d={stateLines} />
25
33
  </g>
26
34
  )
@@ -176,7 +176,7 @@ const TerritoryHexagon = ({
176
176
 
177
177
  return (
178
178
  territoryData && (
179
- <svg viewBox='0 0 45 51' className='territory-wrapper--hex'>
179
+ <svg viewBox='-1 -1 46 53' className='territory-wrapper--hex'>
180
180
  <g {...props} data-tooltip-html={dataTooltipHtml} data-tooltip-id={dataTooltipId} onClick={handleShapeClick}>
181
181
  <polygon
182
182
  stroke={stroke}
@@ -2,7 +2,7 @@ import { useContext } from 'react'
2
2
  import { PatternLines, PatternCircles, PatternWaves } from '@visx/pattern'
3
3
  import ConfigContext from './../../../../context'
4
4
  import { type MapContext } from '../../../../types/MapContext'
5
- import { patternSizes } from './../../helpers/patternSizes'
5
+ import { patternSizes } from '../../helpers/patternSizes'
6
6
  import { getContrastColor } from '@cdc/core/helpers/cove/accessibility'
7
7
  import { type TerritoryShape } from './TerritoryShape'
8
8
 
@@ -17,15 +17,16 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
17
17
  territory,
18
18
  text,
19
19
  textColor,
20
+ backgroundColor,
20
21
  ...props
21
22
  }) => {
22
- const { state, supportedTerritories } = useContext<MapContext>(ConfigContext)
23
+ const { state } = useContext<MapContext>(ConfigContext)
23
24
  const { territoryData, ...otherProps } = props
24
25
  const rectanglePath =
25
- 'M40,0.5 C41.2426407,0.5 42.3676407,1.00367966 43.1819805,1.81801948 C43.9963203,2.63235931 44.5,3.75735931 44.5,5 L44.5,5 L44.5,23 C44.5,24.2426407 43.9963203,25.3676407 43.1819805,26.1819805 C42.3676407,26.9963203 41.2426407,27.5 40,27.5 L40,27.5 L5,27.5 C3.75735931,27.5 2.63235931,26.9963203 1.81801948,26.1819805 C1.00367966,25.3676407 0.5,24.2426407 0.5,23 L0.5,23 L0.5,5 C0.5,3.75735931 1.00367966,2.63235931 1.81801948,1.81801948 C2.63235931,1.00367966 3.75735931,0.5 5,0.5 L5,0.5 Z'
26
+ 'M42,0.5 C42.8284271,0.5 43.5,1.17157288 43.5,2 L43.5,2 L43.5,26 C43.5,26.8284271 42.8284271,27.5 42,27.5 L42,27.5 L3,27.5 C2.17157288,27.5 1.5,26.8284271 1.5,26 L1.5,26 L1.5,2 C1.5,1.17157288 2.17157288,0.5 3,0.5 L3,0.5 Z'
26
27
 
27
28
  return (
28
- <svg viewBox='0 0 45 28' key={territory} className={territory}>
29
+ <svg viewBox='0 0 45 29' key={territory} className={territory}>
29
30
  <g
30
31
  {...otherProps}
31
32
  strokeLinejoin='round'
@@ -41,7 +42,7 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
41
42
  x='50%'
42
43
  y='54%'
43
44
  fill={text}
44
- style={{ stroke: textColor, strokeWidth: 1 }}
45
+ style={{ stroke: 'none' }}
45
46
  className='territory-text'
46
47
  paintOrder='stroke'
47
48
  onClick={handleShapeClick}
@@ -52,8 +53,8 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
52
53
  </text>
53
54
 
54
55
  {state.map.patterns.map((patternData, patternIndex) => {
55
- const patternColor = getContrastColor('#FFF', props.style.fill)
56
- const hasMatchingValues = supportedTerritories[territory]?.includes(patternData?.dataValue)
56
+ const patternColor = patternData.color || getContrastColor('#FFF', backgroundColor)
57
+ const hasMatchingValues = patternData.dataValue === territoryData[patternData.dataKey]
57
58
 
58
59
  if (!hasMatchingValues) return null
59
60
  if (!patternData.pattern) return null
@@ -62,7 +63,7 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
62
63
  <>
63
64
  {patternData?.pattern === 'waves' && (
64
65
  <PatternWaves
65
- id={`territory-${patternData?.dataKey}--${patternIndex}`}
66
+ id={`territory-${territory}-${patternData?.dataKey}--${patternIndex}`}
66
67
  height={patternSizes[patternData?.size] ?? 10}
67
68
  width={patternSizes[patternData?.size] ?? 10}
68
69
  fill={patternColor}
@@ -71,7 +72,7 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
71
72
  )}
72
73
  {patternData?.pattern === 'circles' && (
73
74
  <PatternCircles
74
- id={`territory-${patternData?.dataKey}--${patternIndex}`}
75
+ id={`territory-${territory}-${patternData?.dataKey}--${patternIndex}`}
75
76
  height={patternSizes[patternData?.size] ?? 10}
76
77
  width={patternSizes[patternData?.size] ?? 10}
77
78
  fill={patternColor}
@@ -80,7 +81,7 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
80
81
  )}
81
82
  {patternData?.pattern === 'lines' && (
82
83
  <PatternLines
83
- id={`territory-${patternData?.dataKey}--${patternIndex}`}
84
+ id={`territory-${territory}-${patternData?.dataKey}--${patternIndex}`}
84
85
  height={patternSizes[patternData?.size] ?? 6}
85
86
  width={patternSizes[patternData?.size] ?? 6}
86
87
  stroke={patternColor}
@@ -92,7 +93,7 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
92
93
  stroke={stroke}
93
94
  strokeWidth={strokeWidth}
94
95
  d={rectanglePath}
95
- fill={`url(#territory-${patternData?.dataKey}--${patternIndex})`}
96
+ fill={`url(#territory-${territory}-${patternData?.dataKey}--${patternIndex})`}
96
97
  color={patternData ? 'white' : textColor}
97
98
  className={[
98
99
  `territory-pattern-${patternData.dataKey}`,