@cdc/core 4.24.2 → 4.24.4

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 (84) hide show
  1. package/assets/icon-command.svg +3 -0
  2. package/assets/icon-rotate-left.svg +3 -0
  3. package/assets/icon-sankey.svg +1 -0
  4. package/assets/icon-table.svg +1 -0
  5. package/components/AdvancedEditor.jsx +9 -0
  6. package/components/DataTable/DataTable.tsx +37 -13
  7. package/components/DataTable/DataTableStandAlone.tsx +15 -0
  8. package/components/DataTable/components/CellAnchor.tsx +3 -1
  9. package/components/DataTable/components/ChartHeader.tsx +48 -12
  10. package/components/DataTable/components/DataTableEditorPanel.tsx +42 -0
  11. package/components/DataTable/components/ExpandCollapse.tsx +22 -16
  12. package/components/DataTable/components/MapHeader.tsx +10 -5
  13. package/components/DataTable/helpers/chartCellMatrix.tsx +2 -2
  14. package/components/DataTable/helpers/customColumns.ts +4 -2
  15. package/components/DataTable/helpers/getChartCellValue.ts +4 -2
  16. package/components/DataTable/helpers/getDataSeriesColumns.ts +9 -1
  17. package/components/DataTable/helpers/mapCellMatrix.tsx +2 -2
  18. package/components/DataTable/types/TableConfig.ts +7 -7
  19. package/components/EditorPanel/ColumnsEditor.tsx +312 -0
  20. package/components/EditorPanel/DataTableEditor.tsx +42 -27
  21. package/components/Filters.jsx +35 -17
  22. package/components/Layout/components/Responsive.tsx +184 -0
  23. package/components/Layout/components/Sidebar/components/Sidebar.tsx +47 -0
  24. package/components/Layout/components/Sidebar/components/sidebar.styles.scss +902 -0
  25. package/components/Layout/components/Sidebar/index.tsx +3 -0
  26. package/components/Layout/components/Visualization/index.tsx +79 -0
  27. package/components/Layout/components/Visualization/visualizations.scss +33 -0
  28. package/components/Layout/index.tsx +11 -0
  29. package/components/Layout/styles/editor-grid-view.scss +156 -0
  30. package/components/Layout/styles/editor-utils.scss +197 -0
  31. package/components/Layout/styles/editor.scss +144 -0
  32. package/components/LegendCircle.jsx +4 -3
  33. package/components/MediaControls.jsx +1 -1
  34. package/components/MultiSelect/MultiSelect.tsx +39 -20
  35. package/components/MultiSelect/multiselect.styles.css +44 -27
  36. package/components/NestedDropdown/NestedDropdown.tsx +257 -0
  37. package/components/NestedDropdown/index.ts +1 -0
  38. package/components/NestedDropdown/nesteddropdown.styles.css +70 -0
  39. package/components/Table/Table.tsx +8 -6
  40. package/components/Table/components/Row.tsx +6 -2
  41. package/components/Table/types/RowType.ts +3 -0
  42. package/components/Waiting.jsx +11 -1
  43. package/components/_stories/MultiSelect.stories.tsx +10 -1
  44. package/components/_stories/NestedDropdown.stories.tsx +58 -0
  45. package/components/_stories/styles.scss +1 -0
  46. package/components/createBarElement.jsx +120 -0
  47. package/components/elements/ScreenReaderText.tsx +8 -0
  48. package/components/elements/SkipTo.tsx +46 -0
  49. package/components/managers/DataDesigner.tsx +18 -18
  50. package/components/ui/Icon.tsx +9 -1
  51. package/components/ui/Title/Title.scss +7 -1
  52. package/components/ui/Title/index.tsx +3 -3
  53. package/components/ui/Tooltip.jsx +1 -1
  54. package/data/colorPalettes.js +1 -6
  55. package/helpers/cove/accessibility.ts +23 -0
  56. package/helpers/cove/date.ts +19 -0
  57. package/helpers/{coveUpdateWorker.js → coveUpdateWorker.ts} +9 -5
  58. package/helpers/isDomainExternal.js +14 -0
  59. package/helpers/queryStringUtils.js +26 -0
  60. package/helpers/tests/updateFieldFactory.test.ts +89 -0
  61. package/helpers/updateFieldFactory.ts +38 -0
  62. package/helpers/useDataVizClasses.js +7 -7
  63. package/helpers/ver/4.24.3.ts +56 -0
  64. package/package.json +4 -3
  65. package/styles/_data-table.scss +8 -13
  66. package/styles/_global.scss +7 -4
  67. package/styles/_variables.scss +3 -0
  68. package/styles/base.scss +4 -14
  69. package/styles/v2/base/index.scss +1 -1
  70. package/styles/v2/components/ui/tooltip.scss +0 -21
  71. package/types/Axis.ts +3 -0
  72. package/types/BaseVisualizationType.ts +1 -0
  73. package/types/ConfidenceInterval.ts +1 -0
  74. package/types/ConfigureData.ts +8 -0
  75. package/types/DataDescription.ts +9 -0
  76. package/types/Legend.ts +18 -0
  77. package/types/Region.ts +10 -0
  78. package/types/Runtime.ts +2 -0
  79. package/types/Table.ts +2 -1
  80. package/types/UpdateFieldFunc.ts +1 -1
  81. package/types/Visualization.ts +19 -10
  82. package/components/DataTable/components/SkipNav.tsx +0 -7
  83. package/helpers/cove/date.js +0 -9
  84. package/helpers/ver/4.23.js +0 -10
@@ -0,0 +1,312 @@
1
+ import { AccordionItem, AccordionItemButton, AccordionItemHeading, AccordionItemPanel } from 'react-accessible-accordion'
2
+ import Tooltip from '../ui/Tooltip'
3
+ import Icon from '../ui/Icon'
4
+ import { TextField } from './Inputs'
5
+ import { Visualization } from '../../types/Visualization'
6
+ import { UpdateFieldFunc } from '../../types/UpdateFieldFunc'
7
+ import { Column } from '../../types/Column'
8
+ import _ from 'lodash'
9
+
10
+ interface ColumnsEditorProps {
11
+ config: Visualization
12
+ updateField: UpdateFieldFunc<string | boolean | string[] | number | Column>
13
+ deleteColumn: (colName: string) => void
14
+ }
15
+
16
+ const ColumnsEditor: React.FC<ColumnsEditorProps> = ({ config, updateField, deleteColumn }) => {
17
+ const additionalColumns = Object.keys(config.columns).filter(value => {
18
+ const dataKey = config.xAxis?.dataKey
19
+ const defaultCols = dataKey ? [dataKey] : []
20
+
21
+ if (true === defaultCols.includes(value)) {
22
+ return false
23
+ }
24
+ return true
25
+ })
26
+
27
+ const editColumn = (addCol, columnName, setval) => {
28
+ updateField('columns', addCol, columnName, setval)
29
+ }
30
+
31
+ // just adds a new column but not set to any data yet
32
+ const addAdditionalColumn = number => {
33
+ const columnKey = `additionalColumn${number}`
34
+ const showInViz = config.type === 'table'
35
+ const newColumn: Column = {
36
+ label: 'New Column',
37
+ dataTable: showInViz,
38
+ tooltips: false,
39
+ prefix: '',
40
+ suffix: '',
41
+ forestPlot: false,
42
+ startingPoint: '0',
43
+ forestPlotAlignRight: false,
44
+ roundToPlace: 0,
45
+ commas: false,
46
+ showInViz: false,
47
+ forestPlotStartingPoint: 0
48
+ }
49
+
50
+ updateField('columns', null, columnKey, newColumn)
51
+ }
52
+
53
+ const getColumns = () => {
54
+ const columns: string[] = config.data.flatMap(row => {
55
+ return Object.keys(row).map(columnName => columnName)
56
+ })
57
+
58
+ const { lower, upper } = config.confidenceKeys || {}
59
+ return _.uniq(columns).filter(key => {
60
+ const keyIsPresentInSeries = config.series?.filter(series => series.dataKey === key).length > 0
61
+ if (keyIsPresentInSeries || (config.confidenceKeys && Object.keys(config.confidenceKeys).includes(key) && (lower || upper) && key !== lower && key !== upper)) {
62
+ return false
63
+ }
64
+ return true
65
+ })
66
+ }
67
+
68
+ return (
69
+ <AccordionItem>
70
+ <AccordionItemHeading>
71
+ <AccordionItemButton>Columns</AccordionItemButton>
72
+ </AccordionItemHeading>
73
+ <AccordionItemPanel>
74
+ {'navigation' !== config.type && (
75
+ <fieldset className='primary-fieldset edit-block'>
76
+ <label>
77
+ <span className='edit-label'>
78
+ Configurations
79
+ <Tooltip style={{ textTransform: 'none' }}>
80
+ <Tooltip.Target>
81
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
82
+ </Tooltip.Target>
83
+ <Tooltip.Content>
84
+ <p>You can specify additional columns to display in tooltips and / or the supporting data table.</p>
85
+ </Tooltip.Content>
86
+ </Tooltip>
87
+ </span>
88
+ </label>
89
+ {additionalColumns.map(val => (
90
+ <fieldset className='edit-block' key={val}>
91
+ <button
92
+ className='remove-column'
93
+ onClick={event => {
94
+ event.preventDefault()
95
+ deleteColumn(val)
96
+ }}
97
+ >
98
+ Remove
99
+ </button>
100
+ <label>
101
+ <span className='edit-label column-heading'>Column</span>
102
+ <select
103
+ value={config.columns[val] ? config.columns[val].name : undefined}
104
+ onChange={event => {
105
+ editColumn(val, 'name', event.target.value)
106
+ }}
107
+ >
108
+ {['-Select-', ...getColumns()].map(option => (
109
+ <option>{option}</option>
110
+ ))}
111
+ </select>
112
+ </label>
113
+ {config.type !== 'table' && (
114
+ <label>
115
+ <span className='edit-label column-heading'>Associate to Series</span>
116
+ <select
117
+ value={config.columns[val] ? config.columns[val].series : ''}
118
+ onChange={event => {
119
+ editColumn(val, 'series', event.target.value)
120
+ }}
121
+ >
122
+ <option value=''>Select series</option>
123
+ {(config.series || []).map(series => (
124
+ <option>{series.dataKey}</option>
125
+ ))}
126
+ </select>
127
+ </label>
128
+ )}
129
+
130
+ <TextField value={config.columns[val].label} section='columns' subsection={val} fieldName='label' label='Label' updateField={updateField} />
131
+ <ul className='column-edit'>
132
+ <li className='three-col'>
133
+ <TextField value={config.columns[val].prefix} section='columns' subsection={val} fieldName='prefix' label='Prefix' updateField={updateField} />
134
+ <TextField value={config.columns[val].suffix} section='columns' subsection={val} fieldName='suffix' label='Suffix' updateField={updateField} />
135
+ <TextField type='number' value={config.columns[val].roundToPlace} section='columns' subsection={val} fieldName='roundToPlace' label='Round' updateField={updateField} />
136
+ </li>
137
+ <li>
138
+ <label className='checkbox'>
139
+ <input
140
+ type='checkbox'
141
+ checked={config.columns[val].commas}
142
+ onChange={event => {
143
+ editColumn(val, 'commas', event.target.checked)
144
+ }}
145
+ />
146
+ <span className='edit-label'>Add Commas to Numbers</span>
147
+ </label>
148
+ </li>
149
+ {config.type !== 'table' && (
150
+ <li>
151
+ {config.table.showVertical && (
152
+ <label className='checkbox'>
153
+ <input
154
+ type='checkbox'
155
+ checked={config.columns[val].dataTable}
156
+ onChange={event => {
157
+ editColumn(val, 'dataTable', event.target.checked)
158
+ }}
159
+ />
160
+ <span className='edit-label'>Show in Data Table</span>
161
+ </label>
162
+ )}
163
+ </li>
164
+ )}
165
+ {config.visualizationType === 'Pie' && (
166
+ <li>
167
+ <label className='checkbox'>
168
+ <input
169
+ type='checkbox'
170
+ checked={config.columns[val].showInViz}
171
+ onChange={event => {
172
+ editColumn(val, 'showInViz', event.target.checked)
173
+ }}
174
+ />
175
+ <span className='edit-label'>Show in Visualization</span>
176
+ </label>
177
+ </li>
178
+ )}
179
+ {config.type !== 'table' && (
180
+ <li>
181
+ <label className='checkbox'>
182
+ <input
183
+ type='checkbox'
184
+ checked={config.columns[val].tooltips || false}
185
+ onChange={event => {
186
+ updateField('columns', val, 'tooltips', event.target.checked)
187
+ }}
188
+ />
189
+ <span className='edit-label'>Show in tooltip</span>
190
+ </label>
191
+ </li>
192
+ )}
193
+
194
+ {config.visualizationType === 'Forest Plot' && (
195
+ <>
196
+ <li>
197
+ <label className='checkbox'>
198
+ <input
199
+ type='checkbox'
200
+ checked={config.columns[val].forestPlot || false}
201
+ onChange={event => {
202
+ editColumn(val, 'forestPlot', event.target.checked)
203
+ }}
204
+ />
205
+ <span className='edit-label'>Show in Forest Plot</span>
206
+ </label>
207
+ </li>
208
+ <li>
209
+ <label className='checkbox'>
210
+ <input
211
+ type='checkbox'
212
+ checked={config.columns[val].forestPlotAlignRight || false}
213
+ onChange={event => {
214
+ editColumn(val, 'forestPlotAlignRight', event.target.checked)
215
+ }}
216
+ />
217
+ <span className='edit-label'>Align Right</span>
218
+ </label>
219
+ </li>
220
+
221
+ {!config.columns[val].forestPlotAlignRight && (
222
+ <li>
223
+ <label className='text'>
224
+ <span className='edit-label'>Forest Plot Starting Point</span>
225
+ <input
226
+ type='number'
227
+ value={config.columns[val].forestPlotStartingPoint || 0}
228
+ onChange={event => {
229
+ editColumn(val, 'forestPlotStartingPoint', event.target.value)
230
+ }}
231
+ />
232
+ </label>
233
+ </li>
234
+ )}
235
+ </>
236
+ )}
237
+ </ul>
238
+ </fieldset>
239
+ ))}
240
+ <button
241
+ className={'btn full-width'}
242
+ onClick={event => {
243
+ event.preventDefault()
244
+ addAdditionalColumn(additionalColumns.length + 1)
245
+ }}
246
+ >
247
+ Add Column Configuration
248
+ </button>
249
+ </fieldset>
250
+ )}
251
+ {'category' === config.legend?.type && (
252
+ <fieldset className='primary-fieldset edit-block'>
253
+ <label>
254
+ <span className='edit-label'>
255
+ Additional Category
256
+ <Tooltip style={{ textTransform: 'none' }}>
257
+ <Tooltip.Target>
258
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
259
+ </Tooltip.Target>
260
+ <Tooltip.Content>
261
+ <p>You can provide additional categories to ensure they appear in the legend</p>
262
+ </Tooltip.Content>
263
+ </Tooltip>
264
+ </span>
265
+ </label>
266
+ {config.legend.additionalCategories &&
267
+ config.legend.additionalCategories.map((val, i) => (
268
+ <fieldset className='edit-block' key={val}>
269
+ <button
270
+ className='remove-column'
271
+ onClick={event => {
272
+ event.preventDefault()
273
+ const updatedAdditionaCategories = [...config.legend.additionalCategories]
274
+ updatedAdditionaCategories.splice(i, 1)
275
+ updateField('legend', null, 'additionalCategories', updatedAdditionaCategories)
276
+ }}
277
+ >
278
+ Remove
279
+ </button>
280
+ <TextField
281
+ value={val}
282
+ label='Category'
283
+ section='legend'
284
+ subsection={null}
285
+ fieldName='additionalCategories'
286
+ updateField={(section, subsection, fieldName, value) => {
287
+ const updatedAdditionaCategories = [...config.legend.additionalCategories]
288
+ updatedAdditionaCategories[i] = value
289
+ updateField(section, subsection, fieldName, updatedAdditionaCategories)
290
+ }}
291
+ />
292
+ </fieldset>
293
+ ))}
294
+ <button
295
+ className={'btn full-width'}
296
+ onClick={event => {
297
+ event.preventDefault()
298
+ const updatedAdditionaCategories = [...(config.legend.additionalCategories || [])]
299
+ updatedAdditionaCategories.push('')
300
+ updateField('legend', null, 'additionalCategories', updatedAdditionaCategories)
301
+ }}
302
+ >
303
+ Add Category
304
+ </button>
305
+ </fieldset>
306
+ )}
307
+ </AccordionItemPanel>
308
+ </AccordionItem>
309
+ )
310
+ }
311
+
312
+ export default ColumnsEditor
@@ -5,26 +5,24 @@ import { CheckBox, TextField } from './Inputs'
5
5
  import type { Table } from '@cdc/core/types/Table'
6
6
  import MultiSelect from '../MultiSelect'
7
7
  import { UpdateFieldFunc } from '../../types/UpdateFieldFunc'
8
+ import { Visualization } from '../../types/Visualization'
8
9
 
9
10
  interface DataTableProps {
10
- config: {
11
- table: Table
12
- visualizationType: string
13
- }
11
+ config: Visualization
14
12
  updateField: UpdateFieldFunc<string | boolean | string[] | number>
15
13
  isDashboard: boolean
16
- isLoadedFromUrl: boolean
17
14
  columns: string[]
18
15
  }
19
16
 
20
- const DataTable: React.FC<DataTableProps> = ({ config, updateField, isDashboard, isLoadedFromUrl, columns }) => {
17
+ const DataTable: React.FC<DataTableProps> = ({ config, updateField, isDashboard, columns }) => {
18
+ const isLoadedFromUrl = config.dataKey?.includes('http://') || config?.dataKey?.includes('https://')
21
19
  return (
22
20
  <>
23
21
  <TextField
24
22
  value={config.table.label}
25
23
  updateField={updateField}
26
24
  section='table'
27
- fieldName='table-label'
25
+ fieldName='label'
28
26
  id='tableLabel'
29
27
  label='Data Table Title'
30
28
  placeholder='Data Table'
@@ -77,51 +75,68 @@ const DataTable: React.FC<DataTableProps> = ({ config, updateField, isDashboard,
77
75
  }
78
76
  />
79
77
  )}
80
- <TextField value={config.table.indexLabel} section='table' fieldName='indexLabel' label='Index Column Header' updateField={updateField} />
81
78
  <TextField
82
- value={config.table.caption}
83
- updateField={updateField}
79
+ value={config.table.indexLabel}
84
80
  section='table'
85
- type='textarea'
86
- fieldName='caption'
87
- label='Screen Reader Description'
88
- placeholder=' Data table'
81
+ fieldName='indexLabel'
82
+ label='Index Column Header'
83
+ updateField={updateField}
89
84
  tooltip={
90
85
  <Tooltip style={{ textTransform: 'none' }}>
91
86
  <Tooltip.Target>
92
87
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
93
88
  </Tooltip.Target>
94
89
  <Tooltip.Content>
95
- <p>Enter a description of the data table to be read by screen readers.</p>
90
+ <p>To comply with 508 standards, if the first column in the data table has no header, enter a brief one here.</p>
96
91
  </Tooltip.Content>
97
92
  </Tooltip>
98
93
  }
99
94
  />
100
- <CheckBox value={config.table.limitHeight} section='table' fieldName='limitHeight' label='Limit Table Height' updateField={updateField} />
101
- <CheckBox
102
- value={config.table.customTableConfig}
103
- fieldName='customTableConfig'
104
- label='Customize Table Config'
105
- section='table'
95
+ <TextField
96
+ value={config.table.caption}
106
97
  updateField={updateField}
98
+ section='table'
99
+ type='textarea'
100
+ fieldName='caption'
101
+ label='Screen Reader Description'
102
+ placeholder=' Data table'
107
103
  tooltip={
108
104
  <Tooltip style={{ textTransform: 'none' }}>
109
105
  <Tooltip.Target>
110
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
106
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
111
107
  </Tooltip.Target>
112
108
  <Tooltip.Content>
113
- <p>This will display all available columns in the data set. It will not show any columns where all of the column cells are null.</p>
109
+ <p>Enter a description of the data table to be read by screen readers.</p>
114
110
  </Tooltip.Content>
115
111
  </Tooltip>
116
112
  }
117
113
  />
114
+ <CheckBox value={config.table.limitHeight} section='table' fieldName='limitHeight' label='Limit Table Height' updateField={updateField} />
115
+ {config.type !== 'table' && (
116
+ <CheckBox
117
+ value={config.table.customTableConfig}
118
+ fieldName='customTableConfig'
119
+ label='Customize Table Config'
120
+ section='table'
121
+ updateField={updateField}
122
+ tooltip={
123
+ <Tooltip style={{ textTransform: 'none' }}>
124
+ <Tooltip.Target>
125
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
126
+ </Tooltip.Target>
127
+ <Tooltip.Content>
128
+ <p>This will display all available columns in the data set. It will not show any columns where all of the column cells are null.</p>
129
+ </Tooltip.Content>
130
+ </Tooltip>
131
+ }
132
+ />
133
+ )}
118
134
  {config.table.customTableConfig && <MultiSelect options={columns.map(c => ({ label: c, value: c }))} fieldName='excludeColumns' label='Exclude Columns' section='table' updateField={updateField} />}
119
- {config.table.limitHeight && <TextField value={config.table.height} fieldName='height' label='Data Table Height' type='number' min={0} max={500} placeholder='Height(px)' updateField={updateField} />}
135
+ {config.table.limitHeight && <TextField value={config.table.height} section='table' fieldName='height' label='Data Table Height' type='number' min={0} max={500} placeholder='Height(px)' updateField={updateField} />}
120
136
  <CheckBox value={config.table.expanded} fieldName='expanded' label='Expanded by Default' section='table' updateField={updateField} />
121
- {isDashboard && <CheckBox value={config.table.showDataTableLink} fieldName='showDataTableLink' label='Show Data Table Name & Link' section='table' updateField={updateField} />}
137
+ {isDashboard && config.type !== 'table' && <CheckBox value={config.table.showDataTableLink} fieldName='showDataTableLink' label='Show Data Table Name & Link' section='table' updateField={updateField} />}
122
138
  {isLoadedFromUrl && <CheckBox value={config.table.showDownloadUrl} fieldName='showDownloadUrl' label='Show URL to Automatically Updated Data' section='table' updateField={updateField} />}
123
- <CheckBox value={config.table.download} fieldName='download' label='Show Download CSV Link' section='table' updateField={updateField} />
124
- <CheckBox value={config.table.showDownloadImgButton} fieldName='showDownloadImgButton' label='Display Image Button' section='table' updateField={updateField} />
139
+ {config.type !== 'table' && <CheckBox value={config.table.showDownloadImgButton} fieldName='showDownloadImgButton' label='Display Image Button' section='table' updateField={updateField} />}
125
140
  <label>
126
141
  <span className='edit-label column-heading'>Table Cell Min Width</span>
127
142
  <input type='number' value={config.table.cellMinWidth ? config.table.cellMinWidth : 0} onChange={e => updateField('table', null, 'cellMinWidth', e.target.value)} />
@@ -3,6 +3,7 @@ import { useId } from 'react'
3
3
 
4
4
  // CDC
5
5
  import Button from '@cdc/core/components/elements/Button'
6
+ import { getQueryParams, updateQueryString } from '@cdc/core/helpers/queryStringUtils'
6
7
 
7
8
  // Third Party
8
9
  import PropTypes from 'prop-types'
@@ -72,19 +73,26 @@ export const useFilters = props => {
72
73
  const announceChange = text => {}
73
74
 
74
75
  const changeFilterActive = (index, value) => {
75
- let newFilters = visualizationConfig.type === 'map' ? [...filteredData] : [...visualizationConfig.filters]
76
+ const newFilters = visualizationConfig.type === 'map' ? [...filteredData] : [...visualizationConfig.filters]
76
77
 
77
78
  if (visualizationConfig.filterBehavior === 'Apply Button') {
78
79
  newFilters[index].queuedActive = value
79
80
  setShowApplyButton(true)
80
81
  } else {
81
- newFilters[index].active = value
82
+ const newFilter = newFilters[index]
83
+ newFilter.active = value
84
+
85
+ const queryParams = getQueryParams()
86
+ if (newFilter.setByQueryParameter && queryParams[newFilter.setByQueryParameter] !== newFilter.active) {
87
+ queryParams[newFilter.setByQueryParameter] = newFilter.active
88
+ updateQueryString(queryParams)
89
+ }
82
90
  }
83
- setConfig({
91
+ setConfig({
84
92
  ...visualizationConfig,
85
- filters: newFilters
93
+ filters: newFilters
86
94
  })
87
-
95
+
88
96
  // Used for setting active filter, fromHash breaks the filteredData functionality.
89
97
  if (visualizationConfig.type === 'map' && visualizationConfig.filterBehavior === 'Filter Change') {
90
98
  setFilteredData(newFilters)
@@ -97,13 +105,22 @@ export const useFilters = props => {
97
105
  }
98
106
 
99
107
  const handleApplyButton = newFilters => {
108
+ let needsQueryUpdate = false
109
+ const queryParams = getQueryParams()
100
110
  newFilters.forEach(newFilter => {
101
- if(newFilter.queuedActive){
111
+ if (newFilter.queuedActive) {
102
112
  newFilter.active = newFilter.queuedActive
103
113
  delete newFilter.queuedActive
114
+ if (newFilter.setByQueryParameter && queryParams[newFilter.setByQueryParameter] !== newFilter.active) {
115
+ queryParams[newFilter.setByQueryParameter] = newFilter.active
116
+ needsQueryUpdate = true
117
+ }
104
118
  }
105
119
  })
106
-
120
+ if (needsQueryUpdate) {
121
+ updateQueryString(queryParams)
122
+ }
123
+
107
124
  setConfig({ ...visualizationConfig, filters: newFilters })
108
125
 
109
126
  if (type === 'map') {
@@ -221,17 +238,18 @@ const Filters = props => {
221
238
 
222
239
  const Filters = props => props.children
223
240
 
224
- const filterSectionClassList = ['filters-section', type === 'map' ? general.headerColor : theme]
225
-
241
+ const filterSectionClassList = ['filters-section', type === 'map' ? general.headerColor : visualizationConfig?.visualizationType === 'Spark Line' ? null : theme]
226
242
  // Exterior Section Wrapper
227
243
  Filters.Section = props => {
228
244
  return (
229
- <section className={filterSectionClassList.join(' ')}>
230
- <p className='filters-section__intro-text'>
231
- {filterConstants.introText} {visualizationConfig.filterBehavior === 'Apply Button' && filterConstants.applyText}
232
- </p>
233
- <div className='filters-section__wrapper'>{props.children}</div>
234
- </section>
245
+ visualizationConfig?.filters && (
246
+ <section className={filterSectionClassList.join(' ')}>
247
+ <p className='filters-section__intro-text'>
248
+ {filters?.some(f => f.active) ? filterConstants.introText : ''} {visualizationConfig.filterBehavior === 'Apply Button' && filterConstants.applyText}
249
+ </p>
250
+ <div className='filters-section__wrapper'>{props.children}</div>
251
+ </section>
252
+ )
235
253
  )
236
254
  }
237
255
 
@@ -291,7 +309,7 @@ const Filters = props => {
291
309
  <select
292
310
  id={`filter-${outerIndex}`}
293
311
  name={label}
294
- aria-label={label}
312
+ aria-label={`Filter by ${label}`}
295
313
  className='filter-select'
296
314
  data-index='0'
297
315
  value={active}
@@ -353,7 +371,7 @@ const Filters = props => {
353
371
  )
354
372
 
355
373
  values.push(
356
- <option key={index} value={filterOption}>
374
+ <option key={index} value={filterOption} aria-label={filterOption}>
357
375
  {singleFilter.labels && singleFilter.labels[filterOption] ? singleFilter.labels[filterOption] : filterOption}
358
376
  </option>
359
377
  )