@cdc/map 4.26.2 → 4.26.4

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 (118) hide show
  1. package/CONFIG.md +235 -0
  2. package/README.md +70 -24
  3. package/dist/cdcmap-CY9IcPSi.es.js +6 -0
  4. package/dist/cdcmap-DlpiY3fQ.es.js +4 -0
  5. package/dist/cdcmap.js +31260 -27946
  6. package/examples/{testing-layer-2.json → __data__/testing-layer-2.json} +1 -1
  7. package/examples/{testing-layer.json → __data__/testing-layer.json} +1 -1
  8. package/examples/county-hsa-toggle.json +51993 -0
  9. package/examples/custom-map-layers.json +2 -2
  10. package/examples/default-county.json +3 -3
  11. package/examples/minimal-example.json +69 -0
  12. package/examples/private/annotation-bug.json +642 -0
  13. package/examples/private/css-issue.json +314 -0
  14. package/examples/private/region-breaking.json +1639 -0
  15. package/examples/private/test1.json +27247 -0
  16. package/package.json +4 -4
  17. package/src/CdcMap.tsx +3 -14
  18. package/src/CdcMapComponent.tsx +302 -164
  19. package/src/_stories/CdcMap.Defaults.smoke.stories.tsx +76 -0
  20. package/src/_stories/CdcMap.Editor.ColumnsSectionTests.stories.tsx +601 -0
  21. package/src/_stories/CdcMap.Editor.DataTableSectionTests.stories.tsx +404 -0
  22. package/src/_stories/CdcMap.Editor.FiltersSectionTests.stories.tsx +229 -0
  23. package/src/_stories/CdcMap.Editor.GeneralSectionTests.stories.tsx +262 -0
  24. package/src/_stories/CdcMap.Editor.LegendSectionTests.stories.tsx +541 -0
  25. package/src/_stories/CdcMap.Editor.MultiCountryWorldMapTests.stories.tsx +359 -0
  26. package/src/_stories/CdcMap.Editor.PatternSettingsSectionTests.stories.tsx +516 -0
  27. package/src/_stories/CdcMap.Editor.SmallMultiplesSectionTests.stories.tsx +165 -0
  28. package/src/_stories/CdcMap.Editor.TextAnnotationsSectionTests.stories.tsx +145 -0
  29. package/src/_stories/CdcMap.Editor.TypeSectionTests.stories.tsx +312 -0
  30. package/src/_stories/CdcMap.Editor.VisualSectionTests.stories.tsx +359 -0
  31. package/src/_stories/CdcMap.Editor.ZoomControlsTests.stories.tsx +88 -0
  32. package/src/_stories/{CdcMap.stories.tsx → CdcMap.smoke.stories.tsx} +23 -1
  33. package/src/_stories/Map.HTMLInDataTable.stories.tsx +385 -0
  34. package/src/_stories/_mock/legends/legend-tests.json +3 -3
  35. package/src/_stories/_mock/multi-state-show-unselected.json +82 -0
  36. package/src/cdcMapComponent.styles.css +2 -2
  37. package/src/components/Annotation/Annotation.Draggable.styles.css +4 -4
  38. package/src/components/Annotation/AnnotationDropdown.styles.css +1 -1
  39. package/src/components/Annotation/AnnotationList.styles.css +13 -13
  40. package/src/components/Annotation/AnnotationList.tsx +1 -1
  41. package/src/components/EditorPanel/components/EditorPanel.tsx +905 -416
  42. package/src/components/EditorPanel/components/HexShapeSettings.tsx +1 -1
  43. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +112 -117
  44. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings-style.css +1 -1
  45. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +31 -15
  46. package/src/components/EditorPanel/components/editorPanel.styles.css +55 -25
  47. package/src/components/Legend/components/Legend.tsx +12 -7
  48. package/src/components/Legend/components/LegendGroup/legend.group.css +5 -5
  49. package/src/components/Legend/components/LegendItem.Hex.tsx +4 -2
  50. package/src/components/Legend/components/index.scss +2 -3
  51. package/src/components/NavigationMenu.tsx +2 -1
  52. package/src/components/SmallMultiples/SmallMultiples.css +5 -5
  53. package/src/components/SmallMultiples/SynchronizedTooltip.tsx +1 -1
  54. package/src/components/UsaMap/components/SingleState/SingleState.StateOutput.tsx +32 -17
  55. package/src/components/UsaMap/components/TerritoriesSection.tsx +3 -2
  56. package/src/components/UsaMap/components/Territory/Territory.Rectangle.tsx +13 -8
  57. package/src/components/UsaMap/components/UsaMap.County.tsx +629 -231
  58. package/src/components/UsaMap/components/UsaMap.Region.styles.css +1 -1
  59. package/src/components/UsaMap/components/UsaMap.SingleState.styles.css +2 -2
  60. package/src/components/UsaMap/components/UsaMap.State.tsx +14 -9
  61. package/src/components/UsaMap/data/cb_2019_us_county_20m.json +75817 -1
  62. package/src/components/UsaMap/data/hsa_fips_mapping.json +3144 -0
  63. package/src/components/WorldMap/WorldMap.tsx +10 -13
  64. package/src/components/WorldMap/data/world-topo-updated.json +1 -0
  65. package/src/components/WorldMap/data/world-topo.json +1 -1
  66. package/src/components/WorldMap/worldMap.styles.css +1 -1
  67. package/src/components/ZoomControls.tsx +49 -18
  68. package/src/components/zoomControls.styles.css +27 -11
  69. package/src/data/initial-state.js +15 -5
  70. package/src/data/legacy-defaults.ts +8 -0
  71. package/src/data/supported-counties.json +1 -1
  72. package/src/data/supported-geos.js +19 -0
  73. package/src/helpers/colors.ts +2 -1
  74. package/src/helpers/countyTerritories.ts +38 -0
  75. package/src/helpers/dataTableHelpers.ts +85 -0
  76. package/src/helpers/displayGeoName.ts +19 -11
  77. package/src/helpers/getMapContainerClasses.ts +8 -2
  78. package/src/helpers/getMatchingPatternForRow.ts +67 -0
  79. package/src/helpers/getPatternForRow.ts +11 -18
  80. package/src/helpers/tests/countyTerritories.test.ts +87 -0
  81. package/src/helpers/tests/dataTableHelpers.test.ts +78 -0
  82. package/src/helpers/tests/displayGeoName.test.ts +17 -0
  83. package/src/helpers/tests/getMatchingPatternForRow.test.ts +150 -0
  84. package/src/helpers/tests/getPatternForRow.test.ts +140 -2
  85. package/src/helpers/urlDataHelpers.ts +7 -1
  86. package/src/hooks/useApplyTooltipsToGeo.tsx +7 -4
  87. package/src/hooks/useMapLayers.tsx +1 -1
  88. package/src/hooks/useResizeObserver.ts +36 -22
  89. package/src/hooks/useTooltip.test.tsx +64 -0
  90. package/src/hooks/useTooltip.ts +46 -15
  91. package/src/scss/editor-panel.scss +1 -1
  92. package/src/scss/main.scss +140 -6
  93. package/src/scss/map.scss +9 -4
  94. package/src/store/map.actions.ts +5 -0
  95. package/src/store/map.reducer.ts +13 -0
  96. package/src/test/CdcMap.test.jsx +26 -2
  97. package/src/types/MapConfig.ts +28 -4
  98. package/src/types/MapContext.ts +5 -1
  99. package/topojson-updater/README.txt +1 -1
  100. package/dist/cdcmap-Cf9_fbQf.es.js +0 -6
  101. package/examples/__data__/city-state-data.json +0 -668
  102. package/examples/city-state.json +0 -434
  103. package/examples/default-world-data.json +0 -1450
  104. package/examples/new-cities.json +0 -656
  105. package/src/_stories/CdcMap.Editor.stories.tsx +0 -3475
  106. package/src/helpers/componentHelpers.ts +0 -8
  107. package/topojson-updater/package-lock.json +0 -223
  108. /package/src/_stories/{CdcMap.ColumnWrap.stories.tsx → CdcMap.ColumnWrap.smoke.stories.tsx} +0 -0
  109. /package/src/_stories/{CdcMap.DistrictOfColumbia.stories.tsx → CdcMap.DistrictOfColumbia.smoke.stories.tsx} +0 -0
  110. /package/src/_stories/{CdcMap.Filters.stories.tsx → CdcMap.Filters.smoke.stories.tsx} +0 -0
  111. /package/src/_stories/{CdcMap.Legend.Gradient.stories.tsx → CdcMap.Legend.Gradient.smoke.stories.tsx} +0 -0
  112. /package/src/_stories/{CdcMap.Legend.stories.tsx → CdcMap.Legend.smoke.stories.tsx} +0 -0
  113. /package/src/_stories/{CdcMap.Patterns.stories.tsx → CdcMap.Patterns.smoke.stories.tsx} +0 -0
  114. /package/src/_stories/{CdcMap.SmallMultiples.stories.tsx → CdcMap.SmallMultiples.smoke.stories.tsx} +0 -0
  115. /package/src/_stories/{CdcMap.Table.stories.tsx → CdcMap.Table.smoke.stories.tsx} +0 -0
  116. /package/src/_stories/{CdcMap.ZeroColor.stories.tsx → CdcMap.ZeroColor.smoke.stories.tsx} +0 -0
  117. /package/src/_stories/{GoogleMap.stories.tsx → GoogleMap.smoke.stories.tsx} +0 -0
  118. /package/src/_stories/{UsaMap.NoData.stories.tsx → UsaMap.NoData.smoke.stories.tsx} +0 -0
@@ -31,10 +31,12 @@ const LegendItemHex = props => {
31
31
  <aside id='legend' className={legendClasses.aside.join(' ')} role='region' aria-label='Legend' tabIndex={0}>
32
32
  <section className={legendClasses.section.join(' ')} aria-label='Map Legend'>
33
33
  {shapeGroup.legendTitle && (
34
- <h3 className={legendClasses.title.join(' ')}>{parse(shapeGroup.legendTitle)}</h3>
34
+ <h3 className={[...legendClasses.title, 'cove-prose'].join(' ')}>{parse(shapeGroup.legendTitle)}</h3>
35
35
  )}
36
36
  {shapeGroup.legendDescription && (
37
- <p className={legendClasses.description.join(' ')}>{parse(shapeGroup.legendDescription)}</p>
37
+ <p className={[...legendClasses.description, 'cove-prose'].join(' ')}>
38
+ {parse(shapeGroup.legendDescription)}
39
+ </p>
38
40
  )}
39
41
 
40
42
  <ul className={legendClasses.ul.join(' ')} aria-label='Legend items' style={{ listStyle: 'none' }}>
@@ -1,4 +1,4 @@
1
- @import '@cdc/core/styles/v2/utils/breakpoints';
1
+ @import '@cdc/core/styles/utils/breakpoints';
2
2
 
3
3
  .cdc-map-inner-container {
4
4
  .map-container.world aside.side {
@@ -30,8 +30,6 @@
30
30
  z-index: 1;
31
31
  box-sizing: content-box;
32
32
  max-width: 450px;
33
- margin-top: 2em;
34
- margin-bottom: 2em;
35
33
  align-self: flex-start;
36
34
  z-index: 4;
37
35
  right: 1em;
@@ -126,6 +124,7 @@
126
124
  &--pattern {
127
125
  cursor: default;
128
126
  }
127
+
129
128
  &:focus {
130
129
  outline: none;
131
130
  }
@@ -47,7 +47,8 @@ const NavigationMenu = ({ data, navigationHandler, options, columns, displayGeoN
47
47
  const processedDropdown = {}
48
48
 
49
49
  Object.keys(data).forEach(val => {
50
- const fullName = displayGeoName(val)
50
+ const displayOverride = data[val]?.[columns.geo?.displayColumn]
51
+ const fullName = displayGeoName(val, displayOverride)
51
52
 
52
53
  processedDropdown[fullName] = val
53
54
  })
@@ -1,13 +1,13 @@
1
1
  .small-multiples-container {
2
- width: 100%;
3
2
  display: flex;
4
3
  flex-direction: column;
4
+ width: 100%;
5
5
  }
6
6
 
7
7
  .small-multiples-grid {
8
8
  display: grid;
9
- width: 100%;
10
9
  flex: 1;
10
+ width: 100%;
11
11
  }
12
12
 
13
13
  .small-multiple-tile {
@@ -20,13 +20,13 @@
20
20
  }
21
21
 
22
22
  .tile-title {
23
- margin: 0;
24
23
  font-weight: 700;
25
- text-align: left;
26
24
  line-height: 1.3;
25
+ margin: 0;
26
+ text-align: left;
27
27
  }
28
28
 
29
29
  .tile-map {
30
- width: 100%;
31
30
  flex-shrink: 0;
31
+ width: 100%;
32
32
  }
@@ -88,7 +88,7 @@ const SynchronizedTooltip: React.FC<SynchronizedTooltipProps> = ({ tileTooltipId
88
88
  return (
89
89
  <div
90
90
  ref={tooltipRef}
91
- className='tooltip tooltip-test'
91
+ className='tooltip tooltip-test cove-prose'
92
92
  style={{
93
93
  position: 'fixed',
94
94
  left: `${tooltipState.x + 10}px`,
@@ -4,6 +4,8 @@ import ConfigContext from '../../../../context'
4
4
  import { getGeoStrokeColor } from '../../../../helpers/colors'
5
5
  import { getStatesPicked } from '../../../../helpers/getStatesPicked'
6
6
 
7
+ const GRAYED_OUT_COLOR = '#d3d3d3'
8
+
7
9
  type StateOutputProps = {
8
10
  topoData: Topology
9
11
  path: any
@@ -15,29 +17,42 @@ const StateOutput: React.FC<StateOutputProps> = ({ topoData, path, scale, runtim
15
17
  const { config } = useContext(ConfigContext)
16
18
  if (!topoData?.states) return null
17
19
 
18
- // Use filter-aware state selection instead of direct config access
19
20
  const statesPickedData = getStatesPicked(config, runtimeData)
20
21
  const stateNames = statesPickedData.map(sp => sp.stateName)
21
22
 
22
- const statesPicked = topoData.states.filter(s => {
23
- return stateNames.includes(s.properties.name)
24
- })
23
+ const showUnselected = config.general.hideUnselectedStates === false
24
+
25
+ const selectedStates = topoData.states.filter(s => stateNames.includes(s.properties.name))
26
+ const unselectedStates = showUnselected ? topoData.states.filter(s => !stateNames.includes(s.properties.name)) : []
25
27
 
26
28
  const geoStrokeColor = getGeoStrokeColor(config)
27
29
 
28
- const stateLines = statesPicked.map(s => path(s.geometry))
29
-
30
- return stateLines.map((line, index) => (
31
- <g
32
- key={`single-state-${index}`}
33
- className='single-state'
34
- style={{ fill: 'transparent', pointerEvents: 'none' }}
35
- stroke={geoStrokeColor}
36
- strokeWidth={2 / scale}
37
- >
38
- <path tabIndex={-1} className='state-path' d={line} />
39
- </g>
40
- ))
30
+ return (
31
+ <>
32
+ {unselectedStates.map((s, index) => (
33
+ <g
34
+ key={`unselected-state-${index}`}
35
+ className='single-state unselected'
36
+ style={{ fill: GRAYED_OUT_COLOR, opacity: 0.3, pointerEvents: 'none' }}
37
+ stroke={geoStrokeColor}
38
+ strokeWidth={1 / scale}
39
+ >
40
+ <path tabIndex={-1} className='state-path' d={path(s.geometry)} />
41
+ </g>
42
+ ))}
43
+ {selectedStates.map((s, index) => (
44
+ <g
45
+ key={`single-state-${index}`}
46
+ className='single-state'
47
+ style={{ fill: 'transparent', pointerEvents: 'none' }}
48
+ stroke={geoStrokeColor}
49
+ strokeWidth={2 / scale}
50
+ >
51
+ <path tabIndex={-1} className='state-path' d={path(s.geometry)} />
52
+ </g>
53
+ ))}
54
+ </>
55
+ )
41
56
  }
42
57
 
43
58
  export default StateOutput
@@ -39,6 +39,7 @@ const TerritoriesSection: React.FC<TerritoriesSectionProps> = ({ territories, lo
39
39
  })
40
40
 
41
41
  const isMobileViewport = isMobileTerritoryViewport(vizViewport)
42
+ const useCompactTerritorySpacing = isMobileViewport || currentViewport === 'sm' || currentViewport === 'md'
42
43
  const SVG_GAP = 9
43
44
  const SVG_WIDTH = isMobileViewport ? 30 : 45
44
45
 
@@ -59,7 +60,7 @@ const TerritoriesSection: React.FC<TerritoriesSectionProps> = ({ territories, lo
59
60
  U.S. territories
60
61
  </span>
61
62
  <span
62
- className={`${isMobileViewport ? 'mt-1 mb-3' : 'mt-2 mb-4'} d-flex territories`}
63
+ className={`${useCompactTerritorySpacing ? 'mt-1 mb-3' : 'mt-2 '} d-flex territories`}
63
64
  style={
64
65
  {
65
66
  minWidth: `${usTerritories.length * SVG_WIDTH + (usTerritories.length - 1) * SVG_GAP}px`,
@@ -78,7 +79,7 @@ const TerritoriesSection: React.FC<TerritoriesSectionProps> = ({ territories, lo
78
79
  Freely associated states
79
80
  </span>
80
81
  <span
81
- className={`${isMobileViewport ? 'mt-1 mb-3' : 'mt-2 mb-4'} d-flex territories`}
82
+ className={`${useCompactTerritorySpacing ? 'mt-1 mb-3' : 'mt-2'} d-flex territories`}
82
83
  style={
83
84
  {
84
85
  minWidth: `${
@@ -6,7 +6,7 @@ import { patternSizes } from '../../helpers/patternSizes'
6
6
  import { getContrastColor } from '@cdc/core/helpers/cove/accessibility'
7
7
  import { sanitizeToSvgId } from '@cdc/core/helpers/cove/string'
8
8
  import { type TerritoryShape } from './TerritoryShape'
9
- import { patternValuesMatch } from '../../../../helpers/patternMatching'
9
+ import { getMatchingPatternForRow } from '../../../../helpers/getMatchingPatternForRow'
10
10
 
11
11
  const TerritoryRectangle: React.FC<TerritoryShape> = ({
12
12
  dataTooltipId,
@@ -73,14 +73,19 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
73
73
  {label}
74
74
  </text>
75
75
 
76
- {config.map?.patterns?.map((patternData, patternIndex) => {
76
+ {(() => {
77
+ const matchedPattern = getMatchingPatternForRow(territoryData, config.map?.patterns)
78
+
79
+ if (!matchedPattern) {
80
+ return null
81
+ }
82
+
83
+ const { pattern: patternData, patternIndex, matchedDataKey } = matchedPattern
77
84
  const patternColor = patternData.color || getContrastColor('#FFF', backgroundColor)
78
- const hasMatchingValues = patternValuesMatch(patternData.dataValue, territoryData?.[patternData.dataKey])
79
85
  const sanitizedTerritory = sanitizeToSvgId(territory || label)
80
- const sanitizedDataKey = sanitizeToSvgId(patternData?.dataKey || '')
86
+ const sanitizedDataKey = sanitizeToSvgId(matchedDataKey)
81
87
  const patternId = `${mapId}--territory-${sanitizedTerritory}-${sanitizedDataKey}--${patternIndex}`
82
88
 
83
- if (!hasMatchingValues) return null
84
89
  if (!patternData.pattern) return null
85
90
 
86
91
  return (
@@ -123,8 +128,8 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
123
128
  fill={`url(#${patternId})`}
124
129
  style={{ pointerEvents: 'none' }}
125
130
  className={[
126
- `territory-pattern-${patternData?.dataKey}`,
127
- `territory-pattern-${patternData?.dataKey}--${patternData.dataValue}`
131
+ `territory-pattern-${matchedDataKey}`,
132
+ `territory-pattern-${matchedDataKey}--${patternData.dataValue}`
128
133
  ].join(' ')}
129
134
  />
130
135
  <text
@@ -144,7 +149,7 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
144
149
  </text>
145
150
  </>
146
151
  )
147
- })}
152
+ })()}
148
153
  </g>
149
154
  </svg>
150
155
  )