@cdc/core 4.24.11 → 4.24.12-2

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 (39) hide show
  1. package/components/Alert/components/Alert.tsx +9 -4
  2. package/components/DataTable/DataTable.tsx +19 -8
  3. package/components/DataTable/DataTableStandAlone.tsx +3 -3
  4. package/components/DataTable/components/ExpandCollapse.tsx +1 -1
  5. package/components/DataTable/components/SortIcon/sort-icon.css +15 -0
  6. package/components/DataTable/helpers/boxplotCellMatrix.tsx +6 -2
  7. package/components/DataTable/helpers/getChartCellValue.ts +11 -11
  8. package/components/EditorPanel/DataTableEditor.tsx +29 -23
  9. package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +25 -1
  10. package/components/Filters/Filters.tsx +31 -35
  11. package/components/Filters/helpers/handleSorting.ts +5 -0
  12. package/components/Footnotes/FootnotesStandAlone.tsx +17 -4
  13. package/components/Layout/components/Visualization/visualizations.scss +1 -1
  14. package/components/Legend/Legend.Gradient.tsx +1 -1
  15. package/components/Loader/Loader.tsx +10 -5
  16. package/components/MultiSelect/MultiSelect.tsx +84 -84
  17. package/components/MultiSelect/multiselect.styles.css +10 -0
  18. package/components/NestedDropdown/NestedDropdown.tsx +21 -18
  19. package/components/NestedDropdown/nesteddropdown.styles.css +11 -0
  20. package/components/Table/components/Row.tsx +1 -1
  21. package/components/inputs/{InputToggle.jsx → InputToggle.tsx} +35 -29
  22. package/dist/cove-main.css +6 -3
  23. package/dist/cove-main.css.map +1 -1
  24. package/helpers/addValuesToFilters.ts +22 -8
  25. package/helpers/coveUpdateWorker.ts +1 -1
  26. package/helpers/filterVizData.ts +2 -2
  27. package/helpers/formatConfigBeforeSave.ts +15 -0
  28. package/helpers/gatherQueryParams.ts +2 -3
  29. package/helpers/queryStringUtils.ts +10 -1
  30. package/helpers/tests/addValuesToFilters.test.ts +6 -1
  31. package/helpers/useDataVizClasses.ts +2 -1
  32. package/helpers/ver/4.24.10.ts +12 -0
  33. package/helpers/ver/versionNeedsUpdate.ts +2 -0
  34. package/helpers/viewports.ts +8 -7
  35. package/package.json +2 -2
  36. package/styles/_global-variables.scss +8 -3
  37. package/styles/_reset.scss +0 -1
  38. package/types/Version.ts +1 -0
  39. package/types/VizFilter.ts +2 -1
@@ -1,6 +1,7 @@
1
1
  import _ from 'lodash'
2
2
  import { getQueryStringFilterValue } from '@cdc/core/helpers/queryStringUtils'
3
3
  import { VizFilter } from '../types/VizFilter'
4
+ import { FILTER_STYLE } from '@cdc/dashboard/src/types/FilterStyles'
4
5
 
5
6
  type Filter = {
6
7
  columnName: string
@@ -28,13 +29,16 @@ const cleanLookup = (lookup: Record<string, { values: string[]; orderedValues?:
28
29
  // Gets filter values from dataset
29
30
  const generateValuesForFilter = (filter: VizFilter, data: any[] | MapData) => {
30
31
  const columnName = filter.columnName
32
+ const orderColumn = filter.orderColumn
31
33
  const values: string[] = []
34
+ const valuesWithOrders: [string, string][] = []
32
35
  const subGroupingColumn = filter.subGrouping?.columnName
33
36
  const subValues = cleanLookup(filter.subGrouping?.valuesLookup)
34
37
  if (Array.isArray(data)) {
35
38
  data.forEach(row => {
36
- const value = row[columnName]
39
+ const value: string = row[columnName]
37
40
  if (value !== undefined && !values.includes(value)) {
41
+ if (orderColumn) valuesWithOrders.push([value, row[orderColumn]])
38
42
  values.push(value)
39
43
  }
40
44
  if (subGroupingColumn) {
@@ -57,12 +61,23 @@ const generateValuesForFilter = (filter: VizFilter, data: any[] | MapData) => {
57
61
  rows.forEach(row => {
58
62
  const value = row[columnName]
59
63
  if (value !== undefined && !values.includes(value)) {
64
+ if (orderColumn) valuesWithOrders.push([value, row[orderColumn]])
60
65
  values.push(value)
61
66
  }
62
67
  })
63
68
  })
64
69
  }
65
- filter.values = values
70
+ if (orderColumn) {
71
+ filter.values = valuesWithOrders.sort((a, b) => a[1].localeCompare(b[1])).map(([value]) => value)
72
+ } else if (filter.order && filter.order !== 'cust') {
73
+ const sort = (a, b) => {
74
+ const asc = filter.order !== 'desc'
75
+ return String(asc ? a : b).localeCompare(String(asc ? b : a), 'en', { numeric: true })
76
+ }
77
+ filter.values = values.sort(sort)
78
+ } else {
79
+ filter.values = values
80
+ }
66
81
  if (subGroupingColumn) {
67
82
  filter.subGrouping.valuesLookup = subValues
68
83
  }
@@ -72,7 +87,7 @@ const handleVizParents = (filter: VizFilter, data: any[] | MapData, filtersLooku
72
87
  let filteredData = Array.isArray(data) ? data : Object.values(data).flat(1)
73
88
  filter.parents.forEach(parentKey => {
74
89
  const parent = filtersLookup[parentKey]
75
- if (parent?.filterStyle === 'nested-dropdown') {
90
+ if (parent?.filterStyle === FILTER_STYLE.nestedDropdown) {
76
91
  const { subGrouping } = parent as VizFilter
77
92
  if (subGrouping?.active) {
78
93
  filteredData = filteredData.filter(d => {
@@ -107,11 +122,11 @@ export const addValuesToFilters = (filters: VizFilter[], data: any[] | MapData):
107
122
  filteredData = handleVizParents(filter as VizFilter, data, filtersLookup)
108
123
  }
109
124
  generateValuesForFilter(filterCopy, filteredData)
110
- if (filterCopy.values.length > 0) {
125
+ if (filterCopy.values?.length > 0) {
111
126
  const queryStringFilterValue = getQueryStringFilterValue(filterCopy)
112
127
  if (queryStringFilterValue) {
113
128
  filterCopy.active = queryStringFilterValue
114
- } else if (filterCopy.filterStyle === 'multi-select') {
129
+ } else if (filterCopy.filterStyle === FILTER_STYLE.multiSelect) {
115
130
  const defaultValues = filterCopy.values
116
131
  const active = Array.isArray(filterCopy.active) ? filterCopy.active : [filterCopy.active]
117
132
  filterCopy.active = active.filter(val => includes(defaultValues, val))
@@ -128,12 +143,11 @@ export const addValuesToFilters = (filters: VizFilter[], data: any[] | MapData):
128
143
  values: filterCopy.subGrouping.valuesLookup[groupName].values
129
144
  }
130
145
  const queryStringFilterValue = getQueryStringFilterValue(subGroupingFilter)
131
- const groupActive = filterCopy.active || filterCopy.values[0]
146
+ const groupActive = groupName || filterCopy.values[0]
132
147
  const defaultValue = filterCopy.subGrouping.valuesLookup[groupActive as string].values[0]
133
148
  // if the value doesn't exist in the subGrouping then return the default
134
- const filteredLookupValues = Object.values(filterCopy.subGrouping.valuesLookup).flatMap(v => v.values)
135
149
  const activeValue = queryStringFilterValue || filterCopy.subGrouping.active
136
- filterCopy.subGrouping.active = filteredLookupValues.includes(activeValue) ? activeValue : defaultValue
150
+ filterCopy.subGrouping.active = activeValue || defaultValue
137
151
  }
138
152
  return filterCopy
139
153
  })
@@ -20,7 +20,7 @@ export const coveUpdateWorker = config => {
20
20
  ['4.24.5', update_4_24_5],
21
21
  ['4.24.7', update_4_24_7, true],
22
22
  ['4.24.9', update_4_24_9],
23
- ['4.24.10', update_4_24_10]
23
+ ['4.24.10', update_4_24_10, true]
24
24
  ]
25
25
 
26
26
  versions.forEach(([version, updateFunction, alwaysRun]: [string, UpdateFunction, boolean?]) => {
@@ -36,9 +36,9 @@ export const filterVizData = (filters: Filter[], data) => {
36
36
  }
37
37
  if (filter.filterStyle === 'nested-dropdown' && filter.subGrouping && add === true) {
38
38
  const subGroupActive = filter.subGrouping.active
39
- const value = row[filter.subGrouping.columnName]
39
+ const subGroupValue = row[filter.subGrouping.columnName]
40
40
  if (subGroupActive === undefined) return
41
- if (value != subGroupActive) {
41
+ if (subGroupValue != subGroupActive) {
42
42
  add = false
43
43
  }
44
44
  }
@@ -65,6 +65,7 @@ const cleanSharedFilters = (config: DashboardConfig) => {
65
65
  if (config.dashboard?.sharedFilters) {
66
66
  config.dashboard.sharedFilters.forEach((filter, index) => {
67
67
  delete config.dashboard.sharedFilters[index].active
68
+ if (filter.subGrouping) delete config.dashboard.sharedFilters[index].subGrouping.active
68
69
  if (filter.type === 'urlfilter') {
69
70
  delete config.dashboard.sharedFilters[index].values
70
71
  }
@@ -72,6 +73,18 @@ const cleanSharedFilters = (config: DashboardConfig) => {
72
73
  }
73
74
  }
74
75
 
76
+ const cleanVisualizationFilters = (config: DashboardConfig) => {
77
+ if (config.visualizations) {
78
+ Object.keys(config.visualizations).forEach(vizKey => {
79
+ const vizFilters = config.visualizations[vizKey].filters || []
80
+ vizFilters.forEach((_filter, index) => {
81
+ delete config.visualizations[vizKey].filters[index].active
82
+ delete config.visualizations[vizKey].filters[index].values
83
+ })
84
+ })
85
+ }
86
+ }
87
+
75
88
  const removeRuntimeDataURLs = (config: DashboardConfig) => {
76
89
  if (config.datasets) {
77
90
  Object.keys(config.datasets).forEach(datasetKey => {
@@ -88,6 +101,7 @@ export const formatConfigBeforeSave = configToStrip => {
88
101
  cleanDashboardData(strippedConfig.multiDashboards[i])
89
102
  cleanSharedFilters(strippedConfig.multiDashboards[i])
90
103
  cleanDashboardFootnotes(strippedConfig.multiDashboards[i])
104
+ cleanVisualizationFilters(strippedConfig.multiDashboards[i])
91
105
  })
92
106
  delete strippedConfig.dashboard
93
107
  delete strippedConfig.rows
@@ -98,6 +112,7 @@ export const formatConfigBeforeSave = configToStrip => {
98
112
  cleanDashboardData(strippedConfig)
99
113
  cleanSharedFilters(strippedConfig)
100
114
  cleanDashboardFootnotes(strippedConfig)
115
+ cleanVisualizationFilters(strippedConfig)
101
116
  removeRuntimeDataURLs(strippedConfig)
102
117
  } else {
103
118
  delete strippedConfig.runtime
@@ -5,9 +5,8 @@ const strip = (paramVal: string) => {
5
5
  }
6
6
 
7
7
  const isNumber = (value: string) => {
8
- const hasLetters = value.match(/[a-zA-Z]/)
9
- if (hasLetters) return false
10
- return !isNaN(parseInt(value))
8
+ // matches int and float and negative numbers
9
+ return String(value).match(/^[-]?[0-9\.]+$/)
11
10
  }
12
11
 
13
12
  export const gatherQueryParams = (baseEndpoint: string, params: { key: string; value: string }[]) => {
@@ -16,11 +16,20 @@ export function getQueryStringFilterValue(filter) {
16
16
  export function getQueryParams() {
17
17
  const queryParams = {}
18
18
  for (const [key, value] of Array.from(new URLSearchParams(window.location.search).entries())) {
19
- queryParams[key] = value
19
+ if (!queryParams[key]) queryParams[key] = value
20
+ else {
21
+ // for multiple values of the same key in the query string
22
+ if (Array.isArray(queryParams[key])) queryParams[key].push(value)
23
+ else queryParams[key] = [queryParams[key], value]
24
+ }
20
25
  }
21
26
  return queryParams
22
27
  }
23
28
 
29
+ export function getQueryParam(param) {
30
+ return getQueryParams()[param]
31
+ }
32
+
24
33
  export function updateQueryString(queryParams) {
25
34
  const updateUrl = `${window.location.origin}${window.location.pathname}?${Object.keys(queryParams)
26
35
  .map(queryParam => `${queryParam}=${encodeURIComponent(queryParams[queryParam])}`)
@@ -2,6 +2,7 @@ import _ from 'lodash'
2
2
  import { VizFilter } from '../../types/VizFilter'
3
3
  import { addValuesToFilters } from '../addValuesToFilters'
4
4
  import { describe, it, expect, vi } from 'vitest'
5
+ import { FILTER_STYLE } from '@cdc/dashboard/src/types/FilterStyles'
5
6
 
6
7
  describe('addValuesToFilters', () => {
7
8
  const parentFilter = { columnName: 'parentColumn', id: 11, active: 'apple', values: [] } as VizFilter
@@ -36,7 +37,11 @@ describe('addValuesToFilters', () => {
36
37
  //expect(newFilters[1].values).toEqual([])
37
38
  })
38
39
  it('works for nested dropdowns', () => {
39
- const nestedParentFilter = { ...parentFilter, subGrouping: { columnName: 'childColumn' } }
40
+ const nestedParentFilter = {
41
+ ...parentFilter,
42
+ filterStyle: FILTER_STYLE.nestedDropdown,
43
+ subGrouping: { columnName: 'childColumn' }
44
+ }
40
45
  const newFilters = addValuesToFilters([nestedParentFilter], data)
41
46
  expect(newFilters[0].values).toEqual(['apple', 'pear'])
42
47
  expect(newFilters[0].subGrouping.valuesLookup).toEqual({ apple: { values: ['a', 'b'] }, pear: { values: ['c'] } })
@@ -85,7 +85,8 @@ export default function useDataVizClasses(config, viewport = null) {
85
85
  li: ['single-legend-item', 'legend-container__li'],
86
86
  title: ['legend-container__title'],
87
87
  description: ['legend-container__description'],
88
- div: [legend?.position === 'bottom' && legend?.singleRow ? 'shape-container single-row' : 'shape-container']
88
+ div: [legend?.position === 'bottom' && legend?.singleRow ? 'shape-container single-row' : 'shape-container'],
89
+ resetButton: ['legend-container__reset-button']
89
90
  }
90
91
 
91
92
  return { innerContainerClasses, contentClasses, lineDatapointClass, sparkLineStyles, legendClasses }
@@ -34,12 +34,24 @@ export const setXAxisLabelOffsetToZero = newConfig => {
34
34
  newConfig.xAxis.labelOffset = 0
35
35
  }
36
36
 
37
+ export const defineFilterStyles = newConfig => {
38
+ if (newConfig.filters) {
39
+ newConfig.filters = newConfig.filters.map(filter => {
40
+ if (!filter.filterStyle) {
41
+ filter.filterStyle = 'dropdown'
42
+ }
43
+ return filter
44
+ })
45
+ }
46
+ }
47
+
37
48
  const update_4_24_10 = config => {
38
49
  const ver = '4.24.10'
39
50
  const newConfig = _.cloneDeep(config)
40
51
  setXAxisLabelOffsetToZero(newConfig)
41
52
  changePivotColumns(newConfig)
42
53
  removeMultiSelectPropFromMultiselect(newConfig)
54
+ defineFilterStyles(newConfig)
43
55
  newConfig.version = ver
44
56
  return newConfig
45
57
  }
@@ -7,3 +7,5 @@ export default function versionNeedsUpdate(previousVersion: string, currentVersi
7
7
  if (currMajor === prevMajor && currMinor === prevMinor && currPatch > prevPatch) return true
8
8
  return false
9
9
  }
10
+
11
+ export const isOlderVersion = versionNeedsUpdate
@@ -1,9 +1,10 @@
1
- function isLegendWrapViewport(currentViewport) {
2
- return ['xs', 'xxs'].includes(currentViewport)
3
- }
1
+ import { ViewportSize } from '@cdc/map/src/types/MapConfig'
4
2
 
5
- function isMobileHeightViewport(currentViewport) {
6
- return ['xs', 'xxs'].includes(currentViewport)
7
- }
3
+ const BREAKPOINTS = ['xxs', 'xs', 'sm', 'md', 'lg']
8
4
 
9
- export { isLegendWrapViewport, isMobileHeightViewport }
5
+ export const isBelowBreakpoint = (breakpoint: ViewportSize, currentViewport: ViewportSize) =>
6
+ BREAKPOINTS.indexOf(currentViewport) < BREAKPOINTS.indexOf(breakpoint)
7
+
8
+ export const isLegendWrapViewport = currentViewport => isBelowBreakpoint('sm', currentViewport)
9
+
10
+ export const isMobileHeightViewport = currentViewport => isBelowBreakpoint('sm', currentViewport)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdc/core",
3
- "version": "4.24.11",
3
+ "version": "4.24.12-2",
4
4
  "description": "Core components, styles, hooks, and helpers, for the CDC Open Visualization project",
5
5
  "moduleName": "CdcCore",
6
6
  "main": "dist/cdccore",
@@ -34,7 +34,7 @@
34
34
  "react": "^18.2.0",
35
35
  "react-dom": "^18.2.0"
36
36
  },
37
- "gitHead": "9ab5ee9b2b0ef7321a66a2104be6ce8899ec3808",
37
+ "gitHead": "a60edf1148396309eb473ac9f65426ee40797ddf",
38
38
  "devDependencies": {
39
39
  "sass": "^1.79.4"
40
40
  }
@@ -62,7 +62,12 @@ $colors: (
62
62
  'amber-primary': #fbab18,
63
63
  'amber-secondary': #ffd54f,
64
64
  'amber-tertiary': #ffecb3,
65
- 'amber-quaternary': #fff7e1
65
+ 'amber-quaternary': #fff7e1,
66
+
67
+ 'cool-gray-90': #1c1d1f,
68
+ 'cool-gray-50': #71767a,
69
+ 'cool-gray-30': #a9aeb1,
70
+ 'cool-gray-10': #dfe1e2
66
71
  );
67
72
 
68
73
  @mixin theme() {
@@ -86,8 +91,8 @@ $colors: (
86
91
  --font-size: 17px;
87
92
  }
88
93
 
89
- @media (max-width: 768px) {
94
+ @media (max-width: 576px) {
90
95
  :root {
91
- --font-size: 0.9em;
96
+ --font-size: 13px;
92
97
  }
93
98
  }
@@ -19,7 +19,6 @@
19
19
  }
20
20
  }
21
21
  .cdc-open-viz-module {
22
- span,
23
22
  applet,
24
23
  object,
25
24
  iframe,
@@ -0,0 +1 @@
1
+ export type version = `${number}.${number}.${number}`
@@ -1,4 +1,4 @@
1
- export type OrderBy = 'asc' | 'desc' | 'cust'
1
+ export type OrderBy = 'asc' | 'desc' | 'cust' | 'column'
2
2
 
3
3
  export type FilterBase = {
4
4
  columnName: string
@@ -23,6 +23,7 @@ export type GeneralFilter = FilterBase & {
23
23
  filterStyle: VizFilterStyle
24
24
  label: string
25
25
  order: OrderBy
26
+ orderColumn?: string
26
27
  orderedValues?: string[] // should only exist if the order is 'cust'
27
28
  queryParameter: string
28
29
  setByQueryParameter: string