@cdc/core 4.24.9 → 4.24.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.
Files changed (106) hide show
  1. package/LICENSE +201 -0
  2. package/assets/icon-combo-chart.svg +1 -0
  3. package/assets/icon-epi-chart.svg +27 -0
  4. package/components/AdvancedEditor/AdvancedEditor.tsx +17 -13
  5. package/components/Alert/components/Alert.tsx +34 -8
  6. package/components/BlurStrokeText.tsx +44 -0
  7. package/components/DataTable/DataTable.tsx +62 -36
  8. package/components/DataTable/DataTableStandAlone.tsx +37 -6
  9. package/components/DataTable/components/ChartHeader.tsx +31 -26
  10. package/components/DataTable/components/MapHeader.tsx +19 -10
  11. package/components/DataTable/components/SortIcon/index.tsx +25 -0
  12. package/components/DataTable/components/SortIcon/sort-icon.css +21 -0
  13. package/{styles/_data-table.scss → components/DataTable/data-table.css} +250 -298
  14. package/components/DataTable/helpers/boxplotCellMatrix.tsx +14 -13
  15. package/components/DataTable/helpers/customSort.ts +11 -15
  16. package/components/DataTable/helpers/getChartCellValue.ts +23 -5
  17. package/components/DataTable/helpers/getDataSeriesColumns.ts +5 -1
  18. package/components/DataTable/helpers/getNewSortBy.ts +35 -0
  19. package/components/DataTable/helpers/tests/customSort.test.ts +52 -0
  20. package/components/DataTable/helpers/tests/getNewSortBy.test.ts +26 -0
  21. package/components/EditorPanel/ColumnsEditor.tsx +81 -36
  22. package/components/EditorPanel/DataTableEditor.tsx +149 -43
  23. package/components/EditorPanel/FieldSetWrapper.tsx +2 -2
  24. package/components/EditorPanel/Inputs.tsx +68 -20
  25. package/components/EditorPanel/VizFilterEditor/NestedDropdownEditor.tsx +25 -7
  26. package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +30 -55
  27. package/components/{Filters.tsx → Filters/Filters.tsx} +60 -43
  28. package/components/Filters/helpers/applyQueuedActive.ts +12 -0
  29. package/components/Filters/helpers/getNestedOptions.ts +29 -0
  30. package/components/Filters/helpers/handleSorting.ts +18 -0
  31. package/components/Filters/helpers/tests/applyQueuedActive.test.ts +49 -0
  32. package/components/Filters/helpers/tests/getNestedOptions.test.ts +93 -0
  33. package/components/Filters/helpers/tests/handleSorting.test.ts +68 -0
  34. package/components/Filters/index.ts +5 -0
  35. package/components/Layout/components/Sidebar/components/sidebar.styles.scss +1 -7
  36. package/components/Layout/components/Visualization/visualizations.scss +1 -1
  37. package/components/Legend/Legend.Gradient.tsx +44 -36
  38. package/components/Loader/Loader.tsx +33 -0
  39. package/components/Loader/index.ts +1 -0
  40. package/components/Loader/loader.styles.css +13 -0
  41. package/components/MultiSelect/MultiSelect.tsx +85 -62
  42. package/components/MultiSelect/multiselect.styles.css +10 -7
  43. package/components/NestedDropdown/NestedDropdown.tsx +118 -56
  44. package/components/NestedDropdown/nestedDropdownHelpers.ts +34 -0
  45. package/components/NestedDropdown/nesteddropdown.styles.css +22 -13
  46. package/components/NestedDropdown/tests/nestedDropdownHelpers.test.ts +58 -0
  47. package/components/Table/Table.tsx +102 -34
  48. package/components/Table/components/GroupRow.tsx +1 -1
  49. package/components/_stories/BlurStrokeTest.stories.tsx +27 -0
  50. package/components/_stories/DataTable.stories.tsx +14 -0
  51. package/components/_stories/Filters.stories.tsx +57 -0
  52. package/components/_stories/NestedDropdown.stories.tsx +22 -46
  53. package/components/_stories/_mocks/DataTable/no-data.json +108 -0
  54. package/components/_stories/_mocks/nested-dropdown.json +30 -0
  55. package/components/_stories/styles.scss +0 -1
  56. package/components/ui/Icon.tsx +19 -6
  57. package/components/ui/{Tooltip.jsx → Tooltip.tsx} +38 -14
  58. package/data/colorPalettes.js +107 -10
  59. package/dist/cove-main.css +6080 -0
  60. package/dist/cove-main.css.map +1 -0
  61. package/helpers/DataTransform.ts +2 -1
  62. package/helpers/addValuesToFilters.ts +8 -3
  63. package/helpers/cove/{number.js → number.ts} +62 -27
  64. package/helpers/coveUpdateWorker.ts +6 -7
  65. package/helpers/fetchRemoteData.js +32 -37
  66. package/helpers/formatConfigBeforeSave.ts +17 -1
  67. package/helpers/gatherQueryParams.ts +12 -2
  68. package/helpers/pivotData.ts +52 -11
  69. package/helpers/queryStringUtils.ts +6 -0
  70. package/helpers/tests/gatherQueryParams.test.ts +34 -0
  71. package/helpers/tests/pivotData.test.ts +50 -0
  72. package/helpers/useDataVizClasses.ts +42 -20
  73. package/helpers/ver/4.24.10.ts +47 -0
  74. package/helpers/ver/4.24.9.ts +0 -3
  75. package/helpers/ver/tests/4.24.10.test.ts +45 -0
  76. package/helpers/viewports.ts +9 -0
  77. package/package.json +7 -3
  78. package/styles/_button-section.scss +5 -1
  79. package/styles/_global-variables.scss +20 -2
  80. package/styles/_global.scss +22 -30
  81. package/styles/_reset.scss +2 -26
  82. package/styles/base.scss +0 -1
  83. package/styles/cove-main.scss +6 -0
  84. package/styles/filters.scss +6 -26
  85. package/styles/v2/base/_reset.scss +0 -7
  86. package/styles/v2/components/editor.scss +0 -4
  87. package/styles/v2/components/icon.scss +1 -1
  88. package/styles/v2/components/ui/tooltip.scss +42 -40
  89. package/styles/v2/layout/_component.scss +0 -6
  90. package/styles/v2/layout/index.scss +0 -1
  91. package/types/Axis.ts +4 -0
  92. package/types/BoxPlot.ts +5 -3
  93. package/types/Color.ts +1 -1
  94. package/types/General.ts +1 -0
  95. package/types/Legend.ts +1 -2
  96. package/types/MarkupInclude.ts +1 -0
  97. package/types/Runtime.ts +3 -1
  98. package/types/Series.ts +8 -1
  99. package/types/Table.ts +3 -2
  100. package/types/Visualization.ts +19 -8
  101. package/types/VizFilter.ts +2 -1
  102. package/components/DataTable/components/Icons.tsx +0 -10
  103. package/components/_stories/EditorPanel.stories.tsx +0 -54
  104. package/components/_stories/Layout.Debug.stories.tsx +0 -91
  105. package/components/ui/Select.jsx +0 -30
  106. package/helpers/getGradientLegendWidth.ts +0 -15
@@ -15,25 +15,56 @@ type StandAloneProps = {
15
15
  updateConfig?: (Visualization) => void
16
16
  }
17
17
 
18
- const DataTableStandAlone: React.FC<StandAloneProps> = ({ visualizationKey, config, updateConfig, viewport, isEditor }) => {
19
- const [filteredData, setFilteredData] = useState<Record<string, any>[]>(filterVizData(config.filters, config.formattedData))
18
+ const DataTableStandAlone: React.FC<StandAloneProps> = ({
19
+ visualizationKey,
20
+ config,
21
+ updateConfig,
22
+ viewport,
23
+ isEditor
24
+ }) => {
25
+ const [filteredData, setFilteredData] = useState<Record<string, any>[]>(
26
+ filterVizData(config.filters, config.formattedData || config.data)
27
+ )
20
28
 
21
29
  useEffect(() => {
22
30
  // when using editor changes to filter should update the data
23
- setFilteredData(filterVizData(config.filters, config?.formattedData?.length > 0 ? config.formattedData : config.data))
31
+ setFilteredData(
32
+ filterVizData(config.filters, config?.formattedData?.length > 0 ? config.formattedData : config.data)
33
+ )
24
34
  }, [config.filters])
25
35
 
26
36
  if (isEditor)
27
37
  return (
28
- <EditorWrapper component={DataTableStandAlone} visualizationKey={visualizationKey} visualizationConfig={config} updateConfig={updateConfig} type={'Table'} viewport={viewport}>
38
+ <EditorWrapper
39
+ component={DataTableStandAlone}
40
+ visualizationKey={visualizationKey}
41
+ visualizationConfig={config}
42
+ updateConfig={updateConfig}
43
+ type={'Table'}
44
+ viewport={viewport}
45
+ >
29
46
  <DataTableEditorPanel key={visualizationKey} config={config} updateConfig={updateConfig} />
30
47
  </EditorWrapper>
31
48
  )
32
49
 
33
50
  return (
34
51
  <>
35
- <Filters config={config} setConfig={updateConfig} setFilteredData={setFilteredData} filteredData={filteredData} excludedData={config.formattedData} />
36
- <DataTable expandDataTable={true} config={config} rawData={config.data} runtimeData={filteredData} tabbingId={visualizationKey} tableTitle={config.table.label} viewport={viewport || 'lg'} />
52
+ <Filters
53
+ config={config}
54
+ setConfig={updateConfig}
55
+ setFilteredData={setFilteredData}
56
+ filteredData={filteredData}
57
+ excludedData={config.formattedData}
58
+ />
59
+ <DataTable
60
+ expandDataTable={config.table.expanded}
61
+ config={config}
62
+ rawData={config.data}
63
+ runtimeData={filteredData}
64
+ tabbingId={visualizationKey}
65
+ tableTitle={config.table.label}
66
+ viewport={viewport || 'lg'}
67
+ />
37
68
  </>
38
69
  )
39
70
  }
@@ -1,8 +1,9 @@
1
1
  import { getChartCellValue } from '../helpers/getChartCellValue'
2
2
  import { getSeriesName } from '../helpers/getSeriesName'
3
3
  import { getDataSeriesColumns } from '../helpers/getDataSeriesColumns'
4
- import { DownIcon, UpIcon } from './Icons'
5
4
  import ScreenReaderText from '@cdc/core/components/elements/ScreenReaderText'
5
+ import { SortIcon } from './SortIcon'
6
+ import { getNewSortBy } from '../helpers/getNewSortBy'
6
7
 
7
8
  type ChartHeaderProps = { data; isVertical; config; setSortBy; sortBy; hasRowType? }
8
9
 
@@ -19,17 +20,6 @@ const ChartHeader = ({ data, isVertical, config, setSortBy, sortBy, hasRowType }
19
20
  }
20
21
  }
21
22
 
22
- const handleHeaderClasses = (sortBy, text) => {
23
- let classes = ['sort']
24
- if (sortBy.column === text && sortBy.asc) {
25
- classes.push('sort-asc')
26
- }
27
- if (sortBy.column === text && sortBy.desc) {
28
- classes.push('sort-desc')
29
- }
30
- return classes.join(' ')
31
- }
32
-
33
23
  const ScreenReaderSortByText = ({ text, config, sortBy }) => {
34
24
  const notApplicableText = 'Not Applicable'
35
25
  let columnHeaderText = `${text} `
@@ -47,13 +37,19 @@ const ChartHeader = ({ data, isVertical, config, setSortBy, sortBy, hasRowType }
47
37
 
48
38
  if (columnHeaderText === notApplicableText) return
49
39
 
50
- return <span className='cdcdataviz-sr-only'>{`Press command, modifier, or enter key to sort by ${columnHeaderText} in ${sortBy.column !== columnHeaderText ? 'ascending' : sortBy.column === 'desc' ? 'descending' : 'ascending'} order`}</span>
40
+ return (
41
+ <span className='cdcdataviz-sr-only'>{`Press command, modifier, or enter key to sort by ${columnHeaderText} in ${
42
+ sortBy.column !== columnHeaderText ? 'ascending' : sortBy.column === 'desc' ? 'descending' : 'ascending'
43
+ } order`}</span>
44
+ )
51
45
  }
52
46
 
53
47
  const ColumnHeadingText = ({ column, text, config }) => {
48
+ if (text === 'pivotColumn') return ''
54
49
  let notApplicableText = 'Not Applicable'
55
50
  if (text === '__series__' && config.table.indexLabel) return `${config.table.indexLabel} `
56
- if (text === '__series__' && !config.table.indexLabel) return <ScreenReaderText as='span'>{notApplicableText}</ScreenReaderText>
51
+ if (text === '__series__' && !config.table.indexLabel)
52
+ return <ScreenReaderText as='span'>{notApplicableText}</ScreenReaderText>
57
53
  return text
58
54
  }
59
55
 
@@ -71,7 +67,8 @@ const ChartHeader = ({ data, isVertical, config, setSortBy, sortBy, hasRowType }
71
67
  <tr>
72
68
  {dataSeriesColumns.map((column, index) => {
73
69
  const text = getSeriesName(column, config)
74
-
70
+ const newSortBy = getNewSortBy(sortBy, column, index)
71
+ const sortByAsc = sortBy.column === column ? sortBy.asc : undefined
75
72
  return (
76
73
  <th
77
74
  style={{ minWidth: (config.table.cellMinWidth || 0) + 'px' }}
@@ -81,19 +78,22 @@ const ChartHeader = ({ data, isVertical, config, setSortBy, sortBy, hasRowType }
81
78
  scope='col'
82
79
  onClick={() => {
83
80
  if (hasRowType) return
84
- setSortBy({ column, asc: sortBy.column === column ? !sortBy.asc : false, colIndex: index })
81
+ setSortBy(newSortBy)
85
82
  }}
86
83
  onKeyDown={e => {
87
84
  if (hasRowType) return
88
85
  if (e.keyCode === 13) {
89
- setSortBy({ column, asc: sortBy.column === column ? !sortBy.asc : false, colIndex: index })
86
+ setSortBy(newSortBy)
90
87
  }
91
88
  }}
92
- className={handleHeaderClasses(sortBy, text)}
93
- {...(sortBy.column === column ? (sortBy.asc ? { 'aria-sort': 'ascending' } : { 'aria-sort': 'descending' }) : null)}
89
+ {...(sortBy.column === column
90
+ ? sortBy.asc
91
+ ? { 'aria-sort': 'ascending' }
92
+ : { 'aria-sort': 'descending' }
93
+ : null)}
94
94
  >
95
95
  <ColumnHeadingText text={text} column={column} config={config} />
96
- {column === sortBy.column && <span className={'sort-icon'}>{!sortBy.asc ? <UpIcon /> : <DownIcon />}</span>}
96
+ {column === sortBy.column && !hasRowType && <SortIcon ascending={sortByAsc} />}
97
97
  <ScreenReaderSortByText sortBy={sortBy} config={config} text={text} />
98
98
  </th>
99
99
  )
@@ -107,7 +107,8 @@ const ChartHeader = ({ data, isVertical, config, setSortBy, sortBy, hasRowType }
107
107
  {['__series__', ...Object.keys(data)].slice(sliceVal).map((row, index) => {
108
108
  let column = config.xAxis?.dataKey
109
109
  let text = row !== '__series__' ? getChartCellValue(row, column, config, data) : '__series__'
110
-
110
+ const newSortBy = getNewSortBy(sortBy, column, index)
111
+ const sortByAsc = sortBy.colIndex === index ? sortBy.asc : undefined
111
112
  return (
112
113
  <th
113
114
  style={{ minWidth: (config.table.cellMinWidth || 0) + 'px' }}
@@ -116,18 +117,22 @@ const ChartHeader = ({ data, isVertical, config, setSortBy, sortBy, hasRowType }
116
117
  role='columnheader'
117
118
  scope='col'
118
119
  onClick={() => {
119
- setSortBy({ column: text, asc: sortBy.column === text ? !sortBy.asc : false, colIndex: index })
120
+ setSortBy(newSortBy)
120
121
  }}
121
122
  onKeyDown={e => {
122
123
  if (e.keyCode === 13) {
123
- setSortBy({ column: text, asc: sortBy.column === text ? !sortBy.asc : false, colIndex: index })
124
+ setSortBy(newSortBy)
124
125
  }
125
126
  }}
126
- className={handleHeaderClasses(sortBy, text)}
127
- {...(sortBy.column === text ? (sortBy.asc ? { 'aria-sort': 'ascending' } : { 'aria-sort': 'descending' }) : null)}
127
+ {...(sortBy.column === text
128
+ ? sortBy.asc
129
+ ? { 'aria-sort': 'ascending' }
130
+ : { 'aria-sort': 'descending' }
131
+ : null)}
128
132
  >
129
133
  <ColumnHeadingText text={text} column={column} config={config} />
130
- {index === sortBy.colIndex && <span className={'sort-icon'}>{!sortBy.asc ? <UpIcon /> : <DownIcon />}</span>}
134
+ {index === sortBy.colIndex && !hasRowType && <SortIcon ascending={sortByAsc} />}
135
+
131
136
  <ScreenReaderSortByText text={text} config={config} sortBy={sortBy} />
132
137
  </th>
133
138
  )
@@ -1,16 +1,18 @@
1
1
  import { DataTableProps } from '../DataTable'
2
- import { DownIcon, UpIcon } from './Icons'
3
2
  import ScreenReaderText from '../../elements/ScreenReaderText'
3
+ import { SortIcon } from './SortIcon'
4
+ import { getNewSortBy } from '../helpers/getNewSortBy'
4
5
 
5
6
  type MapHeaderProps = DataTableProps & {
6
7
  sortBy: { column; asc }
7
8
  setSortBy: Function
8
9
  }
9
10
 
10
- const ColumnHeadingText = ({ column, text, config }) => {
11
+ const ColumnHeadingText = ({ text, config }) => {
11
12
  let notApplicableText = 'Not Applicable'
12
13
  if (text === '__series__' && config.table.indexLabel) return `${config.table.indexLabel} `
13
- if (text === '__series__' && !config.table.indexLabel) return <ScreenReaderText as='span'>{notApplicableText}</ScreenReaderText>
14
+ if (text === '__series__' && !config.table.indexLabel)
15
+ return <ScreenReaderText as='span'>{notApplicableText}</ScreenReaderText>
14
16
  return text
15
17
  }
16
18
 
@@ -21,7 +23,7 @@ const MapHeader = ({ columns, config, indexTitle, sortBy, setSortBy }: MapHeader
21
23
  .filter(column => columns[column].dataTable === true && columns[column].name)
22
24
  .map((column, index) => {
23
25
  let text
24
- if (column !== 'geo') {
26
+ if (column && column !== 'geo') {
25
27
  text = columns[column].label ? columns[column].label : columns[column].name
26
28
  } else {
27
29
  text = config.type === 'map' ? indexTitle : config.xAxis?.dataKey
@@ -29,7 +31,8 @@ const MapHeader = ({ columns, config, indexTitle, sortBy, setSortBy }: MapHeader
29
31
  if (config.type === 'map' && (text === undefined || text === '')) {
30
32
  text = 'Location'
31
33
  }
32
-
34
+ const newSortBy = getNewSortBy(sortBy, column, index)
35
+ const sortByAsc = sortBy.column === column ? sortBy.asc : undefined
33
36
  return (
34
37
  <th
35
38
  key={`col-header-${column}__${index}`}
@@ -38,19 +41,25 @@ const MapHeader = ({ columns, config, indexTitle, sortBy, setSortBy }: MapHeader
38
41
  role='columnheader'
39
42
  scope='col'
40
43
  onClick={() => {
41
- setSortBy({ column, asc: sortBy.column === column ? !sortBy.asc : false })
44
+ setSortBy(newSortBy)
42
45
  }}
43
46
  onKeyDown={e => {
44
47
  if (e.keyCode === 13) {
45
- setSortBy({ column, asc: sortBy.column === column ? !sortBy.asc : false })
48
+ setSortBy(newSortBy)
46
49
  }
47
50
  }}
48
51
  className={sortBy.column === column ? (sortBy.asc ? 'sort sort-asc' : 'sort sort-desc') : 'sort'}
49
- {...(sortBy.column === column ? (sortBy.asc ? { 'aria-sort': 'ascending' } : { 'aria-sort': 'descending' }) : null)}
52
+ {...(sortBy.column === column
53
+ ? sortBy.asc
54
+ ? { 'aria-sort': 'ascending' }
55
+ : { 'aria-sort': 'descending' }
56
+ : null)}
50
57
  >
51
58
  <ColumnHeadingText text={text} config={config} column={column} />
52
- {sortBy.column === column && <span className={'sort-icon'}>{!sortBy.asc ? <UpIcon /> : <DownIcon />}</span>}
53
- <span className='cdcdataviz-sr-only'>{`Sort by ${text} in ${sortBy.column === column ? (!sortBy.asc ? 'descending' : 'ascending') : 'descending'} order`}</span>
59
+ <SortIcon ascending={sortByAsc} />
60
+ <span className='cdcdataviz-sr-only'>{`Sort by ${text} in ${
61
+ sortBy.column === column ? (!sortBy.asc ? 'descending' : 'ascending') : 'descending'
62
+ } order`}</span>
54
63
  </th>
55
64
  )
56
65
  })}
@@ -0,0 +1,25 @@
1
+ import './sort-icon.css'
2
+
3
+ const UpIcon = ({ active }) => (
4
+ <svg className={'up' + (active ? ' active' : '')} xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 5'>
5
+ <path d='M0 5l5-5 5 5z' />
6
+ </svg>
7
+ )
8
+ const DownIcon = ({ active }) => (
9
+ <svg className={'down' + (active ? ' active' : '')} xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 5'>
10
+ <path d='M0 0l5 5 5-5z' />
11
+ </svg>
12
+ )
13
+
14
+ type SortIconProps = {
15
+ ascending?: boolean
16
+ }
17
+
18
+ export const SortIcon: React.FC<SortIconProps> = ({ ascending }) => {
19
+ return (
20
+ <span role='button' className={'sort-icon'}>
21
+ <UpIcon active={ascending === true} />
22
+ <DownIcon active={ascending === false} />
23
+ </span>
24
+ )
25
+ }
@@ -0,0 +1,21 @@
1
+ /* format the white triangle sort icon in data table headers */
2
+ .sort-icon {
3
+ fill: white;
4
+ position: relative;
5
+ margin: 0 0.5rem !important;
6
+ :is(svg) {
7
+ position: absolute;
8
+ fill: rgba(255, 255, 255, 0.5);
9
+ &.active {
10
+ fill: white;
11
+ }
12
+ width: 1rem;
13
+ height: 1rem;
14
+ }
15
+ .up {
16
+ bottom: 0.5rem;
17
+ }
18
+ .down {
19
+ top: 0.5rem;
20
+ }
21
+ }