@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.
Files changed (249) hide show
  1. package/.claude/agents/qa-test-developer.md +126 -0
  2. package/CLAUDE.local.md +67 -0
  3. package/LICENSE +201 -0
  4. package/_stories/Gallery.Charts.stories.tsx +35 -42
  5. package/_stories/Gallery.DataBite.stories.tsx +15 -8
  6. package/_stories/Gallery.Maps.stories.tsx +37 -28
  7. package/_stories/Gallery.WaffleChart.stories.tsx +1 -1
  8. package/_stories/PageART.stories.tsx +5 -4
  9. package/_stories/PageBRFSS.stories.tsx +21 -16
  10. package/_stories/PageCancerRegistries.stories.tsx +15 -15
  11. package/_stories/PageEasternEquineEncephalitis.stories.tsx +33 -19
  12. package/_stories/PageExcessiveAlcoholUse.stories.tsx +148 -143
  13. package/_stories/PageMaternalMortality.stories.tsx +5 -4
  14. package/_stories/PageOralHealth.stories.tsx +15 -10
  15. package/_stories/PageRespiratory.stories.tsx +4 -4
  16. package/_stories/PageSmokingTobacco.stories.tsx +15 -10
  17. package/_stories/PageStateDiabetesProfiles.stories.tsx +15 -10
  18. package/_stories/PageWastewater.stories.tsx +44 -30
  19. package/_stories/VegaImport.stories.tsx +401 -0
  20. package/_stories/vega-fixtures/bars-with-line.json +444 -0
  21. package/_stories/vega-fixtures/bars.json +58 -0
  22. package/_stories/vega-fixtures/combo-bar-rolling-mean.json +88 -0
  23. package/_stories/vega-fixtures/combo.json +68 -0
  24. package/_stories/vega-fixtures/grouped-horizontal-bars.json +83 -0
  25. package/_stories/vega-fixtures/grouped-horizontal-bars2.json +231 -0
  26. package/_stories/vega-fixtures/horizontal-bar.json +427 -0
  27. package/_stories/vega-fixtures/horizontal-bars-with-bad-colors.json +197 -0
  28. package/_stories/vega-fixtures/horizontal-bars2.json +58 -0
  29. package/_stories/vega-fixtures/lines.json +227 -0
  30. package/_stories/vega-fixtures/measles-bars.json +348 -0
  31. package/_stories/vega-fixtures/measles-map.json +11101 -0
  32. package/_stories/vega-fixtures/measles-stacked-bars.json +2147 -0
  33. package/_stories/vega-fixtures/multi-dataset.json +255 -0
  34. package/_stories/vega-fixtures/no-data.json +14 -0
  35. package/_stories/vega-fixtures/pie-chart.json +94 -0
  36. package/_stories/vega-fixtures/repeat-spec.json +47 -0
  37. package/_stories/vega-fixtures/stacked-area.json +222 -0
  38. package/_stories/vega-fixtures/stacked-bar-with-rect.json +3412 -0
  39. package/_stories/vega-fixtures/stacked-bars-with-line.json +364 -0
  40. package/_stories/vega-fixtures/stacked-bars.json +212 -0
  41. package/_stories/vega-fixtures/stacked-horizontal-bars.json +140 -0
  42. package/_stories/vega-fixtures/warning-combo.json +59 -0
  43. package/_stories/vega-fixtures/warning-scatter-and-line.json +1182 -0
  44. package/assets/callout-flag.svg +7 -0
  45. package/assets/icon-chart-area.svg +1 -0
  46. package/assets/icon-chart-radar.svg +23 -0
  47. package/assets/logo2.svg +31 -0
  48. package/components/AdvancedEditor/EmbedEditor.tsx +270 -38
  49. package/components/Alert/components/Alert.styles.css +2 -2
  50. package/components/ComboBox/combobox.styles.css +48 -48
  51. package/components/CustomColorsEditor/CustomColorsEditor.css +53 -53
  52. package/components/CustomColorsEditor/CustomColorsEditor.tsx +3 -10
  53. package/components/DataTable/DataTable.tsx +46 -18
  54. package/components/DataTable/DataTableStandAlone.tsx +1 -0
  55. package/components/DataTable/components/ChartHeader.tsx +21 -12
  56. package/components/DataTable/components/MapHeader.tsx +34 -28
  57. package/components/DataTable/components/SortIcon/sort-icon.css +5 -5
  58. package/components/DataTable/data-table.css +50 -52
  59. package/components/DataTable/helpers/applyCustomOrder.ts +17 -0
  60. package/components/DataTable/helpers/getChartCellValue.ts +10 -7
  61. package/components/DataTable/helpers/getMapDataTableColumnKeys.ts +22 -0
  62. package/components/DataTable/helpers/getSeriesName.ts +6 -0
  63. package/components/DataTable/helpers/mapCellMatrix.tsx +33 -23
  64. package/components/DataTable/helpers/tests/mapCellMatrix.test.ts +33 -0
  65. package/components/DownloadButton.tsx +14 -6
  66. package/components/EditorPanel/ColumnsEditor.tsx +38 -31
  67. package/components/EditorPanel/CustomSortOrder.tsx +94 -0
  68. package/components/EditorPanel/DataTableEditor.tsx +139 -23
  69. package/components/EditorPanel/EditorPanel.styles.css +71 -71
  70. package/components/EditorPanel/EditorPanel.tsx +3 -8
  71. package/components/EditorPanel/EditorPanelDispatch.tsx +4 -4
  72. package/components/EditorPanel/FootnotesEditor.tsx +2 -2
  73. package/components/EditorPanel/VizFilterEditor/NestedDropdownEditor.tsx +21 -12
  74. package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +16 -10
  75. package/components/EditorPanel/VizFilterEditor/components/FilterOrder.tsx +33 -29
  76. package/components/EditorPanel/components/MarkupVariablesEditor.tsx +160 -106
  77. package/components/EditorPanel/components/PanelMarkup.tsx +5 -1
  78. package/{styles/v2/components → components/EditorPanel}/editor.scss +76 -22
  79. package/components/EditorPanel/sections/StyleTreatmentSection.tsx +99 -0
  80. package/components/EditorPanel/sections/VisualSection.tsx +11 -0
  81. package/components/EditorWrapper/editor-wrapper.style.css +1 -1
  82. package/components/Filters/Filters.tsx +3 -5
  83. package/components/Filters/components/Tabs.tsx +19 -7
  84. package/{styles → components/Filters}/filters.scss +3 -3
  85. package/components/Footnotes/FootnotesStandAlone.tsx +4 -2
  86. package/components/HeaderThemeSelector/HeaderThemeSelector.css +61 -5
  87. package/components/Layout/components/Responsive.tsx +14 -6
  88. package/components/Layout/components/Sidebar/components/Sidebar.tsx +1 -1
  89. package/components/Layout/components/Sidebar/components/sidebar.styles.scss +14 -20
  90. package/components/Layout/components/Visualization/index.tsx +50 -38
  91. package/components/Layout/components/Visualization/visualizations.scss +232 -15
  92. package/components/Layout/components/VisualizationContainer.test.tsx +67 -0
  93. package/components/Layout/components/VisualizationContainer.tsx +37 -0
  94. package/components/Layout/components/VisualizationContent.test.tsx +182 -0
  95. package/components/Layout/components/VisualizationContent.tsx +75 -0
  96. package/components/Layout/index.tsx +5 -5
  97. package/components/Layout/styles/editor-utils.scss +3 -3
  98. package/components/Layout/styles/editor.scss +4 -4
  99. package/components/Legend/Legend.Gradient.tsx +7 -1
  100. package/components/Loader/loader.styles.css +2 -2
  101. package/components/Loading.jsx +1 -1
  102. package/components/MediaControls.tsx +10 -3
  103. package/components/MultiSelect/multiselect.styles.css +19 -19
  104. package/components/NestedDropdown/nesteddropdown.styles.css +15 -15
  105. package/components/PaletteSelector/PaletteSelector.css +15 -15
  106. package/components/RichTooltip/richTooltip.css +6 -6
  107. package/components/Table/table.styles.css +2 -2
  108. package/components/Waiting.tsx +1 -1
  109. package/components/_stories/CustomColorsEditor.stories.tsx +37 -0
  110. package/components/_stories/DataTable.stories.tsx +1 -0
  111. package/components/_stories/Filters.stories.tsx +1 -1
  112. package/components/_stories/styles.scss +0 -1
  113. package/components/elements/Button.jsx +1 -1
  114. package/components/elements/Card.jsx +1 -1
  115. package/{styles/v2/components → components/elements}/button.scss +9 -8
  116. package/components/inputs/InputCheckbox.jsx +1 -1
  117. package/components/inputs/InputSelect.tsx +1 -1
  118. package/components/inputs/InputText.jsx +1 -1
  119. package/components/inputs/InputToggle.tsx +1 -1
  120. package/{styles/v2/components/input → components/inputs}/_input-check-radio.scss +2 -2
  121. package/{styles/v2/components/input → components/inputs}/_input-group.scss +3 -3
  122. package/{styles/v2/components/input → components/inputs}/_input-slider.scss +2 -2
  123. package/{styles/v2/components/input → components/inputs}/_input.scss +5 -5
  124. package/{styles/v2/components/input → components/inputs}/index.scss +2 -2
  125. package/{styles → components}/loading.scss +1 -1
  126. package/components/managers/DataDesigner.tsx +1 -1
  127. package/{styles/v2/components → components/managers}/data-designer.scss +6 -7
  128. package/components/ui/Accordion.jsx +1 -1
  129. package/components/ui/Icon.tsx +1 -1
  130. package/components/ui/LoadSpin.jsx +1 -1
  131. package/components/ui/Modal.jsx +1 -1
  132. package/components/ui/Overlay.jsx +1 -1
  133. package/components/ui/Title/index.test.tsx +34 -0
  134. package/components/ui/Title/index.tsx +24 -7
  135. package/components/ui/Title/title.styles.css +119 -25
  136. package/components/ui/Tooltip.tsx +1 -1
  137. package/components/ui/_stories/Title.stories.tsx +1 -1
  138. package/{styles/v2/components → components/ui}/accordion.scss +3 -3
  139. package/components/ui/accordion.styles.css +11 -11
  140. package/{styles/v2/components → components/ui}/modal.scss +2 -2
  141. package/{styles/v2/components → components/ui}/overlay.scss +6 -6
  142. package/{styles/v2/components → components}/ui/tooltip.scss +1 -1
  143. package/{styles → components}/waiting.scss +9 -3
  144. package/data/colorPalettes.ts +18 -5
  145. package/data/mapColorPalettes.ts +10 -0
  146. package/devTemplate/dev.js +285 -0
  147. package/devTemplate/index.html +30 -0
  148. package/devTemplate/preview.html +1503 -0
  149. package/devTemplate/sidebar.css +151 -0
  150. package/dist/cove-main.css +2530 -3901
  151. package/dist/cove-main.css.map +1 -1
  152. package/generateViteConfig.js +111 -2
  153. package/helpers/DataTransform.ts +1 -5
  154. package/helpers/backfillDefaults.ts +35 -0
  155. package/helpers/constants.ts +12 -0
  156. package/helpers/cove/date.ts +64 -3
  157. package/helpers/cove/number.ts +29 -15
  158. package/helpers/cove/string.ts +29 -0
  159. package/helpers/coveUpdateWorker.ts +14 -8
  160. package/helpers/displayDataAsText.ts +1 -1
  161. package/helpers/embed/embedCodeGenerator.ts +80 -0
  162. package/helpers/embed/embedHelper.js +169 -0
  163. package/helpers/embed/filterUtils.ts +121 -0
  164. package/helpers/embed/index.ts +17 -0
  165. package/helpers/embed/urlValidation.ts +119 -0
  166. package/helpers/extractDataAndMetadata.ts +20 -0
  167. package/helpers/fetchRemoteData.ts +14 -8
  168. package/helpers/filterVizData.ts +6 -1
  169. package/helpers/getFileExtension.ts +0 -6
  170. package/helpers/labelHash.ts +9 -0
  171. package/helpers/markupProcessor.ts +56 -38
  172. package/helpers/metrics/types.ts +3 -0
  173. package/helpers/palettes/colorDistributions.ts +1 -1
  174. package/helpers/palettes/utils.ts +12 -12
  175. package/helpers/parseCsvWithQuotes.ts +15 -14
  176. package/helpers/prepareScreenshot.ts +33 -10
  177. package/helpers/testing.ts +44 -0
  178. package/helpers/tests/DataTransform.test.ts +125 -0
  179. package/helpers/tests/abbreviateNumber.test.ts +59 -0
  180. package/helpers/tests/backfillDefaults.test.ts +253 -0
  181. package/helpers/tests/date.test.ts +110 -0
  182. package/helpers/tests/extractDataAndMetadata.test.ts +93 -0
  183. package/helpers/tests/markupProcessor.test.ts +315 -124
  184. package/helpers/tests/number.test.ts +42 -0
  185. package/helpers/tests/prepareScreenshot.test.ts +28 -28
  186. package/helpers/tests/testStandaloneBuild.ts +36 -26
  187. package/helpers/tests/useDataVizClasses.test.ts +66 -0
  188. package/helpers/tests/visualizationWrapperUsage.test.ts +57 -0
  189. package/helpers/useDataVizClasses.ts +13 -7
  190. package/helpers/vegaConfig.ts +1 -1
  191. package/helpers/vegaConfigImport.ts +160 -0
  192. package/helpers/ver/4.24.4.ts +24 -0
  193. package/helpers/ver/4.26.1.ts +1 -1
  194. package/helpers/ver/4.26.2.ts +84 -0
  195. package/helpers/ver/4.26.3.ts +44 -0
  196. package/helpers/ver/4.26.4.ts +31 -0
  197. package/helpers/ver/tests/4.26.1.test.ts +105 -0
  198. package/helpers/ver/tests/4.26.2.test.ts +298 -0
  199. package/helpers/ver/tests/4.26.3.test.ts +168 -0
  200. package/helpers/ver/tests/4.26.4.test.ts +88 -0
  201. package/helpers/ver/tests/coveUpdateWorker.test.ts +57 -0
  202. package/helpers/viewports.ts +2 -0
  203. package/package.json +27 -32
  204. package/styles/_global.scss +7 -7
  205. package/styles/_reset.scss +2 -2
  206. package/styles/{v2/base → base}/_file-selector.scss +4 -4
  207. package/styles/{v2/base → base}/_general.scss +2 -4
  208. package/styles/{v2/base → base}/index.scss +1 -1
  209. package/styles/base.scss +107 -165
  210. package/styles/cove-main.scss +3 -6
  211. package/styles/layout/_component.scss +110 -0
  212. package/styles/{v2/layout → layout}/_data-table.scss +7 -7
  213. package/styles/layout/_wrapper-padding.scss +27 -0
  214. package/styles/{v2/main.scss → main.scss} +3 -1
  215. package/styles/{v2/themes → themes}/_color-definitions.scss +46 -41
  216. package/styles/{_accessibility.scss → utils/_accessibility.scss} +1 -1
  217. package/styles/{v2/utils → utils}/_grid.scss +8 -3
  218. package/styles/{_global-variables.scss → utils/_properties.scss} +133 -112
  219. package/styles/{v2/utils → utils}/index.scss +2 -1
  220. package/types/Annotation.ts +10 -11
  221. package/types/Axis.ts +2 -0
  222. package/types/ComponentStyles.ts +1 -0
  223. package/types/ConfigureData.ts +1 -0
  224. package/types/General.ts +2 -0
  225. package/types/MarkupInclude.ts +1 -0
  226. package/types/MarkupVariable.ts +2 -1
  227. package/types/Palette.ts +22 -0
  228. package/types/Table.ts +9 -0
  229. package/types/Visualization.ts +7 -0
  230. package/_stories/StoryRenderingTests.stories.tsx +0 -164
  231. package/helpers/embedCodeGenerator.ts +0 -109
  232. package/styles/_common-components.css +0 -73
  233. package/styles/_variables.scss +0 -63
  234. package/styles/v2/layout/_component.scss +0 -21
  235. package/styles/v2/utils/_variables.scss +0 -9
  236. package/{styles/v2/components/card.scss → components/elements/card.css} +2 -2
  237. /package/{styles/v2/components → components/ui}/icon.scss +0 -0
  238. /package/{styles/v2/components → components/ui}/loadspin.scss +0 -0
  239. /package/styles/{v2/base → base}/_heading.scss +0 -0
  240. /package/styles/{v2/base → base}/_reset.scss +0 -0
  241. /package/styles/{v2/layout → layout}/_alert.scss +0 -0
  242. /package/styles/{v2/layout → layout}/_progression.scss +0 -0
  243. /package/styles/{v2/layout → layout}/_tooltip.scss +0 -0
  244. /package/styles/{v2/layout → layout}/index.scss +0 -0
  245. /package/styles/{v2/themes → themes}/index.scss +0 -0
  246. /package/styles/{v2/utils → utils}/_align.scss +0 -0
  247. /package/styles/{v2/utils → utils}/_animations.scss +0 -0
  248. /package/styles/{v2/utils → utils}/_breakpoints.scss +0 -0
  249. /package/styles/{v2/utils → utils}/_mixins.scss +0 -0
@@ -0,0 +1,99 @@
1
+ import { CheckBox, Select } from '../Inputs'
2
+
3
+ type StyleTreatmentValue = 'legacy' | 'tp5'
4
+
5
+ type StyleTreatmentSectionProps = {
6
+ styleTreatment: StyleTreatmentValue
7
+ onStyleTreatmentChange: (value: StyleTreatmentValue) => void
8
+ showStyleTreatment?: boolean
9
+ showLegacyControls?: boolean
10
+ border?: boolean
11
+ borderColorTheme?: boolean
12
+ accent?: boolean
13
+ background?: boolean
14
+ hideBackgroundColor?: boolean
15
+ showBackground?: boolean
16
+ showHideBackgroundColor?: boolean
17
+ updateField: Function
18
+ }
19
+
20
+ const StyleTreatmentSection = ({
21
+ styleTreatment,
22
+ onStyleTreatmentChange,
23
+ showStyleTreatment = true,
24
+ showLegacyControls = true,
25
+ border,
26
+ borderColorTheme,
27
+ accent,
28
+ background,
29
+ hideBackgroundColor,
30
+ showBackground = false,
31
+ showHideBackgroundColor = false,
32
+ updateField
33
+ }: StyleTreatmentSectionProps) => {
34
+ const hasContent = showStyleTreatment || (showLegacyControls && styleTreatment === 'legacy')
35
+ if (!hasContent) return null
36
+
37
+ return (
38
+ <div className='cove-accordion__panel-section checkbox-group'>
39
+ {showStyleTreatment && (
40
+ <Select
41
+ label='Style Treatment'
42
+ fieldName='styleTreatment'
43
+ value={styleTreatment}
44
+ style={{ width: '100%' }}
45
+ options={[
46
+ { label: 'Legacy', value: 'legacy' },
47
+ { label: 'TP5', value: 'tp5' }
48
+ ]}
49
+ onChange={event => onStyleTreatmentChange(event.target.value as StyleTreatmentValue)}
50
+ />
51
+ )}
52
+ {showLegacyControls && styleTreatment === 'legacy' && (
53
+ <>
54
+ <CheckBox
55
+ value={border}
56
+ section='visual'
57
+ fieldName='border'
58
+ label='Display Border'
59
+ updateField={updateField}
60
+ />
61
+ <CheckBox
62
+ value={borderColorTheme}
63
+ section='visual'
64
+ fieldName='borderColorTheme'
65
+ label='Use Border Color Theme'
66
+ updateField={updateField}
67
+ />
68
+ <CheckBox
69
+ value={accent}
70
+ section='visual'
71
+ fieldName='accent'
72
+ label='Use Accent Style'
73
+ updateField={updateField}
74
+ />
75
+ {showBackground && (
76
+ <CheckBox
77
+ value={background}
78
+ section='visual'
79
+ fieldName='background'
80
+ label='Use Theme Background Color'
81
+ updateField={updateField}
82
+ />
83
+ )}
84
+ {showHideBackgroundColor && (
85
+ <CheckBox
86
+ value={hideBackgroundColor}
87
+ section='visual'
88
+ fieldName='hideBackgroundColor'
89
+ label='Hide Background Color'
90
+ updateField={updateField}
91
+ />
92
+ )}
93
+ </>
94
+ )}
95
+ </div>
96
+ )
97
+ }
98
+
99
+ export default StyleTreatmentSection
@@ -2,6 +2,7 @@ import { ReactNode } from 'react'
2
2
  import { CheckBox } from '../Inputs'
3
3
  import { HeaderThemeSelector } from '../../HeaderThemeSelector'
4
4
  import { UpdateFieldFunc } from '../../../types/UpdateFieldFunc'
5
+ import { isCoveDeveloperMode } from '../../../helpers/queryStringUtils'
5
6
 
6
7
  export interface VisualSectionConfig {
7
8
  visual?: {
@@ -10,6 +11,7 @@ export interface VisualSectionConfig {
10
11
  accent?: boolean
11
12
  background?: boolean
12
13
  hideBackgroundColor?: boolean
14
+ highlightWrappers?: boolean
13
15
  }
14
16
  theme?: string
15
17
  }
@@ -154,6 +156,15 @@ export const VisualSection = <TConfig extends VisualSectionConfig = VisualSectio
154
156
  updateField={updateField}
155
157
  />
156
158
  )}
159
+ {isCoveDeveloperMode() && (
160
+ <CheckBox
161
+ value={visual.highlightWrappers}
162
+ section='visual'
163
+ fieldName='highlightWrappers'
164
+ label='Highlight Layout Wrappers'
165
+ updateField={updateField}
166
+ />
167
+ )}
157
168
  </div>
158
169
  )
159
170
 
@@ -1,7 +1,7 @@
1
1
  .editor-wrapper {
2
2
  --editorPanelWidth: 350px;
3
- position: relative;
4
3
  min-height: 80vh;
4
+ position: relative;
5
5
  .editor-panel {
6
6
  :is(form) {
7
7
  border-right: var(--lightGray) 1px solid;
@@ -1,4 +1,5 @@
1
1
  import { useState, useEffect, useMemo, useRef, useId } from 'react'
2
+ import './filters.scss'
2
3
  import _ from 'lodash'
3
4
  import parse from 'html-react-parser'
4
5
 
@@ -210,12 +211,9 @@ const Filters: React.FC<FilterProps> = ({
210
211
  if (!hasVisibleFilters) return <></>
211
212
 
212
213
  const getClasses = () => {
213
- const { visualizationType, legend } = visualizationConfig || {}
214
- const baseClass = 'filters-section'
215
- const conditionalClass = standaloneMap ? general.headerColor : visualizationType === 'Spark Line' ? null : theme
214
+ const { legend } = visualizationConfig || {}
216
215
  const legendClass = legend && !legend.hide && legend.position === 'top' ? 'mb-0' : null
217
-
218
- return [baseClass, conditionalClass, legendClass, 'w-100'].filter(Boolean)
216
+ return ['filters-section', legendClass, 'w-100'].filter(Boolean)
219
217
  }
220
218
 
221
219
  const getNestedGroup = (singleFilter: VizFilter): string[] => {
@@ -1,14 +1,23 @@
1
1
  import { useEffect, useId, useState } from 'react'
2
2
  import { VizFilter } from '../../../types/VizFilter'
3
3
 
4
+ type TabCompatibleFilter = {
5
+ filterStyle: string
6
+ values: string[]
7
+ active?: string | string[]
8
+ queuedActive?: string | string[]
9
+ labels?: Record<string, string>
10
+ }
11
+
4
12
  type TabsProps = {
5
- filter: VizFilter
13
+ filter: VizFilter | TabCompatibleFilter
6
14
  index: number
7
15
  changeFilterActive: Function
8
- theme: string
16
+ theme?: string
17
+ loading?: boolean
9
18
  }
10
19
 
11
- const Tabs: React.FC<TabsProps> = ({ filter, index: outerIndex, changeFilterActive, theme }) => {
20
+ const Tabs: React.FC<TabsProps> = ({ filter, index: outerIndex, changeFilterActive, loading }) => {
12
21
  const [selectedFilter, setSelectedFilter] = useState<EventTarget>(null)
13
22
 
14
23
  const id = useId()
@@ -21,18 +30,19 @@ const Tabs: React.FC<TabsProps> = ({ filter, index: outerIndex, changeFilterActi
21
30
  }, [selectedFilter])
22
31
 
23
32
  const getClassList = value => {
24
- const isActive = filter.active === value
33
+ const activeValue = filter.queuedActive || filter.active
34
+ const isActive = activeValue === value
25
35
  let classList = []
26
36
  switch (filter.filterStyle) {
27
37
  case 'tab bar':
28
38
  classList = ['button__tab-bar', isActive && 'button__tab-bar--active']
29
39
  break
30
40
  case 'pill':
31
- classList = ['pill', isActive && 'pill--active', theme && theme]
41
+ classList = ['pill', isActive && 'pill--active']
32
42
  break
33
43
  default:
34
44
  const tabSimple = filter.filterStyle === 'tab-simple' && 'tab--simple'
35
- classList = ['tab', isActive && 'tab--active', theme && theme, tabSimple]
45
+ classList = ['tab', isActive && 'tab--active', tabSimple]
36
46
  break
37
47
  }
38
48
  return classList.filter(Boolean).join(' ')
@@ -41,9 +51,11 @@ const Tabs: React.FC<TabsProps> = ({ filter, index: outerIndex, changeFilterActi
41
51
  const Tabs = filter.values.map((value, index) => {
42
52
  return (
43
53
  <button
54
+ type='button'
44
55
  key={`${value}-${outerIndex}-${index}-${id}`}
45
56
  id={`${value}-${outerIndex}-${index}-${id}`}
46
57
  className={getClassList(value)}
58
+ disabled={loading}
47
59
  onClick={e => {
48
60
  changeFilterActive(outerIndex, value)
49
61
  setSelectedFilter(e.target)
@@ -55,7 +67,7 @@ const Tabs: React.FC<TabsProps> = ({ filter, index: outerIndex, changeFilterActi
55
67
  }
56
68
  }}
57
69
  >
58
- {value}
70
+ {filter.labels?.[value] || value}
59
71
  </button>
60
72
  )
61
73
  })
@@ -1,11 +1,10 @@
1
- @import 'v2/utils/breakpoints';
1
+ @import '../../styles/utils/breakpoints';
2
2
 
3
3
  .filters-section {
4
4
  &__wrapper {
5
5
  flex-wrap: wrap;
6
6
  display: flex;
7
7
  gap: 1rem 1.5rem;
8
- margin-bottom: 2rem;
9
8
 
10
9
  label {
11
10
  display: inherit;
@@ -107,7 +106,7 @@ div.single-filters {
107
106
  }
108
107
  }
109
108
 
110
- .cdc-open-viz-module {
109
+ .cove-visualization {
111
110
  @include breakpointClass(xs) {
112
111
  .single-filters--tab-simple .tab-simple-container .tab.tab--simple {
113
112
  font-size: 0.778em;
@@ -152,6 +151,7 @@ div.single-filters {
152
151
  flex: 1 1 0px;
153
152
  padding: 10px;
154
153
  background: none;
154
+ border: none;
155
155
  transition: background 2s;
156
156
 
157
157
  &--active {
@@ -13,9 +13,10 @@ type StandAloneProps = {
13
13
  markupVariables?: MarkupVariable[]
14
14
  enableMarkupVariables?: boolean
15
15
  data?: Object[]
16
+ dataMetadata?: Record<string, string>
16
17
  }
17
18
 
18
- const FootnotesStandAlone: React.FC<StandAloneProps> = ({ config, filters, markupVariables = [], enableMarkupVariables = false, data = [] }) => {
19
+ const FootnotesStandAlone: React.FC<StandAloneProps> = ({ config, filters, markupVariables = [], enableMarkupVariables = false, data = [], dataMetadata }) => {
19
20
  if (!config) return null
20
21
 
21
22
  // Helper function to process markup variables in footnote text
@@ -33,7 +34,8 @@ const FootnotesStandAlone: React.FC<StandAloneProps> = ({ config, filters, marku
33
34
  markupVariables,
34
35
  {
35
36
  filters,
36
- isEditor: false
37
+ isEditor: false,
38
+ dataMetadata
37
39
  }
38
40
  )
39
41
 
@@ -1,3 +1,59 @@
1
+ /* Scoped theme color classes for header theme selector circles */
2
+ .header .color-palette button.theme-purple {
3
+ background: #712177;
4
+ border-bottom-color: #b890bb;
5
+ }
6
+
7
+ .header .color-palette button.theme-brown {
8
+ background: #705043;
9
+ border-bottom-color: #ad907b;
10
+ }
11
+
12
+ .header .color-palette button.theme-teal {
13
+ background: #00695c;
14
+ border-bottom-color: #4ebaaa;
15
+ }
16
+
17
+ .header .color-palette button.theme-pink {
18
+ background: #af4448;
19
+ border-bottom-color: #e57373;
20
+ }
21
+
22
+ .header .color-palette button.theme-orange {
23
+ background: #bb4d00;
24
+ border-bottom-color: #ffad42;
25
+ }
26
+
27
+ .header .color-palette button.theme-slate {
28
+ background: #29434e;
29
+ border-bottom-color: #7e9ba5;
30
+ }
31
+
32
+ .header .color-palette button.theme-indigo {
33
+ background: #26418f;
34
+ border-bottom-color: #92a6dd;
35
+ }
36
+
37
+ .header .color-palette button.theme-cyan {
38
+ background: #007b91;
39
+ border-bottom-color: #65b0bd;
40
+ }
41
+
42
+ .header .color-palette button.theme-green {
43
+ background: #4b830d;
44
+ border-bottom-color: #84bc49;
45
+ }
46
+
47
+ .header .color-palette button.theme-amber {
48
+ background: #fbab18;
49
+ border-bottom-color: #ffd54f;
50
+ }
51
+
52
+ .header .color-palette button.theme-blue {
53
+ background: #005eaa;
54
+ border-bottom-color: #88c3ea;
55
+ }
56
+
1
57
  /* HeaderThemeSelector component styles */
2
58
 
3
59
  .header {
@@ -6,8 +62,8 @@
6
62
 
7
63
  .header .edit-label {
8
64
  display: block;
9
- margin-bottom: 0.5rem;
10
65
  font-weight: 500;
66
+ margin-bottom: 0.5rem;
11
67
  }
12
68
 
13
69
  .header .color-palette {
@@ -20,13 +76,13 @@
20
76
  }
21
77
 
22
78
  .header .color-palette button {
23
- width: 30px;
24
- height: 30px;
25
- border-radius: 50%;
26
79
  border: 2px solid transparent;
80
+ border-radius: 50%;
27
81
  cursor: pointer;
28
- transition: all 0.2s ease;
82
+ height: 30px;
29
83
  outline: none;
84
+ transition: all 0.2s ease;
85
+ width: 30px;
30
86
  }
31
87
 
32
88
  .header .color-palette button:hover {
@@ -13,11 +13,17 @@ const breakpoints = [
13
13
  '1280' // xl
14
14
  ]
15
15
 
16
- const os =
17
- navigator.userAgent.indexOf('Win') !== -1 ? 'Win' : navigator.userAgent.indexOf('Mac') !== -1 ? 'MacOS' : null
16
+ const userAgent = typeof navigator !== 'undefined' ? navigator.userAgent : ''
17
+ const os = userAgent.indexOf('Win') !== -1 ? 'Win' : userAgent.indexOf('Mac') !== -1 ? 'MacOS' : null
18
18
 
19
- const Responsive = ({ children, isEditor }) => {
19
+ type ResponsiveProps = {
20
+ children: React.ReactNode
21
+ isEditor: boolean
22
+ }
23
+
24
+ const Responsive = ({ children, isEditor }: ResponsiveProps) => {
20
25
  const [displayPanel, setDisplayPanel] = useState(false)
26
+ const togglePanel = () => setDisplayPanel(p => !p)
21
27
  const [displayGrid, setDisplayGrid] = useState(false)
22
28
  const [viewportPreview, setViewportPreview] = useState(null)
23
29
  const [rotateAnimation, setRotateAnimation] = useState(false)
@@ -37,7 +43,7 @@ const Responsive = ({ children, isEditor }) => {
37
43
 
38
44
  const onKeypress = key => {
39
45
  if (!isEditor) return key
40
- if (key.code === 'KeyL' && key.ctrlKey) setDisplayPanel(display => !display)
46
+ if (key.code === 'KeyL' && key.ctrlKey) togglePanel()
41
47
  const viewportCommandKey = os === 'MacOS' ? key.metaKey : key.altKey
42
48
  if (viewportCommandKey) {
43
49
  let keyIndex = key.key
@@ -109,9 +115,11 @@ const Responsive = ({ children, isEditor }) => {
109
115
  }
110
116
  })
111
117
 
112
- const onBackClick = () => setDisplayPanel(!displayPanel)
118
+ const onBackClick = () => togglePanel()
113
119
 
114
- if (!isEditor || !displayPanel) return children
120
+ if (!isEditor || !displayPanel) {
121
+ return <div className='cove-visualization__outer'>{children}</div>
122
+ }
115
123
 
116
124
  return (
117
125
  <div className='cove-editor__content' data-grid={displayGrid || null}>
@@ -40,7 +40,7 @@ const Sidebar: React.FC<SidebarProps> = props => {
40
40
  return (
41
41
  <>
42
42
  {/* mimic the editor panel title to keep the button visible. */}
43
- <section className='editor-panel__toggle-wrapper p-absolute' style={{ height: '49.75px', width: '350px' }}>
43
+ <section className='editor-panel__toggle-wrapper' style={{ height: '49.75px', width: '350px' }}>
44
44
  <button className={getButtonClasses()} title={displayPanel ? `Collapse Editor` : `Expand Editor`} onClick={onBackClick}></button>
45
45
  </section>
46
46
  <section className={getSectionClasses()}>
@@ -2,20 +2,20 @@
2
2
  top: 0;
3
3
  }
4
4
 
5
- .cdc-editor .configure .editor-heading + .cdc-open-viz-module .editor-panel__toggle {
5
+ .cdc-editor .configure .editor-heading + .cove-visualization .editor-panel__toggle {
6
6
  top: 12px;
7
7
  position: relative;
8
8
  }
9
9
 
10
- .cdc-editor .configure .cdc-open-viz-module:not(.type-dashboard) .editor-panel__toggle {
10
+ .cdc-editor .configure .cove-visualization:not(.type-dashboard) .editor-panel__toggle {
11
11
  position: absolute;
12
12
  }
13
13
 
14
- .cdc-editor .configure .cdc-open-viz-module:not(.type-dashboard) .sidebar {
14
+ .cdc-editor .configure .cove-visualization:not(.type-dashboard) .sidebar {
15
15
  position: relative;
16
16
  }
17
17
 
18
- .cdc-open-viz-module {
18
+ .cove-visualization {
19
19
  .waiting {
20
20
  padding-top: 0 !important;
21
21
  padding-left: 0 !important;
@@ -26,7 +26,7 @@
26
26
  height: 100%; // take up the whole container
27
27
  top: 0;
28
28
  max-width: 350px;
29
- width: 350px;
29
+ min-width: 0;
30
30
  background-color: var(--white);
31
31
  grid-area: panel;
32
32
 
@@ -440,6 +440,11 @@
440
440
 
441
441
  &.checkbox {
442
442
  display: flex;
443
+ align-items: center;
444
+
445
+ span.edit-label {
446
+ margin-bottom: 0;
447
+ }
443
448
 
444
449
  input {
445
450
  margin-left: 0;
@@ -626,9 +631,9 @@
626
631
 
627
632
  .sort-list {
628
633
  list-style: none;
634
+ padding: 0;
629
635
 
630
636
  > li {
631
- margin-right: 0.3em;
632
637
  margin-bottom: 0.3em;
633
638
  }
634
639
  }
@@ -641,8 +646,8 @@
641
646
  background: #f1f1f1;
642
647
  padding: 0.4em 0.6em;
643
648
  font-size: 0.8em;
644
- margin-bottom: 0.3em;
645
649
  cursor: move;
650
+ width: 100%;
646
651
  }
647
652
 
648
653
  .info {
@@ -799,12 +804,6 @@
799
804
  font-size: 0.75rem;
800
805
  }
801
806
 
802
- .cove-accordion__button .cove-tooltip {
803
- // display: inline-flex;
804
- // right: 1.5rem;
805
- // line-height: inherit;
806
- }
807
-
808
807
  .cove-list-group__item .cove-tooltip {
809
808
  width: 100%;
810
809
  display: block;
@@ -929,15 +928,10 @@
929
928
  }
930
929
  }
931
930
 
932
- &.type-dashboard {
933
- .editor-panel__toggle {
934
- top: 64px;
935
- }
936
- }
937
-
938
931
  .editor-panel__toggle-wrapper {
939
932
  position: absolute;
940
933
  top: 0;
934
+ left: 0;
941
935
  }
942
936
 
943
937
  .editor-panel__toggle {
@@ -952,7 +946,7 @@
952
946
  cursor: pointer;
953
947
  width: 25px;
954
948
  height: 25px;
955
- right: 10px;
949
+ left: calc(100% - 35px);
956
950
  top: 50%;
957
951
  transform: translateY(-50%);
958
952
  box-shadow: rgba(0, 0, 0, 0.5) 0 1px 2px;
@@ -1,24 +1,21 @@
1
1
  // main visualization wrapper
2
- import { ChartConfig } from '@cdc/chart/src/types/ChartConfig'
3
2
  import React, { forwardRef } from 'react'
4
- import { Config as DataBiteConfig } from '@cdc/data-bite/src/types/Config'
5
- import { Config as DataTableConfig } from '@cdc/data-table/src/types/Config'
6
3
  import './visualizations.scss'
7
- import { Config as WaffleChartConfig } from '@cdc/waffle-chart/src/types/Config'
8
- import { MarkupIncludeConfig } from '@cdc/core/types/MarkupInclude'
9
- import { DashboardFilters } from '@cdc/dashboard/src/types/DashboardFilters'
10
- import { MapConfig } from '@cdc/map/src/types/MapConfig'
4
+ import type { AnyVisualization } from '@cdc/core/types/Visualization'
5
+
6
+ export type VisualizationShellConfig = Partial<AnyVisualization> & {
7
+ type?: AnyVisualization['type'] | 'dashboard'
8
+ theme?: string
9
+ visual?: {
10
+ highlightWrappers?: boolean
11
+ whiteBackground?: boolean
12
+ }
13
+ }
11
14
 
12
15
  type VisualizationWrapper = {
13
16
  children: React.ReactNode
14
- config:
15
- | ChartConfig
16
- | DataBiteConfig
17
- | WaffleChartConfig
18
- | MarkupIncludeConfig
19
- | DashboardFilters
20
- | MapConfig
21
- | DataTableConfig
17
+ className?: string
18
+ config: VisualizationShellConfig
22
19
  currentViewport?: string
23
20
  imageId?: string
24
21
  isEditor: boolean
@@ -35,15 +32,17 @@ const Visualization = forwardRef<HTMLDivElement, VisualizationWrapper>((props, r
35
32
  className
36
33
  } = props
37
34
 
35
+ const themeClass = config.type === 'map' ? config?.general?.headerColor || config?.theme : config?.theme
36
+
38
37
  const getWrappingClasses = () => {
39
- let classes = ['cdc-open-viz-module', `${currentViewport}`, `${config?.theme}`]
38
+ let classes = ['cove-visualization', 'cdc-open-viz-module', `${currentViewport}`, `${themeClass}`]
40
39
 
41
40
  if (className) {
42
41
  classes.push(className)
43
42
  }
44
43
 
45
44
  isEditor && classes.push('spacing-wrapper')
46
- isEditor && classes.push('isEditor')
45
+ isEditor && classes.push('is-editor')
47
46
 
48
47
  if (isEditor && showEditorPanel) {
49
48
  classes = classes.filter(item => item !== 'editor-panel--hidden')
@@ -55,9 +54,18 @@ const Visualization = forwardRef<HTMLDivElement, VisualizationWrapper>((props, r
55
54
  classes.push('editor-panel--hidden')
56
55
  }
57
56
 
57
+ if (isEditor && config.visual?.highlightWrappers) {
58
+ classes.push('cove-highlight-wrappers')
59
+ }
60
+
58
61
  if (config.type === 'filtered-text') {
59
62
  classes.push('type-filtered-text', `font-${config.fontSize}`)
60
- classes = classes.filter(item => item !== 'cove-component__content')
63
+ classes = classes.filter(item => item !== 'cove-visualization__body')
64
+ return classes
65
+ }
66
+
67
+ if (config.type === 'dashboard') {
68
+ classes.push('type-dashboard')
61
69
  return classes
62
70
  }
63
71
 
@@ -66,37 +74,31 @@ const Visualization = forwardRef<HTMLDivElement, VisualizationWrapper>((props, r
66
74
  config?.visualizationType === 'Spark Line' && classes.push(`type-sparkline`)
67
75
  return classes
68
76
  }
77
+
69
78
  if (config.type === 'map') {
70
79
  classes.push(`type-map`)
71
- if (config?.runtime?.editorErrorMessage.length !== 0) classes.push('type-map--has-error')
80
+ if (config?.runtime?.editorErrorMessage?.length) classes.push('type-map--has-error')
81
+ return classes
82
+ }
83
+
84
+ if (config.type === 'table') {
85
+ classes.push('type-data-table')
86
+ return classes
72
87
  }
73
88
 
74
89
  if (config.type === 'data-bite') {
75
- classes.push('cdc-open-viz-module', 'type-data-bite', currentViewport, config.theme, `font-${config.fontSize}`)
76
- if (isEditor) {
77
- classes.push('is-editor')
78
- }
90
+ classes.push('type-data-bite', `font-${config.fontSize}`)
91
+ return classes
79
92
  }
80
93
 
81
94
  if (config.type === 'markup-include') {
82
- classes.push('markup-include', 'cdc-open-viz-module')
95
+ classes.push('type-markup-include')
96
+ return classes
83
97
  }
84
98
 
85
99
  if (config.type === 'waffle-chart') {
86
- classes.push(
87
- 'cove',
88
- 'cdc-open-viz-module',
89
- 'type-waffle-chart',
90
- currentViewport,
91
- config.theme,
92
- 'font-' + config.overallFontSize
93
- )
94
-
95
- if (isEditor) {
96
- classes.push('is-editor')
97
- }
100
+ classes.push('type-waffle-chart', 'font-' + config.overallFontSize)
98
101
 
99
- // Add TP5 style classes
100
102
  if (config.visualizationType === 'TP5 Waffle') {
101
103
  classes.push('waffle__style--tp5')
102
104
  if (config.visual?.whiteBackground) {
@@ -104,8 +106,16 @@ const Visualization = forwardRef<HTMLDivElement, VisualizationWrapper>((props, r
104
106
  }
105
107
  }
106
108
 
107
- classes.push('cove-component', 'waffle-chart')
109
+ if (config.visualizationType === 'TP5 Gauge') {
110
+ classes.push('gauge__style--tp5')
111
+ if (config.visual?.whiteBackground) {
112
+ classes.push('white-background-style')
113
+ }
114
+ }
115
+
116
+ return classes
108
117
  }
118
+
109
119
  return classes
110
120
  }
111
121
 
@@ -121,4 +131,6 @@ const Visualization = forwardRef<HTMLDivElement, VisualizationWrapper>((props, r
121
131
  )
122
132
  })
123
133
 
134
+ Visualization.displayName = 'Visualization'
135
+
124
136
  export default Visualization