@cdc/core 4.26.1 → 4.26.3
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/.claude/agents/qa-test-developer.md +126 -0
- package/CLAUDE.local.md +67 -0
- package/LICENSE +201 -0
- package/_stories/Gallery.Charts.stories.tsx +35 -42
- package/_stories/Gallery.DataBite.stories.tsx +15 -8
- package/_stories/Gallery.Maps.stories.tsx +37 -28
- package/_stories/Gallery.WaffleChart.stories.tsx +1 -1
- package/_stories/PageART.stories.tsx +5 -4
- package/_stories/PageBRFSS.stories.tsx +21 -16
- package/_stories/PageCancerRegistries.stories.tsx +15 -15
- package/_stories/PageEasternEquineEncephalitis.stories.tsx +33 -19
- package/_stories/PageExcessiveAlcoholUse.stories.tsx +148 -143
- package/_stories/PageMaternalMortality.stories.tsx +5 -4
- package/_stories/PageOralHealth.stories.tsx +15 -10
- package/_stories/PageRespiratory.stories.tsx +4 -4
- package/_stories/PageSmokingTobacco.stories.tsx +15 -10
- package/_stories/PageStateDiabetesProfiles.stories.tsx +15 -10
- package/_stories/PageWastewater.stories.tsx +44 -30
- package/_stories/VegaImport.stories.tsx +401 -0
- package/_stories/vega-fixtures/bars-with-line.json +444 -0
- package/_stories/vega-fixtures/bars.json +58 -0
- package/_stories/vega-fixtures/combo-bar-rolling-mean.json +88 -0
- package/_stories/vega-fixtures/combo.json +68 -0
- package/_stories/vega-fixtures/grouped-horizontal-bars.json +83 -0
- package/_stories/vega-fixtures/grouped-horizontal-bars2.json +231 -0
- package/_stories/vega-fixtures/horizontal-bar.json +427 -0
- package/_stories/vega-fixtures/horizontal-bars-with-bad-colors.json +197 -0
- package/_stories/vega-fixtures/horizontal-bars2.json +58 -0
- package/_stories/vega-fixtures/lines.json +227 -0
- package/_stories/vega-fixtures/measles-bars.json +348 -0
- package/_stories/vega-fixtures/measles-map.json +11101 -0
- package/_stories/vega-fixtures/measles-stacked-bars.json +2147 -0
- package/_stories/vega-fixtures/multi-dataset.json +255 -0
- package/_stories/vega-fixtures/no-data.json +14 -0
- package/_stories/vega-fixtures/pie-chart.json +94 -0
- package/_stories/vega-fixtures/repeat-spec.json +47 -0
- package/_stories/vega-fixtures/stacked-area.json +222 -0
- package/_stories/vega-fixtures/stacked-bar-with-rect.json +3412 -0
- package/_stories/vega-fixtures/stacked-bars-with-line.json +364 -0
- package/_stories/vega-fixtures/stacked-bars.json +212 -0
- package/_stories/vega-fixtures/stacked-horizontal-bars.json +140 -0
- package/_stories/vega-fixtures/warning-combo.json +59 -0
- package/_stories/vega-fixtures/warning-scatter-and-line.json +1182 -0
- package/assets/callout-flag.svg +7 -0
- package/assets/icon-chart-area.svg +1 -0
- package/assets/icon-chart-radar.svg +23 -0
- package/assets/logo2.svg +31 -0
- package/components/AdvancedEditor/EmbedEditor.tsx +270 -38
- package/components/Alert/components/Alert.styles.css +2 -2
- package/components/ComboBox/combobox.styles.css +48 -48
- package/components/CustomColorsEditor/CustomColorsEditor.css +53 -53
- package/components/CustomColorsEditor/CustomColorsEditor.tsx +3 -10
- package/components/DataTable/DataTable.tsx +46 -18
- package/components/DataTable/DataTableStandAlone.tsx +1 -0
- package/components/DataTable/components/ChartHeader.tsx +21 -12
- package/components/DataTable/components/MapHeader.tsx +34 -28
- package/components/DataTable/components/SortIcon/sort-icon.css +5 -5
- package/components/DataTable/data-table.css +50 -52
- package/components/DataTable/helpers/applyCustomOrder.ts +17 -0
- package/components/DataTable/helpers/getChartCellValue.ts +10 -7
- package/components/DataTable/helpers/getMapDataTableColumnKeys.ts +22 -0
- package/components/DataTable/helpers/getSeriesName.ts +6 -0
- package/components/DataTable/helpers/mapCellMatrix.tsx +33 -23
- package/components/DataTable/helpers/tests/mapCellMatrix.test.ts +33 -0
- package/components/DownloadButton.tsx +14 -6
- package/components/EditorPanel/ColumnsEditor.tsx +38 -31
- package/components/EditorPanel/CustomSortOrder.tsx +94 -0
- package/components/EditorPanel/DataTableEditor.tsx +139 -23
- package/components/EditorPanel/EditorPanel.styles.css +71 -71
- package/components/EditorPanel/EditorPanel.tsx +3 -8
- package/components/EditorPanel/EditorPanelDispatch.tsx +4 -4
- package/components/EditorPanel/FootnotesEditor.tsx +2 -2
- package/components/EditorPanel/VizFilterEditor/NestedDropdownEditor.tsx +21 -12
- package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +16 -10
- package/components/EditorPanel/VizFilterEditor/components/FilterOrder.tsx +33 -29
- package/components/EditorPanel/components/MarkupVariablesEditor.tsx +160 -106
- package/components/EditorPanel/components/PanelMarkup.tsx +5 -1
- package/{styles/v2/components → components/EditorPanel}/editor.scss +76 -22
- package/components/EditorPanel/sections/StyleTreatmentSection.tsx +99 -0
- package/components/EditorPanel/sections/VisualSection.tsx +11 -0
- package/components/EditorWrapper/editor-wrapper.style.css +1 -1
- package/components/Filters/Filters.tsx +3 -5
- package/components/Filters/components/Tabs.tsx +19 -7
- package/{styles → components/Filters}/filters.scss +3 -3
- package/components/Footnotes/FootnotesStandAlone.tsx +4 -2
- package/components/HeaderThemeSelector/HeaderThemeSelector.css +61 -5
- package/components/Layout/components/Responsive.tsx +14 -6
- package/components/Layout/components/Sidebar/components/Sidebar.tsx +1 -1
- package/components/Layout/components/Sidebar/components/sidebar.styles.scss +14 -20
- package/components/Layout/components/Visualization/index.tsx +50 -38
- package/components/Layout/components/Visualization/visualizations.scss +232 -15
- package/components/Layout/components/VisualizationContainer.test.tsx +67 -0
- package/components/Layout/components/VisualizationContainer.tsx +37 -0
- package/components/Layout/components/VisualizationContent.test.tsx +182 -0
- package/components/Layout/components/VisualizationContent.tsx +75 -0
- package/components/Layout/index.tsx +5 -5
- package/components/Layout/styles/editor-utils.scss +3 -3
- package/components/Layout/styles/editor.scss +4 -4
- package/components/Legend/Legend.Gradient.tsx +7 -1
- package/components/Loader/loader.styles.css +2 -2
- package/components/Loading.jsx +1 -1
- package/components/MediaControls.tsx +10 -3
- package/components/MultiSelect/multiselect.styles.css +19 -19
- package/components/NestedDropdown/nesteddropdown.styles.css +15 -15
- package/components/PaletteSelector/PaletteSelector.css +15 -15
- package/components/RichTooltip/richTooltip.css +6 -6
- package/components/Table/table.styles.css +2 -2
- package/components/Waiting.tsx +1 -1
- package/components/_stories/CustomColorsEditor.stories.tsx +37 -0
- package/components/_stories/DataTable.stories.tsx +1 -0
- package/components/_stories/Filters.stories.tsx +1 -1
- package/components/_stories/styles.scss +0 -1
- package/components/elements/Button.jsx +1 -1
- package/components/elements/Card.jsx +1 -1
- package/{styles/v2/components → components/elements}/button.scss +9 -8
- package/components/inputs/InputCheckbox.jsx +1 -1
- package/components/inputs/InputSelect.tsx +1 -1
- package/components/inputs/InputText.jsx +1 -1
- package/components/inputs/InputToggle.tsx +1 -1
- package/{styles/v2/components/input → components/inputs}/_input-check-radio.scss +2 -2
- package/{styles/v2/components/input → components/inputs}/_input-group.scss +3 -3
- package/{styles/v2/components/input → components/inputs}/_input-slider.scss +2 -2
- package/{styles/v2/components/input → components/inputs}/_input.scss +5 -5
- package/{styles/v2/components/input → components/inputs}/index.scss +2 -2
- package/{styles → components}/loading.scss +1 -1
- package/components/managers/DataDesigner.tsx +1 -1
- package/{styles/v2/components → components/managers}/data-designer.scss +6 -7
- package/components/ui/Accordion.jsx +1 -1
- package/components/ui/Icon.tsx +1 -1
- package/components/ui/LoadSpin.jsx +1 -1
- package/components/ui/Modal.jsx +1 -1
- package/components/ui/Overlay.jsx +1 -1
- package/components/ui/Title/index.test.tsx +34 -0
- package/components/ui/Title/index.tsx +24 -7
- package/components/ui/Title/title.styles.css +119 -25
- package/components/ui/Tooltip.tsx +1 -1
- package/components/ui/_stories/Title.stories.tsx +1 -1
- package/{styles/v2/components → components/ui}/accordion.scss +3 -3
- package/components/ui/accordion.styles.css +11 -11
- package/{styles/v2/components → components/ui}/modal.scss +2 -2
- package/{styles/v2/components → components/ui}/overlay.scss +6 -6
- package/{styles/v2/components → components}/ui/tooltip.scss +1 -1
- package/{styles → components}/waiting.scss +9 -3
- package/data/colorPalettes.ts +18 -5
- package/data/mapColorPalettes.ts +10 -0
- package/devTemplate/dev.js +285 -0
- package/devTemplate/index.html +30 -0
- package/devTemplate/preview.html +1503 -0
- package/devTemplate/sidebar.css +151 -0
- package/dist/cove-main.css +2530 -3901
- package/dist/cove-main.css.map +1 -1
- package/generateViteConfig.js +111 -2
- package/helpers/DataTransform.ts +1 -5
- package/helpers/backfillDefaults.ts +35 -0
- package/helpers/constants.ts +12 -0
- package/helpers/cove/date.ts +64 -3
- package/helpers/cove/number.ts +29 -15
- package/helpers/cove/string.ts +29 -0
- package/helpers/coveUpdateWorker.ts +14 -8
- package/helpers/displayDataAsText.ts +1 -1
- package/helpers/embed/embedCodeGenerator.ts +80 -0
- package/helpers/embed/embedHelper.js +169 -0
- package/helpers/embed/filterUtils.ts +121 -0
- package/helpers/embed/index.ts +17 -0
- package/helpers/embed/urlValidation.ts +119 -0
- package/helpers/extractDataAndMetadata.ts +20 -0
- package/helpers/fetchRemoteData.ts +14 -8
- package/helpers/filterVizData.ts +6 -1
- package/helpers/getFileExtension.ts +0 -6
- package/helpers/labelHash.ts +9 -0
- package/helpers/markupProcessor.ts +56 -38
- package/helpers/metrics/types.ts +3 -0
- package/helpers/palettes/colorDistributions.ts +1 -1
- package/helpers/palettes/utils.ts +12 -12
- package/helpers/parseCsvWithQuotes.ts +15 -14
- package/helpers/prepareScreenshot.ts +33 -10
- package/helpers/testing.ts +44 -0
- package/helpers/tests/DataTransform.test.ts +125 -0
- package/helpers/tests/abbreviateNumber.test.ts +59 -0
- package/helpers/tests/backfillDefaults.test.ts +253 -0
- package/helpers/tests/date.test.ts +110 -0
- package/helpers/tests/extractDataAndMetadata.test.ts +93 -0
- package/helpers/tests/markupProcessor.test.ts +315 -124
- package/helpers/tests/number.test.ts +42 -0
- package/helpers/tests/prepareScreenshot.test.ts +28 -28
- package/helpers/tests/testStandaloneBuild.ts +36 -26
- package/helpers/tests/useDataVizClasses.test.ts +66 -0
- package/helpers/tests/visualizationWrapperUsage.test.ts +57 -0
- package/helpers/useDataVizClasses.ts +13 -7
- package/helpers/vegaConfig.ts +1 -1
- package/helpers/vegaConfigImport.ts +160 -0
- package/helpers/ver/4.24.4.ts +24 -0
- package/helpers/ver/4.26.1.ts +1 -1
- package/helpers/ver/4.26.2.ts +84 -0
- package/helpers/ver/4.26.3.ts +44 -0
- package/helpers/ver/4.26.4.ts +31 -0
- package/helpers/ver/tests/4.26.1.test.ts +105 -0
- package/helpers/ver/tests/4.26.2.test.ts +298 -0
- package/helpers/ver/tests/4.26.3.test.ts +168 -0
- package/helpers/ver/tests/4.26.4.test.ts +88 -0
- package/helpers/ver/tests/coveUpdateWorker.test.ts +57 -0
- package/helpers/viewports.ts +2 -0
- package/package.json +27 -32
- package/styles/_global.scss +7 -7
- package/styles/_reset.scss +2 -2
- package/styles/{v2/base → base}/_file-selector.scss +4 -4
- package/styles/{v2/base → base}/_general.scss +2 -4
- package/styles/{v2/base → base}/index.scss +1 -1
- package/styles/base.scss +107 -165
- package/styles/cove-main.scss +3 -6
- package/styles/layout/_component.scss +110 -0
- package/styles/{v2/layout → layout}/_data-table.scss +7 -7
- package/styles/layout/_wrapper-padding.scss +27 -0
- package/styles/{v2/main.scss → main.scss} +3 -1
- package/styles/{v2/themes → themes}/_color-definitions.scss +46 -41
- package/styles/{_accessibility.scss → utils/_accessibility.scss} +1 -1
- package/styles/{v2/utils → utils}/_grid.scss +8 -3
- package/styles/{_global-variables.scss → utils/_properties.scss} +133 -112
- package/styles/{v2/utils → utils}/index.scss +2 -1
- package/types/Annotation.ts +10 -11
- package/types/Axis.ts +2 -0
- package/types/ComponentStyles.ts +1 -0
- package/types/ConfigureData.ts +1 -0
- package/types/General.ts +2 -0
- package/types/MarkupInclude.ts +1 -0
- package/types/MarkupVariable.ts +2 -1
- package/types/Palette.ts +22 -0
- package/types/Table.ts +9 -0
- package/types/Visualization.ts +7 -0
- package/_stories/StoryRenderingTests.stories.tsx +0 -164
- package/helpers/embedCodeGenerator.ts +0 -109
- package/styles/_common-components.css +0 -73
- package/styles/_variables.scss +0 -63
- package/styles/v2/layout/_component.scss +0 -21
- package/styles/v2/utils/_variables.scss +0 -9
- package/{styles/v2/components/card.scss → components/elements/card.css} +2 -2
- /package/{styles/v2/components → components/ui}/icon.scss +0 -0
- /package/{styles/v2/components → components/ui}/loadspin.scss +0 -0
- /package/styles/{v2/base → base}/_heading.scss +0 -0
- /package/styles/{v2/base → base}/_reset.scss +0 -0
- /package/styles/{v2/layout → layout}/_alert.scss +0 -0
- /package/styles/{v2/layout → layout}/_progression.scss +0 -0
- /package/styles/{v2/layout → layout}/_tooltip.scss +0 -0
- /package/styles/{v2/layout → layout}/index.scss +0 -0
- /package/styles/{v2/themes → themes}/index.scss +0 -0
- /package/styles/{v2/utils → utils}/_align.scss +0 -0
- /package/styles/{v2/utils → utils}/_animations.scss +0 -0
- /package/styles/{v2/utils → utils}/_breakpoints.scss +0 -0
- /package/styles/{v2/utils → utils}/_mixins.scss +0 -0
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
.custom-colors-editor {
|
|
2
|
-
|
|
2
|
+
background-color: #f8f9fa;
|
|
3
3
|
border: 1px solid #dee2e6;
|
|
4
4
|
border-radius: 0.25rem;
|
|
5
|
-
|
|
5
|
+
padding: 0.75rem;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
.custom-colors-editor .custom-colors-label {
|
|
9
|
+
color: #495057;
|
|
9
10
|
display: block;
|
|
11
|
+
font-size: 0.875rem;
|
|
10
12
|
font-weight: 600;
|
|
11
13
|
margin-bottom: 0.5rem;
|
|
12
|
-
font-size: 0.875rem;
|
|
13
|
-
color: #495057;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
.custom-colors-editor .custom-colors-notice {
|
|
17
|
-
display: flex;
|
|
18
17
|
align-items: flex-start;
|
|
19
|
-
gap: 0.5rem;
|
|
20
|
-
padding: 0.75rem;
|
|
21
|
-
margin-bottom: 0.75rem;
|
|
22
18
|
background-color: #d1ecf1;
|
|
23
19
|
border: 1px solid #bee5eb;
|
|
24
20
|
border-radius: 0.25rem;
|
|
25
21
|
color: #0c5460;
|
|
22
|
+
display: flex;
|
|
26
23
|
font-size: 0.8125rem;
|
|
24
|
+
gap: 0.5rem;
|
|
27
25
|
line-height: 1.5;
|
|
26
|
+
margin-bottom: 0.75rem;
|
|
27
|
+
padding: 0.75rem;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
.custom-colors-editor .custom-colors-notice .notice-icon {
|
|
31
|
-
|
|
32
|
-
height: 16px;
|
|
31
|
+
color: #17a2b8;
|
|
33
32
|
flex-shrink: 0;
|
|
33
|
+
height: 16px;
|
|
34
34
|
margin-top: 0.125rem;
|
|
35
|
-
|
|
35
|
+
width: 16px;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
.custom-colors-editor .custom-colors-notice strong {
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
|
|
42
42
|
.custom-colors-editor .custom-colors-notice a {
|
|
43
43
|
color: #0c5460;
|
|
44
|
-
text-decoration: underline;
|
|
45
44
|
font-weight: 500;
|
|
45
|
+
text-decoration: underline;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
.custom-colors-editor .custom-colors-notice a:hover {
|
|
@@ -51,21 +51,21 @@
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
.custom-colors-editor .custom-colors-preview {
|
|
54
|
-
display: flex;
|
|
55
|
-
gap: 2px;
|
|
56
|
-
margin-bottom: 0.75rem;
|
|
57
|
-
padding: 0.5rem;
|
|
58
54
|
background-color: #fff;
|
|
59
55
|
border: 1px solid #dee2e6;
|
|
60
56
|
border-radius: 0.25rem;
|
|
57
|
+
display: flex;
|
|
58
|
+
gap: 2px;
|
|
59
|
+
margin-bottom: 0.75rem;
|
|
61
60
|
min-height: 36px;
|
|
62
61
|
overflow: hidden;
|
|
62
|
+
padding: 0.5rem;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
.custom-colors-editor .custom-colors-preview .preview-swatch {
|
|
66
|
+
border-radius: 2px;
|
|
66
67
|
flex: 1;
|
|
67
68
|
min-width: 8px;
|
|
68
|
-
border-radius: 2px;
|
|
69
69
|
transition: transform 0.15s ease;
|
|
70
70
|
}
|
|
71
71
|
|
|
@@ -110,21 +110,21 @@
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
.custom-colors-editor .custom-color-item.dragging {
|
|
113
|
-
opacity: 0.5;
|
|
114
113
|
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
|
115
114
|
cursor: grabbing;
|
|
115
|
+
opacity: 0.5;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
.custom-colors-editor .custom-color-item:hover:not(.dragging) {
|
|
119
|
-
box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.1);
|
|
120
119
|
border-color: #adb5bd;
|
|
120
|
+
box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.1);
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
.custom-colors-editor .color-item-controls {
|
|
124
|
-
display: flex;
|
|
125
124
|
align-items: center;
|
|
126
|
-
|
|
125
|
+
display: flex;
|
|
127
126
|
flex-wrap: wrap;
|
|
127
|
+
gap: 0.5rem;
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
@media (max-width: 576px) {
|
|
@@ -135,12 +135,12 @@
|
|
|
135
135
|
|
|
136
136
|
.custom-colors-editor .color-item-drag-handle {
|
|
137
137
|
color: #adb5bd;
|
|
138
|
-
font-size: 0.875rem;
|
|
139
138
|
cursor: grab;
|
|
140
|
-
user-select: none;
|
|
141
|
-
line-height: 1;
|
|
142
139
|
flex-shrink: 0;
|
|
140
|
+
font-size: 0.875rem;
|
|
141
|
+
line-height: 1;
|
|
143
142
|
padding: 0 0.125rem;
|
|
143
|
+
user-select: none;
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
.custom-colors-editor .color-item-drag-handle:active {
|
|
@@ -152,23 +152,23 @@
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
.custom-colors-editor .color-item-number {
|
|
155
|
+
color: #6c757d;
|
|
156
|
+
flex-shrink: 0;
|
|
157
|
+
font-size: 0.75rem;
|
|
155
158
|
font-weight: 600;
|
|
156
159
|
min-width: 24px;
|
|
157
160
|
text-align: right;
|
|
158
|
-
color: #6c757d;
|
|
159
|
-
font-size: 0.75rem;
|
|
160
|
-
flex-shrink: 0;
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
.custom-colors-editor .color-picker {
|
|
164
|
-
width: 48px;
|
|
165
|
-
height: 34px;
|
|
166
164
|
border: 1px solid #ced4da;
|
|
167
165
|
border-radius: 0.25rem;
|
|
168
166
|
cursor: pointer;
|
|
169
|
-
padding: 2px;
|
|
170
167
|
flex-shrink: 0;
|
|
168
|
+
height: 34px;
|
|
169
|
+
padding: 2px;
|
|
171
170
|
transition: border-color 0.15s ease;
|
|
171
|
+
width: 48px;
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
.custom-colors-editor .color-picker:hover {
|
|
@@ -176,15 +176,15 @@
|
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
.custom-colors-editor .color-picker:focus {
|
|
179
|
-
outline: none;
|
|
180
179
|
border-color: #80bdff;
|
|
181
180
|
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
|
|
181
|
+
outline: none;
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
.custom-colors-editor .color-input-wrapper {
|
|
185
185
|
flex: 1;
|
|
186
|
-
min-width: 0;
|
|
187
186
|
margin-bottom: 0;
|
|
187
|
+
min-width: 0;
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
/* Override TextField label wrapper styles */
|
|
@@ -210,26 +210,26 @@
|
|
|
210
210
|
|
|
211
211
|
.custom-colors-editor .color-item-buttons {
|
|
212
212
|
display: flex;
|
|
213
|
+
flex-shrink: 0;
|
|
213
214
|
gap: 0.25rem;
|
|
214
215
|
margin-left: auto;
|
|
215
|
-
flex-shrink: 0;
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
.custom-colors-editor .btn-move,
|
|
219
219
|
.custom-colors-editor .btn-remove {
|
|
220
|
-
|
|
220
|
+
align-items: center;
|
|
221
|
+
background-color: #fff;
|
|
221
222
|
border: 1px solid #ced4da;
|
|
222
223
|
border-radius: 0.25rem;
|
|
223
|
-
background-color: #fff;
|
|
224
224
|
cursor: pointer;
|
|
225
|
-
font-size: 0.875rem;
|
|
226
|
-
line-height: 1.5;
|
|
227
|
-
transition: all 0.15s ease;
|
|
228
225
|
display: inline-flex;
|
|
229
|
-
|
|
226
|
+
font-size: 0.875rem;
|
|
227
|
+
height: 28px;
|
|
230
228
|
justify-content: center;
|
|
229
|
+
line-height: 1.5;
|
|
231
230
|
min-width: 28px;
|
|
232
|
-
|
|
231
|
+
padding: 0.25rem 0.5rem;
|
|
232
|
+
transition: all 0.15s ease;
|
|
233
233
|
}
|
|
234
234
|
|
|
235
235
|
.custom-colors-editor .btn-move:hover:not(:disabled),
|
|
@@ -246,39 +246,39 @@
|
|
|
246
246
|
|
|
247
247
|
.custom-colors-editor .btn-move:disabled,
|
|
248
248
|
.custom-colors-editor .btn-remove:disabled {
|
|
249
|
-
opacity: 0.35;
|
|
250
249
|
cursor: not-allowed;
|
|
250
|
+
opacity: 0.35;
|
|
251
251
|
}
|
|
252
252
|
|
|
253
253
|
.custom-colors-editor .btn-remove {
|
|
254
254
|
color: #dc3545;
|
|
255
|
-
font-weight: 700;
|
|
256
255
|
font-size: 1.125rem;
|
|
256
|
+
font-weight: 700;
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
.custom-colors-editor .btn-remove:hover:not(:disabled) {
|
|
260
260
|
background-color: #dc3545;
|
|
261
|
-
color: #fff;
|
|
262
261
|
border-color: #dc3545;
|
|
262
|
+
color: #fff;
|
|
263
263
|
}
|
|
264
264
|
|
|
265
265
|
.custom-colors-editor .btn-add-color {
|
|
266
|
-
|
|
267
|
-
padding: 0.5rem;
|
|
266
|
+
background-color: #fff;
|
|
268
267
|
border: 2px dashed #ced4da;
|
|
269
268
|
border-radius: 0.25rem;
|
|
270
|
-
background-color: #fff;
|
|
271
269
|
color: #6c757d;
|
|
272
|
-
font-weight: 600;
|
|
273
|
-
font-size: 0.875rem;
|
|
274
270
|
cursor: pointer;
|
|
271
|
+
font-size: 0.875rem;
|
|
272
|
+
font-weight: 600;
|
|
273
|
+
padding: 0.5rem;
|
|
275
274
|
transition: all 0.15s ease;
|
|
275
|
+
width: 100%;
|
|
276
276
|
}
|
|
277
277
|
|
|
278
278
|
.custom-colors-editor .btn-add-color:hover:not(:disabled) {
|
|
279
|
+
background-color: #e7f1ff;
|
|
279
280
|
border-color: #007bff;
|
|
280
281
|
color: #007bff;
|
|
281
|
-
background-color: #e7f1ff;
|
|
282
282
|
}
|
|
283
283
|
|
|
284
284
|
.custom-colors-editor .btn-add-color:active:not(:disabled) {
|
|
@@ -286,14 +286,14 @@
|
|
|
286
286
|
}
|
|
287
287
|
|
|
288
288
|
.custom-colors-editor .btn-add-color:disabled {
|
|
289
|
-
opacity: 0.5;
|
|
290
289
|
cursor: not-allowed;
|
|
290
|
+
opacity: 0.5;
|
|
291
291
|
}
|
|
292
292
|
|
|
293
293
|
.custom-colors-editor .custom-colors-info {
|
|
294
|
-
text-align: center;
|
|
295
|
-
font-size: 0.75rem;
|
|
296
294
|
color: #6c757d;
|
|
297
|
-
|
|
295
|
+
font-size: 0.75rem;
|
|
298
296
|
font-style: italic;
|
|
297
|
+
margin-top: 0.5rem;
|
|
298
|
+
text-align: center;
|
|
299
299
|
}
|
|
@@ -7,15 +7,13 @@ interface CustomColorsEditorProps {
|
|
|
7
7
|
onChange: (colors: string[]) => void
|
|
8
8
|
label?: string
|
|
9
9
|
minColors?: number
|
|
10
|
-
maxColors?: number
|
|
11
10
|
}
|
|
12
11
|
|
|
13
12
|
const CustomColorsEditor: React.FC<CustomColorsEditorProps> = ({
|
|
14
13
|
colors = [],
|
|
15
14
|
onChange,
|
|
16
15
|
label = 'Custom Colors',
|
|
17
|
-
minColors = 1
|
|
18
|
-
maxColors = 20
|
|
16
|
+
minColors = 1
|
|
19
17
|
}) => {
|
|
20
18
|
const [draggedIndex, setDraggedIndex] = useState<number | null>(null)
|
|
21
19
|
|
|
@@ -26,11 +24,8 @@ const CustomColorsEditor: React.FC<CustomColorsEditorProps> = ({
|
|
|
26
24
|
}
|
|
27
25
|
|
|
28
26
|
const handleAddColor = () => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const defaultColor = colors.length > 0 ? colors[colors.length - 1] : '#3366cc'
|
|
32
|
-
onChange([...colors, defaultColor])
|
|
33
|
-
}
|
|
27
|
+
const defaultColor = colors.length > 0 ? colors[colors.length - 1] : '#3366cc'
|
|
28
|
+
onChange([...colors, defaultColor])
|
|
34
29
|
}
|
|
35
30
|
|
|
36
31
|
const handleRemoveColor = (index: number) => {
|
|
@@ -191,7 +186,6 @@ const CustomColorsEditor: React.FC<CustomColorsEditorProps> = ({
|
|
|
191
186
|
<button
|
|
192
187
|
type="button"
|
|
193
188
|
onClick={handleAddColor}
|
|
194
|
-
disabled={colors.length >= maxColors}
|
|
195
189
|
className="btn-add-color"
|
|
196
190
|
>
|
|
197
191
|
+ Add Color
|
|
@@ -200,7 +194,6 @@ const CustomColorsEditor: React.FC<CustomColorsEditorProps> = ({
|
|
|
200
194
|
<div className="custom-colors-info">
|
|
201
195
|
{colors.length} color{colors.length !== 1 ? 's' : ''}
|
|
202
196
|
{colors.length < minColors && ` (minimum ${minColors} required)`}
|
|
203
|
-
{colors.length >= maxColors && ` (maximum reached)`}
|
|
204
197
|
</div>
|
|
205
198
|
</div>
|
|
206
199
|
)
|
|
@@ -6,6 +6,7 @@ import MediaControls from '@cdc/core/components/MediaControls'
|
|
|
6
6
|
import Loading from '@cdc/core/components/Loading'
|
|
7
7
|
import DownloadButton from '../DownloadButton'
|
|
8
8
|
import { customSort } from './helpers/customSort'
|
|
9
|
+
import { applyCustomOrder } from './helpers/applyCustomOrder'
|
|
9
10
|
import ChartHeader from './components/ChartHeader'
|
|
10
11
|
import BoxplotHeader from './components/BoxplotHeader'
|
|
11
12
|
import MapHeader from './components/MapHeader'
|
|
@@ -25,18 +26,17 @@ import isRightAlignedTableValue from '@cdc/core/helpers/isRightAlignedTableValue
|
|
|
25
26
|
import './data-table.css'
|
|
26
27
|
import _ from 'lodash'
|
|
27
28
|
import { getDataSeriesColumns } from './helpers/getDataSeriesColumns'
|
|
29
|
+
import { getMapDataTableColumnKeys } from './helpers/getMapDataTableColumnKeys'
|
|
28
30
|
|
|
29
31
|
export type DataTableProps = {
|
|
30
32
|
colorScale?: Function
|
|
31
33
|
columns?: Record<string, Column>
|
|
32
34
|
config: TableConfig
|
|
33
35
|
dataConfig?: Object
|
|
34
|
-
defaultSortBy?: string
|
|
35
36
|
displayGeoName?: (row: string) => string
|
|
36
37
|
expandDataTable: boolean
|
|
37
38
|
formatLegendLocation?: (row: string, runtimeLookup: string) => string
|
|
38
39
|
groupBy?: string
|
|
39
|
-
headerColor?: string
|
|
40
40
|
imageRef?: string
|
|
41
41
|
indexTitle?: string
|
|
42
42
|
isDebug?: boolean
|
|
@@ -64,6 +64,7 @@ export type DataTableProps = {
|
|
|
64
64
|
showDownloadImgButton?: boolean
|
|
65
65
|
showDownloadPdfButton?: boolean
|
|
66
66
|
includeContextInDownload?: boolean
|
|
67
|
+
hasSubtextAbove?: boolean
|
|
67
68
|
// Map-specific props (optional)
|
|
68
69
|
legendMemo?: React.MutableRefObject<Map<any, any>>
|
|
69
70
|
legendSpecialClassLastMemo?: React.MutableRefObject<Map<any, any>>
|
|
@@ -75,11 +76,9 @@ const DataTable = (props: DataTableProps) => {
|
|
|
75
76
|
columns,
|
|
76
77
|
config,
|
|
77
78
|
dataConfig,
|
|
78
|
-
defaultSortBy,
|
|
79
79
|
displayGeoName,
|
|
80
80
|
expandDataTable,
|
|
81
81
|
formatLegendLocation,
|
|
82
|
-
headerColor,
|
|
83
82
|
rawData,
|
|
84
83
|
runtimeData: parentRuntimeData,
|
|
85
84
|
tabbingId,
|
|
@@ -91,6 +90,7 @@ const DataTable = (props: DataTableProps) => {
|
|
|
91
90
|
showDownloadImgButton,
|
|
92
91
|
showDownloadPdfButton,
|
|
93
92
|
includeContextInDownload = false,
|
|
93
|
+
hasSubtextAbove = false,
|
|
94
94
|
imageRef
|
|
95
95
|
} = props
|
|
96
96
|
const runtimeData = useMemo(() => {
|
|
@@ -106,12 +106,33 @@ const DataTable = (props: DataTableProps) => {
|
|
|
106
106
|
}, [parentRuntimeData, config.table.pivot?.columnName, config.table.pivot?.valueColumns])
|
|
107
107
|
|
|
108
108
|
const [expanded, setExpanded] = useState(expandDataTable)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
109
|
+
|
|
110
|
+
// Initialize sort state from config.table.defaultSort
|
|
111
|
+
const defaultSort = config.table?.defaultSort
|
|
112
|
+
const [sortBy, setSortBy] = useState<any>(() => {
|
|
113
|
+
if (defaultSort?.column) {
|
|
114
|
+
return {
|
|
115
|
+
column: defaultSort.column,
|
|
116
|
+
asc: defaultSort.sortDirection === 'asc' ? true : defaultSort.sortDirection === 'custom' ? null : false,
|
|
117
|
+
colIndex: null
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return { column: '', asc: false, colIndex: null }
|
|
113
121
|
})
|
|
114
122
|
|
|
123
|
+
// Re-sync sort state when defaultSort changes in the editor
|
|
124
|
+
useEffect(() => {
|
|
125
|
+
if (defaultSort?.column) {
|
|
126
|
+
setSortBy({
|
|
127
|
+
column: defaultSort.column,
|
|
128
|
+
asc: defaultSort.sortDirection === 'asc' ? true : defaultSort.sortDirection === 'custom' ? null : false,
|
|
129
|
+
colIndex: null
|
|
130
|
+
})
|
|
131
|
+
} else {
|
|
132
|
+
setSortBy({ column: '', asc: false, colIndex: null })
|
|
133
|
+
}
|
|
134
|
+
}, [defaultSort?.column, defaultSort?.sortDirection, defaultSort?.customOrder])
|
|
135
|
+
|
|
115
136
|
const [accessibilityLabel, setAccessibilityLabel] = useState('')
|
|
116
137
|
|
|
117
138
|
// Create default refs for map-specific props when not provided
|
|
@@ -157,6 +178,14 @@ const DataTable = (props: DataTableProps) => {
|
|
|
157
178
|
}
|
|
158
179
|
|
|
159
180
|
const rawRows = Object.keys(runtimeData).filter(column => column != 'columns')
|
|
181
|
+
|
|
182
|
+
// Determine if custom order sort is active (user hasn't overridden by clicking a column header)
|
|
183
|
+
const isCustomOrderActive =
|
|
184
|
+
sortBy.asc === null &&
|
|
185
|
+
defaultSort?.sortDirection === 'custom' &&
|
|
186
|
+
defaultSort?.customOrder?.length > 0 &&
|
|
187
|
+
sortBy.column === defaultSort.column
|
|
188
|
+
|
|
160
189
|
const rows =
|
|
161
190
|
isVertical && sortBy.column
|
|
162
191
|
? rawRows.sort((a, b) => {
|
|
@@ -175,6 +204,10 @@ const DataTable = (props: DataTableProps) => {
|
|
|
175
204
|
dataA = timeParse(config.runtime.xAxis.dateParseFormat)(runtimeData[a][config.xAxis.dataKey])
|
|
176
205
|
dataB = timeParse(config.runtime.xAxis.dateParseFormat)(runtimeData[b][config.xAxis.dataKey])
|
|
177
206
|
}
|
|
207
|
+
// Use custom order when active
|
|
208
|
+
if (isCustomOrderActive && dataA !== undefined && dataB !== undefined) {
|
|
209
|
+
return applyCustomOrder(dataA, dataB, defaultSort.customOrder)
|
|
210
|
+
}
|
|
178
211
|
return dataA || dataB ? customSort(dataA, dataB, sortBy, config) : 0
|
|
179
212
|
})
|
|
180
213
|
: rawRows
|
|
@@ -229,14 +262,6 @@ const DataTable = (props: DataTableProps) => {
|
|
|
229
262
|
const getClassNames = (): string => {
|
|
230
263
|
const classes = ['data-table-container']
|
|
231
264
|
|
|
232
|
-
const hasDownloadLinkAbove =
|
|
233
|
-
(config.table.download || showDownloadImgButton || showDownloadPdfButton) && !config.table.showDownloadLinkBelow
|
|
234
|
-
const isStandaloneTable = config.type === 'table'
|
|
235
|
-
|
|
236
|
-
if (!hasDownloadLinkAbove && !isStandaloneTable) {
|
|
237
|
-
classes.push('mt-4')
|
|
238
|
-
}
|
|
239
|
-
|
|
240
265
|
classes.push(viewport)
|
|
241
266
|
|
|
242
267
|
return classes.join(' ')
|
|
@@ -251,6 +276,10 @@ const DataTable = (props: DataTableProps) => {
|
|
|
251
276
|
const getVisibleColumns = () => {
|
|
252
277
|
if (!config.columns) return []
|
|
253
278
|
|
|
279
|
+
if (config.type === 'map') {
|
|
280
|
+
return getMapDataTableColumnKeys(config.columns).map(columnKey => config.columns[columnKey].name)
|
|
281
|
+
}
|
|
282
|
+
|
|
254
283
|
return Object.values(config.columns)
|
|
255
284
|
.filter(col => col.dataTable !== false)
|
|
256
285
|
.map(col => col.name)
|
|
@@ -325,7 +354,7 @@ const DataTable = (props: DataTableProps) => {
|
|
|
325
354
|
const classes = ['download-links']
|
|
326
355
|
if (!belowTable) {
|
|
327
356
|
if (hasDownloadLink) {
|
|
328
|
-
classes.push('
|
|
357
|
+
classes.push('mb-2')
|
|
329
358
|
}
|
|
330
359
|
} else {
|
|
331
360
|
if (hasDownloadLink) {
|
|
@@ -394,7 +423,6 @@ const DataTable = (props: DataTableProps) => {
|
|
|
394
423
|
<DownloadButton
|
|
395
424
|
rawData={getDownloadData()}
|
|
396
425
|
fileName={`${vizTitle || 'data-table'}.csv`}
|
|
397
|
-
headerColor={headerColor}
|
|
398
426
|
interactionLabel={interactionLabel}
|
|
399
427
|
config={config}
|
|
400
428
|
/>
|
|
@@ -62,8 +62,9 @@ const ChartHeader = ({
|
|
|
62
62
|
if (columnHeaderText === notApplicableText) return
|
|
63
63
|
|
|
64
64
|
return (
|
|
65
|
-
<span className='cdcdataviz-sr-only'>{`Press command, modifier, or enter key to sort by ${columnHeaderText} in ${
|
|
66
|
-
|
|
65
|
+
<span className='cdcdataviz-sr-only'>{`Press command, modifier, or enter key to sort by ${columnHeaderText} in ${
|
|
66
|
+
sortBy.column !== columnHeaderText ? 'ascending' : sortBy.column === 'desc' ? 'descending' : 'ascending'
|
|
67
|
+
} order`}</span>
|
|
67
68
|
)
|
|
68
69
|
}
|
|
69
70
|
|
|
@@ -101,14 +102,13 @@ const ChartHeader = ({
|
|
|
101
102
|
const text = getSeriesName(column, config)
|
|
102
103
|
const newSortBy = getNewSortBy(sortBy, column, index)
|
|
103
104
|
const sortByAsc = sortBy.column === column ? sortBy.asc : undefined
|
|
104
|
-
const isSortedCol = column === sortBy.column && !hasRowType
|
|
105
105
|
|
|
106
106
|
return (
|
|
107
107
|
<th
|
|
108
108
|
style={{
|
|
109
109
|
minWidth: (config.table.cellMinWidth || 0) + 'px',
|
|
110
110
|
textAlign: rightAlignedCols && rightAlignedCols[index] ? 'right' : '',
|
|
111
|
-
paddingRight:
|
|
111
|
+
paddingRight: '1.8em'
|
|
112
112
|
}}
|
|
113
113
|
key={`col-header-${column}__${index}`}
|
|
114
114
|
tabIndex={0}
|
|
@@ -123,7 +123,9 @@ const ChartHeader = ({
|
|
|
123
123
|
eventAction: 'click',
|
|
124
124
|
eventLabel: interactionLabel,
|
|
125
125
|
vizTitle: getVizTitle(config),
|
|
126
|
-
specifics: `column: ${newSortBy.column || 'none'}, order: ${
|
|
126
|
+
specifics: `column: ${newSortBy.column || 'none'}, order: ${
|
|
127
|
+
newSortBy.asc === true ? 'asc' : newSortBy.asc === false ? 'desc' : 'none'
|
|
128
|
+
}`
|
|
127
129
|
})
|
|
128
130
|
setSortBy(newSortBy)
|
|
129
131
|
}}
|
|
@@ -137,11 +139,14 @@ const ChartHeader = ({
|
|
|
137
139
|
eventAction: 'keyboard',
|
|
138
140
|
eventLabel: interactionLabel,
|
|
139
141
|
vizTitle: getVizTitle(config),
|
|
140
|
-
specifics: `column: ${newSortBy.column || 'none'}, order: ${
|
|
142
|
+
specifics: `column: ${newSortBy.column || 'none'}, order: ${
|
|
143
|
+
newSortBy.asc === true ? 'asc' : newSortBy.asc === false ? 'desc' : 'none'
|
|
144
|
+
}`
|
|
141
145
|
})
|
|
142
146
|
setSortBy(newSortBy)
|
|
143
147
|
}
|
|
144
148
|
}}
|
|
149
|
+
className={sortBy.column === column ? (sortBy.asc ? 'sort sort-asc' : 'sort sort-desc') : 'sort'}
|
|
145
150
|
{...(sortBy.column === column
|
|
146
151
|
? sortBy.asc
|
|
147
152
|
? { 'aria-sort': 'ascending' }
|
|
@@ -149,7 +154,7 @@ const ChartHeader = ({
|
|
|
149
154
|
: null)}
|
|
150
155
|
>
|
|
151
156
|
<ColumnHeadingText text={text} config={config} />
|
|
152
|
-
|
|
157
|
+
<SortIcon ascending={sortByAsc} />
|
|
153
158
|
<ScreenReaderSortByText sortBy={sortBy} config={config} text={text} />
|
|
154
159
|
</th>
|
|
155
160
|
)
|
|
@@ -169,13 +174,12 @@ const ChartHeader = ({
|
|
|
169
174
|
row !== '__series__' ? getChartCellValue(row, column, config, data, rightAxisItemsMap) : '__series__'
|
|
170
175
|
const newSortBy = getNewSortBy(sortBy, column, index)
|
|
171
176
|
const sortByAsc = sortBy.colIndex === index ? sortBy.asc : undefined
|
|
172
|
-
const isSortedCol = index === sortBy.colIndex && !hasRowType
|
|
173
177
|
return (
|
|
174
178
|
<th
|
|
175
179
|
style={{
|
|
176
180
|
minWidth: (config.table.cellMinWidth || 0) + 'px',
|
|
177
181
|
textAlign: rightAlignedCols && rightAlignedCols[index] ? 'right' : '',
|
|
178
|
-
paddingRight:
|
|
182
|
+
paddingRight: '1.8em'
|
|
179
183
|
}}
|
|
180
184
|
key={`col-header-${text}__${index}`}
|
|
181
185
|
tabIndex={0}
|
|
@@ -190,7 +194,9 @@ const ChartHeader = ({
|
|
|
190
194
|
eventAction: 'click',
|
|
191
195
|
eventLabel: interactionLabel,
|
|
192
196
|
vizTitle: getVizTitle(config),
|
|
193
|
-
specifics: `column: ${newSortBy.column || 'none'}, order: ${
|
|
197
|
+
specifics: `column: ${newSortBy.column || 'none'}, order: ${
|
|
198
|
+
newSortBy.asc === true ? 'asc' : newSortBy.asc === false ? 'desc' : 'none'
|
|
199
|
+
}`
|
|
194
200
|
})
|
|
195
201
|
setSortBy(newSortBy)
|
|
196
202
|
}}
|
|
@@ -203,11 +209,14 @@ const ChartHeader = ({
|
|
|
203
209
|
eventAction: 'keyboard',
|
|
204
210
|
eventLabel: interactionLabel,
|
|
205
211
|
vizTitle: getVizTitle(config),
|
|
206
|
-
specifics: `column: ${newSortBy.column || 'none'}, order: ${
|
|
212
|
+
specifics: `column: ${newSortBy.column || 'none'}, order: ${
|
|
213
|
+
newSortBy.asc === true ? 'asc' : newSortBy.asc === false ? 'desc' : 'none'
|
|
214
|
+
}`
|
|
207
215
|
})
|
|
208
216
|
setSortBy(newSortBy)
|
|
209
217
|
}
|
|
210
218
|
}}
|
|
219
|
+
className={sortBy.colIndex === index ? (sortBy.asc ? 'sort sort-asc' : 'sort sort-desc') : 'sort'}
|
|
211
220
|
{...(sortBy.column === text
|
|
212
221
|
? sortBy.asc
|
|
213
222
|
? { 'aria-sort': 'ascending' }
|
|
@@ -215,7 +224,7 @@ const ChartHeader = ({
|
|
|
215
224
|
: null)}
|
|
216
225
|
>
|
|
217
226
|
<ColumnHeadingText text={text} config={config} />
|
|
218
|
-
|
|
227
|
+
<SortIcon ascending={sortByAsc} />
|
|
219
228
|
|
|
220
229
|
<ScreenReaderSortByText text={text} config={config} sortBy={sortBy} />
|
|
221
230
|
</th>
|