@cdc/map 4.26.2 → 4.26.3

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 (65) hide show
  1. package/LICENSE +201 -0
  2. package/dist/cdcmap-vr9HZwRt.es.js +6 -0
  3. package/dist/cdcmap.js +26781 -24615
  4. package/examples/private/annotation-bug.json +642 -0
  5. package/package.json +3 -3
  6. package/src/CdcMap.tsx +3 -14
  7. package/src/CdcMapComponent.tsx +214 -159
  8. package/src/_stories/CdcMap.Defaults.stories.tsx +76 -0
  9. package/src/_stories/CdcMap.Editor.stories.tsx +187 -14
  10. package/src/_stories/CdcMap.stories.tsx +11 -1
  11. package/src/_stories/Map.HTMLInDataTable.stories.tsx +385 -0
  12. package/src/_stories/_mock/multi-state-show-unselected.json +82 -0
  13. package/src/cdcMapComponent.styles.css +2 -2
  14. package/src/components/Annotation/Annotation.Draggable.styles.css +4 -4
  15. package/src/components/Annotation/AnnotationDropdown.styles.css +1 -1
  16. package/src/components/Annotation/AnnotationList.styles.css +13 -13
  17. package/src/components/EditorPanel/components/EditorPanel.tsx +426 -58
  18. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings-style.css +1 -1
  19. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +5 -2
  20. package/src/components/EditorPanel/components/editorPanel.styles.css +34 -24
  21. package/src/components/Legend/components/Legend.tsx +9 -4
  22. package/src/components/Legend/components/LegendGroup/legend.group.css +5 -5
  23. package/src/components/Legend/components/index.scss +2 -3
  24. package/src/components/NavigationMenu.tsx +2 -1
  25. package/src/components/SmallMultiples/SmallMultiples.css +5 -5
  26. package/src/components/UsaMap/components/SingleState/SingleState.StateOutput.tsx +32 -17
  27. package/src/components/UsaMap/components/TerritoriesSection.tsx +3 -2
  28. package/src/components/UsaMap/components/Territory/Territory.Rectangle.tsx +13 -8
  29. package/src/components/UsaMap/components/UsaMap.County.tsx +410 -183
  30. package/src/components/UsaMap/components/UsaMap.Region.styles.css +1 -1
  31. package/src/components/UsaMap/components/UsaMap.SingleState.styles.css +2 -2
  32. package/src/components/UsaMap/components/UsaMap.State.tsx +13 -8
  33. package/src/components/WorldMap/WorldMap.tsx +10 -13
  34. package/src/components/WorldMap/data/world-topo-updated.json +1 -0
  35. package/src/components/WorldMap/data/world-topo.json +1 -1
  36. package/src/components/WorldMap/worldMap.styles.css +1 -1
  37. package/src/components/ZoomControls.tsx +49 -18
  38. package/src/components/zoomControls.styles.css +27 -11
  39. package/src/data/initial-state.js +14 -5
  40. package/src/data/legacy-defaults.ts +8 -0
  41. package/src/data/supported-geos.js +19 -0
  42. package/src/helpers/colors.ts +2 -1
  43. package/src/helpers/dataTableHelpers.ts +56 -0
  44. package/src/helpers/displayGeoName.ts +19 -11
  45. package/src/helpers/getMapContainerClasses.ts +8 -2
  46. package/src/helpers/getMatchingPatternForRow.ts +67 -0
  47. package/src/helpers/getPatternForRow.ts +11 -18
  48. package/src/helpers/tests/dataTableHelpers.test.ts +78 -0
  49. package/src/helpers/tests/displayGeoName.test.ts +17 -0
  50. package/src/helpers/tests/getMatchingPatternForRow.test.ts +150 -0
  51. package/src/helpers/tests/getPatternForRow.test.ts +140 -2
  52. package/src/helpers/urlDataHelpers.ts +7 -1
  53. package/src/hooks/useResizeObserver.ts +36 -22
  54. package/src/hooks/useTooltip.test.tsx +64 -0
  55. package/src/hooks/useTooltip.ts +28 -8
  56. package/src/scss/editor-panel.scss +1 -1
  57. package/src/scss/main.scss +140 -6
  58. package/src/scss/map.scss +9 -4
  59. package/src/store/map.actions.ts +2 -0
  60. package/src/store/map.reducer.ts +4 -0
  61. package/src/test/CdcMap.test.jsx +2 -2
  62. package/src/types/MapConfig.ts +22 -4
  63. package/src/types/MapContext.ts +3 -1
  64. package/dist/cdcmap-Cf9_fbQf.es.js +0 -6
  65. package/src/helpers/componentHelpers.ts +0 -8
@@ -1,6 +1,7 @@
1
- @import '@cdc/core/styles/v2/utils/breakpoints';
1
+ @import '@cdc/core/styles/utils/breakpoints';
2
2
  @import 'editor-panel';
3
- @import '@cdc/core/styles/accessibility';
3
+ @import '@cdc/core/styles/utils/accessibility';
4
+ @import '@cdc/core/styles/layout/wrapper-padding';
4
5
 
5
6
  .type-map--has-error {
6
7
  .waiting {
@@ -21,7 +22,7 @@
21
22
  }
22
23
 
23
24
  @include breakpointClass(md) {
24
- .map-container.modal-background::before {
25
+ .visualization-container.modal-background::before {
25
26
  border-bottom: var(--lightGray) 1px solid;
26
27
  margin-bottom: -1px;
27
28
  bottom: 1px;
@@ -37,6 +38,129 @@
37
38
  max-width: 100%;
38
39
  background-color: white;
39
40
 
41
+ .cove-visualization__title,
42
+ .cove-visualization__header {
43
+ margin-bottom: 0 !important;
44
+ }
45
+
46
+ &.theme-blue {
47
+ --map-theme-color: #005eaa;
48
+ --map-theme-bg: #d9ebf9;
49
+ }
50
+
51
+ &.theme-purple {
52
+ --map-theme-color: #712177;
53
+ --map-theme-bg: #f3e4f4;
54
+ }
55
+
56
+ &.theme-brown {
57
+ --map-theme-color: #705043;
58
+ --map-theme-bg: #f0e6e1;
59
+ }
60
+
61
+ &.theme-teal {
62
+ --map-theme-color: #00695c;
63
+ --map-theme-bg: #d9f2ef;
64
+ }
65
+
66
+ &.theme-pink {
67
+ --map-theme-color: #af4448;
68
+ --map-theme-bg: #fde7e8;
69
+ }
70
+
71
+ &.theme-orange {
72
+ --map-theme-color: #bb4d00;
73
+ --map-theme-bg: #fff0dd;
74
+ }
75
+
76
+ &.theme-slate {
77
+ --map-theme-color: #29434e;
78
+ --map-theme-bg: #e3e8ea;
79
+ }
80
+
81
+ &.theme-indigo {
82
+ --map-theme-color: #26418f;
83
+ --map-theme-bg: #e5eaf8;
84
+ }
85
+
86
+ &.theme-cyan {
87
+ --map-theme-color: #007b91;
88
+ --map-theme-bg: #dff3f7;
89
+ }
90
+
91
+ &.theme-green {
92
+ --map-theme-color: #4b830d;
93
+ --map-theme-bg: #e8f3dc;
94
+ }
95
+
96
+ &.theme-amber {
97
+ --map-theme-color: #fbab18;
98
+ --map-theme-bg: #fff6da;
99
+ }
100
+
101
+ .cove-visualization__body {
102
+ @include cove-visualization-body-padding;
103
+
104
+ &:not(.no-borders) {
105
+ border: 1px solid var(--lightGray);
106
+ }
107
+
108
+ &.component--has-border-color-theme:not(.no-borders) {
109
+ border-color: var(--map-theme-color, var(--lightGray));
110
+ }
111
+
112
+ &.component--has-accent {
113
+ border-left: 0.5rem solid var(--map-theme-color, var(--blue));
114
+ }
115
+
116
+ &.component--has-background:not(.component--hide-background-color) {
117
+ background-color: var(--map-theme-bg, var(--lightestGray));
118
+ }
119
+
120
+ &.component--hide-background-color {
121
+ background-color: transparent;
122
+ }
123
+
124
+ &.component--tp5-treatment {
125
+ background: transparent;
126
+
127
+ .cdc-callout {
128
+ box-shadow: 0 2px 4px rgb(159 159 159 / 10%);
129
+ border: 1px solid #dff2f6;
130
+ margin: 0;
131
+ padding: 1.25rem;
132
+ border-radius: 0.25rem;
133
+ position: relative;
134
+ background: transparent;
135
+
136
+ .cdc-callout__flag {
137
+ position: absolute;
138
+ top: -0.36rem;
139
+ right: 1.08rem;
140
+ width: 1.84rem;
141
+ height: auto;
142
+ }
143
+
144
+ .cove-visualization__title,
145
+ .cove-visualization__header {
146
+ background: transparent;
147
+ border: 0;
148
+ color: var(--cool-gray-90, #1f2937);
149
+ margin: 0 0 1rem;
150
+ padding: 0;
151
+ border-radius: 0;
152
+
153
+ h2 {
154
+ color: var(--cool-gray-90, #1f2937);
155
+ font-family: var(--fonts-nunito, var(--app-font-secondary));
156
+ font-size: 1.1rem;
157
+ font-weight: 700;
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
163
+
40
164
  header.hidden {
41
165
  display: none;
42
166
  }
@@ -45,17 +169,23 @@
45
169
  border: 0;
46
170
  }
47
171
 
48
- .map-container {
172
+ .visualization-container {
49
173
  display: flex;
50
174
  position: relative;
51
175
  flex-direction: column;
52
176
 
53
177
  &.bottom {
54
178
  flex-direction: column;
179
+ row-gap: var(--cove-visualization-section-gap, 1.5rem);
180
+
181
+ >.legends {
182
+ margin-top: var(--cove-visualization-section-gap, 1.5rem) !important;
183
+ }
55
184
  }
56
185
 
57
186
  &.top {
58
187
  flex-direction: column-reverse;
188
+ row-gap: var(--cove-visualization-section-gap, 1.5rem);
59
189
  }
60
190
 
61
191
  &.modal-background {
@@ -88,7 +218,6 @@
88
218
  /* Constrain the modal's height to 90% of the viewport */
89
219
  overflow-y: auto;
90
220
  /* Enable vertical scrolling if content overflows */
91
- font-size: 1rem;
92
221
  line-height: 1.4em;
93
222
  }
94
223
 
@@ -142,6 +271,11 @@
142
271
  }
143
272
  }
144
273
 
274
+ .visualization-container.legend-wrapped-bottom>.legends,
275
+ .legends.legend-wrapped-bottom {
276
+ margin-top: var(--cove-visualization-section-gap, 1.5rem) !important;
277
+ }
278
+
145
279
  p.subtext {
146
280
  em {
147
281
  font-style: italic;
@@ -213,4 +347,4 @@
213
347
  [tabIndex]:focus {
214
348
  outline-color: rgb(0, 95, 204);
215
349
  }
216
- }
350
+ }
package/src/scss/map.scss CHANGED
@@ -1,23 +1,23 @@
1
1
  @include breakpointClass(md) {
2
2
  // Data Specific
3
- .map-container.data {
3
+ .visualization-container.data {
4
4
  &.side {
5
5
  flex-direction: row;
6
6
  }
7
7
  }
8
- .map-container.map {
8
+ .visualization-container.map {
9
9
  &.side {
10
10
  flex-direction: row;
11
11
  }
12
12
  }
13
13
  // Bubble Specific
14
- .map-container.bubble {
14
+ .visualization-container.bubble {
15
15
  &.side {
16
16
  flex-direction: row;
17
17
  }
18
18
  }
19
19
 
20
- .map-container.us-geocode {
20
+ .visualization-container.us-geocode {
21
21
  &.side {
22
22
  flex-direction: row;
23
23
  }
@@ -114,3 +114,8 @@ canvas {
114
114
  pointer-events: none;
115
115
  display: none;
116
116
  }
117
+
118
+ .county-map-canvas {
119
+ touch-action: none;
120
+ cursor: move;
121
+ }
@@ -11,6 +11,7 @@ type SET_CONFIG = Action<'SET_CONFIG', MapConfig>
11
11
  type SET_COVE_LOADED_HAS_RAN = Action<'SET_COVE_LOADED_HAS_RAN', boolean>
12
12
  type SET_DISPLAY_PANEL = Action<'SET_DISPLAY_PANEL', boolean>
13
13
  type SET_FILTERED_COUNTRY_CODE = Action<'SET_FILTERED_COUNTRY_CODE', string>
14
+ type SET_FILTERED_STATE_CODE = Action<'SET_FILTERED_STATE_CODE', string>
14
15
  type SET_IS_DRAGGING_ANNOTATION = Action<'SET_IS_DRAGGING_ANNOTATION', boolean>
15
16
  type SET_LOADING = Action<'SET_LOADING', boolean>
16
17
  type SET_MODAL = Action<'SET_MODAL', Modal>
@@ -30,6 +31,7 @@ type MapActions =
30
31
  | SET_COVE_LOADED_HAS_RAN
31
32
  | SET_DISPLAY_PANEL
32
33
  | SET_FILTERED_COUNTRY_CODE
34
+ | SET_FILTERED_STATE_CODE
33
35
  | SET_IS_DRAGGING_ANNOTATION
34
36
  | SET_LOADING
35
37
  | SET_MODAL
@@ -24,6 +24,7 @@ export const getInitialState = (configObj = {}): MapState => {
24
24
  coveLoadedHasRan: false,
25
25
  displayPanel: false,
26
26
  filteredCountryCode: '',
27
+ filteredStateCode: '',
27
28
  isDraggingAnnotation: false,
28
29
  topoData: null,
29
30
  translate: [0, 0],
@@ -46,6 +47,7 @@ export type MapState = {
46
47
  coveLoadedHasRan: boolean
47
48
  displayPanel: boolean
48
49
  filteredCountryCode: string
50
+ filteredStateCode: string
49
51
  isDraggingAnnotation: boolean
50
52
  topoData: object | null
51
53
  translate: number[]
@@ -75,6 +77,8 @@ const reducer = (state: MapState, action: MapActions): MapState => {
75
77
  return { ...state, displayPanel: action.payload }
76
78
  case 'SET_FILTERED_COUNTRY_CODE':
77
79
  return { ...state, filteredCountryCode: action.payload }
80
+ case 'SET_FILTERED_STATE_CODE':
81
+ return { ...state, filteredStateCode: action.payload }
78
82
  case 'SET_IS_DRAGGING_ANNOTATION':
79
83
  return { ...state, isDraggingAnnotation: action.payload }
80
84
  case 'SET_TOPO_DATA':
@@ -1,11 +1,11 @@
1
- import path from 'path'
1
+ import path from 'node:path'
2
2
  import { testStandaloneBuild } from '@cdc/core/helpers/tests/testStandaloneBuild.ts'
3
3
  import { describe, it, expect } from 'vitest'
4
4
 
5
5
  describe('Map', () => {
6
6
  it('Can be built in isolation', async () => {
7
7
  const pkgDir = path.join(__dirname, '..')
8
- const result = testStandaloneBuild(pkgDir)
8
+ const result = await testStandaloneBuild(pkgDir)
9
9
  expect(result).toBe(true)
10
10
  }, 300000)
11
11
  })
@@ -10,6 +10,20 @@ import { MarkupConfig } from '@cdc/core/types/MarkupVariable'
10
10
  export type RuntimeFilters = VizFilter[] & { fromHash?: number }
11
11
 
12
12
  type MapVisualSettings = {
13
+ /** border - shows or hides component border */
14
+ border?: boolean
15
+ /** borderColorTheme - use themed border color */
16
+ borderColorTheme?: boolean
17
+ /** accent - use accent styling */
18
+ accent?: boolean
19
+ /** background - use themed background color */
20
+ background?: boolean
21
+ /** hideBackgroundColor - hide default background color */
22
+ hideBackgroundColor?: boolean
23
+ /** tp5Treatment - render the TP5 callout shell */
24
+ tp5Treatment?: boolean
25
+ /** tp5Background - enable the TP5 cyan background */
26
+ tp5Background?: boolean
13
27
  /** minBubbleSize - Minimum Circle Size when the map has a type of bubble */
14
28
  minBubbleSize: number
15
29
  /** maxBubbleSize - Maximum Circle Size when the map has a type of bubble */
@@ -29,9 +43,9 @@ type MapVisualSettings = {
29
43
  }
30
44
 
31
45
  export type PatternSelection = {
32
- // dropdown selection for getting the column used on a pattern
46
+ // column used to match patterns; empty string means match dataValue across all row columns
33
47
  dataKey: string
34
- // text field input to match values found in the column
48
+ // value to match (numeric-like values are compared numerically)
35
49
  dataValue: string
36
50
  // style of pattern to use
37
51
  pattern: 'lines' | 'circles' | 'waves'
@@ -51,7 +65,7 @@ type BaseColumnProperties = Pick<EditorColumnProperties, 'name'> &
51
65
  type SimpleColumnProperties = Pick<EditorColumnProperties, 'name'>
52
66
 
53
67
  // Specific column types for better semantics
54
- type GeoColumnProperties = BaseColumnProperties
68
+ type GeoColumnProperties = BaseColumnProperties & { displayColumn?: string }
55
69
  type LatitudeColumnProperties = SimpleColumnProperties
56
70
  type LongitudeColumnProperties = SimpleColumnProperties
57
71
  type NavigateColumnProperties = SimpleColumnProperties
@@ -156,6 +170,7 @@ export type MapConfig = Visualization & {
156
170
  fipsCode: string
157
171
  stateName: string
158
172
  }[]
173
+ hideUnselectedStates?: boolean
159
174
  countriesPicked?: {
160
175
  iso: string
161
176
  name: string
@@ -197,16 +212,19 @@ export type MapConfig = Visualization & {
197
212
  limitHeight: boolean
198
213
  height: string
199
214
  caption: string
215
+ download: boolean
216
+ downloadDataLabel?: string
217
+ downloadImageLabel?: string
200
218
  showDownloadUrl: boolean
201
219
  showFullGeoNameInCSV: boolean
202
220
  forceDisplay: boolean
203
- download: boolean
204
221
  indexLabel: string
205
222
  cellMinWidth: string
206
223
  }
207
224
  tooltips: {
208
225
  appearanceType: 'hover' | 'click'
209
226
  linkLabel: string
227
+ noDataLabel?: string
210
228
  opacity: number
211
229
  }
212
230
  runtime: {
@@ -11,8 +11,9 @@ export type MapContext = {
11
11
  content: { geoName: string; keyedData: Record<string, any> }
12
12
  dimensions: DimensionsType
13
13
  displayDataAsText: string | number
14
- displayGeoName: (key: string, convertFipsCodes: boolean) => string
14
+ displayGeoName: (key: string, displayOverride?: string) => string
15
15
  filteredCountryCode: string
16
+ filteredStateCode: string
16
17
  generateRuntimeData: (
17
18
  configObj: MapConfig,
18
19
  filters: VizFilter[],
@@ -36,6 +37,7 @@ export type MapContext = {
36
37
  runtimeLegend
37
38
  setParentConfig: Function
38
39
  setRuntimeData: Function
40
+ setFilteredStateCode: (stateCode: string) => void
39
41
  setSharedFilterValue: Function
40
42
  setConfig: (newState: MapConfig) => MapConfig
41
43
  config: MapConfig