@cdc/map 4.26.3 → 4.26.5
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.
- package/CONFIG.md +268 -0
- package/README.md +74 -24
- package/dist/cdcmap-CY9IcPSi.es.js +6 -0
- package/dist/cdcmap-DlpiY3fQ.es.js +4 -0
- package/dist/cdcmap.js +29168 -27482
- package/examples/{testing-layer-2.json → __data__/testing-layer-2.json} +1 -1
- package/examples/{testing-layer.json → __data__/testing-layer.json} +1 -1
- package/examples/county-hsa-toggle.json +51993 -0
- package/examples/custom-map-layers.json +2 -2
- package/examples/default-county.json +6 -3
- package/examples/minimal-example.json +73 -0
- package/examples/private/annotation-bug.json +2 -2
- package/examples/private/css-issue.json +314 -0
- package/examples/private/region-breaking.json +1639 -0
- package/examples/private/test1.json +27247 -0
- package/package.json +4 -4
- package/src/CdcMapComponent.tsx +107 -14
- package/src/_stories/CdcMap.AltText.stories.tsx +122 -0
- package/src/_stories/CdcMap.Editor.ColumnsSectionTests.stories.tsx +600 -0
- package/src/_stories/CdcMap.Editor.DataTableSectionTests.stories.tsx +404 -0
- package/src/_stories/CdcMap.Editor.FiltersSectionTests.stories.tsx +229 -0
- package/src/_stories/CdcMap.Editor.GeneralSectionTests.stories.tsx +262 -0
- package/src/_stories/CdcMap.Editor.LegendSectionTests.stories.tsx +541 -0
- package/src/_stories/CdcMap.Editor.MultiCountryWorldMapTests.stories.tsx +359 -0
- package/src/_stories/CdcMap.Editor.PatternSettingsSectionTests.stories.tsx +516 -0
- package/src/_stories/CdcMap.Editor.SmallMultiplesSectionTests.stories.tsx +165 -0
- package/src/_stories/CdcMap.Editor.TextAnnotationsSectionTests.stories.tsx +145 -0
- package/src/_stories/CdcMap.Editor.TypeSectionTests.stories.tsx +312 -0
- package/src/_stories/CdcMap.Editor.VisualSectionTests.stories.tsx +359 -0
- package/src/_stories/CdcMap.Editor.ZoomControlsTests.stories.tsx +88 -0
- package/src/_stories/CdcMap.FocusVisibility.stories.tsx +87 -0
- package/src/_stories/CdcMap.HiddenMount.stories.tsx +69 -0
- package/src/_stories/CdcMap.ResetBehavior.stories.tsx +32 -0
- package/src/_stories/CdcMap.Zoom.stories.tsx +111 -0
- package/src/_stories/{CdcMap.stories.tsx → CdcMap.smoke.stories.tsx} +60 -0
- package/src/_stories/_mock/alt_text_metadata.json +65 -0
- package/src/_stories/_mock/legends/legend-tests.json +3 -3
- package/src/_stories/_mock/world-bubble-reset.json +138 -0
- package/src/_stories/_mock/world-data-zoom-filters.json +166 -0
- package/src/components/Annotation/AnnotationList.tsx +1 -1
- package/src/components/BubbleList.tsx +13 -0
- package/src/components/EditorPanel/components/EditorPanel.tsx +637 -382
- package/src/components/EditorPanel/components/HexShapeSettings.tsx +1 -1
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +112 -117
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +26 -13
- package/src/components/EditorPanel/components/editorPanel.styles.css +22 -2
- package/src/components/FilterControls.tsx +21 -0
- package/src/components/Legend/components/Legend.tsx +3 -3
- package/src/components/Legend/components/LegendItem.Hex.tsx +4 -2
- package/src/components/SmallMultiples/SmallMultiples.tsx +2 -2
- package/src/components/SmallMultiples/SynchronizedTooltip.tsx +1 -1
- package/src/components/UsaMap/components/UsaMap.County.tsx +309 -108
- package/src/components/UsaMap/components/UsaMap.Region.tsx +5 -2
- package/src/components/UsaMap/components/UsaMap.SingleState.tsx +33 -10
- package/src/components/UsaMap/components/UsaMap.State.tsx +10 -3
- package/src/components/UsaMap/data/cb_2019_us_county_20m.json +75817 -1
- package/src/components/UsaMap/data/hsa_fips_mapping.json +3144 -0
- package/src/components/WorldMap/WorldMap.tsx +37 -4
- package/src/components/WorldMap/data/world-topo.json +1 -1
- package/src/components/ZoomableGroup.tsx +23 -3
- package/src/components/filterControls.styles.css +6 -0
- package/src/data/initial-state.js +3 -0
- package/src/data/supported-counties.json +1 -1
- package/src/helpers/countyTerritories.ts +38 -0
- package/src/helpers/dataTableHelpers.ts +35 -6
- package/src/helpers/generateRuntimeFilters.ts +2 -1
- package/src/helpers/handleMapAriaLabels.ts +45 -30
- package/src/helpers/shouldAutoResetSingleStateZoom.ts +22 -0
- package/src/helpers/tests/countyTerritories.test.ts +87 -0
- package/src/helpers/tests/handleMapAriaLabels.test.ts +71 -0
- package/src/helpers/tests/shouldAutoResetSingleStateZoom.test.ts +71 -0
- package/src/hooks/useApplyTooltipsToGeo.tsx +7 -4
- package/src/hooks/useGeoClickHandler.ts +13 -1
- package/src/hooks/useMapLayers.tsx +1 -1
- package/src/hooks/useStateZoom.tsx +39 -20
- package/src/hooks/useTooltip.test.tsx +2 -16
- package/src/hooks/useTooltip.ts +18 -7
- package/src/index.jsx +5 -2
- package/src/scss/main.scss +6 -21
- package/src/scss/map.scss +20 -0
- package/src/store/map.actions.ts +5 -2
- package/src/store/map.reducer.ts +12 -3
- package/src/test/CdcMap.test.jsx +24 -0
- package/src/types/MapConfig.ts +11 -0
- package/src/types/MapContext.ts +6 -1
- package/topojson-updater/README.txt +1 -1
- package/dist/cdcmap-vr9HZwRt.es.js +0 -6
- package/examples/__data__/city-state-data.json +0 -668
- package/examples/city-state.json +0 -434
- package/examples/default-world-data.json +0 -1450
- package/examples/new-cities.json +0 -656
- package/src/_stories/CdcMap.Editor.stories.tsx +0 -3648
- package/topojson-updater/package-lock.json +0 -223
- /package/src/_stories/{CdcMap.ColumnWrap.stories.tsx → CdcMap.ColumnWrap.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.Defaults.stories.tsx → CdcMap.Defaults.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.DistrictOfColumbia.stories.tsx → CdcMap.DistrictOfColumbia.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.Filters.stories.tsx → CdcMap.Filters.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.Legend.Gradient.stories.tsx → CdcMap.Legend.Gradient.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.Legend.stories.tsx → CdcMap.Legend.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.Patterns.stories.tsx → CdcMap.Patterns.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.SmallMultiples.stories.tsx → CdcMap.SmallMultiples.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.Table.stories.tsx → CdcMap.Table.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.ZeroColor.stories.tsx → CdcMap.ZeroColor.smoke.stories.tsx} +0 -0
- /package/src/_stories/{GoogleMap.stories.tsx → GoogleMap.smoke.stories.tsx} +0 -0
- /package/src/_stories/{UsaMap.NoData.stories.tsx → UsaMap.NoData.smoke.stories.tsx} +0 -0
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdc/map",
|
|
3
|
-
"version": "4.26.
|
|
3
|
+
"version": "4.26.5",
|
|
4
4
|
"description": "React component for visualizing tabular data on a map of the United States or the world.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"bugs": "https://github.com/CDCgov/cdc-open-viz/issues",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@cdc/core": "^4.26.
|
|
8
|
+
"@cdc/core": "^4.26.5",
|
|
9
9
|
"@googlemaps/markerclusterer": "^2.5.3",
|
|
10
10
|
"@hello-pangea/dnd": "^16.2.0",
|
|
11
11
|
"@react-google-maps/api": "^2.20.8",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"d3-scale": "^4.0.2",
|
|
25
25
|
"d3-selection": "^3.0.0",
|
|
26
26
|
"d3-zoom": "^3.0.0",
|
|
27
|
-
"dompurify": "^3.
|
|
27
|
+
"dompurify": "^3.4.0",
|
|
28
28
|
"html-react-parser": "^5.2.3",
|
|
29
29
|
"leaflet": "^1.9.4",
|
|
30
30
|
"lodash": "^4.17.23",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"vite-plugin-svgr": "^4.2.0",
|
|
43
43
|
"whatwg-fetch": "^3.6.20"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "61c025165d96b45a6002c34582c5a622a9d865a9",
|
|
46
46
|
"main": "dist/cdcmap",
|
|
47
47
|
"moduleName": "CdcMap",
|
|
48
48
|
"peerDependencies": {
|
package/src/CdcMapComponent.tsx
CHANGED
|
@@ -14,6 +14,7 @@ import SkipTo from '@cdc/core/components/elements/SkipTo'
|
|
|
14
14
|
import Title from '@cdc/core/components/ui/Title'
|
|
15
15
|
import Waiting from '@cdc/core/components/Waiting'
|
|
16
16
|
import FootnotesStandAlone from '@cdc/core/components/Footnotes/FootnotesStandAlone'
|
|
17
|
+
import { supportedStatesFipsCodes, supportedCounties } from './data/supported-geos'
|
|
17
18
|
|
|
18
19
|
// types
|
|
19
20
|
import { type MapConfig } from './types/MapConfig'
|
|
@@ -24,10 +25,17 @@ import './scss/main.scss'
|
|
|
24
25
|
import './cdcMapComponent.styles.css'
|
|
25
26
|
|
|
26
27
|
// Core Helpers
|
|
27
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
getQueryStringFilterValue,
|
|
30
|
+
isFilterHiddenByQuery,
|
|
31
|
+
removeQueryParam,
|
|
32
|
+
updateQueryParam,
|
|
33
|
+
updateQueryParams
|
|
34
|
+
} from '@cdc/core/helpers/queryStringUtils'
|
|
28
35
|
import { generateRuntimeFilters } from './helpers/generateRuntimeFilters'
|
|
29
36
|
import { type MapReducerType, MapState } from './store/map.reducer'
|
|
30
37
|
import { addValuesToFilters } from '@cdc/core/helpers/addValuesToFilters'
|
|
38
|
+
import { hasVisibleVizFilters } from '@cdc/core/helpers/filterVisibility'
|
|
31
39
|
import { processMarkupVariables } from '@cdc/core/helpers/markupProcessor'
|
|
32
40
|
|
|
33
41
|
// Map Helpers
|
|
@@ -47,7 +55,6 @@ import { generateRuntimeLegend } from './helpers/generateRuntimeLegend'
|
|
|
47
55
|
import generateRuntimeData from './helpers/generateRuntimeData'
|
|
48
56
|
import { reloadURLData } from './helpers/urlDataHelpers'
|
|
49
57
|
import { observeMapSvgLoaded } from './helpers/mapObserverHelpers'
|
|
50
|
-
import { buildBodyWrapClassNames, buildSectionClassNames } from './helpers/componentHelpers'
|
|
51
58
|
import { shouldShowDataTable, filterCountyTableRuntimeDataByStateCode } from './helpers/dataTableHelpers'
|
|
52
59
|
import { prepareSmallMultiplesDataTable } from './helpers/smallMultiplesHelpers'
|
|
53
60
|
|
|
@@ -66,7 +73,6 @@ import useLegendMemo from './hooks/useLegendMemo'
|
|
|
66
73
|
import { LegendMemoProvider } from './context/LegendMemoContext'
|
|
67
74
|
import { VizFilter } from '@cdc/core/types/VizFilter'
|
|
68
75
|
import { getInitialState, mapReducer } from './store/map.reducer'
|
|
69
|
-
import { RuntimeData } from './types/RuntimeData'
|
|
70
76
|
import defaults from './data/initial-state'
|
|
71
77
|
import { LEGACY_MAP_DEFAULTS } from './data/legacy-defaults'
|
|
72
78
|
import { backfillDefaults } from '@cdc/core/helpers/backfillDefaults'
|
|
@@ -79,6 +85,7 @@ import { publishAnalyticsEvent } from '@cdc/core/helpers/metrics/helpers'
|
|
|
79
85
|
import { getVizTitle, getVizSubType } from '@cdc/core/helpers/metrics/utils'
|
|
80
86
|
import { ENABLE_CHART_MAP_TP5_TREATMENT } from '@cdc/core/helpers/constants'
|
|
81
87
|
import CalloutFlag from '@cdc/core/assets/callout-flag.svg?url'
|
|
88
|
+
import { useQueryParamsListener } from '@cdc/core/hooks/useQueryParamsListener'
|
|
82
89
|
|
|
83
90
|
type CdcMapComponent = {
|
|
84
91
|
config: MapConfig
|
|
@@ -88,6 +95,8 @@ type CdcMapComponent = {
|
|
|
88
95
|
logo?: string
|
|
89
96
|
navigationHandler: Function
|
|
90
97
|
setSharedFilter: Function
|
|
98
|
+
clearSharedFilter?: (key: string) => void
|
|
99
|
+
hasActiveSharedFilter?: boolean
|
|
91
100
|
setSharedFilterValue: Function
|
|
92
101
|
setConfig?: Function
|
|
93
102
|
loadConfig?: Function
|
|
@@ -102,6 +111,8 @@ const CdcMapComponent: React.FC<CdcMapComponent> = ({
|
|
|
102
111
|
isEditor = false,
|
|
103
112
|
logo = '',
|
|
104
113
|
setSharedFilter,
|
|
114
|
+
clearSharedFilter,
|
|
115
|
+
hasActiveSharedFilter = false,
|
|
105
116
|
setSharedFilterValue,
|
|
106
117
|
link,
|
|
107
118
|
setConfig: setParentConfig,
|
|
@@ -124,6 +135,7 @@ const CdcMapComponent: React.FC<CdcMapComponent> = ({
|
|
|
124
135
|
modal,
|
|
125
136
|
accessibleStatus,
|
|
126
137
|
filteredCountryCode,
|
|
138
|
+
filteredCountyCode,
|
|
127
139
|
filteredStateCode,
|
|
128
140
|
position,
|
|
129
141
|
scale,
|
|
@@ -165,6 +177,22 @@ const CdcMapComponent: React.FC<CdcMapComponent> = ({
|
|
|
165
177
|
}
|
|
166
178
|
}
|
|
167
179
|
|
|
180
|
+
const setFilters = (filters: VizFilter[]) => {
|
|
181
|
+
const filterCopy = _.cloneDeep(filters)
|
|
182
|
+
if (config.general.showStateDropdown) {
|
|
183
|
+
const [stateFilter, countyFilter] = filterCopy.filter(
|
|
184
|
+
f => f.staticFilter && ['state', 'county'].includes(f.columnName)
|
|
185
|
+
)
|
|
186
|
+
const stateCode = (stateFilter?.active as string) || ''
|
|
187
|
+
const countyCode = (countyFilter?.active as string) || ''
|
|
188
|
+
|
|
189
|
+
setFilteredStateCountyCode(stateCode, countyCode)
|
|
190
|
+
if (countyFilter) filterCopy.pop() // remove county filter
|
|
191
|
+
filterCopy.pop() // remove state filter
|
|
192
|
+
}
|
|
193
|
+
_setRuntimeData(filterCopy)
|
|
194
|
+
}
|
|
195
|
+
|
|
168
196
|
// Refs
|
|
169
197
|
const innerContainerRef = useRef<HTMLDivElement | null>(null)
|
|
170
198
|
const legendRef = useRef(null)
|
|
@@ -360,6 +388,32 @@ const CdcMapComponent: React.FC<CdcMapComponent> = ({
|
|
|
360
388
|
/>
|
|
361
389
|
)
|
|
362
390
|
|
|
391
|
+
const STATE_CODE = 'state-code'
|
|
392
|
+
const COUNTY_CODE = 'county-code'
|
|
393
|
+
const setFilteredStateCountyCode = (stateCode: string, countyCode?: string) => {
|
|
394
|
+
const stateCodePattern = /^\d\d$/
|
|
395
|
+
const normalizedStateCode = stateCodePattern.test(stateCode) ? stateCode : ''
|
|
396
|
+
let _countyCode = ''
|
|
397
|
+
if (countyCode) {
|
|
398
|
+
const countyCodePattern = /^\d{5}$/
|
|
399
|
+
_countyCode = countyCodePattern.test(countyCode) ? countyCode : ''
|
|
400
|
+
}
|
|
401
|
+
if (!normalizedStateCode) {
|
|
402
|
+
updateQueryParams({ [STATE_CODE]: '', [COUNTY_CODE]: '' })
|
|
403
|
+
} else {
|
|
404
|
+
updateQueryParams({ [STATE_CODE]: normalizedStateCode, [COUNTY_CODE]: _countyCode })
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const setFilteredStateCodeFromQuery = ({
|
|
409
|
+
[STATE_CODE]: stateCode,
|
|
410
|
+
[COUNTY_CODE]: countyCode
|
|
411
|
+
}: Record<string, string>) => {
|
|
412
|
+
dispatch({ type: 'SET_FILTERED_STATE_COUNTY_CODE', payload: { stateCode, countyCode } })
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
useQueryParamsListener([STATE_CODE, COUNTY_CODE], setFilteredStateCodeFromQuery)
|
|
416
|
+
|
|
363
417
|
const mapProps = {
|
|
364
418
|
setParentConfig,
|
|
365
419
|
container,
|
|
@@ -369,6 +423,7 @@ const CdcMapComponent: React.FC<CdcMapComponent> = ({
|
|
|
369
423
|
customNavigationHandler,
|
|
370
424
|
dimensions,
|
|
371
425
|
filteredCountryCode,
|
|
426
|
+
filteredCountyCode,
|
|
372
427
|
filteredStateCode,
|
|
373
428
|
isDashboard,
|
|
374
429
|
isEditor,
|
|
@@ -381,8 +436,10 @@ const CdcMapComponent: React.FC<CdcMapComponent> = ({
|
|
|
381
436
|
runtimeLegend,
|
|
382
437
|
scale,
|
|
383
438
|
setConfig,
|
|
384
|
-
|
|
439
|
+
setFilteredStateCountyCode,
|
|
385
440
|
setSharedFilter,
|
|
441
|
+
clearSharedFilter,
|
|
442
|
+
hasActiveSharedFilter,
|
|
386
443
|
setSharedFilterValue,
|
|
387
444
|
config,
|
|
388
445
|
statesToShow,
|
|
@@ -448,6 +505,42 @@ const CdcMapComponent: React.FC<CdcMapComponent> = ({
|
|
|
448
505
|
</a>
|
|
449
506
|
)
|
|
450
507
|
|
|
508
|
+
const applyStateFilter = (config: MapConfig): MapConfig => {
|
|
509
|
+
if (config.general.showStateDropdown && config.general.geoType === 'us-county') {
|
|
510
|
+
const stateFilter: VizFilter = {
|
|
511
|
+
columnName: 'state',
|
|
512
|
+
label: 'Select Location',
|
|
513
|
+
filterStyle: 'dropdown',
|
|
514
|
+
labels: supportedStatesFipsCodes,
|
|
515
|
+
values: Object.keys(supportedStatesFipsCodes),
|
|
516
|
+
resetLabel: 'United States',
|
|
517
|
+
staticFilter: true,
|
|
518
|
+
active: filteredStateCode
|
|
519
|
+
}
|
|
520
|
+
let countyFilter: VizFilter | undefined
|
|
521
|
+
if (filteredStateCode) {
|
|
522
|
+
const counties = Object.keys(supportedCounties).filter(countyCode => countyCode.startsWith(filteredStateCode))
|
|
523
|
+
countyFilter = {
|
|
524
|
+
columnName: 'county',
|
|
525
|
+
label: 'Select County',
|
|
526
|
+
filterStyle: 'dropdown',
|
|
527
|
+
labels: supportedCounties,
|
|
528
|
+
values: counties,
|
|
529
|
+
resetLabel: 'All Counties',
|
|
530
|
+
staticFilter: true,
|
|
531
|
+
active: filteredCountyCode
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
return {
|
|
535
|
+
...config,
|
|
536
|
+
filters: [...(config.filters || []), stateFilter, ...(countyFilter ? [countyFilter] : [])]
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
return config
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
const filterConfig = applyStateFilter(config)
|
|
543
|
+
|
|
451
544
|
return (
|
|
452
545
|
<LegendMemoProvider legendMemo={legendMemo} legendSpecialClassLastMemo={legendSpecialClassLastMemo}>
|
|
453
546
|
<ConfigContext.Provider value={mapProps}>
|
|
@@ -472,7 +565,7 @@ const CdcMapComponent: React.FC<CdcMapComponent> = ({
|
|
|
472
565
|
]
|
|
473
566
|
.filter(Boolean)
|
|
474
567
|
.join(' ')}
|
|
475
|
-
innerProps={{
|
|
568
|
+
innerProps={{ ref: innerContainerRef }}
|
|
476
569
|
bodyWrapClassName={isTp5Treatment ? 'cdc-callout d-flex flex-column' : ''}
|
|
477
570
|
bodyClassName={[
|
|
478
571
|
!config.visual?.border || isTp5Treatment ? 'no-borders' : '',
|
|
@@ -486,19 +579,18 @@ const CdcMapComponent: React.FC<CdcMapComponent> = ({
|
|
|
486
579
|
.filter(Boolean)
|
|
487
580
|
.join(' ')}
|
|
488
581
|
filters={
|
|
489
|
-
|
|
582
|
+
hasVisibleVizFilters(filterConfig.filters) ? (
|
|
490
583
|
<Filters
|
|
491
|
-
config={
|
|
492
|
-
|
|
493
|
-
filteredData={runtimeFilters}
|
|
494
|
-
setFilters={_setRuntimeData}
|
|
584
|
+
config={filterConfig}
|
|
585
|
+
setFilters={setFilters}
|
|
495
586
|
dimensions={dimensions}
|
|
496
|
-
standaloneMap={!config}
|
|
497
587
|
interactionLabel={interactionLabel}
|
|
498
588
|
/>
|
|
499
589
|
) : undefined
|
|
500
590
|
}
|
|
501
|
-
bodySubtext={
|
|
591
|
+
bodySubtext={
|
|
592
|
+
processedSubtext.length > 0 ? <p className='subtext cove-prose'>{parse(processedSubtext)}</p> : null
|
|
593
|
+
}
|
|
502
594
|
bodyFooter={
|
|
503
595
|
<>
|
|
504
596
|
{isDashboard && config.table?.forceDisplay && config.table.showDataTableLink
|
|
@@ -569,13 +661,13 @@ const CdcMapComponent: React.FC<CdcMapComponent> = ({
|
|
|
569
661
|
{config.annotations?.length > 0 && <Annotation.Dropdown />}
|
|
570
662
|
|
|
571
663
|
{processedFootnotes && (
|
|
572
|
-
<section className='footnotes pt-2 mt-4'>{parse(processedFootnotes)}</section>
|
|
664
|
+
<section className='footnotes cove-prose pt-2 mt-4'>{parse(processedFootnotes)}</section>
|
|
573
665
|
)}
|
|
574
666
|
</>
|
|
575
667
|
}
|
|
576
668
|
header={isTp5Treatment ? null : mapTitle}
|
|
577
669
|
messageIsIntroText={!!processedIntroText}
|
|
578
|
-
message={processedIntroText ? parse(processedIntroText) : null}
|
|
670
|
+
message={processedIntroText ? <div className='cove-prose'>{parse(processedIntroText)}</div> : null}
|
|
579
671
|
>
|
|
580
672
|
<>
|
|
581
673
|
{isTp5Treatment && <img src={CalloutFlag} alt='' className='cdc-callout__flag' aria-hidden='true' />}
|
|
@@ -663,6 +755,7 @@ const CdcMapComponent: React.FC<CdcMapComponent> = ({
|
|
|
663
755
|
enableMarkupVariables={config.enableMarkupVariables}
|
|
664
756
|
data={config.data}
|
|
665
757
|
dataMetadata={config.dataMetadata}
|
|
758
|
+
footerClassName='cove-visualization__footnotes'
|
|
666
759
|
/>
|
|
667
760
|
</VisualizationContainer>
|
|
668
761
|
</MapDispatchContext.Provider>
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
+
import { within, expect } from 'storybook/test'
|
|
3
|
+
import CdcMap from '../CdcMap'
|
|
4
|
+
import { assertVisualizationRendered, waitForPresence, waitForEditor, openAccordion } from '@cdc/core/helpers/testing'
|
|
5
|
+
import altTextConfig from './_mock/alt_text_metadata.json'
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof CdcMap> = {
|
|
8
|
+
title: 'Components/Templates/Map/Accessible Alt Text',
|
|
9
|
+
component: CdcMap,
|
|
10
|
+
parameters: {
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component:
|
|
14
|
+
'Demonstrates SVG accessibility for maps: auto-generated aria-label with optional configurable description concatenated into the label for reliable screen reader support.'
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default meta
|
|
21
|
+
type Story = StoryObj<typeof CdcMap>
|
|
22
|
+
|
|
23
|
+
export const MetadataDescription: Story = {
|
|
24
|
+
args: {
|
|
25
|
+
config: {
|
|
26
|
+
...altTextConfig,
|
|
27
|
+
altText: { type: 'metadata', metadataKey: 'altDescription' }
|
|
28
|
+
},
|
|
29
|
+
isEditor: false
|
|
30
|
+
},
|
|
31
|
+
parameters: {
|
|
32
|
+
docs: {
|
|
33
|
+
description: {
|
|
34
|
+
story:
|
|
35
|
+
'Description pulled from dataMetadata is concatenated into the aria-label after the auto-generated title for reliable screen reader support.'
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
play: async ({ canvasElement }) => {
|
|
40
|
+
await assertVisualizationRendered(canvasElement)
|
|
41
|
+
const svg = await waitForPresence('svg[role="img"]', canvasElement)
|
|
42
|
+
|
|
43
|
+
const expected = `United States map with the title: COVID-19 Case Rates by State. ${altTextConfig.dataMetadata.altDescription}`
|
|
44
|
+
expect(svg?.getAttribute('aria-label')).toBe(expected)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const StaticDescription: Story = {
|
|
49
|
+
args: {
|
|
50
|
+
config: {
|
|
51
|
+
...altTextConfig,
|
|
52
|
+
altText: {
|
|
53
|
+
type: 'static',
|
|
54
|
+
value: 'US map showing COVID-19 rates concentrated in the Southeast region.'
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
isEditor: false
|
|
58
|
+
},
|
|
59
|
+
parameters: {
|
|
60
|
+
docs: {
|
|
61
|
+
description: {
|
|
62
|
+
story: 'Static manually written description concatenated with the auto-generated title.'
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
play: async ({ canvasElement }) => {
|
|
67
|
+
await assertVisualizationRendered(canvasElement)
|
|
68
|
+
const svg = await waitForPresence('svg[role="img"]', canvasElement)
|
|
69
|
+
|
|
70
|
+
expect(svg?.getAttribute('aria-label')).toBe(
|
|
71
|
+
'United States map with the title: COVID-19 Case Rates by State. US map showing COVID-19 rates concentrated in the Southeast region.'
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const AutoGenerated: Story = {
|
|
77
|
+
args: {
|
|
78
|
+
config: altTextConfig,
|
|
79
|
+
isEditor: false
|
|
80
|
+
},
|
|
81
|
+
parameters: {
|
|
82
|
+
docs: {
|
|
83
|
+
description: {
|
|
84
|
+
story:
|
|
85
|
+
'No altText configured. Falls back to the auto-generated aria-label: "United States map with the title: COVID-19 Case Rates by State".'
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
play: async ({ canvasElement }) => {
|
|
90
|
+
await assertVisualizationRendered(canvasElement)
|
|
91
|
+
const svg = await waitForPresence('svg[role="img"]', canvasElement)
|
|
92
|
+
|
|
93
|
+
expect(svg?.getAttribute('aria-label')).toBe('United States map with the title: COVID-19 Case Rates by State')
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export const EditorWithMetadata: Story = {
|
|
98
|
+
args: {
|
|
99
|
+
config: {
|
|
100
|
+
...altTextConfig,
|
|
101
|
+
altText: { type: 'metadata', metadataKey: 'altDescription' }
|
|
102
|
+
},
|
|
103
|
+
isEditor: true
|
|
104
|
+
},
|
|
105
|
+
parameters: {
|
|
106
|
+
docs: {
|
|
107
|
+
description: {
|
|
108
|
+
story:
|
|
109
|
+
'Editor mode showing the alt text description control in the General accordion with metadata-driven description.'
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
play: async ({ canvasElement }) => {
|
|
114
|
+
const canvas = within(canvasElement)
|
|
115
|
+
await waitForEditor(canvas)
|
|
116
|
+
|
|
117
|
+
await openAccordion(canvas, 'General')
|
|
118
|
+
|
|
119
|
+
const descPreview = await waitForPresence('[data-testid="alt-text-desc-preview"]', canvasElement)
|
|
120
|
+
expect(descPreview?.textContent).toContain('Choropleth map of the United States')
|
|
121
|
+
}
|
|
122
|
+
}
|