@cdc/chart 4.22.10 → 4.23.1

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 (80) hide show
  1. package/README.md +5 -5
  2. package/dist/495.js +3 -0
  3. package/dist/703.js +1 -0
  4. package/dist/cdcchart.js +723 -6
  5. package/examples/age-adjusted-rates.json +1486 -1218
  6. package/examples/box-plot-data.json +71 -0
  7. package/examples/box-plot.csv +5 -0
  8. package/examples/{private/yaxis-test.json → box-plot.json} +46 -54
  9. package/examples/case-rate-example-config.json +1 -1
  10. package/examples/covid-confidence-example-config.json +33 -33
  11. package/examples/covid-example-config.json +34 -34
  12. package/examples/covid-example-data-confidence.json +30 -30
  13. package/examples/covid-example-data.json +20 -20
  14. package/examples/cutoff-example-config.json +36 -36
  15. package/examples/cutoff-example-data.json +36 -36
  16. package/examples/date-exclusions-config.json +1 -1
  17. package/examples/dynamic-legends.json +124 -124
  18. package/examples/gallery/bar-chart-horizontal/horizontal-bar-chart-with-numbers-on-bar.json +191 -197
  19. package/examples/gallery/bar-chart-horizontal/horizontal-bar-chart.json +230 -240
  20. package/examples/gallery/bar-chart-horizontal/horizontal-stacked.json +239 -247
  21. package/examples/gallery/bar-chart-vertical/combo-line-chart.json +138 -136
  22. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-categorical.json +79 -79
  23. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +80 -80
  24. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-with-confidence.json +67 -67
  25. package/examples/gallery/bar-chart-vertical/vertical-bar-chart.json +179 -110
  26. package/examples/gallery/lollipop/lollipop-style-horizontal.json +215 -219
  27. package/examples/gallery/paired-bar/paired-bar-chart.json +195 -195
  28. package/examples/horizontal-chart.json +35 -35
  29. package/examples/horizontal-stacked-bar-chart.json +34 -34
  30. package/examples/line-chart.json +75 -75
  31. package/examples/new-data.csv +17 -0
  32. package/examples/newdata.json +90 -0
  33. package/examples/paired-bar-data.json +16 -14
  34. package/examples/paired-bar-example.json +48 -48
  35. package/examples/paired-bar-formatted.json +36 -36
  36. package/examples/planet-chart-horizontal-example-config.json +33 -33
  37. package/examples/planet-combo-example-config.json +34 -31
  38. package/examples/planet-example-config.json +35 -33
  39. package/examples/planet-example-data.json +56 -56
  40. package/examples/planet-pie-example-config.json +28 -28
  41. package/examples/stacked-vertical-bar-example.json +1 -1
  42. package/examples/temp-example-config.json +61 -54
  43. package/examples/temp-example-data.json +1 -1
  44. package/package.json +3 -2
  45. package/src/CdcChart.tsx +449 -434
  46. package/src/components/BarChart.tsx +383 -497
  47. package/src/components/BoxPlot.js +92 -0
  48. package/src/components/DataTable.tsx +182 -197
  49. package/src/components/EditorPanel.js +1068 -722
  50. package/src/components/Filters.js +131 -0
  51. package/src/components/Legend.js +286 -329
  52. package/src/components/LineChart.tsx +143 -81
  53. package/src/components/LinearChart.tsx +432 -451
  54. package/src/components/PairedBarChart.tsx +197 -213
  55. package/src/components/PieChart.tsx +105 -151
  56. package/src/components/SparkLine.js +179 -201
  57. package/src/components/useIntersectionObserver.tsx +19 -20
  58. package/src/context.tsx +3 -3
  59. package/src/data/initial-state.js +44 -17
  60. package/src/hooks/useActiveElement.js +13 -13
  61. package/src/hooks/useChartClasses.js +34 -28
  62. package/src/hooks/useColorPalette.ts +56 -63
  63. package/src/hooks/useLegendClasses.js +18 -10
  64. package/src/hooks/useReduceData.ts +64 -77
  65. package/src/hooks/useRightAxis.js +25 -0
  66. package/src/hooks/useTopAxis.js +6 -0
  67. package/src/index.html +19 -19
  68. package/src/index.tsx +13 -16
  69. package/src/scss/DataTable.scss +6 -5
  70. package/src/scss/editor-panel.scss +71 -69
  71. package/src/scss/main.scss +188 -114
  72. package/src/scss/variables.scss +1 -1
  73. package/examples/private/line-test-data.json +0 -22
  74. package/examples/private/line-test-two.json +0 -216
  75. package/examples/private/line-test.json +0 -102
  76. package/examples/private/newtest.csv +0 -101
  77. package/examples/private/shawn.json +0 -1296
  78. package/examples/private/test.json +0 -10124
  79. package/examples/private/yaxis-testing.csv +0 -27
  80. package/examples/private/yaxis.json +0 -28
@@ -0,0 +1,92 @@
1
+ import React, { useContext, useEffect } from 'react'
2
+ import { BoxPlot } from '@visx/stats'
3
+ import { Group } from '@visx/group'
4
+ import { scaleBand, scaleLinear } from '@visx/scale'
5
+ import Context from '../context'
6
+ import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
7
+ import { colorPalettesChart } from '@cdc/core/data/colorPalettes'
8
+ import ReactTooltip from 'react-tooltip'
9
+
10
+ const CoveBoxPlot = ({ xScale, yScale }) => {
11
+ const { transformedData: data, config } = useContext(Context)
12
+
13
+ const {
14
+ boxplot: { columnFirstQuartile, columnThirdQuartile, columnMax, columnMin, columnMedian, columnOutliers },
15
+ width,
16
+ height
17
+ } = config
18
+
19
+ const yMax = config.height - config.runtime.xAxis.size
20
+ const xMax = config.width - config.runtime.yAxis.size - config.yAxis.rightAxisSize
21
+ const boxWidth = xScale.bandwidth()
22
+ const constrainedWidth = Math.min(20, boxWidth)
23
+ const color_0 = colorPalettesChart[config?.palette][0] ? colorPalettesChart[config?.palette][0] : '#000'
24
+
25
+ // tooltips
26
+ const tooltip_id = `cdc-open-viz-tooltip-${config.runtime.uniqueId}`
27
+ const handleTooltip = d => {
28
+ return `
29
+ <strong>${d.columnCategory}</strong></br>
30
+ Q1: ${d.columnFirstQuartile}<br/>
31
+ Q3: ${d.columnThirdQuartile}<br/>
32
+ IQR: ${d.columnIqr}<br/>
33
+ Median: ${d.columnMedian}
34
+ `
35
+ }
36
+ return (
37
+ <ErrorBoundary component='BoxPlot'>
38
+ <Group className='boxplot' key='boxplot-wrapper'>
39
+ {config.boxplot.map((d, i) => {
40
+ const offset = boxWidth - constrainedWidth
41
+ return (
42
+ <BoxPlot
43
+ key={`box-plot-${i}`}
44
+ min={d.columnMin}
45
+ max={d.columnMax}
46
+ left={xScale(d.columnCategory) + config.yAxis.size + offset / 2 + 0.5}
47
+ firstQuartile={d.columnFirstQuartile}
48
+ thirdQuartile={d.columnThirdQuartile}
49
+ median={d.columnMedian}
50
+ boxWidth={constrainedWidth}
51
+ fill={color_0}
52
+ fillOpacity={0.5}
53
+ stroke='black'
54
+ strokeWidth={1}
55
+ valueScale={yScale}
56
+ outliers={d.columnOutliers}
57
+ outlierProps={{
58
+ style: {
59
+ fill: `${color_0}`,
60
+ opacity: 1
61
+ }
62
+ }}
63
+ medianProps={{
64
+ style: {
65
+ stroke: 'black'
66
+ }
67
+ }}
68
+ boxProps={{
69
+ style: {
70
+ stroke: 'black'
71
+ },
72
+ 'data-tip': 'cool'
73
+ }}
74
+ maxProps={{
75
+ style: {
76
+ stroke: 'black'
77
+ }
78
+ }}
79
+ container
80
+ containerProps={{
81
+ 'data-tip': handleTooltip(d),
82
+ 'data-for': tooltip_id
83
+ }}
84
+ />
85
+ )
86
+ })}
87
+ </Group>
88
+ </ErrorBoundary>
89
+ )
90
+ }
91
+
92
+ export default CoveBoxPlot
@@ -1,244 +1,229 @@
1
- import React, {
2
- useContext,
3
- useEffect,
4
- useState,
5
- useMemo,
6
- memo,
7
- Fragment} from 'react';
8
- import {
9
- useTable,
10
- useSortBy,
11
- useResizeColumns,
12
- useBlockLayout
13
- } from 'react-table';
14
- import Papa from 'papaparse';
15
- import { Base64 } from 'js-base64';
16
-
17
- import ErrorBoundary from '@cdc/core/components/ErrorBoundary';
18
- import LegendCircle from '@cdc/core/components/LegendCircle';
19
-
20
- import Context from '../context';
1
+ import React, { useContext, useEffect, useState, useMemo, memo, Fragment } from 'react'
2
+ import { useTable, useSortBy, useResizeColumns, useBlockLayout } from 'react-table'
3
+ import Papa from 'papaparse'
4
+ import { Base64 } from 'js-base64'
5
+
6
+ import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
7
+ import LegendCircle from '@cdc/core/components/LegendCircle'
8
+
9
+ import Context from '../context'
10
+
11
+ import CoveMediaControls from '@cdc/core/helpers/CoveMediaControls'
21
12
 
22
13
  export default function DataTable() {
23
- const { rawData, transformedData: data, config, colorScale, parseDate, formatDate, formatNumber:numberFormatter, colorPalettes } = useContext<any>(Context);
14
+ const { rawData, transformedData: data, config, colorScale, parseDate, formatDate, formatNumber: numberFormatter, colorPalettes, imageId } = useContext<any>(Context)
24
15
 
25
- const legendGlyphSize = 15;
26
- const legendGlyphSizeHalf = legendGlyphSize / 2;
27
- const section = config.orientation ==='horizontal' ? 'yAxis' :'xAxis';
28
- const [tableExpanded, setTableExpanded] = useState<boolean>(config.table.expanded);
29
- const [accessibilityLabel, setAccessibilityLabel] = useState('');
16
+ // Debugging.
17
+ // if (config.visualizationType === 'Box Plot') return null
30
18
 
31
- const DownloadButton = ({ data }: any) => {
32
- const fileName = `${config.title.substring(0, 50)}.csv`;
19
+ const section = config.orientation === 'horizontal' ? 'yAxis' : 'xAxis'
20
+ const [tableExpanded, setTableExpanded] = useState<boolean>(config.table.expanded)
21
+ const [accessibilityLabel, setAccessibilityLabel] = useState('')
33
22
 
34
- const csvData = Papa.unparse(data);
23
+ const DownloadButton = ({ data }: any, type) => {
24
+ const fileName = `${config.title.substring(0, 50)}.csv`
25
+
26
+ const csvData = Papa.unparse(data)
35
27
 
36
28
  const saveBlob = () => {
37
29
  //@ts-ignore
38
30
  if (typeof window.navigator.msSaveBlob === 'function') {
39
- const dataBlob = new Blob([csvData], { type: "text/csv;charset=utf-8;" });
31
+ const dataBlob = new Blob([csvData], { type: 'text/csv;charset=utf-8;' })
40
32
  //@ts-ignore
41
- window.navigator.msSaveBlob(dataBlob, fileName);
33
+ window.navigator.msSaveBlob(dataBlob, fileName)
42
34
  }
43
35
  }
44
36
 
45
- return (
46
- <a
47
- download={fileName}
48
- onClick={saveBlob}
49
- href={`data:text/csv;base64,${Base64.encode(csvData)}`}
50
- aria-label="Download this data in a CSV file format."
51
- className={`btn btn-download no-border`}
52
- >
53
- Download Data (CSV)
54
- </a>
55
- )
56
- };
57
-
58
- // Creates columns structure for the table
59
- const tableColumns = useMemo(() => {
60
- const newTableColumns = config.visualizationType === 'Pie' ? [] : [{
61
- Header: '',
62
- Cell: ({ row }) => {
63
- const seriesLabel = config.runtime.seriesLabels ? config.runtime.seriesLabels[row.original] : row.original;
37
+ switch (type) {
38
+ case 'download':
64
39
  return (
65
- <Fragment>
66
- {config.visualizationType !== 'Pie' &&
67
- <LegendCircle
68
- fill={
69
- // non dynamic leged
70
- !config.legend.dynamicLegend ? colorScale(seriesLabel)
71
- // dynamic legend
72
- : config.legend.dynamicLegend ? colorPalettes[config.palette][row.index]
73
- // fallback
74
- : '#000'} />}
75
- <span>{seriesLabel}</span>
76
- </Fragment>
40
+ <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`}>
41
+ Download Data (CSV)
42
+ </a>
77
43
  )
78
- },
79
- id: 'series-label'
80
- }];
81
-
82
- data.forEach((d) => {
83
- const newCol = {
84
- Header: config.runtime[section].type === 'date' ? formatDate(parseDate(d[config.runtime.originalXAxis.dataKey])) : d[config.runtime.originalXAxis.dataKey],
85
- Cell: ({ row }) => {
86
- return (
87
- <>
88
- {numberFormatter(d[row.original])}
89
- </>
90
- );
91
- },
92
- id: d[config.runtime.originalXAxis.dataKey],
93
- canSort: true
94
- };
95
-
96
- newTableColumns.push(newCol);
97
- });
44
+ default:
45
+ return (
46
+ <a download={fileName} onClick={saveBlob} href={`data:text/csv;base64,${Base64.encode(csvData)}`} aria-label='Download this data in a CSV file format.' className={`no-border`}>
47
+ Download Data (CSV)
48
+ </a>
49
+ )
50
+ }
51
+ }
98
52
 
99
- return newTableColumns;
100
- }, [config,colorScale]);
53
+ // Creates columns structure for the table
54
+ const tableColumns = useMemo(() => {
55
+ const newTableColumns =
56
+ config.visualizationType === 'Pie'
57
+ ? []
58
+ : [
59
+ {
60
+ Header: '',
61
+ Cell: ({ row }) => {
62
+ const seriesLabel = config.runtime.seriesLabels ? config.runtime.seriesLabels[row.original] : row.original
63
+ return (
64
+ <Fragment>
65
+ {config.visualizationType !== 'Pie' && (
66
+ <LegendCircle
67
+ fill={
68
+ // non dynamic leged
69
+ !config.legend.dynamicLegend
70
+ ? colorScale(seriesLabel)
71
+ : // dynamic legend
72
+ config.legend.dynamicLegend
73
+ ? colorPalettes[config.palette][row.index]
74
+ : // fallback
75
+ '#000'
76
+ }
77
+ />
78
+ )}
79
+ <span>{seriesLabel}</span>
80
+ </Fragment>
81
+ )
82
+ },
83
+ id: 'series-label'
84
+ }
85
+ ]
86
+
87
+ data.forEach((d, index) => {
88
+ const newCol = {
89
+ Header: config.runtime[section].type === 'date' ? formatDate(parseDate(d[config.runtime.originalXAxis.dataKey])) : d[config.runtime.originalXAxis.dataKey],
90
+ Cell: ({ row }) => {
91
+ return <>{numberFormatter(d[row.original])}</>
92
+ },
93
+ id: `${d[config.runtime.originalXAxis.dataKey]}--${index}`,
94
+ canSort: true
95
+ }
101
96
 
97
+ newTableColumns.push(newCol)
98
+ })
102
99
 
100
+ return newTableColumns
101
+ }, [config, colorScale])
103
102
 
104
- const tableData = useMemo(
105
- () => config.visualizationType === 'Pie' ? [config.yAxis.dataKey] : config.runtime.seriesKeys,
106
- [config.runtime.seriesKeys]
107
- );
103
+ const tableData = useMemo(() => (config.visualizationType === 'Pie' ? [config.yAxis.dataKey] : config.runtime.seriesKeys), [config.runtime.seriesKeys])
108
104
 
109
105
  // Change accessibility label depending on expanded status
110
106
  useEffect(() => {
111
- const expandedLabel = 'Accessible data table.';
112
- const collapsedLabel = 'Accessible data table. This table is currently collapsed visually but can still be read using a screen reader.';
107
+ const expandedLabel = 'Accessible data table.'
108
+ const collapsedLabel = 'Accessible data table. This table is currently collapsed visually but can still be read using a screen reader.'
113
109
 
114
110
  if (tableExpanded === true && accessibilityLabel !== expandedLabel) {
115
- setAccessibilityLabel(expandedLabel);
111
+ setAccessibilityLabel(expandedLabel)
116
112
  }
117
113
 
118
114
  if (tableExpanded === false && accessibilityLabel !== collapsedLabel) {
119
- setAccessibilityLabel(collapsedLabel);
115
+ setAccessibilityLabel(collapsedLabel)
120
116
  }
121
117
  // eslint-disable-next-line react-hooks/exhaustive-deps
122
- }, [tableExpanded]);
118
+ }, [tableExpanded])
123
119
 
124
120
  const defaultColumn = useMemo(
125
121
  () => ({
126
122
  minWidth: 150,
127
123
  width: 200,
128
- maxWidth: 400,
124
+ maxWidth: 400
129
125
  }),
130
126
  []
131
- );
132
-
133
- const {
134
- getTableProps,
135
- getTableBodyProps,
136
- headerGroups,
137
- rows,
138
- prepareRow,
139
- } = useTable({ columns: tableColumns, data: tableData, defaultColumn }, useSortBy, useBlockLayout, useResizeColumns);
127
+ )
128
+
129
+ const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable({ columns: tableColumns, data: tableData, defaultColumn }, useSortBy, useBlockLayout, useResizeColumns)
140
130
  return (
141
- <ErrorBoundary component="DataTable">
142
- <section id={config?.title ? `dataTableSection__${config?.title.replace(/\s/g, '')}` : `dataTableSection`} className={`data-table-container`} aria-label={accessibilityLabel}>
143
- <div
144
- role="button"
145
- className={tableExpanded ? 'data-table-heading' : 'collapsed data-table-heading'}
146
- tabIndex={0}
147
- onClick={() => { setTableExpanded(!tableExpanded); }}
148
- onKeyDown={(e) => { if (e.keyCode === 13) { setTableExpanded(!tableExpanded); } }}
149
- >
150
- {config.table.label}
151
- </div>
152
- <div
153
- className="table-container"
154
- hidden={!tableExpanded}
155
- style={ { maxHeight: config.table.limitHeight && `${config.table.height}px`, overflowY: 'scroll' } }
156
- >
157
- <table
158
- className={tableExpanded ? 'data-table' : 'data-table cdcdataviz-sr-only'}
159
- {...getTableProps()}
160
- aria-rowcount={ config?.series?.length ? config?.series?.length : '-1' }
161
- >
162
- <caption className='cdcdataviz-sr-only'>{config.table.caption ? config.table.caption : "" }</caption>
163
- <caption className="visually-hidden">{config.table.label}</caption>
164
- <thead>
165
- {headerGroups.map((headerGroup,index) => (
166
- <tr {...headerGroup.getHeaderGroupProps()} key={`headerGroups--${index}`}>
167
- {headerGroup.headers.map((column, index) => (
168
- <th
169
- tabIndex="0"
170
- title={column.Header}
171
- key={`trth--${index}`}
172
- role="columnheader"
173
- scope="col"
174
- {...column.getHeaderProps(column.getSortByToggleProps())}
175
- className={column.isSorted ? column.isSortedDesc ? 'sort sort-desc' : 'sort sort-asc' : 'sort'}
176
- {...(column.isSorted ? column.isSortedDesc ? { 'aria-sort': 'descending' } : { 'aria-sort': 'ascending' } : null)}
177
- >
178
- {index === 0
179
- ? config.table.indexLabel
180
- ? config.table.indexLabel : column.render('Header')
181
- : column.render('Header')
182
- }
183
- <button>
184
- <span className="cdcdataviz-sr-only">{`Sort by ${typeof column.render('Header') === 'string' ? column.render('Header').toLowerCase() : column.render('Header') } in ${ column.isSorted ? column.isSortedDesc ? 'descending' : 'ascending' : 'no'} `} order</span>
185
- </button>
186
- <div {...column.getResizerProps()} className="resizer" />
187
- </th>
188
- ))}
131
+ <ErrorBoundary component='DataTable'>
132
+ <CoveMediaControls.Section classes={['download-links']}>
133
+ <CoveMediaControls.Link config={config} />
134
+ {config.table.download && <DownloadButton data={rawData} type='link' />}
135
+ </CoveMediaControls.Section>
136
+
137
+ <section id={config?.title ? `dataTableSection__${config?.title.replace(/\s/g, '')}` : `dataTableSection`} className={`data-table-container`} aria-label={accessibilityLabel}>
138
+ <div
139
+ role='button'
140
+ className={tableExpanded ? 'data-table-heading' : 'collapsed data-table-heading'}
141
+ tabIndex={0}
142
+ onClick={() => {
143
+ setTableExpanded(!tableExpanded)
144
+ }}
145
+ onKeyDown={e => {
146
+ if (e.keyCode === 13) {
147
+ setTableExpanded(!tableExpanded)
148
+ }
149
+ }}
150
+ >
151
+ {config.table.label}
152
+ </div>
153
+ <div className='table-container' hidden={!tableExpanded} style={{ maxHeight: config.table.limitHeight && `${config.table.height}px`, overflowY: 'scroll' }}>
154
+ <table className={tableExpanded ? 'data-table' : 'data-table cdcdataviz-sr-only'} {...getTableProps()} aria-rowcount={config?.series?.length ? config?.series?.length : '-1'}>
155
+ <caption className='cdcdataviz-sr-only'>{config.table.caption ? config.table.caption : ''}</caption>
156
+ <caption className='visually-hidden'>{config.table.label}</caption>
157
+ <thead>
158
+ {headerGroups.map((headerGroup, index) => (
159
+ <tr {...headerGroup.getHeaderGroupProps()} key={`headerGroups--${index}`}>
160
+ {headerGroup.headers.map((column, index) => (
161
+ <th
162
+ tabIndex='0'
163
+ title={column.Header}
164
+ key={`trth--${index}`}
165
+ role='columnheader'
166
+ scope='col'
167
+ {...column.getHeaderProps(column.getSortByToggleProps())}
168
+ className={column.isSorted ? (column.isSortedDesc ? 'sort sort-desc' : 'sort sort-asc') : 'sort'}
169
+ {...(column.isSorted ? (column.isSortedDesc ? { 'aria-sort': 'descending' } : { 'aria-sort': 'ascending' }) : null)}
170
+ >
171
+ {index === 0 ? (config.table.indexLabel ? config.table.indexLabel : column.render('Header')) : column.render('Header')}
172
+ <button>
173
+ <span className='cdcdataviz-sr-only'>{`Sort by ${typeof column.render('Header') === 'string' ? column.render('Header').toLowerCase() : column.render('Header')} in ${column.isSorted ? (column.isSortedDesc ? 'descending' : 'ascending') : 'no'} `} order</span>
174
+ </button>
175
+ <div {...column.getResizerProps()} className='resizer' />
176
+ </th>
177
+ ))}
178
+ </tr>
179
+ ))}
180
+ </thead>
181
+ <tbody {...getTableBodyProps()}>
182
+ {rows.map((row, index) => {
183
+ prepareRow(row)
184
+ return (
185
+ <tr {...row.getRowProps()} key={`tbody__tr-${index}`}>
186
+ {row.cells.map((cell, index) => {
187
+ return (
188
+ <td tabIndex='0' {...cell.getCellProps()} key={`tbody__tr__td-${index}`} role='gridcell'>
189
+ {cell.render('Cell')}
190
+ </td>
191
+ )
192
+ })}
189
193
  </tr>
190
- ))}
194
+ )
195
+ })}
196
+ </tbody>
197
+ </table>
198
+ {config.regions && config.regions.length > 0 ? (
199
+ <table className='region-table data-table'>
200
+ <caption className='visually-hidden'>Table of the highlighted regions in the visualization</caption>
201
+ <thead>
202
+ <tr>
203
+ <th>Region Name</th>
204
+ <th>Start Date</th>
205
+ <th>End Date</th>
206
+ </tr>
191
207
  </thead>
192
- <tbody {...getTableBodyProps()}>
193
- {rows.map((row, index) => {
194
- prepareRow(row);
208
+ <tbody>
209
+ {config.regions.map((region, index) => {
210
+ if (!Object.keys(region).includes('from') || !Object.keys(region).includes('to')) return null
211
+
195
212
  return (
196
- <tr {...row.getRowProps()} key={`tbody__tr-${index}`}>
197
- {row.cells.map((cell, index) => {
198
- return (
199
- <td
200
- tabIndex="0"
201
- {...cell.getCellProps()}
202
- key={`tbody__tr__td-${index}`}
203
- role="gridcell">
204
- { cell.render('Cell') }
205
- </td>
206
- )
207
- }
208
- )}
213
+ <tr key={`row-${region.label}--${index}`}>
214
+ <td>{region.label}</td>
215
+ <td>{formatDate(parseDate(region.from))}</td>
216
+ <td>{formatDate(parseDate(region.to))}</td>
209
217
  </tr>
210
- );
218
+ )
211
219
  })}
212
220
  </tbody>
213
221
  </table>
214
- {config.regions && config.regions.length > 0 ? (
215
- <table className="region-table data-table">
216
- <caption className="visually-hidden">Table of the highlighted regions in the visualization</caption>
217
- <thead>
218
- <tr>
219
- <th>Region Name</th>
220
- <th>Start Date</th>
221
- <th>End Date</th>
222
- </tr>
223
- </thead>
224
- <tbody>
225
- {config.regions.map((region,index) => {
226
- if(!Object.keys(region).includes('from') || !Object.keys(region).includes('to')) return null
227
-
228
- return (
229
- <tr key={`row-${region.label}--${index}`}>
230
- <td>{region.label}</td>
231
- <td>{formatDate(parseDate(region.from))}</td>
232
- <td>{formatDate(parseDate(region.to))}</td>
233
- </tr>
234
- )
235
- })}
236
- </tbody>
237
- </table>
238
- ) : ''}
239
- </div>
240
- {config.table.download && <DownloadButton data={rawData} />}
222
+ ) : (
223
+ ''
224
+ )}
225
+ </div>
241
226
  </section>
242
227
  </ErrorBoundary>
243
- );
228
+ )
244
229
  }