@cdc/core 4.23.4 → 4.23.6
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.
- package/assets/external-link.svg +1 -0
- package/assets/icon-linear-gauge.svg +1 -0
- package/components/AdvancedEditor.jsx +7 -1
- package/components/DataTable.jsx +657 -0
- package/components/Filters.jsx +62 -7
- package/components/LegendCircle.jsx +2 -2
- package/components/{CoveMediaControls.jsx → MediaControls.jsx} +6 -6
- package/components/RepeatableGroup.jsx +37 -0
- package/components/inputs/InputSelect.jsx +1 -1
- package/components/ui/Accordion.jsx +3 -0
- package/data/colorPalettes.js +3 -3
- package/helpers/DataTransform.js +65 -65
- package/helpers/cove/date.js +9 -0
- package/helpers/cove/number.js +139 -0
- package/helpers/coveUpdateWorker.js +15 -0
- package/helpers/fetchRemoteData.js +12 -2
- package/helpers/validateFipsCodeLength.js +1 -1
- package/helpers/ver/4.23.js +10 -0
- package/package.json +2 -2
- package/styles/_data-table.scss +10 -0
- package/styles/v2/components/input/_input.scss +3 -3
- package/styles/v2/layout/_component.scss +1 -1
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import numberFromString from '@cdc/core/helpers/numberFromString'
|
|
2
|
+
|
|
3
|
+
const abbreviateNumber = num => {
|
|
4
|
+
let unit = ''
|
|
5
|
+
let absNum = Math.abs(num)
|
|
6
|
+
|
|
7
|
+
if (absNum >= 1e9) {
|
|
8
|
+
unit = 'B'
|
|
9
|
+
num = num / 1e9
|
|
10
|
+
} else if (absNum >= 1e6) {
|
|
11
|
+
unit = 'M'
|
|
12
|
+
num = num / 1e6
|
|
13
|
+
} else if (absNum >= 1e3) {
|
|
14
|
+
unit = 'K'
|
|
15
|
+
num = num / 1e3
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return num + unit
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Format numeric data based on settings in config
|
|
22
|
+
const formatNumber = (num, axis, shouldAbbreviate = false, config = null) => {
|
|
23
|
+
if (!config) console.error('no config found in formatNumber')
|
|
24
|
+
// if num is NaN return num
|
|
25
|
+
if (isNaN(num) || !num) return num
|
|
26
|
+
// Check if the input number is negative
|
|
27
|
+
const isNegative = num < 0
|
|
28
|
+
|
|
29
|
+
// If the input number is negative, take the absolute value
|
|
30
|
+
if (isNegative) {
|
|
31
|
+
num = Math.abs(num)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// destructure dataFormat values
|
|
35
|
+
let {
|
|
36
|
+
dataFormat: { commas, abbreviated, roundTo, prefix, suffix, rightRoundTo, bottomRoundTo, rightPrefix, rightSuffix, bottomPrefix, bottomSuffix, bottomAbbreviated }
|
|
37
|
+
} = config
|
|
38
|
+
|
|
39
|
+
// check if value contains comma and remove it. later will add comma below.
|
|
40
|
+
if (String(num).indexOf(',') !== -1) num = num.replaceAll(',', '')
|
|
41
|
+
|
|
42
|
+
let original = num
|
|
43
|
+
let stringFormattingOptions
|
|
44
|
+
if (axis === 'left') {
|
|
45
|
+
stringFormattingOptions = {
|
|
46
|
+
useGrouping: config.dataFormat.commas ? true : false,
|
|
47
|
+
minimumFractionDigits: roundTo ? Number(roundTo) : 0,
|
|
48
|
+
maximumFractionDigits: roundTo ? Number(roundTo) : 0
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (axis === 'right') {
|
|
53
|
+
stringFormattingOptions = {
|
|
54
|
+
useGrouping: config.dataFormat.rightCommas ? true : false,
|
|
55
|
+
minimumFractionDigits: rightRoundTo ? Number(rightRoundTo) : 0,
|
|
56
|
+
maximumFractionDigits: rightRoundTo ? Number(rightRoundTo) : 0
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (axis === 'bottom') {
|
|
61
|
+
stringFormattingOptions = {
|
|
62
|
+
useGrouping: config.dataFormat.bottomCommas ? true : false,
|
|
63
|
+
minimumFractionDigits: bottomRoundTo ? Number(bottomRoundTo) : 0,
|
|
64
|
+
maximumFractionDigits: bottomRoundTo ? Number(bottomRoundTo) : 0
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
num = numberFromString(num)
|
|
69
|
+
|
|
70
|
+
if (isNaN(num)) {
|
|
71
|
+
config.runtime.editorErrorMessage = `Unable to parse number from data ${original}. Try reviewing your data and selections in the Data Series section.`
|
|
72
|
+
return original
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!config.dataFormat) return num
|
|
76
|
+
if (config.dataCutoff) {
|
|
77
|
+
let cutoff = numberFromString(config.dataCutoff)
|
|
78
|
+
|
|
79
|
+
if (num < cutoff) {
|
|
80
|
+
num = cutoff
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// When we're formatting the left axis
|
|
85
|
+
// Use commas also updates bars and the data table
|
|
86
|
+
// We can't use commas when we're formatting the dataFormatted number
|
|
87
|
+
// Example: commas -> 12,000; abbreviated -> 12k (correct); abbreviated & commas -> 12 (incorrect)
|
|
88
|
+
//
|
|
89
|
+
// Edge case for small numbers with decimals
|
|
90
|
+
// - if roundTo undefined which means it is blank, then do not round
|
|
91
|
+
|
|
92
|
+
if ((axis === 'left' && commas && abbreviated && shouldAbbreviate) || (axis === 'bottom' && commas && abbreviated && shouldAbbreviate)) {
|
|
93
|
+
num = num // eslint-disable-line
|
|
94
|
+
} else {
|
|
95
|
+
num = num.toLocaleString('en-US', stringFormattingOptions)
|
|
96
|
+
}
|
|
97
|
+
let result = ''
|
|
98
|
+
|
|
99
|
+
if (abbreviated && axis === 'left' && shouldAbbreviate) {
|
|
100
|
+
num = abbreviateNumber(parseFloat(num))
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (bottomAbbreviated && axis === 'bottom' && shouldAbbreviate) {
|
|
104
|
+
num = abbreviateNumber(parseFloat(num))
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (prefix && axis === 'left') {
|
|
108
|
+
result += prefix
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (rightPrefix && axis === 'right') {
|
|
112
|
+
result += rightPrefix
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (bottomPrefix && axis === 'bottom') {
|
|
116
|
+
result += bottomPrefix
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
result += num
|
|
120
|
+
|
|
121
|
+
if (suffix && axis === 'left') {
|
|
122
|
+
result += suffix
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (rightSuffix && axis === 'right') {
|
|
126
|
+
result += rightSuffix
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (bottomSuffix && axis === 'bottom') {
|
|
130
|
+
result += bottomSuffix
|
|
131
|
+
}
|
|
132
|
+
if (isNegative) {
|
|
133
|
+
result = '-' + result
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return String(result)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export { formatNumber }
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// If config key names or position in the config have been changed with a version change,
|
|
2
|
+
// process those config entries and format old values into new
|
|
3
|
+
import update_4_23 from './ver/4.23'
|
|
4
|
+
|
|
5
|
+
// 4.23.6 ------------------------------------------------------
|
|
6
|
+
const coveUpdateWorker = async config => {
|
|
7
|
+
let genConfig = config
|
|
8
|
+
|
|
9
|
+
// v4.23
|
|
10
|
+
genConfig = await update_4_23(genConfig)
|
|
11
|
+
|
|
12
|
+
return genConfig
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default coveUpdateWorker
|
|
@@ -14,10 +14,20 @@ export default async function (url, visualizationType = '') {
|
|
|
14
14
|
data = await fetch(url.href)
|
|
15
15
|
.then(response => response.text())
|
|
16
16
|
.then(responseText => {
|
|
17
|
+
// for every comma NOT inside quotes, replace with a pipe delimiter
|
|
18
|
+
// - this will let commas inside the quotes not be parsed as a new column
|
|
19
|
+
// - Limitation: if a delimiter other than comma is used in the csv this will break
|
|
20
|
+
// Examples of other delimiters that would break: tab
|
|
21
|
+
responseText = responseText.replace(/(".*?")|,/g, (...m) => m[1] || '|')
|
|
22
|
+
// now strip the double quotes
|
|
23
|
+
responseText = responseText.replace(/["]+/g, '')
|
|
17
24
|
const parsedCsv = Papa.parse(responseText, {
|
|
25
|
+
//quotes: "true", // dont need these
|
|
26
|
+
//quoteChar: "'", // has no effect that I can tell
|
|
18
27
|
header: true,
|
|
19
|
-
|
|
20
|
-
|
|
28
|
+
skipEmptyLines: true,
|
|
29
|
+
delimiter: '|', // we are using pipe symbol as delimiter so setting this explicitly for Papa.parse
|
|
30
|
+
dynamicTyping: false
|
|
21
31
|
})
|
|
22
32
|
return parsedCsv.data
|
|
23
33
|
})
|
|
@@ -28,7 +28,7 @@ export default function validateFipsCodeLength(stateOrData) {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
// Only includes data - get column name from somewhere else
|
|
31
|
-
if (Array.isArray(stateOrData)) {
|
|
31
|
+
if (Array.isArray(stateOrData) && stateOrData.length > 0) {
|
|
32
32
|
let columns = Object.keys(stateOrData[0])
|
|
33
33
|
|
|
34
34
|
let potentialColumnNames = ['fips', 'FIPS', 'fips codes', 'FIPS CODES', 'Fips Codes', 'fips Codes', 'Fips codes', 'FIPS Codes']
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdc/core",
|
|
3
|
-
"version": "4.23.
|
|
3
|
+
"version": "4.23.6",
|
|
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": "
|
|
33
|
+
"gitHead": "aaed0388b487adfeb3e7e278b4ce74df09cbaade"
|
|
34
34
|
}
|
package/styles/_data-table.scss
CHANGED
|
@@ -39,6 +39,7 @@ table.data-table {
|
|
|
39
39
|
border-collapse: collapse;
|
|
40
40
|
overflow: auto;
|
|
41
41
|
appearance: none;
|
|
42
|
+
table-layout: fixed;
|
|
42
43
|
* {
|
|
43
44
|
box-sizing: border-box;
|
|
44
45
|
}
|
|
@@ -172,6 +173,15 @@ table.data-table {
|
|
|
172
173
|
margin-left: 5px;
|
|
173
174
|
}
|
|
174
175
|
}
|
|
176
|
+
|
|
177
|
+
.boxplot-td {
|
|
178
|
+
//display: inline-block;
|
|
179
|
+
//box-sizing: border-box;
|
|
180
|
+
table-layout: fixed;
|
|
181
|
+
width: 200;
|
|
182
|
+
//min-width: 150px;
|
|
183
|
+
//max-width: 400px;
|
|
184
|
+
}
|
|
175
185
|
}
|
|
176
186
|
|
|
177
187
|
.no-data {
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
display: block;
|
|
3
3
|
position: relative;
|
|
4
4
|
padding: 0.5em 0.5em;
|
|
5
|
-
border-width: 1px;
|
|
6
|
-
border-style: solid;
|
|
7
|
-
border-color: #cbcbcb;
|
|
5
|
+
border-width: 1px !important; // intentional use of !important for CDC
|
|
6
|
+
border-style: solid !important; // intentional use of !important for CDC
|
|
7
|
+
border-color: #cbcbcb !important; // intentional use of !important for CDC
|
|
8
8
|
border-radius: 0.1875rem;
|
|
9
9
|
transition: border-color 200ms $transition-expo-out;
|
|
10
10
|
font-family: sans-serif;
|