@cdc/core 4.24.12-2 → 4.25.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 (63) hide show
  1. package/components/DataTable/DataTable.tsx +26 -36
  2. package/components/DataTable/components/ChartHeader.tsx +3 -2
  3. package/components/DataTable/components/ExpandCollapse.tsx +1 -4
  4. package/components/DataTable/data-table.css +2 -7
  5. package/components/DataTable/helpers/customSort.ts +2 -2
  6. package/components/DataTable/helpers/mapCellMatrix.tsx +83 -60
  7. package/components/DataTable/types/TableConfig.ts +0 -1
  8. package/components/EditorPanel/FootnotesEditor.tsx +49 -7
  9. package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +3 -2
  10. package/components/Filters/Filters.tsx +16 -9
  11. package/components/Footnotes/Footnotes.tsx +1 -1
  12. package/components/Layout/components/Visualization/index.tsx +18 -4
  13. package/components/Layout/components/Visualization/visualizations.scss +1 -1
  14. package/components/Legend/Legend.Gradient.tsx +1 -4
  15. package/components/Legend/index.tsx +1 -1
  16. package/components/LegendShape.tsx +2 -3
  17. package/components/MediaControls.jsx +32 -8
  18. package/components/NestedDropdown/NestedDropdown.tsx +7 -12
  19. package/components/NestedDropdown/nesteddropdown.styles.css +11 -5
  20. package/components/Table/Table.tsx +0 -6
  21. package/components/Table/components/Row.tsx +2 -5
  22. package/components/_stories/DataTable.stories.tsx +1 -2
  23. package/components/elements/Button.jsx +38 -19
  24. package/components/elements/Confirm.tsx +45 -0
  25. package/components/elements/Error.tsx +24 -0
  26. package/components/managers/DataDesigner.tsx +198 -143
  27. package/components/ui/Title/Title.scss +12 -5
  28. package/components/ui/Title/index.tsx +1 -1
  29. package/dist/cove-main.css +77 -591
  30. package/dist/cove-main.css.map +1 -1
  31. package/helpers/DataTransform.ts +55 -63
  32. package/helpers/addValuesToFilters.ts +24 -9
  33. package/helpers/cove/accessibility.ts +24 -0
  34. package/helpers/cove/fontSettings.ts +1 -1
  35. package/helpers/cove/number.ts +1 -7
  36. package/helpers/coveUpdateWorker.ts +5 -1
  37. package/helpers/displayDataAsText.ts +64 -0
  38. package/helpers/formatConfigBeforeSave.ts +1 -1
  39. package/helpers/isOlderVersion.ts +20 -0
  40. package/helpers/missingRequiredSections.ts +20 -0
  41. package/helpers/tests/addValuesToFilters.test.ts +13 -0
  42. package/helpers/useDataVizClasses.ts +8 -4
  43. package/helpers/ver/4.24.11.ts +18 -0
  44. package/helpers/ver/4.25.1.ts +18 -0
  45. package/package.json +2 -2
  46. package/styles/_button-section.scss +2 -5
  47. package/styles/_global-variables.scss +17 -7
  48. package/styles/_global.scss +8 -12
  49. package/styles/_reset.scss +4 -5
  50. package/styles/_typography.scss +0 -20
  51. package/styles/_variables.scss +0 -3
  52. package/styles/base.scss +44 -5
  53. package/styles/cove-main.scss +1 -1
  54. package/styles/filters.scss +5 -6
  55. package/styles/v2/base/_general.scss +3 -2
  56. package/styles/v2/components/button.scss +0 -1
  57. package/styles/v2/main.scss +3 -4
  58. package/styles/v2/utils/index.scss +0 -1
  59. package/types/BoxPlot.ts +1 -0
  60. package/types/Runtime.ts +1 -0
  61. package/types/Table.ts +0 -1
  62. package/types/Version.ts +1 -1
  63. package/styles/v2/utils/_spacers.scss +0 -31
@@ -30,7 +30,7 @@ export type DataTableProps = {
30
30
  columns?: Record<string, Column>
31
31
  config: TableConfig
32
32
  dataConfig?: Object
33
- displayDataAsText?: Function
33
+ defaultSortBy?: string
34
34
  displayGeoName?: Function
35
35
  expandDataTable: boolean
36
36
  formatLegendLocation?: Function
@@ -59,6 +59,7 @@ const DataTable = (props: DataTableProps) => {
59
59
  const {
60
60
  config,
61
61
  dataConfig,
62
+ defaultSortBy,
62
63
  tableTitle,
63
64
  vizTitle,
64
65
  rawData,
@@ -88,9 +89,8 @@ const DataTable = (props: DataTableProps) => {
88
89
  }, [parentRuntimeData, config.table.pivot?.columnName, config.table.pivot?.valueColumn])
89
90
 
90
91
  const [expanded, setExpanded] = useState(expandDataTable)
91
-
92
92
  const [sortBy, setSortBy] = useState<any>({
93
- column: '',
93
+ column: defaultSortBy || '',
94
94
  asc: false,
95
95
  colIndex: null
96
96
  })
@@ -207,6 +207,24 @@ const DataTable = (props: DataTableProps) => {
207
207
  [config.runtime?.seriesKeys]) // eslint-disable-line
208
208
 
209
209
  const hasNoData = runtimeData.length === 0
210
+
211
+ const getClassNames = (): string => {
212
+ const classes = ['data-table-container']
213
+
214
+ if (config.table.showDownloadLinkBelow) {
215
+ classes.push('mt-4')
216
+ }
217
+
218
+ const isBrushActive = config?.brush?.active && config.legend?.position !== 'bottom'
219
+ if (isBrushActive) {
220
+ classes.push('brush-active')
221
+ }
222
+
223
+ classes.push(viewport)
224
+
225
+ return classes.join(' ')
226
+ }
227
+
210
228
  if (config.visualizationType !== 'Box Plot') {
211
229
  const getDownloadData = () => {
212
230
  // only use fullGeoName on County maps and no other
@@ -221,11 +239,12 @@ const DataTable = (props: DataTableProps) => {
221
239
  const getMediaControlsClasses = belowTable => {
222
240
  const classes = ['download-links']
223
241
  if (!belowTable) {
242
+ classes.push('mt-4', 'mb-2')
224
243
  const isLegendOnBottom = config?.legend?.position === 'bottom' || isLegendWrapViewport(viewport)
225
244
  if (config.brush?.active && !isLegendOnBottom) classes.push('brush-active')
226
245
  if (config.brush?.active && config.legend.hide) classes.push('brush-active')
227
246
  } else {
228
- classes.push('below-table')
247
+ classes.push('mt-2')
229
248
  }
230
249
  return classes
231
250
  }
@@ -244,23 +263,6 @@ const DataTable = (props: DataTableProps) => {
244
263
  </MediaControls.Section>
245
264
  )
246
265
  }
247
- const getClassNames = (): string => {
248
- const classes = ['data-table-container']
249
- const isBrushActive = config?.brush?.active && config.legend?.position !== 'bottom'
250
-
251
- if (isBrushActive) {
252
- classes.push('brush-active')
253
- }
254
-
255
- classes.push(viewport)
256
-
257
- const downloadLinkClass = !config.table.showDownloadLinkBelow ? 'download-link-above' : ''
258
- if (downloadLinkClass) {
259
- classes.push(downloadLinkClass)
260
- }
261
-
262
- return classes.join(' ')
263
- }
264
266
 
265
267
  return (
266
268
  <ErrorBoundary component='DataTable'>
@@ -268,13 +270,7 @@ const DataTable = (props: DataTableProps) => {
268
270
  <section id={tabbingId.replace('#', '')} className={getClassNames()} aria-label={accessibilityLabel}>
269
271
  <SkipTo skipId={skipId} skipMessage='Skip Data Table' />
270
272
  {config.table.collapsible !== false && (
271
- <ExpandCollapse
272
- expanded={expanded}
273
- setExpanded={setExpanded}
274
- fontSize={config.fontSize}
275
- tableTitle={tableTitle}
276
- viewport={viewport}
277
- />
273
+ <ExpandCollapse expanded={expanded} setExpanded={setExpanded} tableTitle={tableTitle} viewport={viewport} />
278
274
  )}
279
275
  <div className='table-container' style={limitHeight}>
280
276
  <Table
@@ -302,6 +298,7 @@ const DataTable = (props: DataTableProps) => {
302
298
  isVertical={isVertical}
303
299
  sortBy={sortBy}
304
300
  setSortBy={setSortBy}
301
+ viewport={viewport}
305
302
  />
306
303
  )
307
304
  }
@@ -313,7 +310,6 @@ const DataTable = (props: DataTableProps) => {
313
310
  'aria-rowcount': config?.data?.length ? config.data.length : -1,
314
311
  hidden: !expanded
315
312
  }}
316
- fontSize={config.fontSize}
317
313
  />
318
314
 
319
315
  {/* REGION Data Table */}
@@ -336,7 +332,6 @@ const DataTable = (props: DataTableProps) => {
336
332
  </tr>
337
333
  }
338
334
  tableOptions={{ className: 'table table-striped region-table data-table' }}
339
- fontSize={config.fontSize}
340
335
  />
341
336
  )}
342
337
  </div>
@@ -351,11 +346,7 @@ const DataTable = (props: DataTableProps) => {
351
346
  // Render Data Table for Box Plots
352
347
  return (
353
348
  <ErrorBoundary component='DataTable'>
354
- <section
355
- id={tabbingId.replace('#', '')}
356
- className={`data-table-container ${viewport}`}
357
- aria-label={accessibilityLabel}
358
- >
349
+ <section id={tabbingId.replace('#', '')} className={getClassNames()} aria-label={accessibilityLabel}>
359
350
  <SkipTo skipId={skipId} skipMessage='Skip Data Table' />
360
351
  <ExpandCollapse expanded={expanded} setExpanded={setExpanded} tableTitle={tableTitle} />
361
352
  <div className='table-container' style={limitHeight}>
@@ -374,7 +365,6 @@ const DataTable = (props: DataTableProps) => {
374
365
  'aria-rowcount': 11,
375
366
  hidden: !expanded
376
367
  }}
377
- fontSize={config.fontSize}
378
368
  />
379
369
  </div>
380
370
  </section>
@@ -5,9 +5,9 @@ import ScreenReaderText from '@cdc/core/components/elements/ScreenReaderText'
5
5
  import { SortIcon } from './SortIcon'
6
6
  import { getNewSortBy } from '../helpers/getNewSortBy'
7
7
 
8
- type ChartHeaderProps = { data; isVertical; config; setSortBy; sortBy; hasRowType? }
8
+ type ChartHeaderProps = { data; isVertical; config; setSortBy; sortBy; hasRowType?; viewport }
9
9
 
10
- const ChartHeader = ({ data, isVertical, config, setSortBy, sortBy, hasRowType }: ChartHeaderProps) => {
10
+ const ChartHeader = ({ data, isVertical, config, setSortBy, sortBy, hasRowType, viewport }: ChartHeaderProps) => {
11
11
  const groupBy = config.table?.groupBy
12
12
  if (!data) return
13
13
  let dataSeriesColumns = getDataSeriesColumns(config, isVertical, data)
@@ -69,6 +69,7 @@ const ChartHeader = ({ data, isVertical, config, setSortBy, sortBy, hasRowType }
69
69
  const text = getSeriesName(column, config)
70
70
  const newSortBy = getNewSortBy(sortBy, column, index)
71
71
  const sortByAsc = sortBy.column === column ? sortBy.asc : undefined
72
+
72
73
  return (
73
74
  <th
74
75
  style={{ minWidth: (config.table.cellMinWidth || 0) + 'px' }}
@@ -1,13 +1,10 @@
1
1
  import Icon from '../../ui/Icon'
2
- import { fontSizes } from '../../../helpers/cove/fontSettings'
3
2
 
4
3
  const ExpandCollapse = ({ expanded, setExpanded, tableTitle, fontSize, viewport }) => {
5
- const titleFontSize = ['xs', 'xxs'].includes(viewport) ? '13px' : `${fontSizes[fontSize]}px`
6
4
  return (
7
5
  <div
8
- style={{ fontSize: titleFontSize }}
9
6
  role='button'
10
- className={expanded ? 'data-table-heading' : 'collapsed data-table-heading'}
7
+ className={expanded ? 'data-table-heading p-3' : 'collapsed data-table-heading p-3'}
11
8
  onClick={() => {
12
9
  setExpanded(!expanded)
13
10
  }}
@@ -15,9 +15,8 @@
15
15
 
16
16
  .cdc-open-viz-module div.data-table-heading {
17
17
  position: relative;
18
- background: rgba(0, 0, 0, 0.05);
19
- padding: 0.5em 0.7em;
20
- border: var(--lightGray) 1px solid;
18
+ border: var(--cool-gray-10) 1px solid;
19
+ border-radius: 6px;
21
20
 
22
21
  svg {
23
22
  position: absolute;
@@ -31,9 +30,6 @@
31
30
  z-index: 2;
32
31
  position: relative;
33
32
  }
34
- @media (max-width: var(--breakpoint-sm)) {
35
- font-size: var(--font-small) + 0.2em;
36
- }
37
33
  }
38
34
 
39
35
  table.horizontal {
@@ -127,7 +123,6 @@ table.data-table {
127
123
  &:last-child {
128
124
  border-right: 0 !important;
129
125
  }
130
- font-size: var(--font-size);
131
126
  }
132
127
 
133
128
  td {
@@ -25,11 +25,11 @@ export const customSort = (a, b, sortBy, config) => {
25
25
  const trimmedA = String(valueA).trim()
26
26
  const trimmedB = String(valueB).trim()
27
27
 
28
- if (config.xAxis?.dataKey === sortBy.column && config.xAxis.type === 'date') {
28
+ if (config.xAxis?.dataKey === sortBy.column && ['date', 'date-time'].includes(config.xAxis.type)) {
29
29
  const dateA = parseDate(config.xAxis.dateParseFormat, trimmedA)?.getTime()
30
30
 
31
31
  const dateB = parseDate(config.xAxis.dateParseFormat, trimmedB)?.getTime()
32
- console.log(dateA, dateB)
32
+
33
33
  return sortBy.asc ? dateA - dateB : dateB - dateA
34
34
  }
35
35
  // Check if values are numbers
@@ -1,60 +1,83 @@
1
- import LegendShape from '@cdc/core/components/LegendShape'
2
- import CellAnchor from '../components/CellAnchor'
3
- import { DataTableProps } from '../DataTable'
4
- import { ReactNode } from 'react'
5
-
6
- type MapRowsProps = DataTableProps & {
7
- rows: string[]
8
- }
9
-
10
- const mapCellArray = ({ rows, columns, runtimeData, config, applyLegendToRow, displayGeoName, formatLegendLocation, displayDataAsText, navigationHandler, setFilteredCountryCode }: MapRowsProps): ReactNode[][] => {
11
- return rows.map(row =>
12
- Object.keys(columns)
13
- .filter(column => columns[column].dataTable === true && columns[column].name)
14
- .map(column => {
15
- let cellValue
16
-
17
- if (column === 'geo') {
18
- const rowObj = runtimeData[row]
19
- const legendColor = applyLegendToRow(rowObj)
20
-
21
- let labelValue
22
- const mapZoomHandler = config.general.type === 'bubble' && config.general.allowMapZoom && config.general.geoType === 'world' ? () => setFilteredCountryCode(row) : undefined
23
- if ((config.general.geoType !== 'single-state' && config.general.geoType !== 'us-county') || config.general.type === 'us-geocode') {
24
- const capitalize = str => {
25
- return str.charAt(0).toUpperCase() + str.slice(1)
26
- }
27
- labelValue = displayGeoName(row)
28
- labelValue = String(labelValue).startsWith('region') ? capitalize(labelValue) : labelValue
29
- } else {
30
- labelValue = formatLegendLocation(row)
31
- }
32
- cellValue = (
33
- <div className='col-12'>
34
- <LegendShape fill={legendColor[0]} />
35
- <CellAnchor markup={labelValue} row={rowObj} columns={columns} navigationHandler={navigationHandler} mapZoomHandler={mapZoomHandler} />
36
- </div>
37
- )
38
- } else {
39
- // check for special classes
40
- let specialValFound = ''
41
- let columnName = config.columns[column].name
42
- const { specialClasses } = config.legend
43
- if (specialClasses && specialClasses.length && typeof specialClasses[0] === 'object') {
44
- specialClasses.forEach(specialClass => {
45
- if (specialClass.key === columnName) {
46
- if (String(runtimeData[row][specialClass.key]) === specialClass.value) {
47
- specialValFound = specialClass.label
48
- }
49
- }
50
- })
51
- }
52
- cellValue = displayDataAsText(specialValFound || runtimeData[row][columnName], column)
53
- }
54
-
55
- return cellValue
56
- })
57
- )
58
- }
59
-
60
- export default mapCellArray
1
+ import LegendShape from '@cdc/core/components/LegendShape'
2
+ import CellAnchor from '../components/CellAnchor'
3
+ import { DataTableProps } from '../DataTable'
4
+ import { ReactNode } from 'react'
5
+ import { displayDataAsText } from '@cdc/core/helpers/displayDataAsText'
6
+
7
+ type MapRowsProps = DataTableProps & {
8
+ rows: string[]
9
+ }
10
+
11
+ const mapCellArray = ({
12
+ rows,
13
+ columns,
14
+ runtimeData,
15
+ config,
16
+ applyLegendToRow,
17
+ displayGeoName,
18
+ formatLegendLocation,
19
+ navigationHandler,
20
+ setFilteredCountryCode
21
+ }: MapRowsProps): ReactNode[][] => {
22
+ return rows.map(row =>
23
+ Object.keys(columns)
24
+ .filter(column => columns[column].dataTable === true && columns[column].name)
25
+ .map(column => {
26
+ let cellValue
27
+
28
+ if (column === 'geo') {
29
+ const rowObj = runtimeData[row]
30
+ const legendColor = applyLegendToRow(rowObj)
31
+
32
+ let labelValue
33
+ const mapZoomHandler =
34
+ config.general.type === 'bubble' && config.general.allowMapZoom && config.general.geoType === 'world'
35
+ ? () => setFilteredCountryCode(row)
36
+ : undefined
37
+ if (
38
+ (config.general.geoType !== 'single-state' && config.general.geoType !== 'us-county') ||
39
+ config.general.type === 'us-geocode'
40
+ ) {
41
+ const capitalize = str => {
42
+ return str.charAt(0).toUpperCase() + str.slice(1)
43
+ }
44
+ labelValue = displayGeoName(row)
45
+ labelValue = String(labelValue).startsWith('region') ? capitalize(labelValue) : labelValue
46
+ } else {
47
+ labelValue = formatLegendLocation(row)
48
+ }
49
+ cellValue = (
50
+ <div className='col-12'>
51
+ <LegendShape fill={legendColor[0]} />
52
+ <CellAnchor
53
+ markup={labelValue}
54
+ row={rowObj}
55
+ columns={columns}
56
+ navigationHandler={navigationHandler}
57
+ mapZoomHandler={mapZoomHandler}
58
+ />
59
+ </div>
60
+ )
61
+ } else {
62
+ // check for special classes
63
+ let specialValFound = ''
64
+ let columnName = config.columns[column].name
65
+ const { specialClasses } = config.legend
66
+ if (specialClasses && specialClasses.length && typeof specialClasses[0] === 'object') {
67
+ specialClasses.forEach(specialClass => {
68
+ if (specialClass.key === columnName) {
69
+ if (String(runtimeData[row][specialClass.key]) === specialClass.value) {
70
+ specialValFound = specialClass.label
71
+ }
72
+ }
73
+ })
74
+ }
75
+ cellValue = displayDataAsText(specialValFound || runtimeData[row][columnName], column, config)
76
+ }
77
+
78
+ return cellValue
79
+ })
80
+ )
81
+ }
82
+
83
+ export default mapCellArray
@@ -7,7 +7,6 @@ import { Visualization } from '../../../types/Visualization'
7
7
 
8
8
  export type TableConfig = Visualization & {
9
9
  boxplot?: BoxPlot
10
- fontSize: 'small' | 'medium' | 'large'
11
10
  regions?: Region[]
12
11
  runtime?: Runtime
13
12
  runtimeSeriesLabels?: Object
@@ -39,13 +39,40 @@ const FootnotesEditor: React.FC<FootnotesEditorProps> = ({ config, updateField }
39
39
  <>
40
40
  <em>Dynamic Footnotes</em>
41
41
  <div className='row border p-2'>
42
- <InputSelect label='Select a Footnote Dataset' value={config.dataKey} options={dataSetOptions} fieldName='dataKey' updateField={updateField} />
42
+ <InputSelect
43
+ label='Select a Footnote Dataset'
44
+ value={config.dataKey}
45
+ options={dataSetOptions}
46
+ fieldName='dataKey'
47
+ updateField={updateField}
48
+ />
43
49
 
44
50
  {config.dataKey && (
45
51
  <div className='p-3'>
46
- <InputSelect label='Footnote Symbol Column' value={config.dynamicFootnotes?.symbolColumn} options={dataColumns} section='dynamicFootnotes' fieldName='symbolColumn' updateField={updateField} />
47
- <InputSelect label='Footnote Text Column' value={config.dynamicFootnotes?.textColumn} options={dataColumns} section='dynamicFootnotes' fieldName='textColumn' updateField={updateField} />
48
- <InputSelect label='Footnote Order Column' value={config.dynamicFootnotes?.orderColumn} options={dataColumns} section='dynamicFootnotes' fieldName='orderColumn' updateField={updateField} />
52
+ <InputSelect
53
+ label='Footnote Symbol Column'
54
+ value={config.dynamicFootnotes?.symbolColumn}
55
+ options={dataColumns}
56
+ section='dynamicFootnotes'
57
+ fieldName='symbolColumn'
58
+ updateField={updateField}
59
+ />
60
+ <InputSelect
61
+ label='Footnote Text Column'
62
+ value={config.dynamicFootnotes?.textColumn}
63
+ options={dataColumns}
64
+ section='dynamicFootnotes'
65
+ fieldName='textColumn'
66
+ updateField={updateField}
67
+ />
68
+ <InputSelect
69
+ label='Footnote Order Column'
70
+ value={config.dynamicFootnotes?.orderColumn}
71
+ options={dataColumns}
72
+ section='dynamicFootnotes'
73
+ fieldName='orderColumn'
74
+ updateField={updateField}
75
+ />
49
76
  </div>
50
77
  )}
51
78
  </div>
@@ -57,10 +84,25 @@ const FootnotesEditor: React.FC<FootnotesEditorProps> = ({ config, updateField }
57
84
  {config.staticFootnotes?.map((note, index) => (
58
85
  <div key={index} className='row border p-2'>
59
86
  <div className='col-8'>
60
- <InputSelect label='Symbol' value={note.symbol} options={[['', '--Select--'], ...footnotesSymbols]} fieldName='symbol' updateField={(section, subsection, fieldName, value) => updateStaticFootnote(index, { ...note, symbol: value })} />{' '}
61
- <TextField label='Text' value={note.text} fieldName='text' updateField={(section, subsection, fieldName, value) => updateStaticFootnote(index, { ...note, text: value })} />
87
+ <InputSelect
88
+ label='Symbol'
89
+ value={note.symbol}
90
+ options={[['', '--Select--'], ...footnotesSymbols]}
91
+ fieldName='symbol'
92
+ updateField={(section, subsection, fieldName, value) =>
93
+ updateStaticFootnote(index, { ...note, symbol: value })
94
+ }
95
+ />{' '}
96
+ <TextField
97
+ label='Text'
98
+ value={note.text}
99
+ fieldName='text'
100
+ updateField={(section, subsection, fieldName, value) =>
101
+ updateStaticFootnote(index, { ...note, text: value })
102
+ }
103
+ />
62
104
  </div>
63
- <div className='col-2 ml-4'>
105
+ <div className='col-2 ms-4'>
64
106
  <button className='btn btn-danger p-1' onClick={() => deleteStaticFootnote(index)}>
65
107
  Delete
66
108
  </button>
@@ -230,9 +230,10 @@ const VizFilterEditor: React.FC<VizFilterProps> = ({ config, updateField, rawDat
230
230
  value={filter.order || 'asc'}
231
231
  fieldName='order'
232
232
  label='Filter Order'
233
- updateField={(_section, _subSection, _field, value) =>
233
+ updateField={(_section, _subSection, _field, value) => {
234
234
  updateFilterProp('order', filterIndex, value)
235
- }
235
+ if (filter.orderColumn && value !== 'column') updateFilterProp('orderColumn', filterIndex, '')
236
+ }}
236
237
  options={filterOrderOptions}
237
238
  />
238
239
  {filter.order === 'cust' && (
@@ -101,11 +101,11 @@ export const useFilters = props => {
101
101
  const changeFilterActive = (index, value) => {
102
102
  let newFilters = standaloneMap ? [...filteredData] : [...visualizationConfig.filters]
103
103
 
104
+ const newFilter = newFilters[index]
104
105
  if (visualizationConfig.filterBehavior === 'Apply Button') {
105
- newFilters[index].queuedActive = value
106
+ newFilter.queuedActive = value
106
107
  setShowApplyButton(true)
107
108
  } else {
108
- const newFilter = newFilters[index]
109
109
  if (newFilter.filterStyle !== 'nested-dropdown') {
110
110
  newFilter.active = value
111
111
  } else {
@@ -436,16 +436,23 @@ const Filters = (props: FilterProps) => {
436
436
 
437
437
  const classList = [
438
438
  'single-filters',
439
- 'form-group mr-3',
439
+ 'form-group',
440
440
  mobileFilterStyle ? 'single-filters--dropdown' : `single-filters--${filterStyle}`
441
441
  ]
442
442
  const mobileExempt = ['nested-dropdown', 'multi-select'].includes(filterStyle)
443
443
  const showDefaultDropdown = (filterStyle === 'dropdown' || mobileFilterStyle) && !mobileExempt
444
+ const [nestedActiveGroup, nestedActiveSubGroup] = useMemo<string[]>(() => {
445
+ if (filterStyle !== 'nested-dropdown') return []
446
+ return (singleFilter.queuedActive || [singleFilter.active, singleFilter.subGrouping?.active]) as [
447
+ string,
448
+ string
449
+ ]
450
+ }, [singleFilter])
444
451
  return (
445
452
  <div className={classList.join(' ')} key={outerIndex}>
446
453
  <>
447
454
  {label && (
448
- <label className='font-weight-bold mt-1 mb-0' htmlFor={`filter-${outerIndex}`}>
455
+ <label className='font-weight-bold mb-2' htmlFor={`filter-${outerIndex}`}>
449
456
  {label}
450
457
  </label>
451
458
  )}
@@ -463,8 +470,8 @@ const Filters = (props: FilterProps) => {
463
470
  )}
464
471
  {filterStyle === 'nested-dropdown' && (
465
472
  <NestedDropdown
466
- activeGroup={(singleFilter.active as string) || (singleFilter.queuedActive || [])[0]}
467
- activeSubGroup={(singleFilter.subGrouping?.active as string) || (singleFilter.queuedActive || [])[1]}
473
+ activeGroup={nestedActiveGroup}
474
+ activeSubGroup={nestedActiveSubGroup}
468
475
  filterIndex={outerIndex}
469
476
  options={getNestedOptions(singleFilter)}
470
477
  listLabel={label}
@@ -494,15 +501,15 @@ const Filters = (props: FilterProps) => {
494
501
  const conditionalClass = standaloneMap ? general.headerColor : visualizationType === 'Spark Line' ? null : theme
495
502
  const legendClass = legend && !legend.hide && legend.position === 'top' ? 'mb-0' : null
496
503
 
497
- return [baseClass, conditionalClass, legendClass].filter(Boolean)
504
+ return [baseClass, conditionalClass, legendClass, 'w-100'].filter(Boolean)
498
505
  }
499
506
 
500
507
  return (
501
508
  <section className={getClasses().join(' ')}>
502
509
  {visualizationConfig.filterIntro && (
503
- <p className='filters-section__intro-text'>{visualizationConfig.filterIntro}</p>
510
+ <p className='filters-section__intro-text mb-3'>{visualizationConfig.filterIntro}</p>
504
511
  )}
505
- <div className='d-flex flex-wrap w-100 filters-section__wrapper'>
512
+ <div className='d-flex flex-wrap w-100 mb-4 pb-2 filters-section__wrapper'>
506
513
  {' '}
507
514
  <>
508
515
  <Style />
@@ -12,7 +12,7 @@ const Footnotes: React.FC<FootnotesProps> = ({ footnotes }) => {
12
12
  {footnotes.map((note, i) => {
13
13
  return (
14
14
  <li key={note.symbol + i} className='mb-1'>
15
- {note.symbol && <span className='mr-1'>{note.symbol}</span>}
15
+ {note.symbol && <span className='me-1'>{note.symbol}</span>}
16
16
  {note.text}
17
17
  </li>
18
18
  )
@@ -17,10 +17,17 @@ type VisualizationWrapper = {
17
17
  }
18
18
 
19
19
  const Visualization: React.FC<VisualizationWrapper> = forwardRef((props, ref) => {
20
- const { config = {}, isEditor = false, currentViewport = 'lg', imageId = '', showEditorPanel = true, className } = props
20
+ const {
21
+ config = {},
22
+ isEditor = false,
23
+ currentViewport = 'lg',
24
+ imageId = '',
25
+ showEditorPanel = true,
26
+ className
27
+ } = props
21
28
 
22
29
  const getWrappingClasses = () => {
23
- let classes = ['cdc-open-viz-module', `${currentViewport}`, `font-${config?.fontSize}`, `${config?.theme}`]
30
+ let classes = ['cdc-open-viz-module', `${currentViewport}`, `${config?.theme}`]
24
31
 
25
32
  if (className) {
26
33
  classes.push(className)
@@ -40,7 +47,7 @@ const Visualization: React.FC<VisualizationWrapper> = forwardRef((props, ref) =>
40
47
  }
41
48
 
42
49
  if (config.type === 'filtered-text') {
43
- classes.push('type-filtered-text')
50
+ classes.push('type-filtered-text', `font-${config.fontSize}`)
44
51
  classes = classes.filter(item => item !== 'cove-component__content')
45
52
  return classes
46
53
  }
@@ -67,7 +74,14 @@ const Visualization: React.FC<VisualizationWrapper> = forwardRef((props, ref) =>
67
74
  }
68
75
 
69
76
  if (config.type === 'waffle-chart') {
70
- classes.push('cove', 'cdc-open-viz-module', 'type-waffle-chart', currentViewport, config.theme, 'font-' + config.overallFontSize)
77
+ classes.push(
78
+ 'cove',
79
+ 'cdc-open-viz-module',
80
+ 'type-waffle-chart',
81
+ currentViewport,
82
+ config.theme,
83
+ 'font-' + config.overallFontSize
84
+ )
71
85
 
72
86
  if (isEditor) {
73
87
  classes.push('is-editor')
@@ -1,6 +1,6 @@
1
1
  .cdc-open-viz-module {
2
2
  .cdc-chart-inner-container .cove-component__content {
3
- padding: 25px 15px 25px 0 !important;
3
+ padding: 0 15px 27px 0 !important;
4
4
  }
5
5
  &.isEditor {
6
6
  overflow: auto;
@@ -92,10 +92,7 @@ const LegendGradient = ({
92
92
 
93
93
  if (style === 'gradient') {
94
94
  return (
95
- <svg
96
- style={{ overflow: 'visible', width: '100%', marginTop: 10, marginBottom: hideBorder ? 10 : 0 }}
97
- height={newHeight}
98
- >
95
+ <svg className={'w-100 overflow-visible'} height={newHeight}>
99
96
  {/* background border*/}
100
97
  <rect x={0} y={0} width={legendWidth + MARGIN * 2} height={boxHeight + MARGIN * 2} fill='#d3d3d3' />
101
98
  {/* Define the gradient */}
@@ -28,7 +28,7 @@ const ResetButton = props => {
28
28
  if (config.runtime.disabledAmt === 0) return <></>
29
29
 
30
30
  return (
31
- <button onClick={handleReset} className={legendClasses.resetButton.join(' ') || ''}>
31
+ <button onClick={handleReset} className={legendClasses.showAllButton.join(' ') || ''}>
32
32
  Reset
33
33
  </button>
34
34
  )
@@ -10,9 +10,8 @@ interface LegendShapeProps {
10
10
  const LegendShape: React.FC<LegendShapeProps> = props => {
11
11
  const { fill, borderColor, display = 'inline-block', shape = 'circle' } = props
12
12
  const dimensions = { width: '1em', height: '1em' }
13
- const marginRight = ['circle', 'square'].includes(shape) ? '5px' : '0'
13
+ const isCircleOrSquare = ['circle', 'square'].includes(shape)
14
14
  const styles = {
15
- marginRight: marginRight,
16
15
  borderRadius: shape === 'circle' ? '50%' : '0px',
17
16
  verticalAlign: 'middle',
18
17
  display: display,
@@ -22,7 +21,7 @@ const LegendShape: React.FC<LegendShapeProps> = props => {
22
21
  backgroundColor: fill
23
22
  }
24
23
 
25
- return <span className='legend-item' style={styles} />
24
+ return <span className={`legend-item ${isCircleOrSquare ? 'me-2' : ''}`} style={styles} />
26
25
  }
27
26
 
28
27
  export default LegendShape