@cdc/core 4.24.12 → 4.25.2-25
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/components/DataTable/DataTable.tsx +58 -45
- package/components/DataTable/DataTableStandAlone.tsx +3 -3
- package/components/DataTable/components/ChartHeader.tsx +26 -6
- package/components/DataTable/components/ExpandCollapse.tsx +1 -4
- package/components/DataTable/components/MapHeader.tsx +5 -1
- package/components/DataTable/data-table.css +3 -8
- package/components/DataTable/helpers/chartCellMatrix.tsx +14 -5
- package/components/DataTable/helpers/customSort.ts +2 -2
- package/components/DataTable/helpers/mapCellMatrix.tsx +83 -60
- package/components/DataTable/types/TableConfig.ts +0 -1
- package/components/EditorPanel/FootnotesEditor.tsx +49 -7
- package/components/EditorPanel/Inputs.tsx +4 -0
- package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +16 -3
- package/components/Filters/Filters.tsx +95 -51
- package/components/Filters/helpers/filterWrapping.ts +43 -0
- package/components/Filters/helpers/handleSorting.ts +6 -0
- package/components/Filters/helpers/tests/handleSorting.test.ts +26 -0
- package/components/Footnotes/Footnotes.tsx +1 -1
- package/components/Layout/components/Visualization/index.tsx +18 -4
- package/components/Layout/components/Visualization/visualizations.scss +1 -1
- package/components/Legend/Legend.Gradient.tsx +1 -4
- package/components/Legend/index.tsx +1 -1
- package/components/LegendShape.tsx +2 -3
- package/components/MediaControls.jsx +32 -8
- package/components/NestedDropdown/NestedDropdown.tsx +25 -17
- package/components/NestedDropdown/nesteddropdown.styles.css +13 -7
- package/components/Table/Table.tsx +11 -11
- package/components/Table/components/Row.tsx +14 -5
- package/components/_stories/DataTable.stories.tsx +1 -2
- package/components/elements/Button.jsx +38 -19
- package/components/elements/Confirm.tsx +45 -0
- package/components/elements/Error.tsx +24 -0
- package/components/managers/DataDesigner.tsx +198 -143
- package/components/ui/Title/Title.scss +12 -5
- package/components/ui/Title/index.tsx +1 -1
- package/dist/cove-main.css +260 -723
- package/dist/cove-main.css.map +1 -1
- package/helpers/DataTransform.ts +55 -61
- package/helpers/addValuesToFilters.ts +45 -16
- package/helpers/cove/accessibility.ts +24 -0
- package/helpers/cove/fontSettings.ts +1 -1
- package/helpers/cove/number.ts +1 -7
- package/helpers/coveUpdateWorker.ts +5 -1
- package/helpers/displayDataAsText.ts +64 -0
- package/helpers/filterVizData.ts +2 -2
- package/helpers/formatConfigBeforeSave.ts +17 -2
- package/helpers/isOlderVersion.ts +20 -0
- package/helpers/isRightAlignedTableValue.js +14 -0
- package/helpers/missingRequiredSections.ts +20 -0
- package/helpers/queryStringUtils.ts +7 -0
- package/helpers/tests/addValuesToFilters.test.ts +19 -1
- package/helpers/useDataVizClasses.ts +8 -4
- package/helpers/ver/4.24.10.ts +12 -0
- package/helpers/ver/4.24.11.ts +18 -0
- package/helpers/ver/4.24.7.ts +19 -1
- package/helpers/ver/4.25.1.ts +18 -0
- package/package.json +2 -2
- package/styles/_button-section.scss +2 -5
- package/styles/_global-variables.scss +17 -7
- package/styles/_global.scss +8 -12
- package/styles/_reset.scss +4 -5
- package/styles/_typography.scss +0 -20
- package/styles/_variables.scss +0 -3
- package/styles/base.scss +44 -5
- package/styles/cove-main.scss +1 -1
- package/styles/filters.scss +65 -6
- package/styles/v2/base/_general.scss +3 -2
- package/styles/v2/components/button.scss +0 -1
- package/styles/v2/main.scss +3 -4
- package/styles/v2/themes/_color-definitions.scss +4 -4
- package/styles/v2/utils/index.scss +0 -1
- package/types/BoxPlot.ts +1 -0
- package/types/Runtime.ts +1 -0
- package/types/Table.ts +0 -1
- package/types/Version.ts +1 -1
- package/types/VizFilter.ts +3 -1
- package/styles/v2/utils/_spacers.scss +0 -31
|
@@ -42,13 +42,30 @@ const generateMedia = (state, type, elementToCapture) => {
|
|
|
42
42
|
// Apparently some packages use state.title where others use state.general.title
|
|
43
43
|
const handleFileName = state => {
|
|
44
44
|
// dashboard titles
|
|
45
|
-
if (state?.dashboard?.title)
|
|
45
|
+
if (state?.dashboard?.title)
|
|
46
|
+
return (
|
|
47
|
+
state.dashboard.title.replace(/\s+/g, '-').toLowerCase() +
|
|
48
|
+
'-' +
|
|
49
|
+
date.getDate() +
|
|
50
|
+
date.getMonth() +
|
|
51
|
+
date.getFullYear()
|
|
52
|
+
)
|
|
46
53
|
|
|
47
54
|
// map titles
|
|
48
|
-
if (state?.general?.title)
|
|
55
|
+
if (state?.general?.title)
|
|
56
|
+
return (
|
|
57
|
+
state.general.title.replace(/\s+/g, '-').toLowerCase() +
|
|
58
|
+
'-' +
|
|
59
|
+
date.getDate() +
|
|
60
|
+
date.getMonth() +
|
|
61
|
+
date.getFullYear()
|
|
62
|
+
)
|
|
49
63
|
|
|
50
64
|
// chart titles
|
|
51
|
-
if (state?.title)
|
|
65
|
+
if (state?.title)
|
|
66
|
+
return (
|
|
67
|
+
state.title.replace(/\s+/g, '-').toLowerCase() + '-' + date.getDate() + date.getMonth() + date.getFullYear()
|
|
68
|
+
)
|
|
52
69
|
|
|
53
70
|
return 'no-title'
|
|
54
71
|
}
|
|
@@ -59,7 +76,10 @@ const generateMedia = (state, type, elementToCapture) => {
|
|
|
59
76
|
|
|
60
77
|
switch (type) {
|
|
61
78
|
case 'image':
|
|
62
|
-
html2canvas(baseSvg, {
|
|
79
|
+
html2canvas(baseSvg, {
|
|
80
|
+
ignoreElements: el =>
|
|
81
|
+
el.className?.indexOf && el.className.search(/download-buttons|download-links|data-table-container/) !== -1
|
|
82
|
+
}).then(canvas => {
|
|
63
83
|
saveImageAs(canvas.toDataURL(), filename + '.png')
|
|
64
84
|
})
|
|
65
85
|
return
|
|
@@ -98,9 +118,14 @@ const handleTheme = state => {
|
|
|
98
118
|
|
|
99
119
|
// Download CSV
|
|
100
120
|
const Button = ({ state, text, type, title, elementToCapture }) => {
|
|
101
|
-
const buttonClasses = ['btn', 'btn-
|
|
121
|
+
const buttonClasses = ['btn', 'btn-primary']
|
|
102
122
|
return (
|
|
103
|
-
<button
|
|
123
|
+
<button
|
|
124
|
+
className={buttonClasses.join(' ')}
|
|
125
|
+
title={title}
|
|
126
|
+
onClick={() => generateMedia(state, type, elementToCapture)}
|
|
127
|
+
style={{ lineHeight: '1.4em' }}
|
|
128
|
+
>
|
|
104
129
|
{buttonText[type]}
|
|
105
130
|
</button>
|
|
106
131
|
)
|
|
@@ -108,7 +133,7 @@ const Button = ({ state, text, type, title, elementToCapture }) => {
|
|
|
108
133
|
|
|
109
134
|
// Link to CSV/JSON data
|
|
110
135
|
const Link = ({ config, dashboardDataConfig }) => {
|
|
111
|
-
let dataConfig = dashboardDataConfig || config
|
|
136
|
+
let dataConfig = dashboardDataConfig || config
|
|
112
137
|
// Handles Maps & Charts
|
|
113
138
|
if (dataConfig.dataFileSourceType === 'url' && dataConfig.dataFileName && config.table.showDownloadUrl) {
|
|
114
139
|
return (
|
|
@@ -126,7 +151,6 @@ const Link = ({ config, dashboardDataConfig }) => {
|
|
|
126
151
|
) : null
|
|
127
152
|
}
|
|
128
153
|
|
|
129
|
-
// TODO: convert to standardized COVE section
|
|
130
154
|
const Section = ({ children, classes }) => {
|
|
131
155
|
return (
|
|
132
156
|
<section className={classes.join(' ')}>
|
|
@@ -6,12 +6,13 @@ import Loader from '../Loader'
|
|
|
6
6
|
|
|
7
7
|
const Options: React.FC<{
|
|
8
8
|
subOptions: ValueTextPair[]
|
|
9
|
+
handleBlur: React.FocusEventHandler<HTMLLIElement>
|
|
9
10
|
filterIndex: number
|
|
10
11
|
label: string
|
|
11
12
|
handleSubGroupSelect: Function
|
|
12
13
|
userSelectedLabel: string
|
|
13
14
|
userSearchTerm: string
|
|
14
|
-
}> = ({ subOptions, filterIndex, label, handleSubGroupSelect, userSelectedLabel, userSearchTerm }) => {
|
|
15
|
+
}> = ({ subOptions, handleBlur, filterIndex, label, handleSubGroupSelect, userSelectedLabel, userSearchTerm }) => {
|
|
15
16
|
const [isTierOneExpanded, setIsTierOneExpanded] = useState(true)
|
|
16
17
|
const checkMark = <>✔</>
|
|
17
18
|
|
|
@@ -45,6 +46,7 @@ const Options: React.FC<{
|
|
|
45
46
|
tabIndex={0}
|
|
46
47
|
aria-label={label}
|
|
47
48
|
onClick={handleGroupClick}
|
|
49
|
+
onBlur={handleBlur}
|
|
48
50
|
onKeyUp={handleKeyUp}
|
|
49
51
|
className={`nested-dropdown-group-${filterIndex}`}
|
|
50
52
|
>
|
|
@@ -124,25 +126,22 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
|
|
|
124
126
|
}) => {
|
|
125
127
|
const dropdownId = useId()
|
|
126
128
|
|
|
127
|
-
const [userSearchTerm, setUserSearchTerm] = useState(
|
|
128
|
-
const [inputValue, setInputValue] = useState('')
|
|
129
|
+
const [userSearchTerm, setUserSearchTerm] = useState(null)
|
|
129
130
|
|
|
130
|
-
const
|
|
131
|
+
const inputValue = useMemo(() => {
|
|
131
132
|
// value from props
|
|
132
133
|
return activeSubGroup ? `${activeGroup} - ${activeSubGroup}` : ''
|
|
133
|
-
}, [activeSubGroup])
|
|
134
|
+
}, [activeGroup, activeSubGroup])
|
|
134
135
|
const [inputHasFocus, setInputHasFocus] = useState(false)
|
|
135
136
|
const [isListOpened, setIsListOpened] = useState(false)
|
|
136
|
-
|
|
137
|
+
const nestedDropdownRef = useRef(null)
|
|
137
138
|
const searchInput = useRef(null)
|
|
138
139
|
const searchDropdown = useRef(null)
|
|
139
140
|
|
|
140
141
|
const chooseSelectedSubGroup = (tierOne: string | number, tierTwo: string | number) => {
|
|
141
142
|
searchInput.current.focus()
|
|
142
|
-
|
|
143
|
-
setUserSearchTerm('')
|
|
143
|
+
setUserSearchTerm(null)
|
|
144
144
|
setIsListOpened(false)
|
|
145
|
-
setInputValue(selectedItemValue)
|
|
146
145
|
handleSelectedItems([String(tierOne), String(tierTwo)])
|
|
147
146
|
}
|
|
148
147
|
|
|
@@ -220,34 +219,43 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
|
|
|
220
219
|
}
|
|
221
220
|
|
|
222
221
|
const filterOptions = useMemo(() => {
|
|
223
|
-
return filterSearchTerm(userSearchTerm, options)
|
|
222
|
+
return filterSearchTerm(userSearchTerm || '', options)
|
|
224
223
|
}, [userSearchTerm, options])
|
|
225
224
|
|
|
226
225
|
const handleSearchTermChange = e => {
|
|
227
226
|
const newSearchTerm = e.target.value
|
|
228
227
|
setIsListOpened(true)
|
|
229
228
|
setUserSearchTerm(newSearchTerm)
|
|
230
|
-
setInputValue(newSearchTerm)
|
|
231
229
|
}
|
|
232
230
|
|
|
233
|
-
const handleOnBlur = e => {
|
|
231
|
+
const handleOnBlur = (e: React.FocusEvent<HTMLLIElement, Element>): void => {
|
|
234
232
|
if (
|
|
235
233
|
e.relatedTarget === null ||
|
|
236
234
|
![
|
|
237
235
|
`nested-dropdown-${filterIndex}`,
|
|
238
236
|
`nested-dropdown-group-${filterIndex}`,
|
|
239
|
-
`selectable-item-${filterIndex}
|
|
237
|
+
`selectable-item-${filterIndex}`,
|
|
238
|
+
`main-nested-dropdown-container-${filterIndex}`
|
|
240
239
|
].includes(e.relatedTarget.className)
|
|
241
240
|
) {
|
|
242
241
|
setInputHasFocus(false)
|
|
243
242
|
setIsListOpened(false)
|
|
243
|
+
} else {
|
|
244
|
+
;(e.relatedTarget as HTMLElement).focus()
|
|
244
245
|
}
|
|
245
246
|
}
|
|
246
247
|
|
|
248
|
+
function handleBlur(nestedDropdown, handleOnBlur) {
|
|
249
|
+
nestedDropdown?.addEventListener('blur', handleOnBlur)
|
|
250
|
+
}
|
|
251
|
+
handleBlur(searchInput.current, e => handleOnBlur(e))
|
|
252
|
+
handleBlur(searchDropdown.current, e => handleOnBlur(e))
|
|
253
|
+
|
|
247
254
|
return (
|
|
248
255
|
<>
|
|
249
256
|
<div
|
|
250
257
|
id={dropdownId}
|
|
258
|
+
ref={nestedDropdownRef}
|
|
251
259
|
className={`nested-dropdown nested-dropdown-${filterIndex} ${isListOpened ? 'open-filter' : ''}`}
|
|
252
260
|
onKeyUp={handleKeyUp}
|
|
253
261
|
>
|
|
@@ -265,7 +273,7 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
|
|
|
265
273
|
aria-haspopup='true'
|
|
266
274
|
aria-hidden='false'
|
|
267
275
|
tabIndex={0}
|
|
268
|
-
value={
|
|
276
|
+
value={userSearchTerm !== null ? userSearchTerm : inputValue}
|
|
269
277
|
onChange={handleSearchTermChange}
|
|
270
278
|
placeholder={loading ? 'Loading...' : '- Select -'}
|
|
271
279
|
disabled={loading || !options.length}
|
|
@@ -273,7 +281,6 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
|
|
|
273
281
|
if (inputHasFocus) setIsListOpened(!isListOpened)
|
|
274
282
|
}}
|
|
275
283
|
onFocus={() => setInputHasFocus(true)}
|
|
276
|
-
onBlur={e => handleOnBlur(e)}
|
|
277
284
|
/>
|
|
278
285
|
<span className='list-arrow' aria-hidden={true}>
|
|
279
286
|
<Icon display='caretDown' />
|
|
@@ -287,7 +294,7 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
|
|
|
287
294
|
aria-labelledby='main-nested-dropdown'
|
|
288
295
|
aria-expanded={isListOpened}
|
|
289
296
|
ref={searchDropdown}
|
|
290
|
-
className={`main-nested-dropdown-container
|
|
297
|
+
className={`main-nested-dropdown-container-${filterIndex}${isListOpened ? '' : ' hide'}`}
|
|
291
298
|
>
|
|
292
299
|
{filterOptions.length
|
|
293
300
|
? filterOptions.map(([group, subgroup], index) => {
|
|
@@ -296,6 +303,7 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
|
|
|
296
303
|
return (
|
|
297
304
|
<Options
|
|
298
305
|
key={groupTextValue + '_' + index}
|
|
306
|
+
handleBlur={handleOnBlur}
|
|
299
307
|
subOptions={subgroup}
|
|
300
308
|
filterIndex={filterIndex}
|
|
301
309
|
label={groupTextValue}
|
|
@@ -303,7 +311,7 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
|
|
|
303
311
|
chooseSelectedSubGroup(groupValue, subGroupValue)
|
|
304
312
|
}}
|
|
305
313
|
userSelectedLabel={activeGroup + activeSubGroup}
|
|
306
|
-
userSearchTerm={userSearchTerm}
|
|
314
|
+
userSearchTerm={userSearchTerm || ''}
|
|
307
315
|
/>
|
|
308
316
|
)
|
|
309
317
|
})
|
|
@@ -10,23 +10,31 @@
|
|
|
10
10
|
list-style: none;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
* {
|
|
14
|
+
font-family: var(--app-font-secondary) !important;
|
|
15
|
+
font-size: var(--filter-select-font-size) !important;
|
|
16
|
+
}
|
|
17
|
+
|
|
13
18
|
.search-input {
|
|
19
|
+
color: var(--cool-gray-90);
|
|
20
|
+
font-weight: 300;
|
|
21
|
+
|
|
14
22
|
border: none;
|
|
15
23
|
position: relative;
|
|
16
24
|
display: inline-block;
|
|
17
25
|
width: 100%;
|
|
18
26
|
padding: 0;
|
|
19
27
|
&::placeholder {
|
|
20
|
-
color: var(--
|
|
28
|
+
color: var(--cool-gray-90);
|
|
21
29
|
}
|
|
22
30
|
}
|
|
23
31
|
|
|
24
|
-
|
|
32
|
+
[class^='main-nested-dropdown-container-'],
|
|
25
33
|
.nested-dropdown-input-container {
|
|
26
|
-
border: 1px solid var(--
|
|
34
|
+
border: 1px solid var(--cool-gray-10);
|
|
27
35
|
min-width: 200px;
|
|
28
36
|
cursor: pointer;
|
|
29
|
-
padding: 0.
|
|
37
|
+
padding: 0.4rem 0.75rem;
|
|
30
38
|
font-size: 1em;
|
|
31
39
|
}
|
|
32
40
|
|
|
@@ -53,7 +61,6 @@
|
|
|
53
61
|
border-radius: 0.25rem;
|
|
54
62
|
position: relative;
|
|
55
63
|
& > span.list-arrow {
|
|
56
|
-
color: var(--mediumGray);
|
|
57
64
|
position: absolute;
|
|
58
65
|
top: 9px;
|
|
59
66
|
right: 1px;
|
|
@@ -63,13 +70,12 @@
|
|
|
63
70
|
&.disabled {
|
|
64
71
|
background-color: var(--lightestGray);
|
|
65
72
|
& > :is(input) {
|
|
66
|
-
color: var(--darkGray);
|
|
67
73
|
background-color: var(--lightestGray);
|
|
68
74
|
}
|
|
69
75
|
}
|
|
70
76
|
}
|
|
71
77
|
|
|
72
|
-
&
|
|
78
|
+
& [class^='main-nested-dropdown-container-'] {
|
|
73
79
|
max-height: 375px;
|
|
74
80
|
overflow-y: scroll;
|
|
75
81
|
position: absolute;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { ReactNode } from 'react'
|
|
2
2
|
import Row from './components/Row'
|
|
3
3
|
import GroupRow from './components/GroupRow'
|
|
4
|
-
import { CellMatrix
|
|
4
|
+
import { CellMatrix } from './types/CellMatrix'
|
|
5
5
|
import { RowType } from './types/RowType'
|
|
6
6
|
import { PreliminaryDataItem } from '@cdc/chart/src/types/ChartConfig'
|
|
7
7
|
import _ from 'lodash'
|
|
8
8
|
|
|
9
9
|
type TableProps = {
|
|
10
|
-
childrenMatrix: CellMatrix |
|
|
10
|
+
childrenMatrix: CellMatrix | Map<string, CellMatrix>
|
|
11
11
|
noData?: boolean
|
|
12
12
|
tableName: string
|
|
13
13
|
caption: string
|
|
@@ -22,9 +22,9 @@ type TableProps = {
|
|
|
22
22
|
}
|
|
23
23
|
wrapColumns?: boolean
|
|
24
24
|
hasRowType?: boolean // if it has row type then the first column is the row type which will explain how to render the row
|
|
25
|
-
fontSize: 'small' | 'medium' | 'large'
|
|
26
25
|
viewport: 'lg' | 'md' | 'sm' | 'xs' | 'xxs'
|
|
27
26
|
preliminaryData?: PreliminaryDataItem[]
|
|
27
|
+
rightAlignedCols: object
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
type Position = 'sticky'
|
|
@@ -39,9 +39,9 @@ const Table = ({
|
|
|
39
39
|
tableOptions,
|
|
40
40
|
wrapColumns,
|
|
41
41
|
hasRowType,
|
|
42
|
-
fontSize,
|
|
43
42
|
viewport,
|
|
44
|
-
preliminaryData
|
|
43
|
+
preliminaryData,
|
|
44
|
+
rightAlignedCols
|
|
45
45
|
}: TableProps) => {
|
|
46
46
|
const headStyle = stickyHeader ? { position: 'sticky' as Position, top: 0, zIndex: 2 } : {}
|
|
47
47
|
const isGroupedMatrix = !Array.isArray(childrenMatrix)
|
|
@@ -58,9 +58,9 @@ const Table = ({
|
|
|
58
58
|
<thead style={headStyle}>{headContent}</thead>
|
|
59
59
|
<tbody>
|
|
60
60
|
{isGroupedMatrix
|
|
61
|
-
?
|
|
61
|
+
? Array.from(childrenMatrix.keys()).flatMap(groupName => {
|
|
62
62
|
let colSpan = 0
|
|
63
|
-
const rows = childrenMatrix
|
|
63
|
+
const rows = childrenMatrix.get(groupName).map((row, i) => {
|
|
64
64
|
colSpan = row.length
|
|
65
65
|
const key = `${tableName}-${groupName}-row-${i}`
|
|
66
66
|
return (
|
|
@@ -71,8 +71,8 @@ const Table = ({
|
|
|
71
71
|
childRow={row}
|
|
72
72
|
wrapColumns={wrapColumns}
|
|
73
73
|
cellMinWidth={tableOptions.cellMinWidth}
|
|
74
|
-
fontSize={fontSize}
|
|
75
74
|
viewport={viewport}
|
|
75
|
+
rightAlignedCols={rightAlignedCols}
|
|
76
76
|
/>
|
|
77
77
|
)
|
|
78
78
|
})
|
|
@@ -92,8 +92,8 @@ const Table = ({
|
|
|
92
92
|
childRow={childRow}
|
|
93
93
|
wrapColumns={wrapColumns}
|
|
94
94
|
cellMinWidth={tableOptions.cellMinWidth}
|
|
95
|
-
fontSize={fontSize}
|
|
96
95
|
viewport={viewport}
|
|
96
|
+
rightAlignedCols={rightAlignedCols}
|
|
97
97
|
/>
|
|
98
98
|
)
|
|
99
99
|
} else {
|
|
@@ -110,8 +110,8 @@ const Table = ({
|
|
|
110
110
|
isTotal={true}
|
|
111
111
|
wrapColumns={wrapColumns}
|
|
112
112
|
cellMinWidth={tableOptions.cellMinWidth}
|
|
113
|
-
fontSize={fontSize}
|
|
114
113
|
viewport={viewport}
|
|
114
|
+
rightAlignedCols={rightAlignedCols}
|
|
115
115
|
/>
|
|
116
116
|
)
|
|
117
117
|
case RowType.row_group_total:
|
|
@@ -125,8 +125,8 @@ const Table = ({
|
|
|
125
125
|
childRow={childRowCopy}
|
|
126
126
|
wrapColumns={wrapColumns}
|
|
127
127
|
cellMinWidth={tableOptions.cellMinWidth}
|
|
128
|
-
fontSize={fontSize}
|
|
129
128
|
viewport={viewport}
|
|
129
|
+
rightAlignedCols={rightAlignedCols}
|
|
130
130
|
/>
|
|
131
131
|
)
|
|
132
132
|
}
|
|
@@ -8,18 +8,25 @@ type RowProps = {
|
|
|
8
8
|
wrapColumns: boolean
|
|
9
9
|
isTotal?: boolean
|
|
10
10
|
cellMinWidth?: number
|
|
11
|
-
fontSize: 'small' | 'medium' | 'large'
|
|
12
11
|
viewport: 'lg' | 'md' | 'sm' | 'xs' | 'xxs'
|
|
13
12
|
style?: object
|
|
14
13
|
preliminaryData?: PreliminaryDataItem[]
|
|
14
|
+
rightAlignedCols: object
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
const Row: FC<RowProps> = props => {
|
|
18
|
-
const {
|
|
18
|
+
const {
|
|
19
|
+
childRow,
|
|
20
|
+
rowKey,
|
|
21
|
+
wrapColumns,
|
|
22
|
+
cellMinWidth = 0,
|
|
23
|
+
isTotal,
|
|
24
|
+
viewport,
|
|
25
|
+
preliminaryData,
|
|
26
|
+
rightAlignedCols
|
|
27
|
+
} = props
|
|
19
28
|
const whiteSpace = wrapColumns ? 'unset' : 'nowrap'
|
|
20
29
|
const minWidth = cellMinWidth + 'px'
|
|
21
|
-
const fontSizes = { small: 16, medium: 18, large: 20 }
|
|
22
|
-
const cellFontSize = ['xs', 'xxs'].includes(viewport) ? '12px' : `${fontSizes[fontSize]}px`
|
|
23
30
|
|
|
24
31
|
return (
|
|
25
32
|
<tr>
|
|
@@ -30,11 +37,13 @@ const Row: FC<RowProps> = props => {
|
|
|
30
37
|
) && { color: '#777772' }) ||
|
|
31
38
|
{}
|
|
32
39
|
|
|
40
|
+
const textAlign = rightAlignedCols && rightAlignedCols[i] ? 'right' : ''
|
|
41
|
+
|
|
33
42
|
return (
|
|
34
43
|
<Cell
|
|
35
44
|
ariaLabel={style?.color ? 'suppressed data' : ''}
|
|
36
45
|
key={rowKey + '__' + i}
|
|
37
|
-
style={{ whiteSpace, minWidth,
|
|
46
|
+
style={{ whiteSpace, minWidth, textAlign, ...style }}
|
|
38
47
|
isBold={isTotal}
|
|
39
48
|
>
|
|
40
49
|
{child}
|
|
@@ -5,25 +5,41 @@ import LoadSpin from '../ui/LoadSpin'
|
|
|
5
5
|
|
|
6
6
|
import '../../styles/v2/components/button.scss'
|
|
7
7
|
|
|
8
|
-
const Button = ({
|
|
8
|
+
const Button = ({
|
|
9
|
+
style,
|
|
10
|
+
role,
|
|
11
|
+
hoverStyle = {},
|
|
12
|
+
fluid = false,
|
|
13
|
+
loading = false,
|
|
14
|
+
loadingText = 'Loading...',
|
|
15
|
+
flexCenter,
|
|
16
|
+
active = false,
|
|
17
|
+
onClick,
|
|
18
|
+
children,
|
|
19
|
+
...attributes
|
|
20
|
+
}) => {
|
|
9
21
|
const buttonRef = useRef(null)
|
|
10
22
|
|
|
11
|
-
const [
|
|
12
|
-
const [
|
|
13
|
-
const [
|
|
14
|
-
const [
|
|
23
|
+
const [buttonState, setButtonState] = useState('out')
|
|
24
|
+
const [customStyles, setCustomStyles] = useState({ ...style })
|
|
25
|
+
const [childrenWidth, setChildrenWidth] = useState()
|
|
26
|
+
const [loadtextWidth, setLoadtextWidth] = useState()
|
|
15
27
|
|
|
16
28
|
const attributesObj = {
|
|
17
29
|
...attributes,
|
|
18
30
|
style: customStyles,
|
|
19
|
-
className:
|
|
31
|
+
className:
|
|
32
|
+
'cove-button' +
|
|
33
|
+
(flexCenter || 'loader' === role ? ' cove-button--flex-center' : '') +
|
|
34
|
+
(fluid ? ' fluid' : '') +
|
|
35
|
+
(loading ? ' loading' : '') +
|
|
36
|
+
(attributes.className ? ' ' + attributes.className : ''),
|
|
20
37
|
onMouseOver: () => setButtonState('in'),
|
|
21
38
|
onMouseOut: () => setButtonState('out'),
|
|
22
39
|
onFocus: () => setButtonState('in'),
|
|
23
40
|
onBlur: () => setButtonState('out')
|
|
24
41
|
}
|
|
25
42
|
|
|
26
|
-
|
|
27
43
|
useEffect(() => {
|
|
28
44
|
if ('loader' === role && buttonRef.current) {
|
|
29
45
|
//Create ghost object and text nodes for children
|
|
@@ -54,9 +70,8 @@ const Button = ({ style, role, hoverStyle = {}, fluid = false, loading = false,
|
|
|
54
70
|
buttonRef.current.parentNode.removeChild(ghostSpan)
|
|
55
71
|
buttonRef.current.parentNode.removeChild(ghostLoaderSpan)
|
|
56
72
|
}
|
|
57
|
-
return () => {
|
|
58
|
-
|
|
59
|
-
}, [ buttonRef, children, loadingText, role ])
|
|
73
|
+
return () => {}
|
|
74
|
+
}, [buttonRef, children, loadingText, role])
|
|
60
75
|
|
|
61
76
|
useEffect(() => {
|
|
62
77
|
//Adjust button styles depending on cursor, focus, and active, states
|
|
@@ -64,9 +79,10 @@ const Button = ({ style, role, hoverStyle = {}, fluid = false, loading = false,
|
|
|
64
79
|
|
|
65
80
|
// If button state is out, check if its 'active'; we want to keep hover styles applied to 'active' buttons
|
|
66
81
|
if (buttonState === 'out')
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
82
|
+
if (!active)
|
|
83
|
+
// If button state is out, and not 'active', reset display styles back to default
|
|
84
|
+
setCustomStyles({ ...style })
|
|
85
|
+
}, [buttonState, active, style])
|
|
70
86
|
|
|
71
87
|
return (
|
|
72
88
|
<button
|
|
@@ -82,16 +98,19 @@ const Button = ({ style, role, hoverStyle = {}, fluid = false, loading = false,
|
|
|
82
98
|
<>
|
|
83
99
|
{'loader' === role && (
|
|
84
100
|
<>
|
|
85
|
-
<span
|
|
86
|
-
|
|
101
|
+
<span
|
|
102
|
+
className='cove-button__text'
|
|
103
|
+
style={loading ? { width: loadtextWidth + 'px' } : { width: childrenWidth + 'px' }}
|
|
104
|
+
>
|
|
105
|
+
<div className='cove-button__text--loading' style={loading ? { opacity: 1 } : null}>
|
|
87
106
|
{loadingText}
|
|
88
107
|
</div>
|
|
89
|
-
<div className=
|
|
108
|
+
<div className='cove-button__text--children' style={loading ? { opacity: 0 } : null}>
|
|
90
109
|
{children}
|
|
91
110
|
</div>
|
|
92
111
|
</span>
|
|
93
|
-
<div className=
|
|
94
|
-
<LoadSpin className=
|
|
112
|
+
<div className='cove-button__load-spin' style={loading ? { width: '28px', opacity: 1 } : null}>
|
|
113
|
+
<LoadSpin className='ms-1' size={20} />
|
|
95
114
|
</div>
|
|
96
115
|
</>
|
|
97
116
|
)}
|
|
@@ -104,7 +123,7 @@ const Button = ({ style, role, hoverStyle = {}, fluid = false, loading = false,
|
|
|
104
123
|
|
|
105
124
|
Button.propTypes = {
|
|
106
125
|
/** Specify special role type for button */
|
|
107
|
-
role: PropTypes.oneOf([
|
|
126
|
+
role: PropTypes.oneOf(['loader']),
|
|
108
127
|
/** Provide object with styles that overwrite base styles when hovered */
|
|
109
128
|
hoverStyle: PropTypes.object,
|
|
110
129
|
/** Enables button to stretch to the full width of the content */
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import Button from './Button.jsx'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { missingRequiredSections } from '../../helpers/missingRequiredSections.js'
|
|
4
|
+
const Confirm = props => {
|
|
5
|
+
const { updateConfig, config } = props
|
|
6
|
+
const confirmDone = e => {
|
|
7
|
+
if (e) {
|
|
8
|
+
e.preventDefault()
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let newConfig = { ...config }
|
|
12
|
+
delete newConfig.newViz
|
|
13
|
+
|
|
14
|
+
updateConfig(newConfig)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const styles: React.CSSProperties = {
|
|
18
|
+
position: 'relative',
|
|
19
|
+
height: '100vh',
|
|
20
|
+
width: '100%',
|
|
21
|
+
display: 'flex',
|
|
22
|
+
justifyContent: 'center',
|
|
23
|
+
alignItems: 'center',
|
|
24
|
+
gridArea: 'content'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<section className='waiting' style={styles}>
|
|
29
|
+
<section className='waiting-container'>
|
|
30
|
+
<h3>Finish Configuring</h3>
|
|
31
|
+
<p>Set all required options to the left and confirm below to display a preview of the chart.</p>
|
|
32
|
+
<Button
|
|
33
|
+
className='btn btn-primary'
|
|
34
|
+
style={{ margin: '1em auto' }}
|
|
35
|
+
disabled={missingRequiredSections(config)}
|
|
36
|
+
onClick={e => confirmDone(e)}
|
|
37
|
+
>
|
|
38
|
+
I'm Done
|
|
39
|
+
</Button>
|
|
40
|
+
</section>
|
|
41
|
+
</section>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default Confirm
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
const Error = ({ errorMessage }) => {
|
|
3
|
+
const styles: React.CSSProperties = {
|
|
4
|
+
position: 'absolute',
|
|
5
|
+
background: 'white',
|
|
6
|
+
zIndex: '999',
|
|
7
|
+
height: '100vh',
|
|
8
|
+
width: '100%',
|
|
9
|
+
display: 'flex',
|
|
10
|
+
justifyContent: 'center',
|
|
11
|
+
alignItems: 'center',
|
|
12
|
+
gridArea: 'content'
|
|
13
|
+
}
|
|
14
|
+
return (
|
|
15
|
+
<section className='waiting' style={styles}>
|
|
16
|
+
<section className='waiting-container'>
|
|
17
|
+
<h3>Error With Configuration</h3>
|
|
18
|
+
<p>{errorMessage}</p>
|
|
19
|
+
</section>
|
|
20
|
+
</section>
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default Error
|