@cdc/core 4.25.3 → 4.25.5-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 (69) hide show
  1. package/assets/icon-close.svg +1 -1
  2. package/components/DataTable/DataTable.tsx +18 -13
  3. package/components/DataTable/components/CellAnchor.tsx +1 -1
  4. package/components/DataTable/components/ChartHeader.tsx +2 -1
  5. package/components/DataTable/components/MapHeader.tsx +1 -0
  6. package/components/DataTable/helpers/chartCellMatrix.tsx +2 -1
  7. package/components/DataTable/helpers/mapCellMatrix.tsx +17 -7
  8. package/components/DownloadButton.tsx +17 -2
  9. package/components/EditorPanel/DataTableEditor.tsx +1 -1
  10. package/components/EditorPanel/Inputs.tsx +12 -4
  11. package/components/EditorPanel/VizFilterEditor/NestedDropdownEditor.tsx +2 -1
  12. package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +3 -1
  13. package/components/Filters/Filters.tsx +168 -429
  14. package/components/Filters/components/Dropdown.tsx +39 -0
  15. package/components/Filters/components/Tabs.tsx +82 -0
  16. package/components/Filters/helpers/getChangedFilters.ts +31 -0
  17. package/components/Filters/helpers/getNestedOptions.ts +2 -2
  18. package/components/Filters/helpers/getNewRuntime.ts +35 -0
  19. package/components/Filters/helpers/handleSorting.ts +2 -2
  20. package/components/Filters/helpers/tests/getChangedFilters.test.ts +92 -0
  21. package/components/Filters/helpers/tests/getNestedOptions.test.ts +31 -0
  22. package/components/Filters/helpers/tests/getNewRuntime.test.ts +82 -0
  23. package/components/Filters/index.ts +1 -1
  24. package/components/Layout/components/Visualization/index.tsx +3 -3
  25. package/components/Legend/Legend.Gradient.tsx +66 -23
  26. package/components/MultiSelect/multiselect.styles.css +2 -0
  27. package/components/NestedDropdown/NestedDropdown.tsx +2 -2
  28. package/components/RichTooltip/RichTooltip.tsx +37 -0
  29. package/components/RichTooltip/richTooltip.css +16 -0
  30. package/components/Table/Table.tsx +142 -142
  31. package/components/Table/components/Row.tsx +1 -1
  32. package/components/Table/table.styles.css +10 -0
  33. package/components/_stories/DataTable.stories.tsx +9 -2
  34. package/components/_stories/Table.stories.tsx +1 -1
  35. package/components/_stories/styles.scss +0 -4
  36. package/components/ui/Accordion.jsx +8 -1
  37. package/components/ui/Title/index.tsx +4 -1
  38. package/components/ui/Title/{Title.scss → title.styles.css} +0 -2
  39. package/components/ui/_stories/Colors.stories.mdx +220 -0
  40. package/components/ui/_stories/IconGallery.stories.mdx +14 -0
  41. package/components/ui/_stories/Title.stories.tsx +29 -4
  42. package/components/ui/accordion.styles.css +3 -0
  43. package/data/colorPalettes.js +0 -1
  44. package/dist/cove-main.css +3 -8
  45. package/dist/cove-main.css.map +1 -1
  46. package/helpers/constants.ts +6 -0
  47. package/helpers/cove/accessibility.ts +7 -8
  48. package/helpers/coveUpdateWorker.ts +5 -1
  49. package/helpers/filterOrderOptions.ts +17 -0
  50. package/helpers/isNumber.ts +20 -0
  51. package/helpers/isRightAlignedTableValue.js +1 -1
  52. package/helpers/pivotData.ts +16 -11
  53. package/helpers/tests/pivotData.test.ts +74 -0
  54. package/helpers/ver/4.25.3.ts +25 -2
  55. package/helpers/ver/4.25.4.ts +33 -0
  56. package/helpers/ver/tests/4.25.4.test.ts +24 -0
  57. package/helpers/viewports.ts +4 -0
  58. package/package.json +2 -3
  59. package/styles/_global-variables.scss +3 -0
  60. package/styles/_reset.scss +0 -6
  61. package/styles/v2/main.scss +0 -5
  62. package/types/General.ts +1 -0
  63. package/types/Legend.ts +1 -0
  64. package/LICENSE +0 -201
  65. package/components/ui/_stories/Colors.stories.tsx +0 -92
  66. package/components/ui/_stories/Icon.stories.tsx +0 -29
  67. package/helpers/cove/fontSettings.ts +0 -2
  68. package/helpers/isNumber.js +0 -24
  69. package/helpers/isNumberLog.js +0 -18
@@ -1,3 +1,3 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
1
+ <svg xmlns="http://www.w3.org/2000/svg" height="1em" width="1em" viewBox="0 0 24 24" fill="currentColor">
2
2
  <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/>
3
3
  </svg>
@@ -27,7 +27,6 @@ import _ from 'lodash'
27
27
  import { getDataSeriesColumns } from './helpers/getDataSeriesColumns'
28
28
 
29
29
  export type DataTableProps = {
30
- applyLegendToRow?: Function
31
30
  colorScale?: Function
32
31
  columns?: Record<string, Column>
33
32
  config: TableConfig
@@ -35,7 +34,7 @@ export type DataTableProps = {
35
34
  defaultSortBy?: string
36
35
  displayGeoName?: (row: string) => string
37
36
  expandDataTable: boolean
38
- formatLegendLocation?: (row: string) => string
37
+ formatLegendLocation?: (row: string, runtimeLookup: string) => string
39
38
  groupBy?: string
40
39
  headerColor?: string
41
40
  imageRef?: string
@@ -58,20 +57,20 @@ export type DataTableProps = {
58
57
  /* eslint-disable jsx-a11y/no-noninteractive-tabindex, jsx-a11y/no-static-element-interactions */
59
58
  const DataTable = (props: DataTableProps) => {
60
59
  const {
60
+ columns,
61
61
  config,
62
62
  dataConfig,
63
63
  defaultSortBy,
64
64
  displayGeoName,
65
- tableTitle,
66
- vizTitle,
67
- rawData,
68
- runtimeData: parentRuntimeData,
69
- headerColor,
70
65
  expandDataTable,
71
- columns,
72
- viewport,
73
66
  formatLegendLocation,
67
+ headerColor,
68
+ rawData,
69
+ runtimeData: parentRuntimeData,
74
70
  tabbingId,
71
+ tableTitle,
72
+ viewport,
73
+ vizTitle,
75
74
  wrapColumns
76
75
  } = props
77
76
  const runtimeData = useMemo(() => {
@@ -248,9 +247,14 @@ const DataTable = (props: DataTableProps) => {
248
247
  const csvData = config.table?.downloadVisibleDataOnly ? visibleData : rawData
249
248
 
250
249
  // only use fullGeoName on County maps and no other
251
- if (config.general?.geoType === 'us-county') {
250
+ if (config.general?.geoType === 'us-county' || config.table.showFullGeoNameInCSV) {
252
251
  // Add column for full Geo name along with State
253
- return csvData.map(row => ({ FullGeoName: formatLegendLocation(row[config.columns.geo.name]), ...row }))
252
+ return csvData.map(row => {
253
+ return {
254
+ FullGeoName: formatLegendLocation(row[config.columns.geo.name]),
255
+ ...row
256
+ }
257
+ })
254
258
  } else {
255
259
  return csvData
256
260
  }
@@ -275,7 +279,7 @@ const DataTable = (props: DataTableProps) => {
275
279
 
276
280
  const childrenMatrix =
277
281
  config.type === 'map'
278
- ? mapCellMatrix({ rows, wrapColumns, ...props, runtimeData, viewport })
282
+ ? mapCellMatrix({ ...props, rows, wrapColumns, runtimeData, viewport })
279
283
  : chartCellMatrix({ rows, ...props, runtimeData, isVertical, sortBy, hasRowType, viewport })
280
284
 
281
285
  // If every value in a column is a number, record the column index so the header and cells can be right-aligned
@@ -352,7 +356,8 @@ const DataTable = (props: DataTableProps) => {
352
356
  }`,
353
357
  'aria-live': 'assertive',
354
358
  'aria-rowcount': config?.data?.length ? config.data.length : -1,
355
- hidden: !expanded
359
+ hidden: !expanded,
360
+ cellMinWidth: 100
356
361
  }}
357
362
  rightAlignedCols={rightAlignedCols}
358
363
  />
@@ -6,7 +6,7 @@ const CellAnchor = ({ markup, row, columns, navigationHandler, mapZoomHandler })
6
6
  if (columns.navigate && row[columns.navigate.name]) {
7
7
  return (
8
8
  <span
9
- onClick={() => navigationHandler(row[columns.navigate.name])}
9
+ onClick={() => navigationHandler('_blank', row[columns.navigate.name])}
10
10
  className='table-link'
11
11
  title='Click for more information (Opens in a new window)'
12
12
  role='link'
@@ -4,6 +4,7 @@ import { getDataSeriesColumns } from '../helpers/getDataSeriesColumns'
4
4
  import ScreenReaderText from '@cdc/core/components/elements/ScreenReaderText'
5
5
  import { SortIcon } from './SortIcon'
6
6
  import { getNewSortBy } from '../helpers/getNewSortBy'
7
+ import parse from 'html-react-parser'
7
8
 
8
9
  type ChartHeaderProps = { data; isVertical; config; setSortBy; sortBy; hasRowType?; viewport; rightAlignedCols }
9
10
 
@@ -75,7 +76,7 @@ const ChartHeader = ({
75
76
  return (
76
77
  <tr>
77
78
  {dataSeriesColumns.map((column, index) => {
78
- const text = getSeriesName(column, config)
79
+ const text = parse(getSeriesName(column, config))
79
80
  const newSortBy = getNewSortBy(sortBy, column, index)
80
81
  const sortByAsc = sortBy.column === column ? sortBy.asc : undefined
81
82
  const isSortedCol = column === sortBy.column && !hasRowType
@@ -36,6 +36,7 @@ const MapHeader = ({ columns, config, indexTitle, sortBy, setSortBy, rightAligne
36
36
  return (
37
37
  <th
38
38
  style={{
39
+ minWidth: (config.table.cellMinWidth || 0) + 'px',
39
40
  textAlign: rightAlignedCols && rightAlignedCols[index] ? 'right' : '',
40
41
  paddingRight: '1.3em'
41
42
  }}
@@ -7,6 +7,7 @@ import { getDataSeriesColumns } from './getDataSeriesColumns'
7
7
  import { ReactNode } from 'react'
8
8
  import { CellMatrix, GroupCellMatrix } from '../../Table/types/CellMatrix'
9
9
  import { getRowType } from './getRowType'
10
+ import parse from 'html-react-parser'
10
11
 
11
12
  type ChartRowsProps = DataTableProps & {
12
13
  rows: string[]
@@ -84,7 +85,7 @@ const chartCellArray = ({
84
85
  ? [
85
86
  <>
86
87
  {colorScale && colorScale(seriesName) && <LegendShape fill={colorScale(seriesName)} />}
87
- {seriesName}
88
+ {parse(seriesName)}
88
89
  </>
89
90
  ]
90
91
  : []
@@ -4,6 +4,7 @@ import { DataTableProps } from '../DataTable'
4
4
  import { ReactNode } from 'react'
5
5
  import { displayDataAsText } from '@cdc/core/helpers/displayDataAsText'
6
6
  import _ from 'lodash'
7
+ import { applyLegendToRow } from '@cdc/map/src/helpers/applyLegendToRow'
7
8
 
8
9
  type MapRowsProps = DataTableProps & {
9
10
  rows: string[]
@@ -72,27 +73,36 @@ const mapCellArray = ({
72
73
  columns,
73
74
  runtimeData,
74
75
  config,
75
- applyLegendToRow,
76
76
  displayGeoName,
77
77
  formatLegendLocation,
78
78
  navigationHandler,
79
- setFilteredCountryCode
79
+ setFilteredCountryCode,
80
+ legendMemo,
81
+ legendSpecialClassLastMemo,
82
+ runtimeLegend
80
83
  }: MapRowsProps): ReactNode[][] => {
84
+ const { allowMapZoom, geoType, type } = config.general
81
85
  return rows.map(row =>
82
86
  Object.keys(columns)
83
87
  .filter(column => columns[column].dataTable === true && columns[column].name)
84
88
  .map(column => {
85
89
  if (column === 'geo') {
86
90
  const rowObj = runtimeData[row]
87
- const legendColor = applyLegendToRow(rowObj)
91
+ if (!rowObj) {
92
+ throw new Error('No row object found')
93
+ }
94
+
95
+ const legendColor = applyLegendToRow(rowObj, config, runtimeLegend, legendMemo, legendSpecialClassLastMemo)
96
+
97
+ if (!legendColor) {
98
+ console.error('No legend color found') // eslint-disable-line no-console
99
+ }
88
100
  const labelValue = getGeoLabel(config, row, formatLegendLocation, displayGeoName)
89
101
  const mapZoomHandler =
90
- config.general.type === 'bubble' && config.general.allowMapZoom && config.general.geoType === 'world'
91
- ? () => setFilteredCountryCode(row)
92
- : undefined
102
+ type === 'bubble' && allowMapZoom && geoType === 'world' ? () => setFilteredCountryCode(row) : undefined
93
103
  return (
94
104
  <div className='col-12'>
95
- <LegendShape fill={legendColor[0]} />
105
+ {legendColor && legendColor.length > 0 && <LegendShape fill={legendColor[0]} />}
96
106
  <CellAnchor
97
107
  markup={labelValue}
98
108
  row={rowObj}
@@ -9,7 +9,12 @@ type DownloadButtonProps = {
9
9
 
10
10
  const DownloadButton = ({ rawData, fileName, headerColor, skipId }: DownloadButtonProps) => {
11
11
  const csvData = Papa.unparse(rawData)
12
- const blob = new Blob([csvData], { type: 'text/csv;charset=utf-8;' })
12
+ // Prepend a Byte Order Mark (BOM) to the CSV data.
13
+ // The BOM is a special marker that helps applications like Excel recognize the file as UTF-8 encoded.
14
+ // Adding the BOM ensures that Excel interprets special characters correctly.
15
+ const bom = '\uFEFF'
16
+ const utf8EncodedCsvData = new TextEncoder().encode(bom + csvData)
17
+ const blob = new Blob([utf8EncodedCsvData], { type: 'text/csv;charset=utf-8;' })
13
18
 
14
19
  const saveBlob = () => {
15
20
  //@ts-ignore
@@ -20,7 +25,17 @@ const DownloadButton = ({ rawData, fileName, headerColor, skipId }: DownloadButt
20
25
  }
21
26
 
22
27
  return (
23
- <a download={fileName} type='button' onClick={saveBlob} href={URL.createObjectURL(blob)} aria-label='Download this data in a CSV file format.' className={`${headerColor} no-border`} id={`${skipId}`} data-html2canvas-ignore role='button'>
28
+ <a
29
+ download={fileName}
30
+ type='button'
31
+ onClick={saveBlob}
32
+ href={URL.createObjectURL(blob)}
33
+ aria-label='Download this data in a CSV file format.'
34
+ className={`${headerColor} no-border`}
35
+ id={`${skipId}`}
36
+ data-html2canvas-ignore
37
+ role='button'
38
+ >
24
39
  Download Data (CSV)
25
40
  </a>
26
41
  )
@@ -196,7 +196,7 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
196
196
  />
197
197
  )}
198
198
  {config?.visualizationType !== 'Sankey' && (
199
- <label>
199
+ <label onClick={e => e.preventDefault()}>
200
200
  <span className='edit-label column-heading mt-1'>Exclude Columns </span>
201
201
  <MultiSelect
202
202
  key={excludedColumns.join('') + 'excluded'}
@@ -1,6 +1,6 @@
1
1
  import { memo, useEffect, useState } from 'react'
2
2
  import { useDebounce } from 'use-debounce'
3
- import { DROPDOWN_STYLES } from '../Filters/Filters'
3
+ import { DROPDOWN_STYLES } from '../Filters/components/Dropdown'
4
4
 
5
5
  export type Input = {
6
6
  label: string
@@ -118,9 +118,17 @@ const CheckBox = memo((props: CheckboxProps) => {
118
118
  return <></>
119
119
  }
120
120
  return (
121
- <label className='checkbox column-heading'>
121
+ <label
122
+ className='checkbox column-heading'
123
+ onClick={e => {
124
+ if (!['SPAN', 'INPUT'].includes(e.target.nodeName)) {
125
+ e.preventDefault()
126
+ }
127
+ }}
128
+ >
122
129
  <input
123
130
  type='checkbox'
131
+ className='edit-checkbox'
124
132
  name={fieldName}
125
133
  checked={value}
126
134
  onChange={e => {
@@ -161,7 +169,7 @@ const Select = memo((props: SelectProps) => {
161
169
  initial: initialValue,
162
170
  ...attributes
163
171
  } = props
164
- const optionsJsx = options.map((option, index) => {
172
+ const optionsJsx = options?.map((option, index) => {
165
173
  if (typeof option === 'string') {
166
174
  return (
167
175
  <option value={option} key={index}>
@@ -178,7 +186,7 @@ const Select = memo((props: SelectProps) => {
178
186
  })
179
187
 
180
188
  if (initialValue) {
181
- optionsJsx.unshift(
189
+ optionsJsx?.unshift(
182
190
  <option value='' key='initial'>
183
191
  {initialValue}
184
192
  </option>
@@ -1,6 +1,7 @@
1
1
  import _ from 'lodash'
2
2
  import { SubGrouping, VizFilter, OrderBy } from '../../../types/VizFilter'
3
- import { filterOrderOptions, handleSorting } from '../../Filters'
3
+ import { handleSorting } from '../../Filters/helpers/handleSorting'
4
+ import { filterOrderOptions } from '../../../helpers/filterOrderOptions'
4
5
  import FilterOrder from './components/FilterOrder'
5
6
  import { Visualization } from '../../../types/Visualization'
6
7
  import { useMemo } from 'react'
@@ -5,7 +5,9 @@ import { Visualization } from '../../../types/Visualization'
5
5
  import { UpdateFieldFunc } from '../../../types/UpdateFieldFunc'
6
6
  import _ from 'lodash'
7
7
  import { MultiSelectFilter, VizFilter, VizFilterStyle } from '../../../types/VizFilter'
8
- import { filterStyleOptions, handleSorting, filterOrderOptions } from '../../Filters'
8
+ import { handleSorting } from '../../Filters/helpers/handleSorting'
9
+ import { filterOrderOptions } from '../../../helpers/filterOrderOptions'
10
+ import { filterStyleOptions } from '../../Filters'
9
11
  import FieldSetWrapper from '../FieldSetWrapper'
10
12
 
11
13
  import FilterOrder from './components/FilterOrder'