@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.
- package/LICENSE +201 -0
- package/assets/icon-deviation-bar.svg +1 -0
- package/components/DataTable/DataTable.tsx +223 -0
- package/components/DataTable/components/BoxplotHeader.tsx +16 -0
- package/components/DataTable/components/CellAnchor.tsx +44 -0
- package/components/DataTable/components/ChartHeader.tsx +103 -0
- package/components/DataTable/components/ExpandCollapse.tsx +21 -0
- package/components/DataTable/components/Icons.tsx +10 -0
- package/components/DataTable/components/MapHeader.tsx +56 -0
- package/components/DataTable/components/SkipNav.tsx +7 -0
- package/components/DataTable/helpers/boxplotCellMatrix.tsx +64 -0
- package/components/DataTable/helpers/chartCellMatrix.tsx +92 -0
- package/components/DataTable/helpers/customColumns.ts +25 -0
- package/components/DataTable/helpers/customSort.ts +55 -0
- package/components/DataTable/helpers/getChartCellValue.ts +56 -0
- package/components/DataTable/helpers/getDataSeriesColumns.ts +29 -0
- package/components/DataTable/helpers/getSeriesName.ts +26 -0
- package/components/DataTable/helpers/mapCellMatrix.tsx +56 -0
- package/components/DataTable/helpers/regionCellMatrix.tsx +13 -0
- package/components/DataTable/helpers/standardizeState.js +76 -0
- package/components/DataTable/index.ts +1 -0
- package/components/DataTable/types/TableConfig.ts +52 -0
- package/components/DownloadButton.tsx +29 -0
- package/components/EditorPanel/DataTableEditor.tsx +133 -0
- package/components/EditorPanel/Inputs.tsx +150 -0
- package/components/Filters.jsx +3 -3
- package/components/LegendCircle.jsx +2 -2
- package/components/MediaControls.jsx +1 -1
- package/components/MultiSelect/MultiSelect.tsx +95 -0
- package/components/MultiSelect/index.ts +1 -0
- package/components/MultiSelect/multiselect.styles.css +50 -0
- package/components/Table/Table.tsx +69 -0
- package/components/Table/components/Cell.tsx +9 -0
- package/components/Table/components/GroupRow.tsx +20 -0
- package/components/Table/components/Row.tsx +26 -0
- package/components/Table/index.ts +1 -0
- package/components/Table/types/CellMatrix.ts +4 -0
- package/components/Table/types/RowType.ts +5 -0
- package/components/_stories/DataTable.stories.tsx +103 -0
- package/components/_stories/EditorPanel.stories.tsx +53 -0
- package/components/_stories/Inputs.stories.tsx +37 -0
- package/components/_stories/MultiSelect.stories.tsx +24 -0
- package/components/_stories/Table.stories.tsx +53 -0
- package/components/_stories/_mocks/dashboard_no_filter.json +121 -0
- package/components/_stories/_mocks/example-city-state.json +808 -0
- package/components/_stories/_mocks/row_type.json +42 -0
- package/components/_stories/styles.scss +9 -0
- package/components/inputs/{InputSelect.jsx → InputSelect.tsx} +15 -5
- package/components/managers/{DataDesigner.jsx → DataDesigner.tsx} +103 -94
- package/components/ui/{Icon.jsx → Icon.tsx} +3 -3
- package/components/ui/Title/Title.scss +95 -0
- package/components/ui/Title/index.tsx +34 -0
- package/components/ui/_stories/Title.stories.tsx +21 -0
- package/helpers/DataTransform.ts +75 -20
- package/helpers/cove/string.ts +11 -0
- package/helpers/fetchRemoteData.js +1 -1
- package/helpers/getFileExtension.ts +28 -5
- package/package.json +2 -2
- package/styles/_data-table.scss +3 -0
- package/styles/heading-colors.scss +0 -3
- package/styles/v2/layout/_component.scss +0 -11
- package/types/Axis.ts +41 -0
- package/types/Color.ts +5 -0
- package/types/Column.ts +15 -0
- package/types/ComponentStyles.ts +7 -0
- package/types/ComponentThemes.ts +13 -0
- package/types/EditorColumnProperties.ts +8 -0
- package/types/FilterBehavior.ts +1 -0
- package/types/Runtime.ts +29 -0
- package/types/Series.ts +1 -0
- package/types/Table.ts +18 -0
- package/types/UpdateFieldFunc.ts +1 -0
- package/types/Visualization.ts +21 -0
- package/components/DataTable.jsx +0 -754
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"type": "row_group",
|
|
4
|
+
"overall": "",
|
|
5
|
+
"male": "",
|
|
6
|
+
"female": "",
|
|
7
|
+
"row_type": "row_group",
|
|
8
|
+
"nullColumn": null
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"type": "row_group_total",
|
|
12
|
+
"overall": "100",
|
|
13
|
+
"male": "50",
|
|
14
|
+
"female": "50",
|
|
15
|
+
"row_type": "row_group_total",
|
|
16
|
+
"nullColumn": null
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"type": "regular",
|
|
20
|
+
"overall": "50",
|
|
21
|
+
"male": "25",
|
|
22
|
+
"female": "25",
|
|
23
|
+
"row_type": null,
|
|
24
|
+
"nullColumn": null
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"type": "regular",
|
|
28
|
+
"overall": "50",
|
|
29
|
+
"male": "25",
|
|
30
|
+
"female": "25",
|
|
31
|
+
"row_type": null,
|
|
32
|
+
"nullColumn": null
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"type": "total",
|
|
36
|
+
"overall": "100",
|
|
37
|
+
"male": "50",
|
|
38
|
+
"female": "50",
|
|
39
|
+
"row_type": "total",
|
|
40
|
+
"nullColumn": null
|
|
41
|
+
}
|
|
42
|
+
]
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
import React, { memo } from 'react'
|
|
2
|
-
|
|
3
1
|
import '../../styles/v2/components/input/index.scss'
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
interface InputProps {
|
|
4
|
+
label?
|
|
5
|
+
value?
|
|
6
|
+
options: string[] | { [key: string]: string }
|
|
7
|
+
fieldName
|
|
8
|
+
section?
|
|
9
|
+
subsection?
|
|
10
|
+
required?
|
|
11
|
+
updateField
|
|
12
|
+
initial?
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const InputSelect = ({ label, value, options, fieldName, section = null, subsection = null, required = false, updateField, initial: initialValue, ...attributes }: InputProps) => {
|
|
16
|
+
let optionsJsx = []
|
|
7
17
|
|
|
8
18
|
if (Array.isArray(options)) {
|
|
9
19
|
//Handle basic array
|
|
@@ -48,6 +58,6 @@ const InputSelect = memo(({ label, value, options, fieldName, section = null, su
|
|
|
48
58
|
</select>
|
|
49
59
|
</label>
|
|
50
60
|
)
|
|
51
|
-
}
|
|
61
|
+
}
|
|
52
62
|
|
|
53
63
|
export default InputSelect
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
2
|
|
|
3
3
|
import Button from '../elements/Button'
|
|
4
4
|
import Card from '../elements/Card'
|
|
@@ -6,77 +6,109 @@ import Card from '../elements/Card'
|
|
|
6
6
|
import { DATA_TABLE_VERTICAL, DATA_TABLE_HORIZONTAL, DATA_TABLE_SINGLE_ROW, DATA_TABLE_MULTI_ROW } from '../../templates/dataDesignerTables'
|
|
7
7
|
import '../../styles/v2/components/data-designer.scss'
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
type DataDesignerProps = {
|
|
10
|
+
configureData?: any // todo: add description here when understood better
|
|
11
|
+
updateDescriptionProp?: (vizKey: string, dataKey: string, propName: string, value: any) => void // used to update data description fields
|
|
12
|
+
visualizationKey?: any // todo: add description here when understood better
|
|
13
|
+
dataKey?: string // appears to be the data file name, ie valid-data.csv
|
|
14
|
+
config?: any // can be one of many different types of chart configs that aren't fully established yet
|
|
15
|
+
setConfig?: (newConfig: any) => void
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const DataDesigner = (props: DataDesignerProps) => {
|
|
10
19
|
const { configureData, updateDescriptionProp, visualizationKey, dataKey, config, setConfig } = props
|
|
20
|
+
const hasDataOrientation = config?.visualizationType !== 'Forest Plot'
|
|
21
|
+
const hasMultipleSeries = config?.visualizationType !== 'Forest Plot'
|
|
22
|
+
const hasRowSelection = config?.visualizationType !== 'Forest Plot'
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (config?.visualizationType === 'Forest Plot') {
|
|
26
|
+
// needed to properly set data up?
|
|
27
|
+
setConfig({
|
|
28
|
+
...config,
|
|
29
|
+
dataDescription: {
|
|
30
|
+
series: true,
|
|
31
|
+
horizontal: false,
|
|
32
|
+
singleRow: true
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
}, [])
|
|
11
37
|
|
|
12
38
|
return (
|
|
13
39
|
<div className='cove-data-designer__container'>
|
|
14
40
|
<div className='mb-2'>
|
|
15
41
|
<div className='cove-heading--3 fw-bold mb-1'>Describe Data</div>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
<
|
|
20
|
-
className=
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
className=
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
42
|
+
{hasDataOrientation && (
|
|
43
|
+
<>
|
|
44
|
+
<div className='cove-heading--3 fw-normal mb-1'>Data Orientation</div>
|
|
45
|
+
<div className='grid grid-gap-2 mb-4'>
|
|
46
|
+
<div className='column'>
|
|
47
|
+
<button
|
|
48
|
+
className={'cove-data-designer__button' + (configureData.dataDescription && configureData.dataDescription.horizontal === false ? ' active' : '')}
|
|
49
|
+
onClick={() => {
|
|
50
|
+
updateDescriptionProp(visualizationKey, dataKey, 'horizontal', false)
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
<Card>
|
|
54
|
+
<strong className='cove-heading--3'>Vertical</strong>
|
|
55
|
+
<p className='mb-1'>
|
|
56
|
+
Values for map geography or chart date/category axis are contained in a single <em>column</em>.
|
|
57
|
+
</p>
|
|
58
|
+
{DATA_TABLE_VERTICAL}
|
|
59
|
+
</Card>
|
|
60
|
+
</button>
|
|
61
|
+
</div>
|
|
62
|
+
<div className='column'>
|
|
63
|
+
<button
|
|
64
|
+
className={'cove-data-designer__button' + (configureData.dataDescription && configureData.dataDescription.horizontal === true ? ' active' : '')}
|
|
65
|
+
onClick={() => {
|
|
66
|
+
updateDescriptionProp(visualizationKey, dataKey, 'horizontal', true)
|
|
67
|
+
}}
|
|
68
|
+
>
|
|
69
|
+
<Card>
|
|
70
|
+
<strong className='cove-heading--3'>Horizontal</strong>
|
|
71
|
+
<p className='mb-1'>
|
|
72
|
+
Values for map geography or chart date/category axis are contained in a single <em>row</em>
|
|
73
|
+
</p>
|
|
74
|
+
{DATA_TABLE_HORIZONTAL}
|
|
75
|
+
</Card>
|
|
76
|
+
</button>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</>
|
|
80
|
+
)}
|
|
51
81
|
</div>
|
|
52
82
|
{configureData.dataDescription && (
|
|
53
83
|
<>
|
|
54
|
-
|
|
55
|
-
<div className='mb-
|
|
56
|
-
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
84
|
+
{hasMultipleSeries && (
|
|
85
|
+
<div className='mb-2'>
|
|
86
|
+
<div className='mb-1'>Are there multiple series represented in your data?</div>
|
|
87
|
+
<div>
|
|
88
|
+
<Button
|
|
89
|
+
style={{ backgroundColor: '#00345d' }}
|
|
90
|
+
hoverStyle={{ backgroundColor: '#015daa' }}
|
|
91
|
+
className='mr-1'
|
|
92
|
+
onClick={() => {
|
|
93
|
+
updateDescriptionProp(visualizationKey, dataKey, 'series', true)
|
|
94
|
+
}}
|
|
95
|
+
active={configureData.dataDescription.series === true}
|
|
96
|
+
>
|
|
97
|
+
Yes
|
|
98
|
+
</Button>
|
|
99
|
+
<Button
|
|
100
|
+
style={{ backgroundColor: '#00345d' }}
|
|
101
|
+
hoverStyle={{ backgroundColor: '#015daa' }}
|
|
102
|
+
onClick={() => {
|
|
103
|
+
updateDescriptionProp(visualizationKey, dataKey, 'series', false)
|
|
104
|
+
}}
|
|
105
|
+
active={configureData.dataDescription.series === false}
|
|
106
|
+
>
|
|
107
|
+
No
|
|
108
|
+
</Button>
|
|
109
|
+
</div>
|
|
78
110
|
</div>
|
|
79
|
-
|
|
111
|
+
)}
|
|
80
112
|
{configureData.dataDescription.horizontal === true && configureData.dataDescription.series === true && (
|
|
81
113
|
<div className='mb-2'>
|
|
82
114
|
<div className='mb-1'>Which property in the dataset represents which series the row is describing?</div>
|
|
@@ -95,7 +127,7 @@ const DataDesigner = props => {
|
|
|
95
127
|
</select>
|
|
96
128
|
</div>
|
|
97
129
|
)}
|
|
98
|
-
{configureData.dataDescription.horizontal === false && configureData.dataDescription.series === true && (
|
|
130
|
+
{configureData.dataDescription.horizontal === false && configureData.dataDescription.series === true && hasRowSelection && (
|
|
99
131
|
<>
|
|
100
132
|
<div className='mb-2'>
|
|
101
133
|
<div className='mb-1'>Are the series values in your data represented in a single row, or across multiple rows?</div>
|
|
@@ -166,16 +198,16 @@ const DataDesigner = props => {
|
|
|
166
198
|
</div>
|
|
167
199
|
<div className='mb-2'>
|
|
168
200
|
<div className='mb-1'>Which properties in the dataset represent the numeric value? (all remaining properties will be treated as filters)</div>
|
|
169
|
-
{configureData.dataDescription.
|
|
201
|
+
{configureData.dataDescription.valueKeysTallSupport && configureData.dataDescription.valueKeysTallSupport.length > 0 && (
|
|
170
202
|
<ul className='value-list'>
|
|
171
|
-
{configureData.dataDescription.
|
|
203
|
+
{configureData.dataDescription.valueKeysTallSupport.map((valueKey, index) => (
|
|
172
204
|
<li key={`value-keys-list-${index}`}>
|
|
173
205
|
{valueKey}
|
|
174
206
|
<button
|
|
175
207
|
onClick={() => {
|
|
176
|
-
let newValueKeys = configureData.dataDescription.
|
|
208
|
+
let newValueKeys = configureData.dataDescription.valueKeysTallSupport
|
|
177
209
|
newValueKeys.splice(index, 1)
|
|
178
|
-
updateDescriptionProp(visualizationKey, dataKey, '
|
|
210
|
+
updateDescriptionProp(visualizationKey, dataKey, 'valueKeysTallSupport', newValueKeys)
|
|
179
211
|
}}
|
|
180
212
|
>
|
|
181
213
|
X
|
|
@@ -186,14 +218,14 @@ const DataDesigner = props => {
|
|
|
186
218
|
)}
|
|
187
219
|
<select
|
|
188
220
|
onChange={e => {
|
|
189
|
-
if (e.target.value && (!configureData.dataDescription.
|
|
190
|
-
updateDescriptionProp(visualizationKey, dataKey, '
|
|
221
|
+
if (e.target.value && (!configureData.dataDescription.valueKeysTallSupport || configureData.dataDescription.valueKeysTallSupport.indexOf(e.target.value) === -1)) {
|
|
222
|
+
updateDescriptionProp(visualizationKey, dataKey, 'valueKeysTallSupport', [...(configureData.dataDescription.valueKeysTallSupport || []), e.target.value])
|
|
191
223
|
}
|
|
192
224
|
}}
|
|
193
225
|
>
|
|
194
226
|
<option value=''>Choose an option</option>
|
|
195
227
|
{Object.keys(configureData.data[0])
|
|
196
|
-
.filter(value => !configureData.dataDescription.
|
|
228
|
+
.filter(value => !configureData.dataDescription.valueKeysTallSupport || configureData.dataDescription.valueKeysTallSupport.indexOf(value) === -1)
|
|
197
229
|
.map((value, index) => (
|
|
198
230
|
<option value={value} key={`value-keys-option-${index}`}>
|
|
199
231
|
{value}
|
|
@@ -247,7 +279,7 @@ const DataDesigner = props => {
|
|
|
247
279
|
{config?.visualizationType === 'Forest Plot' && (
|
|
248
280
|
<>
|
|
249
281
|
<div className='mb-2'>
|
|
250
|
-
<div className='mb-1'>Which column represents the
|
|
282
|
+
<div className='mb-1'>Which column represents the Study ID?</div>
|
|
251
283
|
<select
|
|
252
284
|
onChange={e => {
|
|
253
285
|
setConfig({
|
|
@@ -337,29 +369,6 @@ const DataDesigner = props => {
|
|
|
337
369
|
))}
|
|
338
370
|
</select>
|
|
339
371
|
</div>
|
|
340
|
-
|
|
341
|
-
<div className='mb-2'>
|
|
342
|
-
<div className='mb-1'>Which shape do you want to use in your forest plot?</div>
|
|
343
|
-
<select
|
|
344
|
-
onChange={e => {
|
|
345
|
-
setConfig({
|
|
346
|
-
...config,
|
|
347
|
-
forestPlot: {
|
|
348
|
-
...config.forestPlot,
|
|
349
|
-
shape: e.target.value
|
|
350
|
-
}
|
|
351
|
-
})
|
|
352
|
-
}}
|
|
353
|
-
defaultValue={'Select'}
|
|
354
|
-
>
|
|
355
|
-
<option value=''>Choose an option</option>
|
|
356
|
-
{['text', 'circle', 'square', 'diamond'].map((value, index) => (
|
|
357
|
-
<option value={value} key={index}>
|
|
358
|
-
{value}
|
|
359
|
-
</option>
|
|
360
|
-
))}
|
|
361
|
-
</select>
|
|
362
|
-
</div>
|
|
363
372
|
</>
|
|
364
373
|
)}
|
|
365
374
|
</>
|
|
@@ -69,17 +69,17 @@ const iconHash = {
|
|
|
69
69
|
|
|
70
70
|
export const ICON_TYPES = Object.keys(iconHash)
|
|
71
71
|
|
|
72
|
-
const Icon = ({ display = '', base, alt = '', size, color, style, ...attributes }) => {
|
|
72
|
+
const Icon = ({ display = '', base = undefined, alt = '', size = undefined, color = undefined, style = undefined, ...attributes }) => {
|
|
73
73
|
const IconObj = iconHash[display] || null
|
|
74
74
|
|
|
75
75
|
const filteredAttrs = { ...attributes }
|
|
76
76
|
delete filteredAttrs.className
|
|
77
77
|
|
|
78
78
|
const styles = {
|
|
79
|
-
...style,
|
|
80
79
|
color: color ? color : null,
|
|
81
80
|
width: size ? size + 'px' : null,
|
|
82
|
-
cursor: display === 'move' ? 'move' : 'default'
|
|
81
|
+
cursor: display === 'move' ? 'move' : 'default',
|
|
82
|
+
...style
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
return (
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
.cove-component__header {
|
|
2
|
+
position: relative;
|
|
3
|
+
padding: 0.6em 0.8em;
|
|
4
|
+
margin: 0;
|
|
5
|
+
color: #fff;
|
|
6
|
+
font-size: 1.1em;
|
|
7
|
+
|
|
8
|
+
border-top-left-radius: 3px;
|
|
9
|
+
border-top-right-radius: 3px;
|
|
10
|
+
|
|
11
|
+
&.mb-0 {
|
|
12
|
+
margin-bottom: 0 !important;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
em {
|
|
16
|
+
font-style: italic;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
strong {
|
|
20
|
+
font-weight: bold;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
&:not(:empty) {
|
|
24
|
+
padding: 0.6em 0.8em;
|
|
25
|
+
border-bottom-width: 4px;
|
|
26
|
+
border-bottom-style: solid;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&.bite-header {
|
|
30
|
+
margin-bottom: 0 !important;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// THEMES
|
|
34
|
+
&.theme-purple {
|
|
35
|
+
background: #712177;
|
|
36
|
+
border-bottom-color: #b890bb;
|
|
37
|
+
}
|
|
38
|
+
&.theme-brown {
|
|
39
|
+
background: #705043;
|
|
40
|
+
border-bottom-color: #ad907b;
|
|
41
|
+
}
|
|
42
|
+
&.theme-teal {
|
|
43
|
+
background: #00695c;
|
|
44
|
+
border-bottom-color: #4ebaaa;
|
|
45
|
+
}
|
|
46
|
+
&.theme-pink {
|
|
47
|
+
background: #af4448;
|
|
48
|
+
border-bottom-color: #e57373;
|
|
49
|
+
}
|
|
50
|
+
&.theme-orange {
|
|
51
|
+
background: #bb4d00;
|
|
52
|
+
border-bottom-color: #ffad42;
|
|
53
|
+
}
|
|
54
|
+
&.theme-slate {
|
|
55
|
+
background: #29434e;
|
|
56
|
+
border-bottom-color: #7e9ba5;
|
|
57
|
+
}
|
|
58
|
+
&.theme-indigo {
|
|
59
|
+
background: #26418f;
|
|
60
|
+
border-bottom-color: #92a6dd;
|
|
61
|
+
}
|
|
62
|
+
&.theme-cyan {
|
|
63
|
+
background: #007b91;
|
|
64
|
+
border-bottom-color: #65b0bd;
|
|
65
|
+
}
|
|
66
|
+
&.theme-green {
|
|
67
|
+
background: #4b830d;
|
|
68
|
+
border-bottom-color: #84bc49;
|
|
69
|
+
}
|
|
70
|
+
&.theme-amber {
|
|
71
|
+
background: #fbab18;
|
|
72
|
+
border-bottom-color: #ffd54f;
|
|
73
|
+
}
|
|
74
|
+
&.theme-blue {
|
|
75
|
+
background: #005eaa;
|
|
76
|
+
border-bottom-color: #88c3ea;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
&.mb-0 {
|
|
80
|
+
margin-bottom: 0 !important;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// add additional space below title if needed
|
|
85
|
+
.map-title.cove-component__header,
|
|
86
|
+
.type-chart .cove-component__header {
|
|
87
|
+
&:not(:empty) {
|
|
88
|
+
margin: 0 0 1rem 0 !important;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// fix sparkline bottom margin gap
|
|
93
|
+
.type-sparkline.type-chart .cove-component__header {
|
|
94
|
+
margin: 0px !important;
|
|
95
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import parse from 'html-react-parser'
|
|
3
|
+
import './Title.scss'
|
|
4
|
+
|
|
5
|
+
type HeaderProps = {
|
|
6
|
+
title?: string
|
|
7
|
+
isDashboard?: boolean
|
|
8
|
+
superTitle?: string
|
|
9
|
+
classes?: string[]
|
|
10
|
+
style?: React.CSSProperties
|
|
11
|
+
showTitle?: boolean
|
|
12
|
+
ariaLevel?: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const Title = (props: HeaderProps) => {
|
|
16
|
+
const { isDashboard, title, superTitle, classes = [], showTitle = true, ariaLevel = 2 } = props
|
|
17
|
+
|
|
18
|
+
// standard classes every vis should have
|
|
19
|
+
const updatedClasses = ['cove-component__header', 'component__header', ...classes]
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
title &&
|
|
23
|
+
showTitle && (
|
|
24
|
+
<header className={updatedClasses.join(' ')} aria-hidden='true' style={props.style} aria-level={ariaLevel}>
|
|
25
|
+
{superTitle && <sup>{parse(superTitle)}</sup>}
|
|
26
|
+
<div>
|
|
27
|
+
{parse(title)} {isDashboard}
|
|
28
|
+
</div>
|
|
29
|
+
</header>
|
|
30
|
+
)
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default Title
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
|
|
3
|
+
import Title from '../Title'
|
|
4
|
+
|
|
5
|
+
const meta: Meta = {
|
|
6
|
+
title: 'Components/Atoms/Title',
|
|
7
|
+
component: Title
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
type Story = StoryObj
|
|
11
|
+
|
|
12
|
+
export const Primary: Story = {
|
|
13
|
+
args: {
|
|
14
|
+
title: 'My Title',
|
|
15
|
+
superTitle: 'My super title',
|
|
16
|
+
isDashboard: false,
|
|
17
|
+
classes: ['theme-blue']
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default meta
|