@cdc/dashboard 4.22.10 → 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/README.md +36 -36
- package/dist/cdcdashboard.js +6 -6
- package/examples/default-data.json +367 -367
- package/examples/default-filter-control.json +176 -174
- package/examples/default-multi-dataset.json +505 -497
- package/examples/default.json +161 -155
- package/examples/private/chart-issue.json +3462 -3466
- package/examples/private/no-issue.json +3462 -3466
- package/examples/private/totals-two.json +103 -103
- package/examples/private/totals.json +102 -102
- package/examples/temp-example-data.json +1 -1
- package/examples/test-example.json +163 -1
- package/package.json +7 -7
- package/src/CdcDashboard.js +200 -124
- package/src/CdcDashboard.jsx +271 -277
- package/src/ConfigContext.js +3 -3
- package/src/components/Column.jsx +10 -9
- package/src/components/DataTable.tsx +91 -111
- package/src/components/EditorPanel.js +184 -246
- package/src/components/Grid.jsx +8 -4
- package/src/components/Header.jsx +209 -118
- package/src/components/Row.js +30 -29
- package/src/components/Row.jsx +36 -52
- package/src/components/Widget.js +68 -61
- package/src/components/Widget.jsx +85 -62
- package/src/data/initial-state.js +3 -9
- package/src/index.html +24 -26
- package/src/index.js +12 -12
- package/src/scss/editor-panel.scss +494 -489
- package/src/scss/grid.scss +20 -19
- package/src/scss/main.scss +16 -15
- package/src/scss/variables.scss +1 -1
package/src/ConfigContext.js
CHANGED
|
@@ -7,7 +7,7 @@ import Widget from './Widget'
|
|
|
7
7
|
const Column = ({ data, rowIdx, colIdx }) => {
|
|
8
8
|
const { visualizations } = useContext(ConfigContext)
|
|
9
9
|
|
|
10
|
-
const [
|
|
10
|
+
const [{ isOver, canDrop }, drop] = useDrop(() => ({
|
|
11
11
|
accept: 'vis-widget',
|
|
12
12
|
drop: () => ({
|
|
13
13
|
rowIdx,
|
|
@@ -15,7 +15,7 @@ const Column = ({ data, rowIdx, colIdx }) => {
|
|
|
15
15
|
canDrop
|
|
16
16
|
}),
|
|
17
17
|
canDrop: () => !data.widget,
|
|
18
|
-
collect:
|
|
18
|
+
collect: monitor => ({
|
|
19
19
|
isOver: monitor.isOver(),
|
|
20
20
|
canDrop: !!monitor.canDrop()
|
|
21
21
|
})
|
|
@@ -23,10 +23,7 @@ const Column = ({ data, rowIdx, colIdx }) => {
|
|
|
23
23
|
|
|
24
24
|
const widget = data.widget ? visualizations[data.widget] : null
|
|
25
25
|
|
|
26
|
-
let classNames = [
|
|
27
|
-
'builder-column',
|
|
28
|
-
'column-size--' + data.width,
|
|
29
|
-
]
|
|
26
|
+
let classNames = ['builder-column', 'column-size--' + data.width]
|
|
30
27
|
|
|
31
28
|
if (isOver && canDrop) {
|
|
32
29
|
classNames.push('column--drop')
|
|
@@ -38,9 +35,13 @@ const Column = ({ data, rowIdx, colIdx }) => {
|
|
|
38
35
|
|
|
39
36
|
return (
|
|
40
37
|
<div className={classNames.join(' ')} ref={drop}>
|
|
41
|
-
{widget ?
|
|
42
|
-
<Widget data={{ rowIdx, colIdx, ...widget }} type={widget.visualizationType ?? widget.general?.geoType}/>
|
|
43
|
-
|
|
38
|
+
{widget ? (
|
|
39
|
+
<Widget data={{ rowIdx, colIdx, ...widget }} type={widget.visualizationType ?? widget.general?.geoType} />
|
|
40
|
+
) : (
|
|
41
|
+
<p className='builder-column__text'>
|
|
42
|
+
Drag and drop <br /> visualization
|
|
43
|
+
</p>
|
|
44
|
+
)}
|
|
44
45
|
</div>
|
|
45
46
|
)
|
|
46
47
|
}
|
|
@@ -1,170 +1,150 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
useMemo,
|
|
6
|
-
memo } from 'react';
|
|
7
|
-
import {
|
|
8
|
-
useTable,
|
|
9
|
-
useSortBy,
|
|
10
|
-
useResizeColumns,
|
|
11
|
-
useBlockLayout
|
|
12
|
-
} from 'react-table';
|
|
13
|
-
import Papa from 'papaparse';
|
|
14
|
-
import { Base64 } from 'js-base64';
|
|
15
|
-
|
|
16
|
-
import ErrorBoundary from '@cdc/core/components/ErrorBoundary';
|
|
1
|
+
import React, { useContext, useEffect, useState, useMemo, memo } from 'react'
|
|
2
|
+
import { useTable, useSortBy, useResizeColumns, useBlockLayout } from 'react-table'
|
|
3
|
+
import Papa from 'papaparse'
|
|
4
|
+
import { Base64 } from 'js-base64'
|
|
17
5
|
|
|
18
|
-
|
|
6
|
+
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
19
7
|
|
|
20
|
-
|
|
8
|
+
export default function DataTable(props) {
|
|
9
|
+
const { data, datasetKey, config } = props
|
|
21
10
|
|
|
22
|
-
const [tableExpanded, setTableExpanded] = useState<boolean>(config.table ? config.table.expanded : false)
|
|
23
|
-
const [accessibilityLabel, setAccessibilityLabel] = useState('')
|
|
11
|
+
const [tableExpanded, setTableExpanded] = useState<boolean>(config.table ? config.table.expanded : false)
|
|
12
|
+
const [accessibilityLabel, setAccessibilityLabel] = useState('')
|
|
24
13
|
|
|
25
14
|
const DownloadButton = memo(({ data }: any) => {
|
|
26
|
-
const fileName = `${config.title ? config.title.substring(0, 50) : 'cdc-open-viz'}.csv
|
|
15
|
+
const fileName = `${config.title ? config.title.substring(0, 50) : 'cdc-open-viz'}.csv`
|
|
27
16
|
|
|
28
|
-
const csvData = Papa.unparse(data)
|
|
17
|
+
const csvData = Papa.unparse(data)
|
|
29
18
|
|
|
30
19
|
const saveBlob = () => {
|
|
31
20
|
//@ts-ignore
|
|
32
21
|
if (typeof window.navigator.msSaveBlob === 'function') {
|
|
33
|
-
const dataBlob = new Blob([csvData], { type:
|
|
22
|
+
const dataBlob = new Blob([csvData], { type: 'text/csv;charset=utf-8;' })
|
|
34
23
|
//@ts-ignore
|
|
35
|
-
window.navigator.msSaveBlob(dataBlob, fileName)
|
|
24
|
+
window.navigator.msSaveBlob(dataBlob, fileName)
|
|
36
25
|
}
|
|
37
26
|
}
|
|
38
27
|
|
|
39
28
|
return (
|
|
40
|
-
<a
|
|
41
|
-
download={fileName}
|
|
42
|
-
onClick={saveBlob}
|
|
43
|
-
href={`data:text/csv;base64,${Base64.encode(csvData)}`}
|
|
44
|
-
aria-label="Download this data in a CSV file format."
|
|
45
|
-
className={`btn btn-download no-border`}
|
|
46
|
-
>
|
|
29
|
+
<a download={fileName} onClick={saveBlob} href={`data:text/csv;base64,${Base64.encode(csvData)}`} aria-label='Download this data in a CSV file format.' className={`btn btn-download no-border`}>
|
|
47
30
|
Download {datasetKey ? `"${datasetKey}"` : 'Data'} (CSV)
|
|
48
31
|
</a>
|
|
49
32
|
)
|
|
50
|
-
})
|
|
51
|
-
|
|
33
|
+
})
|
|
34
|
+
|
|
52
35
|
// Creates columns structure for the table
|
|
53
36
|
const tableColumns = useMemo(() => {
|
|
54
|
-
const newTableColumns = []
|
|
37
|
+
const newTableColumns = []
|
|
55
38
|
|
|
56
39
|
// catch no data errors and update the table header.
|
|
57
|
-
if(data.length === 0) {
|
|
58
|
-
return [
|
|
59
|
-
|
|
60
|
-
|
|
40
|
+
if (data.length === 0) {
|
|
41
|
+
return [
|
|
42
|
+
{
|
|
43
|
+
Header: 'No Data Found'
|
|
44
|
+
}
|
|
45
|
+
]
|
|
61
46
|
} else {
|
|
62
|
-
Object.keys(data[0]).map(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
newTableColumns.push(newCol);
|
|
77
|
-
});
|
|
47
|
+
Object.keys(data[0]).map(key => {
|
|
48
|
+
const newCol = {
|
|
49
|
+
Header: key,
|
|
50
|
+
Cell: ({ row }) => {
|
|
51
|
+
return <>{row.original[key]}</>
|
|
52
|
+
},
|
|
53
|
+
id: key,
|
|
54
|
+
canSort: true
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
newTableColumns.push(newCol)
|
|
58
|
+
})
|
|
78
59
|
}
|
|
79
60
|
|
|
80
|
-
return newTableColumns
|
|
81
|
-
}, [config])
|
|
61
|
+
return newTableColumns
|
|
62
|
+
}, [config])
|
|
82
63
|
|
|
83
|
-
const tableData = useMemo(
|
|
84
|
-
() => data,
|
|
85
|
-
[data]
|
|
86
|
-
);
|
|
64
|
+
const tableData = useMemo(() => data, [data])
|
|
87
65
|
|
|
88
66
|
// Change accessibility label depending on expanded status
|
|
89
67
|
useEffect(() => {
|
|
90
|
-
const expandedLabel = 'Accessible data table.'
|
|
91
|
-
const collapsedLabel = 'Accessible data table. This table is currently collapsed visually but can still be read using a screen reader.'
|
|
68
|
+
const expandedLabel = 'Accessible data table.'
|
|
69
|
+
const collapsedLabel = 'Accessible data table. This table is currently collapsed visually but can still be read using a screen reader.'
|
|
92
70
|
|
|
93
71
|
if (tableExpanded === true && accessibilityLabel !== expandedLabel) {
|
|
94
|
-
setAccessibilityLabel(expandedLabel)
|
|
72
|
+
setAccessibilityLabel(expandedLabel)
|
|
95
73
|
}
|
|
96
74
|
|
|
97
75
|
if (tableExpanded === false && accessibilityLabel !== collapsedLabel) {
|
|
98
|
-
setAccessibilityLabel(collapsedLabel)
|
|
76
|
+
setAccessibilityLabel(collapsedLabel)
|
|
99
77
|
}
|
|
100
78
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
101
|
-
}, [tableExpanded])
|
|
79
|
+
}, [tableExpanded])
|
|
102
80
|
|
|
103
81
|
const defaultColumn = useMemo(
|
|
104
82
|
() => ({
|
|
105
83
|
minWidth: 150,
|
|
106
84
|
width: 200,
|
|
107
|
-
maxWidth: 400
|
|
85
|
+
maxWidth: 400
|
|
108
86
|
}),
|
|
109
87
|
[]
|
|
110
|
-
)
|
|
88
|
+
)
|
|
111
89
|
|
|
112
|
-
const {
|
|
113
|
-
getTableProps,
|
|
114
|
-
getTableBodyProps,
|
|
115
|
-
headerGroups,
|
|
116
|
-
rows,
|
|
117
|
-
prepareRow,
|
|
118
|
-
} = useTable({ columns: tableColumns, data: tableData, defaultColumn }, useSortBy, useBlockLayout, useResizeColumns);
|
|
90
|
+
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable({ columns: tableColumns, data: tableData, defaultColumn }, useSortBy, useBlockLayout, useResizeColumns)
|
|
119
91
|
|
|
120
92
|
return (
|
|
121
|
-
<ErrorBoundary component=
|
|
93
|
+
<ErrorBoundary component='DataTable'>
|
|
122
94
|
<section className={`data-table-container`} aria-label={accessibilityLabel}>
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
95
|
+
<div
|
|
96
|
+
role='button'
|
|
97
|
+
className={tableExpanded ? 'data-table-heading' : 'collapsed data-table-heading'}
|
|
98
|
+
onClick={() => {
|
|
99
|
+
setTableExpanded(!tableExpanded)
|
|
100
|
+
}}
|
|
101
|
+
tabIndex={0}
|
|
102
|
+
onKeyDown={e => {
|
|
103
|
+
if (e.keyCode === 13) {
|
|
104
|
+
setTableExpanded(!tableExpanded)
|
|
105
|
+
}
|
|
106
|
+
}}
|
|
107
|
+
>
|
|
108
|
+
{config.table.label}
|
|
109
|
+
{datasetKey ? `: ${datasetKey}` : ''}
|
|
110
|
+
</div>
|
|
111
|
+
<div className='table-container' style={{ maxHeight: config.table && config.table.limitHeight && `${config.table.height}px`, overflowY: 'scroll' }}>
|
|
112
|
+
<table className={tableExpanded ? 'data-table' : 'data-table cdcdataviz-sr-only'} hidden={!tableExpanded} {...getTableProps()}>
|
|
113
|
+
<caption className='visually-hidden'>{config.table.label}</caption>
|
|
114
|
+
<thead>
|
|
115
|
+
{headerGroups &&
|
|
116
|
+
headerGroups.map(headerGroup => (
|
|
138
117
|
<tr {...headerGroup.getHeaderGroupProps()}>
|
|
139
|
-
{headerGroup.headers.map(
|
|
140
|
-
<th tabIndex=
|
|
118
|
+
{headerGroup.headers.map(column => (
|
|
119
|
+
<th tabIndex='0' {...column.getHeaderProps(column.getSortByToggleProps())} className={column.isSorted ? (column.isSortedDesc ? 'sort sort-desc' : 'sort sort-asc') : 'sort'} title={column.Header}>
|
|
141
120
|
{column.render('Header')}
|
|
142
|
-
<div {...column.getResizerProps()} className=
|
|
121
|
+
<div {...column.getResizerProps()} className='resizer' />
|
|
143
122
|
</th>
|
|
144
123
|
))}
|
|
145
124
|
</tr>
|
|
146
125
|
))}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
126
|
+
</thead>
|
|
127
|
+
{rows && (
|
|
128
|
+
<tbody {...getTableBodyProps()}>
|
|
129
|
+
{rows.map(row => {
|
|
130
|
+
prepareRow(row)
|
|
131
|
+
return (
|
|
132
|
+
<tr {...row.getRowProps()}>
|
|
133
|
+
{row.cells &&
|
|
134
|
+
row.cells.map(cell => (
|
|
135
|
+
<td tabIndex='0' {...cell.getCellProps()}>
|
|
156
136
|
{cell.render('Cell')}
|
|
157
137
|
</td>
|
|
158
138
|
))}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
139
|
+
</tr>
|
|
140
|
+
)
|
|
141
|
+
})}
|
|
142
|
+
</tbody>
|
|
143
|
+
)}
|
|
144
|
+
</table>
|
|
145
|
+
</div>
|
|
146
|
+
{config.table.download && <DownloadButton data={data} />}
|
|
167
147
|
</section>
|
|
168
148
|
</ErrorBoundary>
|
|
169
|
-
)
|
|
149
|
+
)
|
|
170
150
|
}
|