@cdc/map 4.25.3 → 4.25.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.
Files changed (119) hide show
  1. package/.idea/map.iml +12 -0
  2. package/.idea/modules.xml +8 -0
  3. package/.idea/vcs.xml +6 -0
  4. package/dist/cdcmap.js +31254 -32242
  5. package/examples/hex-colors.json +3 -3
  6. package/examples/m2.json +32904 -0
  7. package/examples/private/test.json +470 -1457
  8. package/examples/private/{mmr.json → wastewatermap.json} +86 -115
  9. package/index.html +36 -63
  10. package/package.json +7 -19
  11. package/src/CdcMap.tsx +56 -1552
  12. package/src/CdcMapComponent.tsx +608 -0
  13. package/src/_stories/CdcMap.Legend.Gradient.stories.tsx +10 -0
  14. package/src/_stories/CdcMap.Legend.stories.tsx +67 -0
  15. package/src/_stories/CdcMap.Table.stories.tsx +19 -0
  16. package/src/_stories/CdcMap.stories.tsx +12 -1
  17. package/src/_stories/UsaMap.NoData.stories.tsx +4 -4
  18. package/src/_stories/_mock/default-patterns.json +8 -5
  19. package/src/_stories/_mock/legend-bins.json +428 -0
  20. package/{examples/private/default-patterns.json → src/_stories/_mock/legends/legend-tests.json} +36 -131
  21. package/src/cdcMapComponent.styles.css +9 -0
  22. package/src/components/Annotation/Annotation.Draggable.tsx +27 -26
  23. package/src/components/Annotation/AnnotationDropdown.tsx +5 -6
  24. package/src/components/BubbleList.tsx +135 -49
  25. package/src/components/CityList.tsx +89 -87
  26. package/src/components/DataTable.tsx +8 -8
  27. package/src/components/EditorPanel/components/EditorPanel.tsx +823 -885
  28. package/src/components/EditorPanel/components/Error.tsx +9 -2
  29. package/src/components/EditorPanel/components/HexShapeSettings.tsx +127 -141
  30. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +55 -86
  31. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +89 -75
  32. package/src/components/EditorPanel/components/editorPanel.styles.css +95 -0
  33. package/src/components/Geo.tsx +9 -1
  34. package/src/components/GoogleMap/components/GoogleMap.tsx +1 -1
  35. package/src/components/Legend/components/Legend.tsx +92 -87
  36. package/src/components/Legend/components/LegendGroup/Legend.Group.tsx +128 -0
  37. package/src/components/Legend/components/LegendGroup/legend.group.css +27 -0
  38. package/src/components/Legend/components/LegendItem.Hex.tsx +4 -1
  39. package/src/components/Legend/components/index.scss +74 -17
  40. package/src/components/Modal.tsx +17 -7
  41. package/src/components/NavigationMenu.tsx +11 -9
  42. package/src/components/UsaMap/components/SingleState/SingleState.CountyOutput.tsx +12 -8
  43. package/src/components/UsaMap/components/SingleState/SingleState.StateOutput.tsx +4 -4
  44. package/src/components/UsaMap/components/TerritoriesSection.tsx +33 -10
  45. package/src/components/UsaMap/components/Territory/Territory.Hexagon.tsx +12 -10
  46. package/src/components/UsaMap/components/Territory/Territory.Rectangle.tsx +12 -14
  47. package/src/components/UsaMap/components/Territory/TerritoryShape.ts +2 -1
  48. package/src/components/UsaMap/components/UsaMap.County.tsx +138 -96
  49. package/src/components/UsaMap/components/UsaMap.Region.styles.css +72 -0
  50. package/src/components/UsaMap/components/UsaMap.Region.tsx +56 -103
  51. package/src/components/UsaMap/components/UsaMap.SingleState.styles.css +10 -0
  52. package/src/components/UsaMap/components/UsaMap.SingleState.tsx +65 -74
  53. package/src/components/UsaMap/components/UsaMap.State.tsx +112 -91
  54. package/src/components/UsaMap/helpers/map.ts +1 -1
  55. package/src/components/UsaMap/helpers/shapes.ts +20 -7
  56. package/src/components/WorldMap/WorldMap.tsx +64 -118
  57. package/src/components/WorldMap/worldMap.styles.css +28 -0
  58. package/src/components/ZoomControls.tsx +15 -13
  59. package/src/components/zoomControls.styles.css +53 -0
  60. package/src/context.ts +17 -9
  61. package/src/data/initial-state.js +5 -2
  62. package/src/helpers/addUIDs.ts +150 -0
  63. package/src/helpers/applyColorToLegend.ts +39 -64
  64. package/src/helpers/applyLegendToRow.ts +51 -0
  65. package/src/helpers/colorDistributions.ts +12 -0
  66. package/src/helpers/constants.ts +44 -0
  67. package/src/helpers/displayGeoName.ts +9 -2
  68. package/src/helpers/formatLegendLocation.ts +3 -2
  69. package/src/helpers/generateColorsArray.ts +2 -1
  70. package/src/helpers/generateRuntimeData.ts +78 -0
  71. package/src/helpers/generateRuntimeFilters.ts +63 -0
  72. package/src/helpers/generateRuntimeLegend.ts +566 -0
  73. package/src/helpers/generateRuntimeLegendHash.ts +16 -15
  74. package/src/helpers/getColumnNames.ts +19 -0
  75. package/src/helpers/getMapContainerClasses.ts +23 -0
  76. package/src/helpers/getStatePicked.ts +8 -0
  77. package/src/helpers/handleMapTabbing.ts +31 -0
  78. package/src/helpers/hashObj.ts +1 -1
  79. package/src/helpers/index.ts +22 -0
  80. package/src/helpers/navigationHandler.ts +3 -3
  81. package/src/helpers/resetLegendToggles.ts +13 -0
  82. package/src/helpers/setBinNumbers.ts +5 -0
  83. package/src/helpers/sortSpecialClassesLast.ts +7 -0
  84. package/src/helpers/tests/getColumnNames.test.ts +52 -0
  85. package/src/helpers/titleCase.ts +1 -1
  86. package/src/helpers/toggleLegendActive.ts +25 -0
  87. package/src/hooks/useApplyTooltipsToGeo.tsx +51 -0
  88. package/src/hooks/useColumnsRequiredChecker.ts +51 -0
  89. package/src/hooks/useGeoClickHandler.ts +45 -0
  90. package/src/hooks/useLegendSeparators.ts +26 -0
  91. package/src/hooks/useMapLayers.tsx +34 -60
  92. package/src/hooks/useModal.ts +22 -0
  93. package/src/hooks/useResizeObserver.ts +4 -5
  94. package/src/hooks/useStateZoom.tsx +52 -75
  95. package/src/hooks/useTooltip.ts +2 -3
  96. package/src/index.jsx +3 -9
  97. package/src/scss/editor-panel.scss +3 -99
  98. package/src/scss/main.scss +1 -19
  99. package/src/scss/map.scss +15 -220
  100. package/src/store/map.actions.ts +46 -0
  101. package/src/store/map.reducer.ts +96 -0
  102. package/src/types/Annotations.ts +24 -0
  103. package/src/types/MapConfig.ts +23 -3
  104. package/src/types/MapContext.ts +36 -35
  105. package/src/types/Modal.ts +1 -0
  106. package/src/types/RuntimeData.ts +3 -0
  107. package/examples/private/DEV-9644.json +0 -184
  108. package/examples/private/DEV-9989.json +0 -229
  109. package/examples/private/ardi.json +0 -180
  110. package/examples/private/colors 2.json +0 -416
  111. package/examples/private/colors.json +0 -416
  112. package/examples/private/colors.json.zip +0 -0
  113. package/examples/private/customColors.json +0 -45348
  114. package/examples/test.json +0 -183
  115. package/src/helpers/closeModal.ts +0 -9
  116. package/src/scss/btn.scss +0 -69
  117. package/src/scss/filters.scss +0 -27
  118. package/src/scss/variables.scss +0 -1
  119. /package/src/hooks/{useActiveElement.js → useActiveElement.ts} +0 -0
@@ -4,6 +4,7 @@
4
4
  .map-container.world aside.side {
5
5
  border-top: 0;
6
6
  }
7
+
7
8
  @include breakpointClass(md) {
8
9
  .map-container.world aside.side {
9
10
  border-top: var(--cool-gray-10) 1px solid;
@@ -19,10 +20,12 @@
19
20
  border-radius: 6px;
20
21
 
21
22
  @include breakpointClass(md) {
23
+
22
24
  &.bottom,
23
25
  &.top {
24
26
  border: var(--cool-gray-10) 1px solid;
25
27
  }
28
+
26
29
  &.side {
27
30
  z-index: 1;
28
31
  box-sizing: content-box;
@@ -40,7 +43,8 @@
40
43
  display: block;
41
44
  column-count: 2;
42
45
  column-fill: balance;
43
- & > li {
46
+
47
+ &>li {
44
48
  white-space: nowrap;
45
49
  }
46
50
  }
@@ -53,6 +57,7 @@
53
57
  flex-wrap: wrap;
54
58
  }
55
59
  }
60
+
56
61
  &.no-border {
57
62
  border: none;
58
63
  }
@@ -70,6 +75,10 @@
70
75
  .legend-container {
71
76
  position: relative;
72
77
 
78
+ .legend-container__li--disabled {
79
+ opacity: 0.4;
80
+ }
81
+
73
82
  .tspan {
74
83
  font-size: var(--legend-item-font-size) !important;
75
84
  }
@@ -79,14 +88,16 @@
79
88
  font-weight: var(--legend-title-font-weight);
80
89
  padding-bottom: 0;
81
90
  display: inline-block;
82
- color: black;
83
91
  }
92
+
84
93
  .legend-container__description {
85
94
  font-size: var(--legend-description-font-size);
86
95
  }
96
+
87
97
  .legend-container__reset-button {
88
98
  margin-top: 1em;
89
99
  }
100
+
90
101
  p {
91
102
  line-height: 1.4em;
92
103
  }
@@ -96,9 +107,11 @@
96
107
  row-gap: var(--space-between-legend-item-rows);
97
108
  column-gap: var(--space-between-legend-item-columns);
98
109
  }
99
- .legend-container__ul:not(.single-row) {
110
+
111
+
112
+ .legend-container__ul:not(.single-row, .legend-container__ul--single-column) {
100
113
  list-style: none;
101
- display: grid;
114
+ display: grid !important;
102
115
  grid-template-columns: 1fr;
103
116
 
104
117
  @include breakpoint(md) {
@@ -111,25 +124,51 @@
111
124
  }
112
125
 
113
126
  &.vertical-sorted {
114
- flex-direction: column;
127
+ // Remove the grid overrides - let the existing column rules handle this
128
+ display: block !important; // Switch from grid to block to enable columns
129
+
130
+ @include breakpoint(md) {
131
+ column-count: 2;
132
+ column-fill: balance;
133
+ }
134
+
135
+ // Add spacing between legend items in vertical sorted mode
136
+ .legend-container__li {
137
+ margin-bottom: var(--space-between-legend-item-rows);
138
+
139
+ &:last-child {
140
+ margin-bottom: 0; // Remove margin from last item
141
+ }
142
+ }
115
143
  }
116
144
 
117
145
  &:not(.vertical-sorted, .legend-container__ul--single-column, .single-row) {
118
146
  width: 100%;
119
147
  }
148
+
120
149
  .legend-container__li {
121
- flex-shrink: 0;
122
- display: inline-block;
150
+ display: flex;
151
+ align-items: center;
152
+ gap: 0.5em;
153
+ width: 100%;
123
154
  padding-right: 1em;
124
155
  vertical-align: middle;
125
156
  transition: 0.1s opacity;
126
- display: flex;
127
157
  cursor: pointer;
128
- white-space: wrap;
129
158
  flex-grow: 1;
159
+ white-space: nowrap; // Prevents label wrapping
160
+
161
+ .legend-item {
162
+ display: flex;
163
+ justify-content: center;
164
+ align-items: center;
165
+ flex-shrink: 0;
166
+ }
167
+
130
168
  &:last-child {
131
169
  margin-bottom: 0;
132
170
  }
171
+
133
172
  @include breakpoint(md) {
134
173
  white-space: nowrap;
135
174
  }
@@ -137,6 +176,7 @@
137
176
  &.legend-container__li--disabled {
138
177
  opacity: 0.4;
139
178
  }
179
+
140
180
  &.legend-container__li--not-disabled {
141
181
  outline: 1px solid #005ea2;
142
182
  outline-offset: 5px;
@@ -144,6 +184,7 @@
144
184
  }
145
185
  }
146
186
  }
187
+
147
188
  .legend-container__ul.single-row {
148
189
  width: 100%;
149
190
  cursor: pointer;
@@ -154,12 +195,13 @@
154
195
  justify-content: flex-start;
155
196
  flex-wrap: wrap;
156
197
 
157
- & > li {
198
+ &>li {
158
199
  white-space: wrap;
159
200
  display: flex;
160
201
  justify-content: center;
161
202
  align-items: center;
162
203
  vertical-align: middle;
204
+
163
205
  @include breakpoint(md) {
164
206
  white-space: nowrap;
165
207
  }
@@ -169,6 +211,7 @@
169
211
  }
170
212
  }
171
213
  }
214
+
172
215
  .legend-container__ul.patterns-only {
173
216
  margin-top: 10px;
174
217
  }
@@ -191,19 +234,24 @@
191
234
  @include breakpointClass(md) {
192
235
  width: 25%;
193
236
  min-width: 200px;
237
+
194
238
  .legend-section ul {
195
239
  flex-direction: column;
240
+
196
241
  li {
197
242
  width: 100%;
243
+
198
244
  &:nth-last-of-type(-n + 2) {
199
245
  padding-bottom: 1em;
200
246
  }
247
+
201
248
  &:last-child {
202
249
  padding-bottom: 0;
203
250
  }
204
251
  }
205
252
  }
206
253
  }
254
+
207
255
  li {
208
256
  width: 100%;
209
257
  }
@@ -213,6 +261,7 @@
213
261
  .legend-container ul:not(.single-row) {
214
262
  align-items: flex-start;
215
263
  justify-content: space-between;
264
+
216
265
  li {
217
266
  flex-grow: 1;
218
267
  padding-right: 0.5em;
@@ -222,24 +271,29 @@
222
271
 
223
272
  .filters-section {
224
273
  padding: 0 1em 1em;
274
+
225
275
  .heading-3 {
226
276
  font-weight: bold;
227
277
  margin-bottom: 0.5em;
228
278
  }
279
+
229
280
  form {
230
281
  margin-top: 0.5em;
231
282
  line-height: 2em;
232
283
  display: flex;
233
284
  align-items: flex-end;
234
- section + section {
285
+
286
+ section+section {
235
287
  margin-left: 0.75em;
236
288
  }
289
+
237
290
  select {
238
291
  display: block;
239
292
  font-size: 1em;
240
293
  }
241
294
  }
242
295
  }
296
+
243
297
  & .shape-container {
244
298
  &.single-row {
245
299
  display: flex;
@@ -248,26 +302,29 @@
248
302
  justify-content: flex-start;
249
303
  flex-wrap: wrap;
250
304
 
251
- & > div {
305
+ &>div {
252
306
  margin-right: 2em;
253
307
  }
254
- & > div:last-child {
308
+
309
+ &>div:last-child {
255
310
  margin-right: 0;
256
311
  }
257
312
  }
258
313
 
259
- & > div {
314
+ &>div {
260
315
  display: flex;
261
316
  flex-direction: row;
262
317
  }
263
- & div > svg {
318
+
319
+ & div>svg {
264
320
  width: 25px;
265
321
  height: 32px;
266
322
  }
267
- & div > p {
323
+
324
+ & div>p {
268
325
  white-space: nowrap;
269
326
  margin-top: 1px;
270
327
  }
271
328
  }
272
329
  }
273
- }
330
+ }
@@ -1,14 +1,15 @@
1
1
  import { useContext } from 'react'
2
- import LegendShape from '@cdc/core/components/LegendShape'
3
- import ConfigContext from '../context'
2
+ import ConfigContext, { MapDispatchContext } from '../context'
4
3
  import Icon from '@cdc/core/components/ui/Icon'
4
+ import useApplyTooltipsToGeo from '../hooks/useApplyTooltipsToGeo'
5
+ import { MapContext } from '../types/MapContext'
5
6
 
6
7
  const Modal = () => {
7
- const { applyTooltipsToGeo, applyLegendToRow, content, state, currentViewport: viewport } = useContext(ConfigContext)
8
- const { capitalizeLabels } = state.tooltips
8
+ const { content, config, currentViewport: viewport } = useContext<MapContext>(ConfigContext)
9
+ const { capitalizeLabels } = config.tooltips
10
+ const { applyTooltipsToGeo } = useApplyTooltipsToGeo()
9
11
  const tooltip = applyTooltipsToGeo(content.geoName, content.keyedData, 'jsx')
10
- const type = state.general.type
11
- const legendColors = applyLegendToRow(content.keyedData)
12
+ const dispatch = useContext(MapDispatchContext)
12
13
 
13
14
  return (
14
15
  <section
@@ -18,7 +19,16 @@ const Modal = () => {
18
19
  aria-hidden='true'
19
20
  >
20
21
  <div className='content'>{tooltip}</div>
21
- <Icon display='close' alt='Close Modal' size={20} color='#000' className='modal-close' />
22
+ <Icon
23
+ display='close'
24
+ alt='Close Modal'
25
+ size={20}
26
+ color='#000'
27
+ className='modal-close'
28
+ onClick={() => {
29
+ dispatch({ type: 'SET_MODAL', payload: null })
30
+ }}
31
+ />
22
32
  </section>
23
33
  )
24
34
  }
@@ -24,7 +24,7 @@ const NavigationMenu = ({ data, navigationHandler, options, columns, displayGeoN
24
24
  navGo = 'Ir'
25
25
  break
26
26
  default:
27
- navSelect = 'Select an Item'
27
+ navSelect = 'Select a Location'
28
28
  navGo = 'Go'
29
29
  }
30
30
 
@@ -55,15 +55,17 @@ const NavigationMenu = ({ data, navigationHandler, options, columns, displayGeoN
55
55
  <form onSubmit={handleSubmit} type='get'>
56
56
  <label htmlFor={mapTabbingID.replace('#', '')}>
57
57
  <div className='select-heading'>{navSelect}</div>
58
- <select value={activeGeo} id={mapTabbingID.replace('#', '')} onChange={e => setActiveGeo(e.target.value)}>
59
- {Object.keys(dropdownItems).map(key => (
60
- <option key={key} value={key}>
61
- {key}
62
- </option>
63
- ))}
64
- </select>
58
+ <div className='d-flex'>
59
+ <select value={activeGeo} id={mapTabbingID.replace('#', '')} onChange={e => setActiveGeo(e.target.value)}>
60
+ {Object.keys(dropdownItems).map(key => (
61
+ <option key={key} value={key}>
62
+ {key}
63
+ </option>
64
+ ))}
65
+ </select>
66
+ <input type='submit' value={navGo} className={`${options.headerColor} btn`} id='cdcnavmap-dropdown-go' />
67
+ </div>
65
68
  </label>
66
- <input type='submit' value={navGo} className={`${options.headerColor} btn`} id='cdcnavmap-dropdown-go' />
67
69
  </form>
68
70
  </section>
69
71
  )
@@ -1,7 +1,10 @@
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
+ import { getGeoFillColor, displayGeoName } from '../../../../helpers'
5
+ import useApplyTooltipsToGeo from '../../../../hooks/useApplyTooltipsToGeo'
6
+ import { applyLegendToRow } from '../../../../helpers/applyLegendToRow'
7
+ import useGeoClickHandler, { geoClickHandler } from '././../../../../hooks/useGeoClickHandler'
5
8
 
6
9
  interface CountyOutputProps {
7
10
  counties: any[]
@@ -12,10 +15,11 @@ interface CountyOutputProps {
12
15
  }
13
16
 
14
17
  const CountyOutput: React.FC<CountyOutputProps> = ({ path, counties, scale, geoStrokeColor, tooltipId }) => {
15
- const { applyTooltipsToGeo, applyLegendToRow, displayGeoName, state, data, geoClickHandler } =
16
- useContext<MapContext>(ConfigContext)
18
+ const { config, data, legendMemo, legendSpecialClassLastMemo, runtimeLegend } = useContext<MapContext>(ConfigContext)
19
+ const { applyTooltipsToGeo } = useApplyTooltipsToGeo()
20
+ const geoFillColor = getGeoFillColor(config)
21
+ const { geoClickHandler } = useGeoClickHandler()
17
22
 
18
- const geoFillColor = getGeoFillColor(state)
19
23
  return (
20
24
  <>
21
25
  {counties.map(county => {
@@ -31,7 +35,7 @@ const CountyOutput: React.FC<CountyOutputProps> = ({ path, counties, scale, geoS
31
35
 
32
36
  // Once we receive data for this geographic item, setup variables.
33
37
  if (geoData !== undefined) {
34
- legendColors = applyLegendToRow(geoData)
38
+ legendColors = applyLegendToRow(geoData, config, runtimeLegend, legendMemo, legendSpecialClassLastMemo)
35
39
  }
36
40
 
37
41
  const geoDisplayName = displayGeoName(geoKey)
@@ -55,8 +59,8 @@ const CountyOutput: React.FC<CountyOutputProps> = ({ path, counties, scale, geoS
55
59
 
56
60
  // When to add pointer cursor
57
61
  if (
58
- (state.columns.navigate && geoData[state.columns.navigate.name]) ||
59
- state.tooltips.appearanceType === 'hover'
62
+ (config.columns.navigate && geoData[config.columns.navigate.name]) ||
63
+ config.tooltips.appearanceType === 'hover'
60
64
  ) {
61
65
  styles.cursor = 'pointer'
62
66
  }
@@ -65,7 +69,7 @@ const CountyOutput: React.FC<CountyOutputProps> = ({ path, counties, scale, geoS
65
69
  <g
66
70
  key={`key--${county.id}`}
67
71
  className={`county county--${geoDisplayName.split(' ').join('')} county--${
68
- geoData[state.columns.geo.name]
72
+ geoData[config.columns.geo.name]
69
73
  }`}
70
74
  style={styles}
71
75
  onClick={() => geoClickHandler(geoDisplayName, geoData)}
@@ -10,14 +10,14 @@ type StateOutputProps = {
10
10
  }
11
11
 
12
12
  const StateOutput: React.FC<StateOutputProps> = ({ topoData, path, scale, stateToShow }: StateOutputProps) => {
13
- const { state } = useContext(ConfigContext)
13
+ const { config } = useContext(ConfigContext)
14
14
  if (!topoData?.objects?.states) return null
15
15
  let geo = topoData.objects.states.geometries.filter(s => {
16
- return s.properties.name === state.general.statePicked.stateName
16
+ return s.properties.name === config.general.statePicked.stateName
17
17
  })
18
18
 
19
- const geoStrokeColor = getGeoStrokeColor(state)
20
- const geoFillColor = getGeoFillColor(state)
19
+ const geoStrokeColor = getGeoStrokeColor(config)
20
+ const geoFillColor = getGeoFillColor(config)
21
21
 
22
22
  let stateLines = path(mesh(topoData, geo[0]))
23
23
 
@@ -1,4 +1,7 @@
1
- import React from 'react'
1
+ import React, { useContext } from 'react'
2
+
3
+ import ConfigContext from '../../../context'
4
+ import { isMobileTerritoryViewport } from '@cdc/core/helpers/viewports'
2
5
 
3
6
  type TerritoriesSectionProps = {
4
7
  territories: JSX.Element[]
@@ -9,6 +12,8 @@ type TerritoriesSectionProps = {
9
12
  }
10
13
 
11
14
  const TerritoriesSection: React.FC<TerritoriesSectionProps> = ({ territories, logo, config, territoriesData }) => {
15
+ const { currentViewport } = useContext<MapContext>(ConfigContext)
16
+
12
17
  // filter territioriesData into the two groups below
13
18
  const freelyAssociatedKeys = territoriesData.filter(territory => {
14
19
  return ['US-FM', 'US-MH', 'US-PW'].includes(territory)
@@ -33,6 +38,10 @@ const TerritoriesSection: React.FC<TerritoriesSectionProps> = ({ territories, lo
33
38
  return a.props.label.localeCompare(b.props.label)
34
39
  })
35
40
 
41
+ const isMobileViewport = isMobileTerritoryViewport(currentViewport)
42
+ const SVG_GAP = 9
43
+ const SVG_WIDTH = isMobileViewport ? 30 : 45
44
+
36
45
  return (
37
46
  territoriesData.length > 0 && (
38
47
  <>
@@ -43,18 +52,32 @@ const TerritoriesSection: React.FC<TerritoriesSectionProps> = ({ territories, lo
43
52
  <img src={logo} alt='' className='map-logo' style={{ maxWidth: '50px' }} />
44
53
  )}
45
54
  </div>
46
- <div>
55
+ <div className='d-flex flex-wrap' style={{ columnGap: '1.5rem' }}>
47
56
  {(usTerritories.length > 0 || config.general.territoriesAlwaysShow) && (
48
- <>
49
- <h5 className='territories-label'>U.S. Territories</h5>
50
- <span className='mt-1 mb-2 d-flex flex-wrap territories'>{usTerritories}</span>
51
- </>
57
+ <div>
58
+ <h5 className='territories-label'>U.S. territories</h5>
59
+ <span
60
+ className={`mt-2 ${isMobileViewport ? 'mb-3' : 'mb-4'} d-flex territories`}
61
+ style={{ minWidth: `${usTerritories.length * SVG_WIDTH + (usTerritories.length - 1) * SVG_GAP}px` }}
62
+ >
63
+ {usTerritories}
64
+ </span>
65
+ </div>
52
66
  )}
53
67
  {(freelyAssociatedStates.length > 0 || config.general.territoriesAlwaysShow) && (
54
- <>
55
- <h5 className='territories-label'>Freely Associated States</h5>
56
- <span className='mt-1 mb-2 d-flex flex-wrap territories'>{freelyAssociatedStates}</span>
57
- </>
68
+ <div>
69
+ <h5 className='territories-label'>Freely associated states</h5>
70
+ <span
71
+ className={`mt-2 ${isMobileViewport ? 'mb-3' : 'mb-4'} d-flex territories`}
72
+ style={{
73
+ minWidth: `${
74
+ freelyAssociatedStates.length * SVG_WIDTH + (freelyAssociatedStates.length - 1) * SVG_GAP
75
+ }px`
76
+ }}
77
+ >
78
+ {freelyAssociatedStates}
79
+ </span>
80
+ </div>
58
81
  )}
59
82
  </div>
60
83
  </div>
@@ -5,6 +5,7 @@ import { MapContext } from './../../../../types/MapContext'
5
5
  import HexIcon from '../HexIcon'
6
6
  import { Text } from '@visx/text'
7
7
  import { getContrastColor } from '@cdc/core/helpers/cove/accessibility'
8
+ import { APP_FONT_COLOR } from '@cdc/core/helpers/constants'
8
9
 
9
10
  const offsets = {
10
11
  'US-VT': [50, -8],
@@ -37,16 +38,16 @@ const TerritoryHexagon = ({
37
38
  handleShapeClick,
38
39
  label,
39
40
  stroke,
41
+ strokeColor,
40
42
  strokeWidth,
41
43
  territory,
42
44
  territoryData,
43
- text,
44
45
  textColor,
45
46
  ...props
46
47
  }) => {
47
- const { state } = useContext<MapContext>(ConfigContext)
48
+ const { config } = useContext<MapContext>(ConfigContext)
48
49
 
49
- const isHex = state.general.displayAsHex
50
+ const isHex = config.general.displayAsHex
50
51
 
51
52
  // Labels
52
53
  const hexagonLabel = (geo, bgColor = '#FFFFFF', projection) => {
@@ -61,7 +62,7 @@ const TerritoryHexagon = ({
61
62
 
62
63
  return (
63
64
  <>
64
- {state.hexMap.shapeGroups.map((group, groupIndex) => {
65
+ {config.hexMap.shapeGroups.map((group, groupIndex) => {
65
66
  return group.items.map((item, itemIndex) => {
66
67
  if (!geoData) return
67
68
  switch (item.operator) {
@@ -116,7 +117,7 @@ const TerritoryHexagon = ({
116
117
  }
117
118
 
118
119
  let x = 0,
119
- y = state.hexMap.type === 'shapes' ? -10 : 5
120
+ y = config.hexMap.type === 'shapes' ? -10 : 5
120
121
 
121
122
  // used to nudge/move some of the labels for better readability
122
123
  if (nudges[abbr] && false === isHex) {
@@ -125,14 +126,15 @@ const TerritoryHexagon = ({
125
126
  }
126
127
 
127
128
  if (undefined === offsets[abbr] || isHex) {
128
- let y = state.hexMap.type === 'shapes' ? '30%' : '50%'
129
+ let y = config.hexMap.type === 'shapes' ? '30%' : '50%'
129
130
  return (
130
131
  <>
131
132
  <Text
132
133
  fontSize={14}
133
134
  x={'50%'}
134
135
  y={y}
135
- style={{ fill: 'currentColor', stroke: 'initial', fontWeight: 400, opacity: 1, fillOpacity: 1 }}
136
+ style={{ fill: 'currentColor', stroke: strokeColor, fontWeight: 900, opacity: 1, fillOpacity: 1 }}
137
+ paintOrder='stroke'
136
138
  textAnchor='middle'
137
139
  verticalAnchor='middle'
138
140
  onClick={handleShapeClick}
@@ -141,7 +143,7 @@ const TerritoryHexagon = ({
141
143
  >
142
144
  {abbr.substring(3)}
143
145
  </Text>
144
- {state.general.displayAsHex && state.hexMap.type === 'shapes' && getArrowDirection(territoryData, geo, true)}
146
+ {config.general.displayAsHex && config.hexMap.type === 'shapes' && getArrowDirection(territoryData, geo, true)}
145
147
  </>
146
148
  )
147
149
  }
@@ -162,7 +164,7 @@ const TerritoryHexagon = ({
162
164
  x={4}
163
165
  strokeWidth='0'
164
166
  fontSize={13}
165
- style={{ fill: '#202020' }}
167
+ style={{ fill: APP_FONT_COLOR }}
166
168
  alignmentBaseline='middle'
167
169
  transform={`translate(${centroid[0] + dx}, ${centroid[1] + dy})`}
168
170
  onClick={handleShapeClick}
@@ -183,7 +185,7 @@ const TerritoryHexagon = ({
183
185
  strokeWidth={strokeWidth}
184
186
  points='22 0 44 12.702 44 38.105 22 50.807 0 38.105 0 12.702'
185
187
  />
186
- {state.general.displayAsHex && hexagonLabel(territoryData, stroke, false)}
188
+ {config.general.displayAsHex && hexagonLabel(territoryData, stroke, false)}
187
189
  </g>
188
190
  </svg>
189
191
  )
@@ -13,14 +13,14 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
13
13
  hasPattern,
14
14
  label,
15
15
  stroke,
16
+ strokeColor,
16
17
  strokeWidth,
17
18
  territory,
18
- text,
19
19
  textColor,
20
20
  backgroundColor,
21
21
  ...props
22
22
  }) => {
23
- const { state } = useContext<MapContext>(ConfigContext)
23
+ const { config } = useContext<MapContext>(ConfigContext)
24
24
  const { territoryData, ...otherProps } = props
25
25
  const rectanglePath =
26
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'
@@ -41,8 +41,8 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
41
41
  dominantBaseline='middle'
42
42
  x='50%'
43
43
  y='54%'
44
- fill={text}
45
- style={{ stroke: 'none' }}
44
+ fill={textColor}
45
+ stroke={strokeColor}
46
46
  className='territory-text'
47
47
  paintOrder='stroke'
48
48
  onClick={handleShapeClick}
@@ -52,7 +52,7 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
52
52
  {label}
53
53
  </text>
54
54
 
55
- {state.map.patterns.map((patternData, patternIndex) => {
55
+ {config.map.patterns.map((patternData, patternIndex) => {
56
56
  const patternColor = patternData.color || getContrastColor('#FFF', backgroundColor)
57
57
  const hasMatchingValues = patternData.dataValue === territoryData?.[patternData.dataKey]
58
58
 
@@ -67,6 +67,7 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
67
67
  height={patternSizes[patternData?.size] ?? 10}
68
68
  width={patternSizes[patternData?.size] ?? 10}
69
69
  fill={patternColor}
70
+ strokeWidth={0.25}
70
71
  complement
71
72
  />
72
73
  )}
@@ -76,6 +77,8 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
76
77
  height={patternSizes[patternData?.size] ?? 10}
77
78
  width={patternSizes[patternData?.size] ?? 10}
78
79
  fill={patternColor}
80
+ stroke={patternColor}
81
+ radius={0.5}
79
82
  complement
80
83
  />
81
84
  )}
@@ -85,7 +88,7 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
85
88
  height={patternSizes[patternData?.size] ?? 6}
86
89
  width={patternSizes[patternData?.size] ?? 6}
87
90
  stroke={patternColor}
88
- strokeWidth={1}
91
+ strokeWidth={0.75}
89
92
  orientation={['diagonalRightToLeft']}
90
93
  />
91
94
  )}
@@ -94,7 +97,6 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
94
97
  strokeWidth={strokeWidth}
95
98
  d={rectanglePath}
96
99
  fill={`url(#territory-${territory}-${patternData?.dataKey}--${patternIndex})`}
97
- color={patternData ? 'white' : textColor}
98
100
  className={[
99
101
  `territory-pattern-${patternData?.dataKey}`,
100
102
  `territory-pattern-${patternData?.dataKey}--${patternData.dataValue}`
@@ -105,14 +107,10 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
105
107
  dominantBaseline='middle'
106
108
  x='50%'
107
109
  y='54%'
108
- fill={text}
109
- style={{
110
- fill: patternData ? 'white' : 'black',
111
- stroke: patternData ? 'black' : textColor,
112
- strokeWidth: patternData ? 6 : 0
113
- }}
110
+ fill={textColor}
111
+ stroke={strokeColor}
114
112
  className='territory-text'
115
- paint-order='stroke'
113
+ paintOrder='stroke'
116
114
  onClick={handleShapeClick}
117
115
  data-tooltip-id={dataTooltipId}
118
116
  data-tooltip-html={dataTooltipHtml}
@@ -1,13 +1,14 @@
1
1
  export type TerritoryShape = {
2
2
  handleShapeClick: () => void
3
+ backgroundColor: string
3
4
  dataTooltipHtml: string
4
5
  dataTooltipId: string
5
6
  hasPattern: boolean
6
7
  label: string
7
8
  stroke: string
9
+ strokeColor: string
8
10
  strokeWidth: number
9
11
  territory: string
10
12
  territoryData: object
11
- text: string
12
13
  textColor: string
13
14
  }