@cdc/core 4.24.10 → 4.24.11
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/AdvancedEditor/AdvancedEditor.tsx +17 -13
- package/components/Alert/components/Alert.tsx +34 -8
- package/components/DataTable/DataTable.tsx +12 -2
- package/components/DataTable/data-table.css +4 -22
- package/components/DataTable/helpers/boxplotCellMatrix.tsx +14 -13
- package/components/DataTable/helpers/getChartCellValue.ts +23 -5
- package/components/EditorPanel/ColumnsEditor.tsx +81 -36
- package/components/EditorPanel/DataTableEditor.tsx +33 -33
- package/components/EditorPanel/FieldSetWrapper.tsx +2 -2
- package/components/EditorPanel/Inputs.tsx +26 -16
- package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +30 -55
- package/components/Filters/Filters.tsx +12 -4
- package/components/Layout/components/Sidebar/components/sidebar.styles.scss +0 -4
- package/components/Layout/components/Visualization/visualizations.scss +1 -1
- package/components/Legend/Legend.Gradient.tsx +49 -34
- package/components/MultiSelect/MultiSelect.tsx +85 -62
- package/components/MultiSelect/multiselect.styles.css +10 -7
- package/components/NestedDropdown/NestedDropdown.tsx +40 -20
- package/components/NestedDropdown/nesteddropdown.styles.css +15 -13
- package/components/Table/Table.tsx +102 -34
- package/components/_stories/DataTable.stories.tsx +14 -0
- package/components/_stories/Filters.stories.tsx +57 -0
- package/components/_stories/_mocks/DataTable/no-data.json +108 -0
- package/components/ui/Icon.tsx +19 -6
- package/dist/cove-main.css +20 -54
- package/dist/cove-main.css.map +1 -1
- package/helpers/DataTransform.ts +2 -1
- package/helpers/cove/{number.js → number.ts} +25 -11
- package/helpers/fetchRemoteData.js +32 -37
- package/helpers/formatConfigBeforeSave.ts +1 -0
- package/helpers/queryStringUtils.ts +6 -0
- package/helpers/useDataVizClasses.ts +42 -20
- package/package.json +2 -2
- package/styles/_button-section.scss +1 -1
- package/styles/_global-variables.scss +3 -3
- package/styles/_global.scss +21 -22
- package/styles/_reset.scss +0 -11
- package/styles/filters.scss +0 -22
- package/styles/v2/base/_reset.scss +0 -7
- package/styles/v2/components/editor.scss +0 -4
- package/styles/v2/components/icon.scss +1 -1
- package/types/Axis.ts +2 -0
- package/types/BoxPlot.ts +5 -3
- package/types/Color.ts +1 -1
- package/types/Legend.ts +1 -2
- package/types/MarkupInclude.ts +1 -0
- package/types/Runtime.ts +3 -1
- package/types/Series.ts +8 -1
- package/types/Table.ts +1 -1
- package/types/Visualization.ts +7 -8
- package/components/ui/Select.jsx +0 -30
- package/helpers/getGradientLegendWidth.ts +0 -15
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { useState, useEffect, useRef, useMemo } from 'react'
|
|
1
|
+
import { useState, useEffect, useRef, useMemo, useId } from 'react'
|
|
2
2
|
import './nesteddropdown.styles.css'
|
|
3
3
|
import Icon from '@cdc/core/components/ui/Icon'
|
|
4
4
|
import { filterSearchTerm, NestedOptions, ValueTextPair } from './nestedDropdownHelpers'
|
|
5
5
|
|
|
6
6
|
const Options: React.FC<{
|
|
7
7
|
subOptions: ValueTextPair[]
|
|
8
|
+
filterIndex: number
|
|
8
9
|
label: string
|
|
9
10
|
handleSubGroupSelect: Function
|
|
10
11
|
userSelectedLabel: string
|
|
11
12
|
userSearchTerm: string
|
|
12
|
-
}> = ({ subOptions, label, handleSubGroupSelect, userSelectedLabel, userSearchTerm }) => {
|
|
13
|
+
}> = ({ subOptions, filterIndex, label, handleSubGroupSelect, userSelectedLabel, userSearchTerm }) => {
|
|
13
14
|
const [isTierOneExpanded, setIsTierOneExpanded] = useState(true)
|
|
14
15
|
const checkMark = <>✔</>
|
|
15
16
|
|
|
@@ -18,7 +19,7 @@ const Options: React.FC<{
|
|
|
18
19
|
}, [userSearchTerm])
|
|
19
20
|
|
|
20
21
|
const handleGroupClick = e => {
|
|
21
|
-
const leaveExpanded = e.target.className ===
|
|
22
|
+
const leaveExpanded = e.target.className === `selectable-item-${filterIndex}` ? true : !isTierOneExpanded
|
|
22
23
|
setIsTierOneExpanded(leaveExpanded)
|
|
23
24
|
}
|
|
24
25
|
|
|
@@ -26,10 +27,10 @@ const Options: React.FC<{
|
|
|
26
27
|
const currentItem = e.target
|
|
27
28
|
if (e.key === 'ArrowRight') setIsTierOneExpanded(true)
|
|
28
29
|
else if (e.key === 'ArrowLeft') {
|
|
29
|
-
if (currentItem.className ===
|
|
30
|
+
if (currentItem.className === `selectable-item-${filterIndex}`) currentItem.parentNode.parentNode.focus()
|
|
30
31
|
setIsTierOneExpanded(false)
|
|
31
32
|
} else if (e.key === 'Enter') {
|
|
32
|
-
currentItem.className ===
|
|
33
|
+
currentItem.className === `selectable-item-${filterIndex}`
|
|
33
34
|
? handleSubGroupSelect(currentItem.dataset.value)
|
|
34
35
|
: setIsTierOneExpanded(!isTierOneExpanded)
|
|
35
36
|
}
|
|
@@ -44,7 +45,7 @@ const Options: React.FC<{
|
|
|
44
45
|
aria-label={label}
|
|
45
46
|
onClick={handleGroupClick}
|
|
46
47
|
onKeyUp={handleKeyUp}
|
|
47
|
-
className=
|
|
48
|
+
className={`nested-dropdown-group-${filterIndex}`}
|
|
48
49
|
>
|
|
49
50
|
<span className={'font-weight-bold'}>{label} </span>
|
|
50
51
|
{
|
|
@@ -73,7 +74,7 @@ const Options: React.FC<{
|
|
|
73
74
|
return (
|
|
74
75
|
<li
|
|
75
76
|
key={regionID}
|
|
76
|
-
className=
|
|
77
|
+
className={`selectable-item-${filterIndex}`}
|
|
77
78
|
tabIndex={0}
|
|
78
79
|
role='treeitem'
|
|
79
80
|
aria-label={regionID}
|
|
@@ -104,6 +105,7 @@ const Options: React.FC<{
|
|
|
104
105
|
type NestedDropdownProps = {
|
|
105
106
|
activeGroup: string
|
|
106
107
|
activeSubGroup?: string
|
|
108
|
+
filterIndex: number
|
|
107
109
|
isEditor?: boolean
|
|
108
110
|
isUrlFilter?: boolean
|
|
109
111
|
listLabel: string
|
|
@@ -116,9 +118,11 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
|
|
|
116
118
|
options,
|
|
117
119
|
activeGroup,
|
|
118
120
|
activeSubGroup,
|
|
121
|
+
filterIndex,
|
|
119
122
|
listLabel,
|
|
120
123
|
handleSelectedItems
|
|
121
124
|
}) => {
|
|
125
|
+
const dropdownId = useId()
|
|
122
126
|
const groupFilterActive = activeGroup
|
|
123
127
|
const subGroupFilterActive = activeSubGroup || ''
|
|
124
128
|
|
|
@@ -150,7 +154,7 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
|
|
|
150
154
|
setIsListOpened(true)
|
|
151
155
|
// Move focus from Input to top of dropdown
|
|
152
156
|
Dropdown.firstChild.focus()
|
|
153
|
-
} else if (className ===
|
|
157
|
+
} else if (className === `selectable-item-${filterIndex}`) {
|
|
154
158
|
// Move focus to next item on list: next Tier Two item or the next Tier One or SearchInput
|
|
155
159
|
const itemToFocusOnAfterKeyUp = nextSibling ?? parentNode.parentNode.nextSibling ?? searchInput.current
|
|
156
160
|
itemToFocusOnAfterKeyUp.focus()
|
|
@@ -175,7 +179,7 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
|
|
|
175
179
|
// Move focus to last item of the last collapsed Tier Two in dropdown
|
|
176
180
|
Dropdown.lastChild.lastChild.lastChild.focus()
|
|
177
181
|
}
|
|
178
|
-
} else if (className ===
|
|
182
|
+
} else if (className === `selectable-item-${filterIndex}`) {
|
|
179
183
|
// Move focus to previous Tier Two or Move focus to current Tier One
|
|
180
184
|
const itemToFocusOnAfterKeyUp = previousSibling ?? parentNode.parentNode
|
|
181
185
|
itemToFocusOnAfterKeyUp.focus()
|
|
@@ -214,7 +218,7 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
|
|
|
214
218
|
}
|
|
215
219
|
}
|
|
216
220
|
|
|
217
|
-
const filterOptions
|
|
221
|
+
const filterOptions = useMemo(() => {
|
|
218
222
|
return filterSearchTerm(userSearchTerm, options)
|
|
219
223
|
}, [userSearchTerm, options])
|
|
220
224
|
|
|
@@ -225,16 +229,35 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
|
|
|
225
229
|
setInputValue(newSearchTerm)
|
|
226
230
|
}
|
|
227
231
|
|
|
232
|
+
const handleOnBlur = e => {
|
|
233
|
+
if (
|
|
234
|
+
e.relatedTarget === null ||
|
|
235
|
+
![
|
|
236
|
+
`nested-dropdown-${filterIndex}`,
|
|
237
|
+
`nested-dropdown-group-${filterIndex}`,
|
|
238
|
+
`selectable-item-${filterIndex}`
|
|
239
|
+
].includes(e.relatedTarget.className)
|
|
240
|
+
) {
|
|
241
|
+
setInputHasFocus(false)
|
|
242
|
+
setIsListOpened(false)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
228
246
|
return (
|
|
229
247
|
<>
|
|
230
|
-
{listLabel &&
|
|
248
|
+
{listLabel && (
|
|
249
|
+
<label className='text-capitalize font-weight-bold' htmlFor={dropdownId}>
|
|
250
|
+
{listLabel}
|
|
251
|
+
</label>
|
|
252
|
+
)}
|
|
231
253
|
<div
|
|
232
|
-
id=
|
|
233
|
-
className={`nested-dropdown ${isListOpened ? 'open-filter' : ''}`}
|
|
254
|
+
id={dropdownId}
|
|
255
|
+
className={`nested-dropdown nested-dropdown-${filterIndex} ${isListOpened ? 'open-filter' : ''}`}
|
|
234
256
|
onKeyUp={handleKeyUp}
|
|
235
257
|
>
|
|
236
258
|
<div className='nested-dropdown-input-container' aria-label='searchInput' role='textbox'>
|
|
237
259
|
<input
|
|
260
|
+
id={`nested-dropdown-${filterIndex}`}
|
|
238
261
|
className='search-input'
|
|
239
262
|
ref={searchInput}
|
|
240
263
|
aria-label='searchInput'
|
|
@@ -243,19 +266,15 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
|
|
|
243
266
|
tabIndex={0}
|
|
244
267
|
value={inputValue}
|
|
245
268
|
onChange={handleSearchTermChange}
|
|
246
|
-
placeholder={'Select
|
|
269
|
+
placeholder={'- Select -'}
|
|
247
270
|
onClick={() => {
|
|
248
271
|
if (inputHasFocus) setIsListOpened(!isListOpened)
|
|
249
272
|
}}
|
|
250
273
|
onFocus={() => setInputHasFocus(true)}
|
|
251
|
-
onBlur={
|
|
274
|
+
onBlur={e => handleOnBlur(e)}
|
|
252
275
|
/>
|
|
253
276
|
<span className='list-arrow' aria-hidden={true}>
|
|
254
|
-
|
|
255
|
-
<Icon display='caretFilledUp' alt='arrow pointing up' />
|
|
256
|
-
) : (
|
|
257
|
-
<Icon display='caretFilledDown' alt='arrow pointing down' />
|
|
258
|
-
)}
|
|
277
|
+
<Icon display='caretDown' />
|
|
259
278
|
</span>
|
|
260
279
|
</div>
|
|
261
280
|
<ul
|
|
@@ -275,6 +294,7 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
|
|
|
275
294
|
<Options
|
|
276
295
|
key={groupTextValue + '_' + index}
|
|
277
296
|
subOptions={subgroup}
|
|
297
|
+
filterIndex={filterIndex}
|
|
278
298
|
label={groupTextValue}
|
|
279
299
|
handleSubGroupSelect={subGroupValue => {
|
|
280
300
|
chooseSelectedSubGroup(groupValue, subGroupValue)
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
.nested-dropdown {
|
|
9
|
-
|
|
9
|
+
[class^='nested-dropdown-group-'] {
|
|
10
10
|
list-style: none;
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -15,19 +15,19 @@
|
|
|
15
15
|
position: relative;
|
|
16
16
|
display: inline-block;
|
|
17
17
|
width: 100%;
|
|
18
|
+
padding: 0;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
.main-nested-dropdown-container,
|
|
21
22
|
.nested-dropdown-input-container {
|
|
22
|
-
padding: 7px 15px;
|
|
23
|
-
background: #fff;
|
|
24
23
|
border: 1px solid var(--lightGray);
|
|
25
|
-
|
|
26
|
-
width: 325px;
|
|
24
|
+
min-width: 200px;
|
|
27
25
|
cursor: pointer;
|
|
26
|
+
padding: 0.375rem 0.75rem;
|
|
27
|
+
font-size: 1em;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
[class^='selectable-item-'] {
|
|
31
31
|
list-style: none;
|
|
32
32
|
padding-left: 20px;
|
|
33
33
|
position: relative;
|
|
@@ -45,15 +45,16 @@
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
.nested-dropdown-input-container {
|
|
48
|
+
display: block;
|
|
49
|
+
width: 100%;
|
|
50
|
+
border-radius: 0.25rem;
|
|
48
51
|
position: relative;
|
|
49
52
|
& > span.list-arrow {
|
|
53
|
+
color: var(--mediumGray);
|
|
50
54
|
position: absolute;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
padding: 9px;
|
|
55
|
-
background: #fff;
|
|
56
|
-
pointer-events: none;
|
|
55
|
+
top: 9px;
|
|
56
|
+
right: 1px;
|
|
57
|
+
float: right;
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
|
|
@@ -62,7 +63,8 @@
|
|
|
62
63
|
overflow-y: scroll;
|
|
63
64
|
position: absolute;
|
|
64
65
|
z-index: 3;
|
|
65
|
-
width:
|
|
66
|
+
min-width: 200px;
|
|
67
|
+
background: white;
|
|
66
68
|
}
|
|
67
69
|
|
|
68
70
|
.hide {
|
|
@@ -4,9 +4,11 @@ import GroupRow from './components/GroupRow'
|
|
|
4
4
|
import { CellMatrix, GroupCellMatrix } from './types/CellMatrix'
|
|
5
5
|
import { RowType } from './types/RowType'
|
|
6
6
|
import { PreliminaryDataItem } from '@cdc/chart/src/types/ChartConfig'
|
|
7
|
+
import _ from 'lodash'
|
|
7
8
|
|
|
8
9
|
type TableProps = {
|
|
9
10
|
childrenMatrix: CellMatrix | GroupCellMatrix
|
|
11
|
+
noData?: boolean
|
|
10
12
|
tableName: string
|
|
11
13
|
caption: string
|
|
12
14
|
stickyHeader?: boolean
|
|
@@ -27,46 +29,112 @@ type TableProps = {
|
|
|
27
29
|
|
|
28
30
|
type Position = 'sticky'
|
|
29
31
|
|
|
30
|
-
const Table = ({
|
|
32
|
+
const Table = ({
|
|
33
|
+
childrenMatrix,
|
|
34
|
+
noData,
|
|
35
|
+
tableName,
|
|
36
|
+
caption,
|
|
37
|
+
stickyHeader,
|
|
38
|
+
headContent,
|
|
39
|
+
tableOptions,
|
|
40
|
+
wrapColumns,
|
|
41
|
+
hasRowType,
|
|
42
|
+
fontSize,
|
|
43
|
+
viewport,
|
|
44
|
+
preliminaryData
|
|
45
|
+
}: TableProps) => {
|
|
31
46
|
const headStyle = stickyHeader ? { position: 'sticky' as Position, top: 0, zIndex: 2 } : {}
|
|
32
47
|
const isGroupedMatrix = !Array.isArray(childrenMatrix)
|
|
33
48
|
|
|
34
49
|
return (
|
|
35
50
|
<table {...tableOptions}>
|
|
36
51
|
<caption className='visually-hidden'>{caption}</caption>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
52
|
+
{noData ? (
|
|
53
|
+
<tr>
|
|
54
|
+
<td className='py-5 text-center'>No Data</td>
|
|
55
|
+
</tr>
|
|
56
|
+
) : (
|
|
57
|
+
<>
|
|
58
|
+
<thead style={headStyle}>{headContent}</thead>
|
|
59
|
+
<tbody>
|
|
60
|
+
{isGroupedMatrix
|
|
61
|
+
? Object.keys(childrenMatrix).flatMap(groupName => {
|
|
62
|
+
let colSpan = 0
|
|
63
|
+
const rows = childrenMatrix[groupName].map((row, i) => {
|
|
64
|
+
colSpan = row.length
|
|
65
|
+
const key = `${tableName}-${groupName}-row-${i}`
|
|
66
|
+
return (
|
|
67
|
+
<Row
|
|
68
|
+
preliminaryData={preliminaryData}
|
|
69
|
+
key={key}
|
|
70
|
+
rowKey={key}
|
|
71
|
+
childRow={row}
|
|
72
|
+
wrapColumns={wrapColumns}
|
|
73
|
+
cellMinWidth={tableOptions.cellMinWidth}
|
|
74
|
+
fontSize={fontSize}
|
|
75
|
+
viewport={viewport}
|
|
76
|
+
/>
|
|
77
|
+
)
|
|
78
|
+
})
|
|
79
|
+
return [<GroupRow label={groupName} colSpan={colSpan} key={`${tableName}-${groupName}`} />, ...rows]
|
|
80
|
+
})
|
|
81
|
+
: childrenMatrix.map((childRow, i) => {
|
|
82
|
+
let childRowCopy = [...childRow]
|
|
83
|
+
let rowType = undefined
|
|
84
|
+
if (hasRowType) rowType = childRowCopy.shift()
|
|
85
|
+
const key = `${tableName}-row-${i}`
|
|
86
|
+
if (rowType === undefined) {
|
|
87
|
+
return (
|
|
88
|
+
<Row
|
|
89
|
+
preliminaryData={preliminaryData}
|
|
90
|
+
key={key}
|
|
91
|
+
rowKey={key}
|
|
92
|
+
childRow={childRow}
|
|
93
|
+
wrapColumns={wrapColumns}
|
|
94
|
+
cellMinWidth={tableOptions.cellMinWidth}
|
|
95
|
+
fontSize={fontSize}
|
|
96
|
+
viewport={viewport}
|
|
97
|
+
/>
|
|
98
|
+
)
|
|
99
|
+
} else {
|
|
100
|
+
switch (rowType) {
|
|
101
|
+
case RowType.row_group:
|
|
102
|
+
return <GroupRow label={childRowCopy[0]} colSpan={childRowCopy.length} key={key} />
|
|
103
|
+
case RowType.total:
|
|
104
|
+
return (
|
|
105
|
+
<Row
|
|
106
|
+
preliminaryData={preliminaryData}
|
|
107
|
+
key={key}
|
|
108
|
+
rowKey={key}
|
|
109
|
+
childRow={childRowCopy}
|
|
110
|
+
isTotal={true}
|
|
111
|
+
wrapColumns={wrapColumns}
|
|
112
|
+
cellMinWidth={tableOptions.cellMinWidth}
|
|
113
|
+
fontSize={fontSize}
|
|
114
|
+
viewport={viewport}
|
|
115
|
+
/>
|
|
116
|
+
)
|
|
117
|
+
case RowType.row_group_total:
|
|
118
|
+
return <GroupRow label={childRowCopy[0]} colSpan={1} key={key} data={childRowCopy.slice(1)} />
|
|
119
|
+
default:
|
|
120
|
+
return (
|
|
121
|
+
<Row
|
|
122
|
+
preliminaryData={preliminaryData}
|
|
123
|
+
key={key}
|
|
124
|
+
rowKey={key}
|
|
125
|
+
childRow={childRowCopy}
|
|
126
|
+
wrapColumns={wrapColumns}
|
|
127
|
+
cellMinWidth={tableOptions.cellMinWidth}
|
|
128
|
+
fontSize={fontSize}
|
|
129
|
+
viewport={viewport}
|
|
130
|
+
/>
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
})}
|
|
135
|
+
</tbody>
|
|
136
|
+
</>
|
|
137
|
+
)}
|
|
70
138
|
</table>
|
|
71
139
|
)
|
|
72
140
|
}
|
|
@@ -2,6 +2,7 @@ import { Meta, StoryObj } from '@storybook/react'
|
|
|
2
2
|
|
|
3
3
|
import DataTable from '../DataTable'
|
|
4
4
|
import './styles.scss'
|
|
5
|
+
import NoDataConfig from './_mocks/DataTable/no-data.json'
|
|
5
6
|
import Example_1 from './_mocks/dashboard_no_filter.json'
|
|
6
7
|
import CityStateExample from './_mocks/example-city-state.json'
|
|
7
8
|
import { displayGeoName } from '@cdc/map/src/helpers/displayGeoName'
|
|
@@ -62,6 +63,19 @@ export const Grouped: Story = {
|
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
|
|
66
|
+
const noDataData = NoDataConfig.datasets['dev-8931-hide-markup-include.csv'].data
|
|
67
|
+
export const NoData: Story = {
|
|
68
|
+
args: {
|
|
69
|
+
config: NoDataConfig,
|
|
70
|
+
dataConfig: { data: noDataData },
|
|
71
|
+
rawData: noDataData,
|
|
72
|
+
runtimeData: noDataData,
|
|
73
|
+
expandDataTable: true,
|
|
74
|
+
tableTitle: 'No Data Table',
|
|
75
|
+
viewport: 'lg',
|
|
76
|
+
tabbingId: '#asdf'
|
|
77
|
+
}
|
|
78
|
+
}
|
|
65
79
|
export const RowType: Story = {
|
|
66
80
|
args: {
|
|
67
81
|
config: {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
|
|
3
|
+
import Filters from '../Filters'
|
|
4
|
+
import { VizFilter } from '../../types/VizFilter'
|
|
5
|
+
import { faker } from '@faker-js/faker'
|
|
6
|
+
import _ from 'lodash'
|
|
7
|
+
import { Visualization } from '../../types/Visualization'
|
|
8
|
+
|
|
9
|
+
const meta: Meta<typeof Filters> = {
|
|
10
|
+
title: 'Components/Molecules/Visualization Filters',
|
|
11
|
+
component: Filters
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type Story = StoryObj<typeof Filters>
|
|
15
|
+
|
|
16
|
+
faker.seed(123)
|
|
17
|
+
|
|
18
|
+
const animalData = _.times(7, () => ({ bear: faker.animal.bear(), cat: faker.animal.cat(), cow: faker.animal.cow() }))
|
|
19
|
+
const generateFilters = filterStyle => {
|
|
20
|
+
return ['bear', 'cat', 'cow'].map(columnName => {
|
|
21
|
+
return {
|
|
22
|
+
filterStyle,
|
|
23
|
+
label: columnName.toUpperCase(),
|
|
24
|
+
columnName
|
|
25
|
+
} as VizFilter
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const generateConfig = filterStyle =>
|
|
30
|
+
({
|
|
31
|
+
args: {
|
|
32
|
+
config: {
|
|
33
|
+
filters: generateFilters(filterStyle),
|
|
34
|
+
data: animalData
|
|
35
|
+
} as Visualization,
|
|
36
|
+
filteredData: animalData,
|
|
37
|
+
setFilteredData: () => {},
|
|
38
|
+
setConfig: () => {},
|
|
39
|
+
exclusions: []
|
|
40
|
+
}
|
|
41
|
+
} as Story)
|
|
42
|
+
|
|
43
|
+
export const Dropdown: Story = generateConfig('dropdown')
|
|
44
|
+
|
|
45
|
+
export const DropdownBar: Story = generateConfig('dropdown bar')
|
|
46
|
+
|
|
47
|
+
export const MultiSelect: Story = generateConfig('multi-select')
|
|
48
|
+
|
|
49
|
+
export const NestedDropdown: Story = generateConfig('nested-dropdown')
|
|
50
|
+
|
|
51
|
+
export const Pill: Story = generateConfig('pill')
|
|
52
|
+
|
|
53
|
+
export const Tab: Story = generateConfig('tab')
|
|
54
|
+
|
|
55
|
+
export const TabBar: Story = generateConfig('tab bar')
|
|
56
|
+
|
|
57
|
+
export default meta
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"dashboard": {
|
|
3
|
+
"theme": "theme-blue",
|
|
4
|
+
"sharedFilters": []
|
|
5
|
+
},
|
|
6
|
+
"rows": [
|
|
7
|
+
{
|
|
8
|
+
"columns": [
|
|
9
|
+
{
|
|
10
|
+
"width": 12,
|
|
11
|
+
"widget": "table1730380781112"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"uuid": 1730380998726
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"visualizations": {
|
|
18
|
+
"table1730380781112": {
|
|
19
|
+
"filters": [],
|
|
20
|
+
"filterBehavior": "Filter Change",
|
|
21
|
+
"newViz": false,
|
|
22
|
+
"openModal": true,
|
|
23
|
+
"uid": "table1730380781112",
|
|
24
|
+
"type": "table",
|
|
25
|
+
"table": {
|
|
26
|
+
"label": "Data Table",
|
|
27
|
+
"show": true,
|
|
28
|
+
"showDownloadUrl": false,
|
|
29
|
+
"showVertical": true,
|
|
30
|
+
"expanded": true,
|
|
31
|
+
"collapsible": true
|
|
32
|
+
},
|
|
33
|
+
"columns": {
|
|
34
|
+
"additionalColumn1": {
|
|
35
|
+
"label": "New Column",
|
|
36
|
+
"dataTable": true,
|
|
37
|
+
"tooltips": false,
|
|
38
|
+
"prefix": "",
|
|
39
|
+
"suffix": "",
|
|
40
|
+
"forestPlot": false,
|
|
41
|
+
"startingPoint": "0",
|
|
42
|
+
"forestPlotAlignRight": false,
|
|
43
|
+
"roundToPlace": 0,
|
|
44
|
+
"commas": false,
|
|
45
|
+
"showInViz": false,
|
|
46
|
+
"forestPlotStartingPoint": 0
|
|
47
|
+
},
|
|
48
|
+
"Class": {
|
|
49
|
+
"name": "Class",
|
|
50
|
+
"dataTable": false
|
|
51
|
+
},
|
|
52
|
+
"Data_Type": {
|
|
53
|
+
"name": "Data_Type",
|
|
54
|
+
"dataTable": false
|
|
55
|
+
},
|
|
56
|
+
"Question": {
|
|
57
|
+
"name": "Question",
|
|
58
|
+
"dataTable": false
|
|
59
|
+
},
|
|
60
|
+
"Response": {
|
|
61
|
+
"name": "Response",
|
|
62
|
+
"dataTable": false
|
|
63
|
+
},
|
|
64
|
+
"Topic": {
|
|
65
|
+
"name": "Topic",
|
|
66
|
+
"dataTable": false
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"dataFormat": {},
|
|
70
|
+
"visualizationType": "table",
|
|
71
|
+
"dataDescription": {
|
|
72
|
+
"horizontal": false,
|
|
73
|
+
"series": false
|
|
74
|
+
},
|
|
75
|
+
"dataKey": "dev-8931-hide-markup-include.csv"
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"table": {
|
|
79
|
+
"label": "Data Table",
|
|
80
|
+
"show": true,
|
|
81
|
+
"showDownloadUrl": false,
|
|
82
|
+
"showDownloadLinkBelow": true,
|
|
83
|
+
"showVertical": true
|
|
84
|
+
},
|
|
85
|
+
"newViz": true,
|
|
86
|
+
"datasets": {
|
|
87
|
+
"dev-8931-hide-markup-include.csv": {
|
|
88
|
+
"data": [],
|
|
89
|
+
"dataFileSize": 10023,
|
|
90
|
+
"dataFileName": "dev-8931-hide-markup-include.csv",
|
|
91
|
+
"dataFileSourceType": "file",
|
|
92
|
+
"dataFileFormat": "CSV",
|
|
93
|
+
"preview": true
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"isResponsiveTicks": false,
|
|
97
|
+
"type": "dashboard",
|
|
98
|
+
"barThickness": "0.37",
|
|
99
|
+
"xAxis": {
|
|
100
|
+
"type": "categorical",
|
|
101
|
+
"size": 75,
|
|
102
|
+
"maxTickRotation": 45,
|
|
103
|
+
"labelOffset": 0
|
|
104
|
+
},
|
|
105
|
+
"runtime": {},
|
|
106
|
+
"version": "4.24.10",
|
|
107
|
+
"uuid": 1730380778769
|
|
108
|
+
}
|
package/components/ui/Icon.tsx
CHANGED
|
@@ -88,15 +88,24 @@ type IconProps = {
|
|
|
88
88
|
/* Returns icon data as plain svg */
|
|
89
89
|
base?: boolean
|
|
90
90
|
/* Sets alt text for the icon */
|
|
91
|
-
alt
|
|
91
|
+
alt?: string
|
|
92
92
|
/* Override the width of the icon (scales height proportionally)*/
|
|
93
93
|
size?: number
|
|
94
94
|
/* Override the color of the icon */
|
|
95
95
|
color?: string
|
|
96
|
-
style?:
|
|
96
|
+
style?: object
|
|
97
|
+
className?: string // className attribute will be ignored.
|
|
97
98
|
}
|
|
98
99
|
|
|
99
|
-
const Icon: React.FC<IconProps> = ({
|
|
100
|
+
const Icon: React.FC<IconProps> = ({
|
|
101
|
+
display = '',
|
|
102
|
+
base = undefined,
|
|
103
|
+
alt = '',
|
|
104
|
+
size = undefined,
|
|
105
|
+
color = undefined,
|
|
106
|
+
style = undefined,
|
|
107
|
+
...attributes
|
|
108
|
+
}) => {
|
|
100
109
|
const IconObj = iconHash[display] || null
|
|
101
110
|
|
|
102
111
|
const filteredAttrs = { ...attributes }
|
|
@@ -112,10 +121,14 @@ const Icon: React.FC<IconProps> = ({ display = '', base = undefined, alt = '', s
|
|
|
112
121
|
return (
|
|
113
122
|
<>
|
|
114
123
|
{base ? (
|
|
115
|
-
<IconObj title={alt} />
|
|
124
|
+
<IconObj title={alt || display} />
|
|
116
125
|
) : (
|
|
117
|
-
<span
|
|
118
|
-
|
|
126
|
+
<span
|
|
127
|
+
className={`cove-icon${attributes.className ? ' ' + attributes.className : ''}`}
|
|
128
|
+
style={styles}
|
|
129
|
+
{...filteredAttrs}
|
|
130
|
+
>
|
|
131
|
+
<IconObj title={alt || display} />
|
|
119
132
|
</span>
|
|
120
133
|
)}
|
|
121
134
|
</>
|