@cdc/core 4.23.10 → 4.24.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 (74) hide show
  1. package/LICENSE +201 -0
  2. package/assets/icon-deviation-bar.svg +1 -0
  3. package/components/DataTable/DataTable.tsx +223 -0
  4. package/components/DataTable/components/BoxplotHeader.tsx +16 -0
  5. package/components/DataTable/components/CellAnchor.tsx +44 -0
  6. package/components/DataTable/components/ChartHeader.tsx +103 -0
  7. package/components/DataTable/components/ExpandCollapse.tsx +21 -0
  8. package/components/DataTable/components/Icons.tsx +10 -0
  9. package/components/DataTable/components/MapHeader.tsx +56 -0
  10. package/components/DataTable/components/SkipNav.tsx +7 -0
  11. package/components/DataTable/helpers/boxplotCellMatrix.tsx +64 -0
  12. package/components/DataTable/helpers/chartCellMatrix.tsx +92 -0
  13. package/components/DataTable/helpers/customColumns.ts +25 -0
  14. package/components/DataTable/helpers/customSort.ts +55 -0
  15. package/components/DataTable/helpers/getChartCellValue.ts +56 -0
  16. package/components/DataTable/helpers/getDataSeriesColumns.ts +29 -0
  17. package/components/DataTable/helpers/getSeriesName.ts +26 -0
  18. package/components/DataTable/helpers/mapCellMatrix.tsx +56 -0
  19. package/components/DataTable/helpers/regionCellMatrix.tsx +13 -0
  20. package/components/DataTable/helpers/standardizeState.js +76 -0
  21. package/components/DataTable/index.ts +1 -0
  22. package/components/DataTable/types/TableConfig.ts +52 -0
  23. package/components/DownloadButton.tsx +29 -0
  24. package/components/EditorPanel/DataTableEditor.tsx +133 -0
  25. package/components/EditorPanel/Inputs.tsx +150 -0
  26. package/components/Filters.jsx +3 -3
  27. package/components/LegendCircle.jsx +2 -2
  28. package/components/MediaControls.jsx +1 -1
  29. package/components/MultiSelect/MultiSelect.tsx +95 -0
  30. package/components/MultiSelect/index.ts +1 -0
  31. package/components/MultiSelect/multiselect.styles.css +50 -0
  32. package/components/Table/Table.tsx +69 -0
  33. package/components/Table/components/Cell.tsx +9 -0
  34. package/components/Table/components/GroupRow.tsx +20 -0
  35. package/components/Table/components/Row.tsx +26 -0
  36. package/components/Table/index.ts +1 -0
  37. package/components/Table/types/CellMatrix.ts +4 -0
  38. package/components/Table/types/RowType.ts +5 -0
  39. package/components/_stories/DataTable.stories.tsx +103 -0
  40. package/components/_stories/EditorPanel.stories.tsx +53 -0
  41. package/components/_stories/Inputs.stories.tsx +37 -0
  42. package/components/_stories/MultiSelect.stories.tsx +24 -0
  43. package/components/_stories/Table.stories.tsx +53 -0
  44. package/components/_stories/_mocks/dashboard_no_filter.json +121 -0
  45. package/components/_stories/_mocks/example-city-state.json +808 -0
  46. package/components/_stories/_mocks/row_type.json +42 -0
  47. package/components/_stories/styles.scss +9 -0
  48. package/components/inputs/{InputSelect.jsx → InputSelect.tsx} +15 -5
  49. package/components/managers/{DataDesigner.jsx → DataDesigner.tsx} +103 -94
  50. package/components/ui/{Icon.jsx → Icon.tsx} +3 -3
  51. package/components/ui/Title/Title.scss +95 -0
  52. package/components/ui/Title/index.tsx +34 -0
  53. package/components/ui/_stories/Title.stories.tsx +21 -0
  54. package/helpers/DataTransform.ts +75 -20
  55. package/helpers/cove/string.ts +11 -0
  56. package/helpers/fetchRemoteData.js +1 -1
  57. package/helpers/getFileExtension.ts +28 -5
  58. package/package.json +2 -2
  59. package/styles/_data-table.scss +3 -0
  60. package/styles/heading-colors.scss +0 -3
  61. package/styles/v2/layout/_component.scss +0 -11
  62. package/types/Axis.ts +41 -0
  63. package/types/Color.ts +5 -0
  64. package/types/Column.ts +15 -0
  65. package/types/ComponentStyles.ts +7 -0
  66. package/types/ComponentThemes.ts +13 -0
  67. package/types/EditorColumnProperties.ts +8 -0
  68. package/types/FilterBehavior.ts +1 -0
  69. package/types/Runtime.ts +29 -0
  70. package/types/Series.ts +1 -0
  71. package/types/Table.ts +18 -0
  72. package/types/UpdateFieldFunc.ts +1 -0
  73. package/types/Visualization.ts +21 -0
  74. package/components/DataTable.jsx +0 -754
@@ -1,4 +1,4 @@
1
- type DataArray = Record<string,any>[]
1
+ type DataArray = Record<string, any>[]
2
2
 
3
3
  export class DataTransform {
4
4
  constants: any
@@ -17,12 +17,12 @@ export class DataTransform {
17
17
  const errorsFound: any[] = []
18
18
 
19
19
  // Empty data
20
- if (0 === data.length) {
20
+ if (!data || 0 === data.length) {
21
21
  errorsFound.push(this.constants.errorMessageEmptyData)
22
22
  }
23
23
 
24
24
  // Does it have the correct data structure?
25
- if (!data.filter || data.filter(row => typeof row !== 'object').length > 0) {
25
+ if (!data?.filter || data.filter(row => typeof row !== 'object').length > 0) {
26
26
  errorsFound.push(this.constants.errorMessageFormat)
27
27
  }
28
28
 
@@ -49,6 +49,10 @@ export class DataTransform {
49
49
 
50
50
  //Performs standardizations based on developer provided description of the data
51
51
  developerStandardize(data, description) {
52
+ if (!data) {
53
+ return []
54
+ }
55
+
52
56
  //Validate the description object
53
57
  if (!description) {
54
58
  return undefined
@@ -98,7 +102,7 @@ export class DataTransform {
98
102
 
99
103
  return standardized
100
104
  } else {
101
- let standardized: {key: string, value: any}[] = []
105
+ let standardized: { key: string; value: any }[] = []
102
106
 
103
107
  data.forEach(row => {
104
108
  let nonNumericKeys: string[] = []
@@ -124,8 +128,36 @@ export class DataTransform {
124
128
  return standardized
125
129
  }
126
130
  } else if (description.series === true && description.singleRow === false) {
127
- if (description.seriesKey !== undefined && description.xKey !== undefined && (description.valueKey !== undefined || (description.valueKeys !== undefined && description.valueKeys.length > 0))) {
128
- if (description.valueKeys !== undefined) {
131
+ if (description.seriesKey !== undefined && description.xKey !== undefined && (description.valueKey !== undefined || (description.valueKeys !== undefined && description.valueKeys.length > 0) || (description.valueKeysTallSupport !== undefined && description.valueKeysTallSupport.length > 0))) {
132
+ if (description.valueKeysTallSupport !== undefined) {
133
+ let standardizedMapped = {}
134
+ let standardized: string[] = []
135
+
136
+ data.forEach(row => {
137
+ let uniqueKey = row[description.xKey];
138
+ Object.keys(row).forEach(key => {
139
+ if(key !== description.xKey && key !== description.seriesKey && description.valueKeysTallSupport.indexOf(key) === -1 && (!description.ignoredKeys || description.ignoredKeys.indexOf(key) === -1)){
140
+ uniqueKey += "|" + row[key];
141
+ }
142
+ })
143
+
144
+ if(!standardizedMapped[uniqueKey]){
145
+ standardizedMapped[uniqueKey] = {[description.xKey]: row[description.xKey]}
146
+ }
147
+ Object.keys(row).forEach(key => {
148
+ if(key !== description.xKey && key !== description.seriesKey && description.valueKeysTallSupport.indexOf(key) === -1 && (!description.ignoredKeys || description.ignoredKeys.indexOf(key) === -1)){
149
+ standardizedMapped[uniqueKey][key] = row[key];
150
+ }
151
+ })
152
+ description.valueKeysTallSupport.forEach(valueKey => {
153
+ standardizedMapped[uniqueKey][row[description.seriesKey] + '-' + valueKey] = row[valueKey];
154
+ })
155
+ })
156
+
157
+ standardized = Object.keys(standardizedMapped).map(key => standardizedMapped[key]);
158
+
159
+ return standardized
160
+ } else if (description.valueKeys !== undefined) {
129
161
  let standardizedMapped = {}
130
162
  let standardized: string[] = []
131
163
  let valueKeys = description.valueKeys
@@ -218,7 +250,7 @@ export class DataTransform {
218
250
  */
219
251
  cleanData(data: DataArray, excludeKey, testing = false): DataArray {
220
252
  let cleanedupData: DataArray = []
221
- if(!Array.isArray(data)) debugger;
253
+ if (!Array.isArray(data)) debugger
222
254
  if (testing) console.log('## Data to clean=', data)
223
255
  if (excludeKey === undefined) {
224
256
  console.log('COVE: cleanData excludeKey undefined')
@@ -228,7 +260,7 @@ export class DataTransform {
228
260
  if (testing) console.log('clean', i, ' d', d)
229
261
  let cleaned = {}
230
262
  Object.keys(d).forEach(function (key) {
231
- const value = d[key];
263
+ const value = d[key]
232
264
  if (key === excludeKey) {
233
265
  // pass thru
234
266
  cleaned[key] = value
@@ -259,21 +291,44 @@ export class DataTransform {
259
291
  return cleanedupData
260
292
  }
261
293
 
262
- // clean out %, $, commas from numbers when needing to do sorting!
263
- cleanDataPoint(data, testing = false) {
264
- if (testing) console.log('clean', data)
265
- let cleaned = ''
294
+ applySuppression = (data, suppressedData) => {
295
+ if (!suppressedData || suppressedData.length === 0) return data
266
296
 
267
- // remove comma and dollar signs
268
- let tmp = ''
269
- if (typeof data === 'string') {
270
- tmp = data!== null && data !== '' ? data.replace(/[,\$\%]/g, '') : ''
271
- } else {
272
- tmp = data !== null && data !== '' ? data : ''
297
+ // Create a new array to store the result without modifying the original data
298
+ const result = data.map(item => {
299
+ // Create a new object to store the updated item without modifying the original item
300
+ const newItem = { ...item }
301
+
302
+ // For each suppressedData item
303
+ for (let i = 0; i < suppressedData.length; i++) {
304
+ // If the object contains the column and its value matches the suppressed one
305
+ if (newItem[suppressedData[i].column] && newItem[suppressedData[i].column] === suppressedData[i].value) {
306
+ // Replace the value with the label in the new object
307
+ newItem[suppressedData[i].column] = suppressedData[i].label
308
+ }
273
309
  }
274
310
 
275
- if (testing) console.log('## cleanedData =', tmp)
276
- return tmp
311
+ return newItem
312
+ })
313
+
314
+ return result
315
+ }
316
+
317
+ // clean out %, $, commas from numbers when needing to do sorting!
318
+ cleanDataPoint(data, testing = false) {
319
+ if (testing) console.log('clean', data)
320
+ let cleaned = ''
321
+
322
+ // remove comma and dollar signs
323
+ let tmp = ''
324
+ if (typeof data === 'string') {
325
+ tmp = data !== null && data !== '' ? data.replace(/[,\$\%]/g, '') : ''
326
+ } else {
327
+ tmp = data !== null && data !== '' ? data : ''
328
+ }
329
+
330
+ if (testing) console.log('## cleanedData =', tmp)
331
+ return tmp
277
332
  }
278
333
  }
279
334
 
@@ -0,0 +1,11 @@
1
+ /**
2
+ * regex
3
+ * - /\w\S* replaces zero or more whitespace characters
4
+ * - g makes it find all matches in the string
5
+ * - the callback function capitalizes the word
6
+ * */
7
+ export const capitalizeSplitAndJoin = function (splittingCharacter: string = ' ', joiningCharacter: string = '') {
8
+ return this.split(splittingCharacter)
9
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
10
+ .join(joiningCharacter)
11
+ }
@@ -2,7 +2,7 @@ import Papa from 'papaparse'
2
2
 
3
3
  export default async function (url, visualizationType = '') {
4
4
  try {
5
- url = new URL(url)
5
+ url = new URL(url, window.location.origin)
6
6
 
7
7
  const path = url.pathname
8
8
  const regex = /(?:\.([^.]+))?$/
@@ -1,5 +1,28 @@
1
- export const getFileExtension = (path: string): string => {
2
- const regex = /(?:\.([^.]+))?$/
3
- const outCome: RegExpExecArray | null = regex.exec(path)
4
- return outCome ? outCome[1] : ''
5
- }
1
+ // export const getFileExtensionx = (path: string): string => {
2
+ // const regex = /(?:\.([^.]+))?$/
3
+ // const outCome: RegExpExecArray | null = regex.exec(path)
4
+ // return outCome ? outCome[1] : ''
5
+ // }
6
+
7
+ export const getFileExtension = (url: string): string => {
8
+ const regexForExtension = /(?:\.([^.]+))$/
9
+ const regexForQueryParam = /[?&]wt=(csv|json)(?:&|$)/ // Regular expression for 'wt' query parameter
10
+
11
+ const urlObject = new URL(url, window.location.origin)
12
+ const pathname = urlObject.pathname
13
+ const searchParams = urlObject.search
14
+
15
+ // First, try to get the extension from the pathname
16
+ const pathnameMatch = regexForExtension.exec(pathname)
17
+ if (pathnameMatch && pathnameMatch[1]) {
18
+ return pathnameMatch[1]
19
+ }
20
+
21
+ // Then, try to get it from the query parameter 'wt'
22
+ const queryParamsMatch = regexForQueryParam.exec(searchParams)
23
+ if (queryParamsMatch && queryParamsMatch[1]) {
24
+ return queryParamsMatch[1]
25
+ }
26
+
27
+ return ''
28
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdc/core",
3
- "version": "4.23.10",
3
+ "version": "4.24.1",
4
4
  "description": "Core components, styles, hooks, and helpers, for the CDC Open Visualization project",
5
5
  "moduleName": "CdcCore",
6
6
  "main": "dist/cdccore",
@@ -30,5 +30,5 @@
30
30
  "react": "^18.2.0",
31
31
  "react-dom": "^18.2.0"
32
32
  },
33
- "gitHead": "b3f3263e444bbf99d525b05040be22f06553760e"
33
+ "gitHead": "a352a3f74f4b681191e3244061dbb3621f36eec3"
34
34
  }
@@ -51,6 +51,7 @@ table.data-table {
51
51
  overflow: auto;
52
52
  appearance: none;
53
53
  table-layout: fixed;
54
+ display: grid;
54
55
  * {
55
56
  box-sizing: border-box;
56
57
  }
@@ -64,6 +65,7 @@ table.data-table {
64
65
  background: none;
65
66
  font-size: initial;
66
67
  color: #fff;
68
+ border: 0;
67
69
  }
68
70
 
69
71
  tr {
@@ -136,6 +138,7 @@ table.data-table {
136
138
  }
137
139
 
138
140
  tbody {
141
+ display: table-cell;
139
142
  tr {
140
143
  width: 100%;
141
144
  &:hover {
@@ -1,6 +1,3 @@
1
- div.dashboard-title,
2
- div.chart-title,
3
- div.map-title,
4
1
  .color-palette li,
5
2
  .btn {
6
3
  &.theme-purple {
@@ -3,17 +3,6 @@
3
3
  // box-shadow: rgba(0, 0, 0, 0.2) 3px 6px 10px; // no box shadows
4
4
  }
5
5
 
6
- .cove-component__header {
7
- width: 100%;
8
- padding: 0.6rem 0.8rem;
9
- border-bottom-width: 3px;
10
- border-bottom-style: solid;
11
- border-radius: 3px 3px 0 0;
12
- font-size: 1.1rem;
13
- transition: background-color 200ms ease, border-color 200ms ease;
14
- color: #fff;
15
- }
16
-
17
6
  .cove-component__content {
18
7
  padding-top: 1rem;
19
8
  border: solid 1px #ccc;
package/types/Axis.ts ADDED
@@ -0,0 +1,41 @@
1
+ export type Anchor = {
2
+ value: string
3
+ color: string
4
+ lineStyle: string
5
+ }
6
+
7
+ export type Axis = {
8
+ anchors?: Anchor[]
9
+ dataKey: string
10
+ dateDisplayFormat: string
11
+ dateParseFormat: string
12
+ displayNumbersOnBar?: boolean
13
+ enablePadding?: boolean
14
+ gridLines?: boolean
15
+ hideAxis?: boolean
16
+ hideLabel?: boolean
17
+ hideTicks?: boolean
18
+ label?: string
19
+ labelOffset?: number
20
+ labelPlacement?: string
21
+ max?: string
22
+ maxTickRotation?: number
23
+ min?: string
24
+ numTicks?: number
25
+ rightAxisSize?: number
26
+ rightHideAxis?: boolean
27
+ rightHideLabel?: boolean
28
+ rightHideTicks?: boolean
29
+ rightLabel?: string
30
+ rightLabelOffsetSize?: number
31
+ rightMax?: string
32
+ rightNumTicks?: number
33
+ sortDates?: boolean
34
+ showTargetLabel?: boolean
35
+ size?: number
36
+ target?: number
37
+ targetLabel?: string
38
+ tickRotation?: number
39
+ tickWidthMax?: number
40
+ type: string
41
+ }
package/types/Color.ts ADDED
@@ -0,0 +1,5 @@
1
+ type RGB = `rgb(${number}, ${number}, ${number})`
2
+ type RGBA = `rgba(${number}, ${number}, ${number}, ${number})`
3
+ type HEX = `#${string}`
4
+
5
+ type Color = RGB | RGBA | HEX
@@ -0,0 +1,15 @@
1
+ export type Column = {
2
+ name?: string
3
+ label: string
4
+ prefix: string
5
+ suffix: string
6
+ roundToPlace: number
7
+ commas: boolean
8
+ dataTable: boolean
9
+ startingPoint: string
10
+ series?: string
11
+ tooltips: boolean
12
+ forestPlot: boolean
13
+ forestPlotAlignRight: boolean
14
+ forestPlotStartingPoint: number
15
+ }
@@ -0,0 +1,7 @@
1
+ export type ComponentStyles = {
2
+ border: boolean
3
+ accent: boolean
4
+ background: boolean
5
+ hideBackgroundColor: boolean
6
+ borderColorTheme: boolean
7
+ }
@@ -0,0 +1,13 @@
1
+ // prettier-ignore
2
+ export type ComponentThemes =
3
+ | 'theme-amber'
4
+ | 'theme-blue'
5
+ | 'theme-brown'
6
+ | 'theme-cyan'
7
+ | 'theme-green'
8
+ | 'theme-indigo'
9
+ | 'theme-orange'
10
+ | 'theme-pink'
11
+ | 'theme-purple'
12
+ | 'theme-slate'
13
+ | 'theme-teal'
@@ -0,0 +1,8 @@
1
+ export type EditorColumnProperties = {
2
+ dataTable: boolean
3
+ label: string
4
+ name: string
5
+ prefix: string
6
+ suffix: string
7
+ tooltip: boolean
8
+ }
@@ -0,0 +1 @@
1
+ export type FilterBehavior = 'Apply Button' | 'Filter Change'
@@ -0,0 +1,29 @@
1
+ import { Axis } from './Axis'
2
+
3
+ export type ForecastingSeriesKey = {
4
+ stages: {
5
+ key: string
6
+ color: string
7
+ }[]
8
+ }
9
+
10
+ export type BarSeriesKey = {
11
+ key: string
12
+ color: string
13
+ }
14
+
15
+ export type Runtime = {
16
+ barSeriesKeys?: BarSeriesKey[]
17
+ forecastingSeriesKeys?: ForecastingSeriesKey[]
18
+ originalXAxis: {
19
+ dataKey: string
20
+ name: string
21
+ axis: string
22
+ }
23
+ xAxis: Axis
24
+ yAxis: Axis
25
+ seriesKeys: any[]
26
+ seriesLabels: string[]
27
+ seriesLabelsAll: string[]
28
+ editorErrorMessage: string
29
+ }
@@ -0,0 +1 @@
1
+ export type Series = { dataKey: string; name: string; axis: string; type: string }[]
package/types/Table.ts ADDED
@@ -0,0 +1,18 @@
1
+ export type Table = {
2
+ cellMinWidth?: number
3
+ label?: string
4
+ show?: boolean
5
+ showVertical?: boolean
6
+ indexLabel?: string
7
+ caption?: string
8
+ limitHeight?: boolean
9
+ height?: number
10
+ expanded?: boolean
11
+ showDataTableLink?: boolean
12
+ showDownloadUrl?: boolean
13
+ download?: boolean
14
+ showDownloadImgButton?: boolean
15
+ showDownloadPdfButton?: boolean
16
+ customTableConfig?: boolean
17
+ excludeColumns?: string[]
18
+ }
@@ -0,0 +1 @@
1
+ export type UpdateFieldFunc<T> = (section: string | null, subsection: string | null, fieldName: string, value: T) => void
@@ -0,0 +1,21 @@
1
+ export type Visualization = {
2
+ autoLoad: boolean
3
+ data: any
4
+ dataDescription: Object
5
+ dataKey: string
6
+ editing: boolean
7
+ formattedData: any
8
+ general: any
9
+ hide: any[]
10
+ newViz: boolean
11
+ openModal: boolean
12
+ originalFormattedData: any
13
+ table: {
14
+ showDataTableLink: boolean
15
+ }
16
+ title: string
17
+ type: 'chart' | 'map' | 'data-bite' | 'waffle-chart' | 'markup-include' | 'filtered-text' | 'filter-dropdowns'
18
+ uid: string
19
+ usesSharedFilter: any
20
+ visualizationType: string
21
+ }