@cdc/core 4.24.5 → 4.24.9
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/icon-gear-multi.svg +23 -0
- package/components/AdvancedEditor/AdvancedEditor.tsx +93 -0
- package/components/AdvancedEditor/advanced-editor-styles.css +3 -0
- package/components/AdvancedEditor/index.ts +1 -0
- package/components/Alert/components/Alert.styles.css +15 -0
- package/components/Alert/components/Alert.tsx +39 -0
- package/components/Alert/index.tsx +3 -0
- package/components/DataTable/DataTable.tsx +127 -32
- package/components/DataTable/DataTableStandAlone.tsx +4 -25
- package/components/DataTable/components/DataTableEditorPanel.tsx +4 -4
- package/components/DataTable/components/ExpandCollapse.tsx +1 -1
- package/components/DataTable/helpers/chartCellMatrix.tsx +6 -12
- package/components/DataTable/helpers/getChartCellValue.ts +9 -5
- package/components/DataTable/helpers/getDataSeriesColumns.ts +10 -7
- package/components/DataTable/helpers/getRowType.ts +6 -0
- package/components/DataTable/helpers/mapCellMatrix.tsx +3 -3
- package/components/DataTable/types/TableConfig.ts +2 -1
- package/components/EditorPanel/ColumnsEditor.tsx +3 -30
- package/components/EditorPanel/DataTableEditor.tsx +66 -22
- package/components/EditorPanel/FieldSetWrapper.tsx +51 -0
- package/components/EditorPanel/FootnotesEditor.tsx +77 -0
- package/components/EditorPanel/Inputs.tsx +13 -4
- package/components/EditorPanel/VizFilterEditor/NestedDropdownEditor.tsx +268 -0
- package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +306 -0
- package/components/EditorPanel/VizFilterEditor/components/FilterOrder.tsx +40 -0
- package/components/EditorPanel/VizFilterEditor/index.ts +1 -0
- package/components/EditorWrapper/EditorWrapper.tsx +3 -4
- package/components/EditorWrapper/index.ts +1 -0
- package/components/Filters.tsx +520 -0
- package/components/Footnotes/Footnotes.tsx +25 -0
- package/components/Footnotes/FootnotesStandAlone.tsx +45 -0
- package/components/Footnotes/footnotes.css +5 -0
- package/components/Footnotes/index.ts +1 -0
- package/components/Layout/components/Responsive.tsx +14 -4
- package/components/Layout/components/Sidebar/components/Sidebar.tsx +14 -5
- package/components/Layout/components/Sidebar/components/sidebar.styles.scss +23 -20
- package/components/Layout/components/Visualization/index.tsx +19 -6
- package/components/Layout/components/Visualization/visualizations.scss +32 -26
- package/components/Layout/styles/editor.scss +0 -8
- package/components/Legend/Legend.Gradient.tsx +133 -0
- package/components/LegendShape.tsx +28 -0
- package/components/MultiSelect/MultiSelect.tsx +41 -11
- package/components/MultiSelect/multiselect.styles.css +0 -3
- package/components/NestedDropdown/NestedDropdown.tsx +47 -52
- package/components/NestedDropdown/nesteddropdown.styles.css +19 -25
- package/components/Table/Table.tsx +8 -5
- package/components/Table/components/Cell.tsx +2 -2
- package/components/Table/components/Row.tsx +25 -7
- package/components/_stories/Footnotes.stories.tsx +17 -0
- package/components/_stories/Layout.Debug.stories.tsx +91 -0
- package/components/_stories/_mocks/bar-chart-suppressed.json +474 -0
- package/components/_stories/styles.scss +14 -1
- package/components/createBarElement.jsx +4 -4
- package/components/inputs/InputSelect.tsx +17 -6
- package/components/ui/Icon.tsx +22 -16
- package/components/ui/Title/Title.scss +0 -8
- package/helpers/DataTransform.ts +2 -2
- package/helpers/addValuesToFilters.ts +135 -0
- package/helpers/cove/accessibility.ts +17 -4
- package/helpers/cove/fontSettings.ts +2 -0
- package/helpers/coveUpdateWorker.ts +30 -9
- package/helpers/filterVizData.ts +49 -0
- package/helpers/formatConfigBeforeSave.ts +95 -0
- package/helpers/gatherQueryParams.ts +14 -7
- package/helpers/getGradientLegendWidth.ts +15 -0
- package/helpers/getTextWidth.ts +18 -0
- package/helpers/lineChartHelpers.js +2 -1
- package/helpers/pivotData.ts +18 -0
- package/helpers/queryStringUtils.ts +29 -0
- package/helpers/scaling.ts +7 -0
- package/helpers/tests/addValuesToFilters.test.ts +55 -0
- package/helpers/tests/filterVizData.test.ts +31 -0
- package/helpers/tests/invertValue.test.ts +35 -0
- package/helpers/tests/updateFieldFactory.test.ts +1 -0
- package/helpers/updateFieldFactory.ts +1 -1
- package/helpers/updatePaletteNames.ts +19 -0
- package/helpers/{useDataVizClasses.js → useDataVizClasses.ts} +3 -2
- package/helpers/ver/4.24.5.ts +3 -3
- package/helpers/ver/4.24.7.ts +123 -0
- package/helpers/ver/4.24.9.ts +63 -0
- package/helpers/ver/tests/4.24.9.test.ts +22 -0
- package/helpers/ver/versionNeedsUpdate.ts +9 -0
- package/package.json +6 -4
- package/styles/_button-section.scss +7 -2
- package/styles/_data-table.scss +0 -1
- package/styles/_global.scss +6 -2
- package/styles/base.scss +4 -0
- package/styles/filters.scss +4 -0
- package/styles/v2/themes/_color-definitions.scss +1 -0
- package/types/Annotation.ts +46 -0
- package/types/Axis.ts +3 -2
- package/types/ConfigureData.ts +1 -1
- package/types/Dimensions.ts +1 -0
- package/types/Footnotes.ts +17 -0
- package/types/General.ts +5 -0
- package/types/Runtime.ts +2 -7
- package/types/Table.ts +6 -0
- package/types/Visualization.ts +31 -9
- package/types/VizFilter.ts +39 -7
- package/LICENSE +0 -201
- package/components/AdvancedEditor.jsx +0 -74
- package/components/EditorPanel/VizFilterEditor.tsx +0 -234
- package/components/Filters.jsx +0 -461
- package/components/LegendCircle.jsx +0 -17
- package/helpers/queryStringUtils.js +0 -26
- package/helpers/updatePaletteNames.js +0 -16
- package/types/BaseVisualizationType.ts +0 -1
- /package/components/{Waiting.jsx → Waiting.tsx} +0 -0
- /package/helpers/ver/{4.23.4.ts → 4.24.4.ts} +0 -0
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
|
|
12
12
|
.cdc-editor .configure .cdc-open-viz-module:not(.type-dashboard) .editor-panel__toggle {
|
|
13
13
|
position: absolute;
|
|
14
|
-
top: 10px;
|
|
15
14
|
}
|
|
16
15
|
|
|
17
16
|
.cdc-editor .configure .cdc-open-viz-module:not(.type-dashboard) .sidebar {
|
|
@@ -25,24 +24,14 @@
|
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
.sidebar {
|
|
28
|
-
position:
|
|
29
|
-
height:
|
|
27
|
+
position: static;
|
|
28
|
+
height: 100%; // take up the whole container
|
|
30
29
|
top: 0;
|
|
31
30
|
max-width: 350px;
|
|
32
31
|
width: 350px;
|
|
33
32
|
background-color: var(--white);
|
|
34
33
|
grid-area: panel;
|
|
35
34
|
|
|
36
|
-
.editor-toggle {
|
|
37
|
-
position: fixed !important;
|
|
38
|
-
top: 10px !important;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
.editor-panel {
|
|
42
|
-
position: fixed !important;
|
|
43
|
-
top: 0 !important;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
35
|
&.editor-panel--hidden &.hidden {
|
|
47
36
|
display: none;
|
|
48
37
|
}
|
|
@@ -601,7 +590,7 @@
|
|
|
601
590
|
/* clicking anywhere will focus the input */
|
|
602
591
|
cursor: text;
|
|
603
592
|
|
|
604
|
-
span {
|
|
593
|
+
span:not(.cove-tooltip, .cove-icon) {
|
|
605
594
|
display: inline;
|
|
606
595
|
}
|
|
607
596
|
}
|
|
@@ -723,6 +712,10 @@
|
|
|
723
712
|
margin-right: 5px;
|
|
724
713
|
}
|
|
725
714
|
|
|
715
|
+
.cove-tooltip {
|
|
716
|
+
position: relative;
|
|
717
|
+
}
|
|
718
|
+
|
|
726
719
|
// tooltips
|
|
727
720
|
.cove-label + .cove-tooltip {
|
|
728
721
|
top: 1px;
|
|
@@ -731,9 +724,9 @@
|
|
|
731
724
|
}
|
|
732
725
|
|
|
733
726
|
.cove-accordion__button .cove-tooltip {
|
|
734
|
-
display: inline-flex;
|
|
735
|
-
right: 1.5rem;
|
|
736
|
-
line-height: inherit;
|
|
727
|
+
// display: inline-flex;
|
|
728
|
+
// right: 1.5rem;
|
|
729
|
+
// line-height: inherit;
|
|
737
730
|
}
|
|
738
731
|
|
|
739
732
|
.cove-list-group__item .cove-tooltip {
|
|
@@ -854,6 +847,10 @@
|
|
|
854
847
|
border-bottom: #565656 3px solid;
|
|
855
848
|
z-index: 3;
|
|
856
849
|
margin: 0;
|
|
850
|
+
|
|
851
|
+
&.collapsed {
|
|
852
|
+
display: none;
|
|
853
|
+
}
|
|
857
854
|
}
|
|
858
855
|
|
|
859
856
|
&.type-dashboard {
|
|
@@ -862,20 +859,26 @@
|
|
|
862
859
|
}
|
|
863
860
|
}
|
|
864
861
|
|
|
862
|
+
.editor-panel__toggle-wrapper {
|
|
863
|
+
position: absolute;
|
|
864
|
+
top: 0;
|
|
865
|
+
}
|
|
866
|
+
|
|
865
867
|
.editor-panel__toggle {
|
|
866
868
|
background: #f2f2f2;
|
|
867
869
|
border-radius: 60px;
|
|
868
870
|
color: #000;
|
|
869
871
|
font-size: 1em;
|
|
870
872
|
border: 0;
|
|
871
|
-
position:
|
|
873
|
+
position: absolute;
|
|
872
874
|
z-index: 100;
|
|
873
875
|
transition: 0.1s background;
|
|
874
876
|
cursor: pointer;
|
|
875
877
|
width: 25px;
|
|
876
878
|
height: 25px;
|
|
877
|
-
|
|
878
|
-
top:
|
|
879
|
+
right: 10px;
|
|
880
|
+
top: 50%;
|
|
881
|
+
transform: translateY(-50%);
|
|
879
882
|
box-shadow: rgba(0, 0, 0, 0.5) 0 1px 2px;
|
|
880
883
|
|
|
881
884
|
&:before {
|
|
@@ -1,25 +1,31 @@
|
|
|
1
1
|
// main visualization wrapper
|
|
2
2
|
import { ChartConfig } from '@cdc/chart/src/types/ChartConfig'
|
|
3
|
-
import React, { forwardRef
|
|
3
|
+
import React, { forwardRef } from 'react'
|
|
4
4
|
import { Config as DataBiteConfig } from '@cdc/data-bite/src/types/Config'
|
|
5
5
|
import './visualizations.scss'
|
|
6
6
|
import { Config as WaffleChartConfig } from '@cdc/waffle-chart/src/types/Config'
|
|
7
7
|
import { MarkupIncludeConfig } from '@cdc/core/types/MarkupInclude'
|
|
8
|
+
import { DashboardFilters } from '@cdc/dashboard/src/types/DashboardFilters'
|
|
8
9
|
|
|
9
10
|
type VisualizationWrapper = {
|
|
10
11
|
children: React.ReactNode
|
|
11
|
-
config: ChartConfig | DataBiteConfig | WaffleChartConfig | MarkupIncludeConfig
|
|
12
|
-
currentViewport
|
|
13
|
-
imageId
|
|
12
|
+
config: ChartConfig | DataBiteConfig | WaffleChartConfig | MarkupIncludeConfig | DashboardFilters
|
|
13
|
+
currentViewport?: string
|
|
14
|
+
imageId?: string
|
|
14
15
|
isEditor: boolean
|
|
15
|
-
showEditorPanel
|
|
16
|
+
showEditorPanel?: boolean
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
const Visualization: React.FC<VisualizationWrapper> = forwardRef((props, ref) => {
|
|
19
|
-
const { config = {}, isEditor = false, currentViewport = 'lg', imageId = '', showEditorPanel = true } = props
|
|
20
|
+
const { config = {}, isEditor = false, currentViewport = 'lg', imageId = '', showEditorPanel = true, className } = props
|
|
20
21
|
|
|
21
22
|
const getWrappingClasses = () => {
|
|
22
23
|
let classes = ['cdc-open-viz-module', `${currentViewport}`, `font-${config?.fontSize}`, `${config?.theme}`]
|
|
24
|
+
|
|
25
|
+
if (className) {
|
|
26
|
+
classes.push(className)
|
|
27
|
+
}
|
|
28
|
+
|
|
23
29
|
isEditor && classes.push('spacing-wrapper')
|
|
24
30
|
isEditor && classes.push('isEditor')
|
|
25
31
|
|
|
@@ -33,6 +39,12 @@ const Visualization: React.FC<VisualizationWrapper> = forwardRef((props, ref) =>
|
|
|
33
39
|
classes.push('editor-panel--hidden')
|
|
34
40
|
}
|
|
35
41
|
|
|
42
|
+
if (config.type === 'filtered-text') {
|
|
43
|
+
classes.push('type-filtered-text')
|
|
44
|
+
classes = classes.filter(item => item !== 'cove-component__content')
|
|
45
|
+
return classes
|
|
46
|
+
}
|
|
47
|
+
|
|
36
48
|
if (config.type === 'chart') {
|
|
37
49
|
classes.push('type-chart')
|
|
38
50
|
config?.visualizationType === 'Spark Line' && classes.push(`type-sparkline`)
|
|
@@ -40,6 +52,7 @@ const Visualization: React.FC<VisualizationWrapper> = forwardRef((props, ref) =>
|
|
|
40
52
|
}
|
|
41
53
|
if (config.type === 'map') {
|
|
42
54
|
classes.push(`type-map`)
|
|
55
|
+
if (config?.runtime?.editorErrorMessage.length !== 0) classes.push('type-map--has-error')
|
|
43
56
|
}
|
|
44
57
|
|
|
45
58
|
if (config.type === 'data-bite') {
|
|
@@ -1,33 +1,39 @@
|
|
|
1
|
-
.cdc-open-viz-module
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
transition: grid-template-columns 400ms ease-in-out;
|
|
5
|
-
|
|
6
|
-
.editor-panel__toggle {
|
|
7
|
-
transition: left 400ms ease-in-out;
|
|
1
|
+
.cdc-open-viz-module {
|
|
2
|
+
.cdc-chart-inner-container .cove-component__content {
|
|
3
|
+
padding: 25px 15px !important;
|
|
8
4
|
}
|
|
5
|
+
&.isEditor {
|
|
6
|
+
overflow: auto;
|
|
7
|
+
display: grid;
|
|
8
|
+
transition: grid-template-columns 400ms ease-in-out;
|
|
9
|
+
min-height: 100vh;
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
.editor-panel__toggle {
|
|
12
|
+
transition: left 400ms ease-in-out;
|
|
13
|
+
}
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
15
|
+
.sidebar {
|
|
16
|
+
transition: left 400ms ease-in-out;
|
|
17
|
+
}
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
&.editor-panel--visible {
|
|
20
|
+
grid-template-areas: 'panel content';
|
|
21
|
+
grid-template-columns: 350px calc(100% - 350px);
|
|
22
|
+
overflow: hidden;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
&.editor-panel--hidden {
|
|
26
|
+
grid-template-areas: 'panel content';
|
|
27
|
+
grid-template-columns: 0px 100%;
|
|
28
|
+
}
|
|
23
29
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
.cove-editor__content,
|
|
31
|
+
.cove-component__content {
|
|
32
|
+
grid-area: content;
|
|
33
|
+
position: relative;
|
|
34
|
+
left: 0;
|
|
35
|
+
width: 100% !important;
|
|
36
|
+
grid-area: content;
|
|
37
|
+
}
|
|
32
38
|
}
|
|
33
39
|
}
|
|
@@ -4,14 +4,6 @@ $mediumGray: #e6e6e6;
|
|
|
4
4
|
|
|
5
5
|
@import 'editor-grid-view.scss';
|
|
6
6
|
|
|
7
|
-
.cdc-open-viz-module.isEditor {
|
|
8
|
-
background: $mediumGray !important;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
// .cdc-open-viz-module .form-container {
|
|
12
|
-
// height: 100%;
|
|
13
|
-
// }
|
|
14
|
-
|
|
15
7
|
.cove-editor {
|
|
16
8
|
display: grid;
|
|
17
9
|
grid-template-areas: 'panel content';
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Group } from '@visx/group'
|
|
2
|
+
import { Text } from '@visx/text'
|
|
3
|
+
import { type ViewportSize, type MapConfig } from '@cdc/map/src/types/MapConfig'
|
|
4
|
+
import { type ChartConfig } from '@cdc/chart/src/types/ChartConfig'
|
|
5
|
+
import { getGradientLegendWidth } from '@cdc/core/helpers/getGradientLegendWidth'
|
|
6
|
+
import { DimensionsType } from '../../types/Dimensions'
|
|
7
|
+
|
|
8
|
+
type CombinedConfig = MapConfig | ChartConfig
|
|
9
|
+
|
|
10
|
+
interface GradientProps {
|
|
11
|
+
labels: string[]
|
|
12
|
+
colors: string[]
|
|
13
|
+
config: CombinedConfig
|
|
14
|
+
dimensions: DimensionsType
|
|
15
|
+
currentViewport: ViewportSize
|
|
16
|
+
getTextWidth: (text: string, font: string) => string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const LegendGradient = ({
|
|
20
|
+
labels,
|
|
21
|
+
colors,
|
|
22
|
+
config,
|
|
23
|
+
dimensions,
|
|
24
|
+
currentViewport,
|
|
25
|
+
getTextWidth
|
|
26
|
+
}: GradientProps): JSX.Element => {
|
|
27
|
+
let [width] = dimensions
|
|
28
|
+
|
|
29
|
+
const legendWidth = getGradientLegendWidth(width, currentViewport)
|
|
30
|
+
const uniqueID = `${config.uid}-${Date.now()}`
|
|
31
|
+
|
|
32
|
+
const numTicks = colors?.length
|
|
33
|
+
|
|
34
|
+
const longestLabel = labels && labels.length > 0 ? labels.reduce((a, b) => (a.length > b.length ? a : b)) : ''
|
|
35
|
+
const boxHeight = 20
|
|
36
|
+
let height = 50
|
|
37
|
+
const margin = 1
|
|
38
|
+
|
|
39
|
+
// configure tick witch and angle
|
|
40
|
+
const textWidth = getTextWidth(longestLabel, `normal 14px sans-serif`)
|
|
41
|
+
const rotationAngle = Number(config.legend.tickRotation) || 0
|
|
42
|
+
// Convert the angle from degrees to radians
|
|
43
|
+
const angleInRadians = rotationAngle * (Math.PI / 180)
|
|
44
|
+
const newHeight = height + Number(textWidth) * Math.sin(angleInRadians)
|
|
45
|
+
|
|
46
|
+
// configre gradient colors
|
|
47
|
+
const stops = colors.map((color, index) => {
|
|
48
|
+
const offset = (index / (colors.length - 1)) * 100
|
|
49
|
+
return <stop key={index} offset={`${offset}%`} style={{ stopColor: color, stopOpacity: 1 }} />
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
// render ticks and labels
|
|
53
|
+
const ticks = labels.map((key, index) => {
|
|
54
|
+
const segmentWidth = legendWidth / numTicks
|
|
55
|
+
const xPositionX = index * segmentWidth + segmentWidth
|
|
56
|
+
const textAnchor = rotationAngle ? 'end' : 'middle'
|
|
57
|
+
const verticalAnchor = rotationAngle ? 'middle' : 'start'
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<Group top={margin}>
|
|
61
|
+
<line x1={xPositionX} x2={xPositionX} y1={30} y2={boxHeight} stroke='black' />
|
|
62
|
+
<Text
|
|
63
|
+
angle={-config.legend.tickRotation}
|
|
64
|
+
x={xPositionX}
|
|
65
|
+
y={boxHeight}
|
|
66
|
+
dy={10}
|
|
67
|
+
dx={-segmentWidth / 2}
|
|
68
|
+
fontSize='14'
|
|
69
|
+
textAnchor={textAnchor}
|
|
70
|
+
verticalAnchor={verticalAnchor}
|
|
71
|
+
>
|
|
72
|
+
{key}
|
|
73
|
+
</Text>
|
|
74
|
+
</Group>
|
|
75
|
+
)
|
|
76
|
+
})
|
|
77
|
+
if ((config.type === 'map' && config.legend.position === 'side') || !config.legend.position) {
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
if (
|
|
81
|
+
config.type === 'chart' &&
|
|
82
|
+
(config.legend.position === 'left' || config.legend.position === 'right' || !config.legend.position)
|
|
83
|
+
) {
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (config.legend.style === 'gradient') {
|
|
88
|
+
return (
|
|
89
|
+
<svg style={{ overflow: 'visible', width: '100%', marginTop: 10 }} height={newHeight}>
|
|
90
|
+
{/* background border*/}
|
|
91
|
+
<rect
|
|
92
|
+
x={0}
|
|
93
|
+
y={0}
|
|
94
|
+
width={legendWidth + margin * 2}
|
|
95
|
+
height={boxHeight + margin * 2}
|
|
96
|
+
fill='#d3d3d3'
|
|
97
|
+
strokeWidth='0.5'
|
|
98
|
+
/>
|
|
99
|
+
{/* Define the gradient */}
|
|
100
|
+
<linearGradient id={`gradient-smooth-${uniqueID}`} x1='0%' y1='0%' x2='100%' y2='0%'>
|
|
101
|
+
{stops}
|
|
102
|
+
</linearGradient>
|
|
103
|
+
|
|
104
|
+
{config.legend.subStyle === 'smooth' && (
|
|
105
|
+
<rect x={1} y={1} width={legendWidth} height={boxHeight} fill={`url(#gradient-smooth-${uniqueID})`} />
|
|
106
|
+
)}
|
|
107
|
+
|
|
108
|
+
{config.legend.subStyle === 'linear blocks' &&
|
|
109
|
+
colors.map((color, index) => {
|
|
110
|
+
const segmentWidth = legendWidth / numTicks
|
|
111
|
+
const xPosition = index * segmentWidth
|
|
112
|
+
return (
|
|
113
|
+
<Group>
|
|
114
|
+
<rect
|
|
115
|
+
key={index}
|
|
116
|
+
x={xPosition}
|
|
117
|
+
y={0}
|
|
118
|
+
width={segmentWidth}
|
|
119
|
+
height={boxHeight}
|
|
120
|
+
fill={color}
|
|
121
|
+
stroke='white'
|
|
122
|
+
strokeWidth='0'
|
|
123
|
+
/>
|
|
124
|
+
</Group>
|
|
125
|
+
)
|
|
126
|
+
})}
|
|
127
|
+
{/* Ticks and labels */}
|
|
128
|
+
<g>{ticks}</g>
|
|
129
|
+
</svg>
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
export default LegendGradient
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
interface LegendShapeProps {
|
|
4
|
+
fill: string
|
|
5
|
+
borderColor?: string
|
|
6
|
+
display?: 'inline-block' | 'block' | 'inline'
|
|
7
|
+
shape?: 'circle' | 'square'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const LegendShape: React.FC<LegendShapeProps> = props => {
|
|
11
|
+
const { fill, borderColor, display = 'inline-block', shape = 'circle' } = props
|
|
12
|
+
const dimensions = { width: '1em', height: '1em' }
|
|
13
|
+
const marginRight = ['circle', 'square'].includes(shape) ? '5px' : '0'
|
|
14
|
+
const styles = {
|
|
15
|
+
marginRight: marginRight,
|
|
16
|
+
borderRadius: shape === 'circle' ? '50%' : '0px',
|
|
17
|
+
verticalAlign: 'middle',
|
|
18
|
+
display: display,
|
|
19
|
+
height: dimensions.height,
|
|
20
|
+
width: dimensions.width,
|
|
21
|
+
border: borderColor ? `${borderColor} 1px solid` : 'rgba(0,0,0,.3) 1px solid',
|
|
22
|
+
backgroundColor: fill
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return <span className='legend-item' style={styles} />
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default LegendShape
|
|
@@ -6,7 +6,7 @@ import './multiselect.styles.css'
|
|
|
6
6
|
import { UpdateFieldFunc } from '../../types/UpdateFieldFunc'
|
|
7
7
|
|
|
8
8
|
interface Option {
|
|
9
|
-
value: string
|
|
9
|
+
value: string | number
|
|
10
10
|
label: string
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -17,12 +17,13 @@ interface MultiSelectProps {
|
|
|
17
17
|
options: Option[]
|
|
18
18
|
updateField: UpdateFieldFunc<string[]>
|
|
19
19
|
label?: string
|
|
20
|
-
selected?: string[]
|
|
20
|
+
selected?: (string | number)[]
|
|
21
21
|
limit?: number
|
|
22
|
+
tooltip?: React.ReactNode
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
const MultiSelect: React.FC<MultiSelectProps> = ({ section = null, subsection = null, fieldName, label, options, updateField, selected, limit }) => {
|
|
25
|
-
const preselectedItems = options.filter(opt => selected
|
|
25
|
+
const MultiSelect: React.FC<MultiSelectProps> = ({ section = null, subsection = null, fieldName, label, options, updateField, selected = [], limit, tooltip }) => {
|
|
26
|
+
const preselectedItems = options.filter(opt => selected.includes(opt.value)).slice(0, limit)
|
|
26
27
|
const [selectedItems, setSelectedItems] = useState<Option[]>(preselectedItems)
|
|
27
28
|
const [expanded, setExpanded] = useState(false)
|
|
28
29
|
const multiSelectRef = useRef(null)
|
|
@@ -68,22 +69,41 @@ const MultiSelect: React.FC<MultiSelectProps> = ({ section = null, subsection =
|
|
|
68
69
|
return (
|
|
69
70
|
<div ref={multiSelectRef} className='cove-multiselect'>
|
|
70
71
|
{label && (
|
|
71
|
-
<
|
|
72
|
+
<span id={multiID} className='edit-label column-heading'>
|
|
72
73
|
{label}
|
|
73
|
-
</
|
|
74
|
+
</span>
|
|
74
75
|
)}
|
|
75
76
|
|
|
77
|
+
{tooltip && tooltip}
|
|
78
|
+
|
|
76
79
|
<div className='wrapper'>
|
|
77
80
|
<div className='selected'>
|
|
78
81
|
{selectedItems.map(item => (
|
|
79
|
-
<div key={item.value} aria-labelledby={label ? multiID : undefined}
|
|
82
|
+
<div key={item.value} aria-labelledby={label ? multiID : undefined}>
|
|
80
83
|
{item.label}
|
|
81
|
-
<button
|
|
84
|
+
<button
|
|
85
|
+
aria-label='Remove'
|
|
86
|
+
onClick={e => {
|
|
87
|
+
e.preventDefault()
|
|
88
|
+
handleItemRemove(item)
|
|
89
|
+
}}
|
|
90
|
+
onKeyUp={e => {
|
|
91
|
+
handleItemRemove(item, e)
|
|
92
|
+
}}
|
|
93
|
+
>
|
|
82
94
|
x
|
|
83
95
|
</button>
|
|
84
96
|
</div>
|
|
85
97
|
))}
|
|
86
|
-
<button
|
|
98
|
+
<button
|
|
99
|
+
aria-label={expanded ? 'Collapse' : 'Expand'}
|
|
100
|
+
aria-labelledby={label ? multiID : undefined}
|
|
101
|
+
className='expand'
|
|
102
|
+
onClick={e => {
|
|
103
|
+
e.preventDefault()
|
|
104
|
+
setExpanded(!expanded)
|
|
105
|
+
}}
|
|
106
|
+
>
|
|
87
107
|
<Icon display={expanded ? 'caretDown' : 'caretUp'} style={{ cursor: 'pointer' }} />
|
|
88
108
|
</button>
|
|
89
109
|
</div>
|
|
@@ -98,11 +118,21 @@ const MultiSelect: React.FC<MultiSelectProps> = ({ section = null, subsection =
|
|
|
98
118
|
</Tooltip>
|
|
99
119
|
)}
|
|
100
120
|
</div>
|
|
101
|
-
<ul className={'dropdown' + (expanded ? '' : '
|
|
121
|
+
<ul className={'dropdown' + (expanded ? '' : ' d-none')}>
|
|
102
122
|
{options
|
|
103
123
|
.filter(option => !selectedItems.find(item => item.value === option.value))
|
|
104
124
|
.map(option => (
|
|
105
|
-
<li
|
|
125
|
+
<li
|
|
126
|
+
className='cove-multiselect-li'
|
|
127
|
+
key={option.value}
|
|
128
|
+
role='option'
|
|
129
|
+
tabIndex={0}
|
|
130
|
+
onClick={e => {
|
|
131
|
+
e.preventDefault()
|
|
132
|
+
handleItemSelect(option, e)
|
|
133
|
+
}}
|
|
134
|
+
onKeyUp={e => handleItemSelect(option, e)}
|
|
135
|
+
>
|
|
106
136
|
{option.label}
|
|
107
137
|
</li>
|
|
108
138
|
))}
|