@cdc/map 4.22.10-alpha.1 → 4.22.11
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/dist/cdcmap.js +10 -10
- package/examples/private/atsdr.json +19 -29
- package/examples/private/atsdr_new.json +1 -1
- package/examples/private/bubble.json +282 -284
- package/examples/private/city-state.json +427 -427
- package/examples/private/city-state2.json +433 -433
- package/examples/private/cty-issue.json +42765 -42768
- package/examples/private/default-usa.json +2 -5
- package/examples/private/default-world-data.json +1443 -1443
- package/examples/private/default.json +965 -965
- package/examples/private/diff.json +226 -0
- package/examples/private/filters.json +1 -0
- package/examples/private/legend-issue.json +3271 -1
- package/examples/private/map-issue.json +166 -0
- package/examples/private/map-rounding-error.json +42756 -42759
- package/examples/private/mdx.json +209 -209
- package/examples/private/monkeypox.json +375 -375
- package/examples/private/regions.json +51 -51
- package/examples/private/wcmsrd-13881-data.json +2856 -2856
- package/examples/private/wcmsrd-13881.json +5818 -5822
- package/examples/private/wcmsrd-14492-data.json +291 -291
- package/examples/private/wcmsrd-14492.json +103 -113
- package/examples/private/wcmsrd-test.json +264 -267
- package/examples/private/world.json +1579 -1579
- package/examples/private/worldmap.json +1489 -1489
- package/package.json +3 -3
- package/src/CdcMap.js +231 -315
- package/src/components/BubbleList.js +199 -240
- package/src/components/CityList.js +50 -96
- package/src/components/CountyMap.js +511 -600
- package/src/components/DataTable.js +218 -253
- package/src/components/EditorPanel.js +2338 -2551
- package/src/components/Geo.js +4 -14
- package/src/components/Modal.js +13 -23
- package/src/components/NavigationMenu.js +43 -39
- package/src/components/Sidebar.js +83 -93
- package/src/components/SingleStateMap.js +95 -151
- package/src/components/UsaMap.js +165 -214
- package/src/components/UsaRegionMap.js +122 -160
- package/src/components/WorldMap.js +96 -179
- package/src/components/ZoomableGroup.js +6 -26
- package/src/data/initial-state.js +1 -0
- package/src/hooks/useActiveElement.js +13 -13
- package/src/hooks/useColorPalette.ts +66 -74
- package/src/hooks/useZoomPan.js +22 -23
- package/src/index.html +1 -2
- package/src/scss/sidebar.scss +22 -0
|
@@ -1,367 +1,332 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
useTable, useSortBy, useResizeColumns, useBlockLayout
|
|
6
|
-
} from 'react-table';
|
|
7
|
-
import Papa from 'papaparse';
|
|
8
|
-
import ExternalIcon from '../images/external-link.svg'; // TODO: Move to Icon component
|
|
9
|
-
|
|
10
|
-
import ErrorBoundary from '@cdc/core/components/ErrorBoundary';
|
|
11
|
-
import LegendCircle from '@cdc/core/components/LegendCircle';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import Loading from '@cdc/core/components/Loading';
|
|
15
|
-
|
|
16
|
-
const DataTable = (props) => {
|
|
17
|
-
const {
|
|
18
|
-
state,
|
|
19
|
-
tableTitle,
|
|
20
|
-
indexTitle,
|
|
21
|
-
mapTitle,
|
|
22
|
-
rawData,
|
|
23
|
-
showDownloadButton,
|
|
24
|
-
runtimeData,
|
|
25
|
-
runtimeLegend,
|
|
26
|
-
headerColor,
|
|
27
|
-
expandDataTable,
|
|
28
|
-
columns,
|
|
29
|
-
displayDataAsText,
|
|
30
|
-
applyLegendToRow,
|
|
31
|
-
displayGeoName,
|
|
32
|
-
navigationHandler,
|
|
33
|
-
viewport,
|
|
34
|
-
formatLegendLocation,
|
|
35
|
-
tabbingId,
|
|
36
|
-
setFilteredCountryCode
|
|
37
|
-
} = props;
|
|
38
|
-
|
|
39
|
-
const [expanded, setExpanded] = useState(expandDataTable);
|
|
40
|
-
|
|
41
|
-
const [accessibilityLabel, setAccessibilityLabel] = useState('');
|
|
1
|
+
import React, { useEffect, useState, useMemo, memo, useCallback } from 'react'
|
|
2
|
+
import { useTable, useSortBy, useResizeColumns, useBlockLayout } from 'react-table'
|
|
3
|
+
import Papa from 'papaparse'
|
|
4
|
+
import ExternalIcon from '../images/external-link.svg' // TODO: Move to Icon component
|
|
42
5
|
|
|
43
|
-
|
|
6
|
+
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
7
|
+
import LegendCircle from '@cdc/core/components/LegendCircle'
|
|
8
|
+
|
|
9
|
+
import Loading from '@cdc/core/components/Loading'
|
|
10
|
+
|
|
11
|
+
const DataTable = props => {
|
|
12
|
+
const { state, tableTitle, indexTitle, mapTitle, rawData, showDownloadButton, runtimeData, runtimeLegend, headerColor, expandDataTable, columns, displayDataAsText, applyLegendToRow, displayGeoName, navigationHandler, viewport, formatLegendLocation, tabbingId, setFilteredCountryCode } = props
|
|
44
13
|
|
|
45
|
-
const
|
|
14
|
+
const [expanded, setExpanded] = useState(expandDataTable)
|
|
15
|
+
|
|
16
|
+
const [accessibilityLabel, setAccessibilityLabel] = useState('')
|
|
17
|
+
|
|
18
|
+
const [ready, setReady] = useState(false)
|
|
46
19
|
|
|
20
|
+
const fileName = `${mapTitle || 'data-table'}.csv`
|
|
47
21
|
|
|
48
22
|
// Catch all sorting method used on load by default but also on user click
|
|
49
23
|
// Having a custom method means we can add in any business logic we want going forward
|
|
50
|
-
const customSort = useCallback(
|
|
51
|
-
|
|
24
|
+
const customSort = useCallback(
|
|
25
|
+
(a, b) => {
|
|
26
|
+
const digitRegex = /\d+/
|
|
52
27
|
|
|
53
|
-
|
|
28
|
+
const hasNumber = value => digitRegex.test(value)
|
|
54
29
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
30
|
+
// force null and undefined to the bottom
|
|
31
|
+
a = a === null || a === undefined ? '' : a
|
|
32
|
+
b = b === null || b === undefined ? '' : b
|
|
58
33
|
|
|
59
|
-
|
|
60
|
-
|
|
34
|
+
// convert any strings that are actually numbers to proper data type
|
|
35
|
+
const aNum = Number(a)
|
|
61
36
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
37
|
+
if (!Number.isNaN(aNum)) {
|
|
38
|
+
a = aNum
|
|
39
|
+
}
|
|
65
40
|
|
|
66
|
-
|
|
41
|
+
const bNum = Number(b)
|
|
67
42
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
43
|
+
if (!Number.isNaN(bNum)) {
|
|
44
|
+
b = bNum
|
|
45
|
+
}
|
|
71
46
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
47
|
+
// remove iso code prefixes
|
|
48
|
+
if (typeof a === 'string') {
|
|
49
|
+
a = a.replace('us-', '')
|
|
50
|
+
a = displayGeoName(a)
|
|
51
|
+
}
|
|
77
52
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
53
|
+
if (typeof b === 'string') {
|
|
54
|
+
b = b.replace('us-', '')
|
|
55
|
+
b = displayGeoName(b)
|
|
56
|
+
}
|
|
82
57
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
58
|
+
// force any string values to lowercase
|
|
59
|
+
a = typeof a === 'string' ? a.toLowerCase() : a
|
|
60
|
+
b = typeof b === 'string' ? b.toLowerCase() : b
|
|
86
61
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
62
|
+
// If the string contains a number, remove the text from the value and only sort by the number. Only uses the first number it finds.
|
|
63
|
+
if (typeof a === 'string' && hasNumber(a) === true) {
|
|
64
|
+
a = a.match(digitRegex)[0]
|
|
90
65
|
|
|
91
|
-
|
|
92
|
-
|
|
66
|
+
a = Number(a)
|
|
67
|
+
}
|
|
93
68
|
|
|
94
|
-
|
|
95
|
-
|
|
69
|
+
if (typeof b === 'string' && hasNumber(b) === true) {
|
|
70
|
+
b = b.match(digitRegex)[0]
|
|
96
71
|
|
|
97
|
-
|
|
98
|
-
|
|
72
|
+
b = Number(b)
|
|
73
|
+
}
|
|
99
74
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
75
|
+
// When comparing a number to a string, always send string to bottom
|
|
76
|
+
if (typeof a === 'number' && typeof b === 'string') {
|
|
77
|
+
return 1
|
|
78
|
+
}
|
|
104
79
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
80
|
+
if (typeof b === 'number' && typeof a === 'string') {
|
|
81
|
+
return -1
|
|
82
|
+
}
|
|
108
83
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
84
|
+
// Return either 1 or -1 to indicate a sort priority
|
|
85
|
+
if (a > b) {
|
|
86
|
+
return 1
|
|
87
|
+
}
|
|
88
|
+
if (a < b) {
|
|
89
|
+
return -1
|
|
90
|
+
}
|
|
91
|
+
// returning 0, undefined or any falsey value will use subsequent sorts or
|
|
92
|
+
// the index as a tiebreaker
|
|
93
|
+
return 0
|
|
94
|
+
},
|
|
95
|
+
[displayGeoName]
|
|
96
|
+
)
|
|
120
97
|
|
|
121
98
|
// Optionally wrap cell with anchor if config defines a navigation url
|
|
122
|
-
const getCellAnchor = useCallback(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
99
|
+
const getCellAnchor = useCallback(
|
|
100
|
+
(markup, row) => {
|
|
101
|
+
if (columns.navigate && row[columns.navigate.name]) {
|
|
102
|
+
markup = (
|
|
103
|
+
<span
|
|
104
|
+
onClick={() => navigationHandler(row[columns.navigate.name])}
|
|
105
|
+
className='table-link'
|
|
106
|
+
title='Click for more information (Opens in a new window)'
|
|
107
|
+
role='link'
|
|
108
|
+
tabIndex='0'
|
|
109
|
+
onKeyDown={e => {
|
|
110
|
+
if (e.keyCode === 13) {
|
|
111
|
+
navigationHandler(row[columns.navigate.name])
|
|
112
|
+
}
|
|
113
|
+
}}
|
|
114
|
+
>
|
|
115
|
+
{markup}
|
|
116
|
+
<ExternalIcon className='inline-icon' />
|
|
117
|
+
</span>
|
|
118
|
+
)
|
|
119
|
+
}
|
|
142
120
|
|
|
143
|
-
|
|
144
|
-
|
|
121
|
+
return markup
|
|
122
|
+
},
|
|
123
|
+
[columns.navigate, navigationHandler]
|
|
124
|
+
)
|
|
145
125
|
|
|
146
126
|
const DownloadButton = memo(() => {
|
|
147
|
-
const csvData = Papa.unparse(rawData)
|
|
127
|
+
const csvData = Papa.unparse(rawData)
|
|
148
128
|
|
|
149
|
-
const blob = new Blob([csvData], {type:
|
|
129
|
+
const blob = new Blob([csvData], { type: 'text/csv;charset=utf-8;' })
|
|
150
130
|
|
|
151
131
|
const saveBlob = () => {
|
|
152
132
|
//@ts-ignore
|
|
153
133
|
if (typeof window.navigator.msSaveBlob === 'function') {
|
|
154
134
|
//@ts-ignore
|
|
155
|
-
navigator.msSaveBlob(blob, fileName)
|
|
135
|
+
navigator.msSaveBlob(blob, fileName)
|
|
156
136
|
}
|
|
157
137
|
}
|
|
158
138
|
|
|
159
139
|
return (
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
onClick={saveBlob}
|
|
164
|
-
href={URL.createObjectURL(blob)}
|
|
165
|
-
aria-label="Download this data in a CSV file format."
|
|
166
|
-
className={`${headerColor} btn btn-download no-border`}
|
|
167
|
-
id={`${skipId}`}
|
|
168
|
-
data-html2canvas-ignore
|
|
169
|
-
role="button"
|
|
170
|
-
>
|
|
171
|
-
Download Data (CSV)
|
|
172
|
-
</a>
|
|
140
|
+
<a download={fileName} type='button' onClick={saveBlob} href={URL.createObjectURL(blob)} aria-label='Download this data in a CSV file format.' className={`${headerColor} btn btn-download no-border`} id={`${skipId}`} data-html2canvas-ignore role='button'>
|
|
141
|
+
Download Data (CSV)
|
|
142
|
+
</a>
|
|
173
143
|
)
|
|
174
|
-
}, [rawData])
|
|
144
|
+
}, [rawData])
|
|
175
145
|
|
|
176
146
|
// Creates columns structure for the table
|
|
177
147
|
const tableColumns = useMemo(() => {
|
|
178
|
-
const newTableColumns = []
|
|
148
|
+
const newTableColumns = []
|
|
179
149
|
|
|
180
|
-
Object.keys(columns).forEach(
|
|
150
|
+
Object.keys(columns).forEach(column => {
|
|
181
151
|
if (columns[column].dataTable === true && columns[column].name) {
|
|
182
152
|
const newCol = {
|
|
183
153
|
Header: columns[column].label ? columns[column].label : columns[column].name,
|
|
184
154
|
id: column,
|
|
185
|
-
accessor:
|
|
155
|
+
accessor: row => {
|
|
186
156
|
if (runtimeData) {
|
|
187
|
-
if(state.legend.specialClasses && state.legend.specialClasses.length && typeof state.legend.specialClasses[0] === 'object'){
|
|
188
|
-
for(let i = 0; i < state.legend.specialClasses.length; i++){
|
|
189
|
-
if(String(runtimeData[row][state.legend.specialClasses[i].key]) === state.legend.specialClasses[i].value){
|
|
190
|
-
return state.legend.specialClasses[i].label
|
|
157
|
+
if (state.legend.specialClasses && state.legend.specialClasses.length && typeof state.legend.specialClasses[0] === 'object') {
|
|
158
|
+
for (let i = 0; i < state.legend.specialClasses.length; i++) {
|
|
159
|
+
if (String(runtimeData[row][state.legend.specialClasses[i].key]) === state.legend.specialClasses[i].value) {
|
|
160
|
+
return state.legend.specialClasses[i].label
|
|
191
161
|
}
|
|
192
162
|
}
|
|
193
163
|
}
|
|
194
|
-
return runtimeData[row][columns[column].name] ?? null
|
|
164
|
+
return runtimeData[row][columns[column].name] ?? null
|
|
195
165
|
}
|
|
196
166
|
|
|
197
|
-
return null
|
|
167
|
+
return null
|
|
198
168
|
},
|
|
199
169
|
sortType: (a, b) => customSort(a.values[column], b.values[column])
|
|
200
|
-
}
|
|
170
|
+
}
|
|
201
171
|
|
|
202
172
|
if (column === 'geo') {
|
|
203
|
-
newCol.Header = indexTitle || 'Location'
|
|
173
|
+
newCol.Header = indexTitle || 'Location'
|
|
204
174
|
newCol.Cell = ({ row, value }) => {
|
|
205
|
-
const rowObj = runtimeData[row.original]
|
|
175
|
+
const rowObj = runtimeData[row.original]
|
|
206
176
|
|
|
207
|
-
const legendColor = applyLegendToRow(rowObj)
|
|
177
|
+
const legendColor = applyLegendToRow(rowObj)
|
|
208
178
|
|
|
209
|
-
if(state.general.geoType !== 'us-county' || state.general.type === 'us-geocode') {
|
|
210
|
-
var labelValue = displayGeoName(row.original)
|
|
179
|
+
if (state.general.geoType !== 'us-county' || state.general.type === 'us-geocode') {
|
|
180
|
+
var labelValue = displayGeoName(row.original)
|
|
211
181
|
} else {
|
|
212
182
|
var labelValue = formatLegendLocation(row.original)
|
|
213
183
|
}
|
|
214
184
|
|
|
215
|
-
labelValue = getCellAnchor(labelValue, rowObj)
|
|
185
|
+
labelValue = getCellAnchor(labelValue, rowObj)
|
|
216
186
|
|
|
217
187
|
const cellMarkup = (
|
|
218
188
|
<>
|
|
219
189
|
<LegendCircle fill={legendColor[0]} />
|
|
220
190
|
{labelValue}
|
|
221
191
|
</>
|
|
222
|
-
)
|
|
192
|
+
)
|
|
223
193
|
|
|
224
|
-
return cellMarkup
|
|
225
|
-
}
|
|
194
|
+
return cellMarkup
|
|
195
|
+
}
|
|
226
196
|
} else {
|
|
227
197
|
newCol.Cell = ({ value }) => {
|
|
228
|
-
const cellMarkup = displayDataAsText(value, column)
|
|
198
|
+
const cellMarkup = displayDataAsText(value, column)
|
|
229
199
|
|
|
230
|
-
return
|
|
231
|
-
}
|
|
200
|
+
return cellMarkup
|
|
201
|
+
}
|
|
232
202
|
}
|
|
233
203
|
|
|
234
|
-
newTableColumns.push(newCol)
|
|
204
|
+
newTableColumns.push(newCol)
|
|
235
205
|
}
|
|
236
|
-
})
|
|
206
|
+
})
|
|
237
207
|
|
|
238
|
-
return newTableColumns
|
|
239
|
-
}, [indexTitle, columns, runtimeData,getCellAnchor,displayDataAsText,applyLegendToRow,customSort,displayGeoName,state.legend.specialClasses])
|
|
208
|
+
return newTableColumns
|
|
209
|
+
}, [indexTitle, columns, runtimeData, getCellAnchor, displayDataAsText, applyLegendToRow, customSort, displayGeoName, state.legend.specialClasses])
|
|
240
210
|
|
|
241
211
|
const tableData = useMemo(
|
|
242
|
-
() =>
|
|
243
|
-
|
|
244
|
-
|
|
212
|
+
() =>
|
|
213
|
+
Object.keys(runtimeData)
|
|
214
|
+
.filter(key => applyLegendToRow(runtimeData[key]))
|
|
215
|
+
.sort((a, b) => customSort(a, b)),
|
|
216
|
+
[runtimeData, applyLegendToRow, customSort]
|
|
217
|
+
)
|
|
245
218
|
|
|
246
219
|
// Change accessibility label depending on expanded status
|
|
247
220
|
useEffect(() => {
|
|
248
|
-
const expandedLabel = 'Accessible data table.'
|
|
249
|
-
const collapsedLabel = 'Accessible data table. This table is currently collapsed visually but can still be read using a screen reader.'
|
|
221
|
+
const expandedLabel = 'Accessible data table.'
|
|
222
|
+
const collapsedLabel = 'Accessible data table. This table is currently collapsed visually but can still be read using a screen reader.'
|
|
250
223
|
|
|
251
224
|
if (expanded === true && accessibilityLabel !== expandedLabel) {
|
|
252
|
-
setAccessibilityLabel(expandedLabel)
|
|
225
|
+
setAccessibilityLabel(expandedLabel)
|
|
253
226
|
}
|
|
254
227
|
|
|
255
228
|
if (expanded === false && accessibilityLabel !== collapsedLabel) {
|
|
256
|
-
setAccessibilityLabel(collapsedLabel)
|
|
229
|
+
setAccessibilityLabel(collapsedLabel)
|
|
257
230
|
}
|
|
258
231
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
259
|
-
}, [expanded, applyLegendToRow, customSort])
|
|
232
|
+
}, [expanded, applyLegendToRow, customSort])
|
|
260
233
|
|
|
261
234
|
const defaultColumn = useMemo(
|
|
262
235
|
() => ({
|
|
263
236
|
minWidth: 150,
|
|
264
237
|
width: 200,
|
|
265
|
-
maxWidth: 400
|
|
238
|
+
maxWidth: 400
|
|
266
239
|
}),
|
|
267
240
|
[]
|
|
268
|
-
)
|
|
241
|
+
)
|
|
269
242
|
|
|
270
243
|
const mapLookup = {
|
|
271
244
|
'us-county': 'United States County Map',
|
|
272
245
|
'single-state': 'State Map',
|
|
273
|
-
|
|
274
|
-
|
|
246
|
+
us: 'United States Map',
|
|
247
|
+
world: 'World Map'
|
|
275
248
|
}
|
|
276
249
|
|
|
277
|
-
const {
|
|
278
|
-
getTableProps,
|
|
279
|
-
getTableBodyProps,
|
|
280
|
-
headerGroups,
|
|
281
|
-
rows,
|
|
282
|
-
prepareRow,
|
|
283
|
-
} = useTable({ columns: tableColumns, data: tableData, defaultColumn }, useSortBy, useBlockLayout, useResizeColumns);
|
|
250
|
+
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable({ columns: tableColumns, data: tableData, defaultColumn }, useSortBy, useBlockLayout, useResizeColumns)
|
|
284
251
|
|
|
285
|
-
const rand = Math.random().toString(16).substr(2, 8)
|
|
252
|
+
const rand = Math.random().toString(16).substr(2, 8)
|
|
286
253
|
const skipId = `btn__${rand}`
|
|
287
254
|
|
|
288
|
-
if(!state.data) return <Loading />
|
|
255
|
+
if (!state.data) return <Loading />
|
|
289
256
|
return (
|
|
290
|
-
<ErrorBoundary component=
|
|
257
|
+
<ErrorBoundary component='DataTable'>
|
|
291
258
|
<section id={tabbingId.replace('#', '')} className={`data-table-container ${viewport}`} aria-label={accessibilityLabel}>
|
|
292
259
|
<a id='skip-nav' className='cdcdataviz-sr-only-focusable' href={`#${skipId}`}>
|
|
293
260
|
Skip Navigation or Skip to Content
|
|
294
261
|
</a>
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
style={ { maxHeight: state.dataTable.limitHeight && `${state.dataTable.height}px`, overflowY: 'scroll' } }
|
|
307
|
-
>
|
|
308
|
-
<table
|
|
309
|
-
height={expanded ? null : 0} {...getTableProps()}
|
|
310
|
-
aria-live="assertive"
|
|
311
|
-
className={expanded ? 'data-table' : 'data-table cdcdataviz-sr-only'}
|
|
312
|
-
hidden={!expanded}
|
|
313
|
-
aria-rowcount={state?.data.length ? state.data.length : '-1' }
|
|
262
|
+
<div
|
|
263
|
+
className={expanded ? 'data-table-heading' : 'collapsed data-table-heading'}
|
|
264
|
+
onClick={() => {
|
|
265
|
+
setExpanded(!expanded)
|
|
266
|
+
}}
|
|
267
|
+
tabIndex='0'
|
|
268
|
+
onKeyDown={e => {
|
|
269
|
+
if (e.keyCode === 13) {
|
|
270
|
+
setExpanded(!expanded)
|
|
271
|
+
}
|
|
272
|
+
}}
|
|
314
273
|
>
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
<tr {...row.getRowProps()} role="row">
|
|
347
|
-
{row.cells.map((cell) => {
|
|
348
|
-
return (
|
|
349
|
-
<td tabIndex="0" {...cell.getCellProps()} role="gridcell" onClick={ (e) => (state.general.type === 'bubble' && state.general.allowMapZoom && state.general.geoType === 'world') ? setFilteredCountryCode(cell.row.original) : true }>
|
|
350
|
-
{cell.render('Cell')}
|
|
351
|
-
</td>
|
|
352
|
-
)
|
|
353
|
-
}
|
|
354
|
-
)}
|
|
274
|
+
{tableTitle}
|
|
275
|
+
</div>
|
|
276
|
+
<div className='table-container' style={{ maxHeight: state.dataTable.limitHeight && `${state.dataTable.height}px`, overflowY: 'scroll' }}>
|
|
277
|
+
<table height={expanded ? null : 0} {...getTableProps()} aria-live='assertive' className={expanded ? 'data-table' : 'data-table cdcdataviz-sr-only'} hidden={!expanded} aria-rowcount={state?.data.length ? state.data.length : '-1'}>
|
|
278
|
+
<caption className='cdcdataviz-sr-only'>{state.dataTable.caption ? state.dataTable.caption : `Datatable showing data for the ${mapLookup[state.general.geoType]} figure.`}</caption>
|
|
279
|
+
<thead style={{ position: 'sticky', top: 0, zIndex: 999 }}>
|
|
280
|
+
{headerGroups.map(headerGroup => (
|
|
281
|
+
<tr {...headerGroup.getHeaderGroupProps()}>
|
|
282
|
+
{headerGroup.headers.map(column => (
|
|
283
|
+
<th
|
|
284
|
+
tabIndex='0'
|
|
285
|
+
title={column.Header}
|
|
286
|
+
role='columnheader'
|
|
287
|
+
scope='col'
|
|
288
|
+
{...column.getHeaderProps(column.getSortByToggleProps())}
|
|
289
|
+
className={column.isSorted ? (column.isSortedDesc ? 'sort sort-desc' : 'sort sort-asc') : 'sort'}
|
|
290
|
+
onKeyDown={e => {
|
|
291
|
+
if (e.keyCode === 13) {
|
|
292
|
+
column.toggleSortBy()
|
|
293
|
+
}
|
|
294
|
+
}}
|
|
295
|
+
//aria-sort={column.isSorted ? column.isSortedDesc ? 'descending' : 'ascending' : 'none' }
|
|
296
|
+
{...(column.isSorted ? (column.isSortedDesc ? { 'aria-sort': 'descending' } : { 'aria-sort': 'ascending' }) : null)}
|
|
297
|
+
>
|
|
298
|
+
{column.render('Header')}
|
|
299
|
+
<button>
|
|
300
|
+
<span className='cdcdataviz-sr-only'>{`Sort by ${column.render('Header').toLowerCase()} in ${column.isSorted ? (column.isSortedDesc ? 'descending' : 'ascending') : 'no'} `} order</span>
|
|
301
|
+
</button>
|
|
302
|
+
<div {...column.getResizerProps()} className='resizer' />
|
|
303
|
+
</th>
|
|
304
|
+
))}
|
|
355
305
|
</tr>
|
|
356
|
-
)
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
306
|
+
))}
|
|
307
|
+
</thead>
|
|
308
|
+
<tbody {...getTableBodyProps()}>
|
|
309
|
+
{rows.map(row => {
|
|
310
|
+
prepareRow(row)
|
|
311
|
+
return (
|
|
312
|
+
<tr {...row.getRowProps()} role='row'>
|
|
313
|
+
{row.cells.map(cell => {
|
|
314
|
+
return (
|
|
315
|
+
<td tabIndex='0' {...cell.getCellProps()} role='gridcell' onClick={e => (state.general.type === 'bubble' && state.general.allowMapZoom && state.general.geoType === 'world' ? setFilteredCountryCode(cell.row.original) : true)}>
|
|
316
|
+
{cell.render('Cell')}
|
|
317
|
+
</td>
|
|
318
|
+
)
|
|
319
|
+
})}
|
|
320
|
+
</tr>
|
|
321
|
+
)
|
|
322
|
+
})}
|
|
323
|
+
</tbody>
|
|
324
|
+
</table>
|
|
325
|
+
</div>
|
|
326
|
+
{showDownloadButton === true && <DownloadButton />}
|
|
327
|
+
</section>
|
|
363
328
|
</ErrorBoundary>
|
|
364
|
-
)
|
|
365
|
-
}
|
|
329
|
+
)
|
|
330
|
+
}
|
|
366
331
|
|
|
367
|
-
export default DataTable
|
|
332
|
+
export default DataTable
|