@cdc/dashboard 4.26.2 → 4.26.4

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 (109) hide show
  1. package/CONFIG.md +172 -0
  2. package/README.md +60 -20
  3. package/dist/cdcdashboard-CY9IcPSi.es.js +6 -0
  4. package/dist/cdcdashboard-DlpiY3fQ.es.js +4 -0
  5. package/dist/cdcdashboard.js +56686 -50281
  6. package/examples/__data__/data-2.json +6 -0
  7. package/examples/__data__/data-with-metadata.json +18 -0
  8. package/examples/__data__/data.json +6 -0
  9. package/examples/default.json +7 -36
  10. package/examples/legend-issue.json +1 -1
  11. package/examples/minimal-example.json +34 -0
  12. package/examples/private/dengue.json +4640 -0
  13. package/examples/private/inline-markup.json +775 -0
  14. package/examples/private/link_to_file.json +16662 -0
  15. package/examples/private/recent-update.json +1456 -0
  16. package/examples/private/toggle.json +10137 -0
  17. package/examples/sankey.json +3 -3
  18. package/examples/test-api-filter-reset.json +4 -4
  19. package/examples/tp5-test.json +86 -4
  20. package/package.json +9 -9
  21. package/src/CdcDashboard.tsx +2 -1
  22. package/src/CdcDashboardComponent.tsx +48 -28
  23. package/src/_stories/Dashboard.DataSetup.stories.tsx +6 -1
  24. package/src/_stories/Dashboard.Pages.smoke.stories.tsx +22 -0
  25. package/src/_stories/Dashboard.smoke.stories.tsx +33 -0
  26. package/src/_stories/Dashboard.stories.tsx +4523 -83
  27. package/src/_stories/_mock/dashboard-data-driven-colors.json +171 -0
  28. package/src/_stories/_mock/tab-simple-filter.json +153 -0
  29. package/src/_stories/_mock/tp5-test.json +86 -5
  30. package/src/components/DashboardEditors.tsx +15 -0
  31. package/src/components/DashboardFilters/DashboardFilters.test.tsx +129 -0
  32. package/src/components/DashboardFilters/DashboardFilters.tsx +29 -10
  33. package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +12 -8
  34. package/src/components/DashboardFilters/DashboardFiltersEditor/components/APIModal.tsx +6 -4
  35. package/src/components/DashboardFilters/DashboardFiltersEditor/components/DeleteFilterModal.tsx +59 -58
  36. package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.test.tsx +127 -0
  37. package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +29 -6
  38. package/src/components/DashboardFilters/DashboardFiltersEditor/components/NestedDropDownDashboard.tsx +10 -9
  39. package/src/components/DashboardFilters/DashboardFiltersWrapper.tsx +8 -8
  40. package/src/components/DashboardFilters/_stories/DashboardFilters.stories.tsx +1 -1
  41. package/src/components/DashboardFilters/dashboardfilter.styles.css +3 -3
  42. package/src/components/DataDesignerModal.tsx +2 -2
  43. package/src/components/ExpandCollapseButtons.tsx +6 -4
  44. package/src/components/Grid.tsx +4 -3
  45. package/src/components/Header/Header.tsx +27 -5
  46. package/src/components/Header/index.scss +1 -1
  47. package/src/components/MultiConfigTabs/MultiConfigTabs.tsx +141 -140
  48. package/src/components/MultiConfigTabs/multiconfigtabs.styles.css +6 -6
  49. package/src/components/Row.tsx +30 -8
  50. package/src/components/Toggle/toggle-style.css +7 -7
  51. package/src/components/VisualizationRow.tsx +81 -22
  52. package/src/components/VisualizationsPanel/VisualizationsPanel.tsx +2 -55
  53. package/src/components/VisualizationsPanel/visualizations-panel-styles.css +2 -2
  54. package/src/components/Widget/Widget.tsx +7 -6
  55. package/src/components/Widget/widget.styles.css +48 -17
  56. package/src/data/initial-state.js +2 -1
  57. package/src/helpers/addVisualization.ts +73 -0
  58. package/src/helpers/formatConfigBeforeSave.ts +1 -1
  59. package/src/helpers/getVizConfig.ts +13 -3
  60. package/src/helpers/iconHash.tsx +45 -36
  61. package/src/helpers/processDataLegacy.ts +19 -14
  62. package/src/helpers/tests/addVisualization.test.ts +52 -0
  63. package/src/helpers/tests/formatConfigBeforeSave.test.ts +81 -1
  64. package/src/scss/editor-panel.scss +1 -1
  65. package/src/scss/grid.scss +38 -8
  66. package/src/scss/main.scss +237 -40
  67. package/src/store/dashboard.reducer.ts +2 -1
  68. package/src/test/CdcDashboard.test.jsx +26 -2
  69. package/src/test/CdcDashboardComponent.test.tsx +74 -0
  70. package/src/types/FilterStyles.ts +2 -1
  71. package/src/types/SharedFilter.ts +1 -0
  72. package/tests/fixtures/dashboard-config-with-metadata.json +89 -0
  73. package/vite.config.js +2 -2
  74. package/dist/cdcdashboard-Cf9_fbQf.es.js +0 -6
  75. package/examples/DEV-6574.json +0 -2224
  76. package/examples/api-dashboard-data.json +0 -272
  77. package/examples/api-dashboard-years.json +0 -11
  78. package/examples/api-geographies-data.json +0 -11
  79. package/examples/chart-data.json +0 -5409
  80. package/examples/custom/css/respiratory.css +0 -236
  81. package/examples/custom/js/respiratory.js +0 -242
  82. package/examples/default-data.json +0 -368
  83. package/examples/default-filter-control.json +0 -209
  84. package/examples/default-multi-dataset-shared-filter.json +0 -1729
  85. package/examples/default-multi-dataset.json +0 -506
  86. package/examples/ed-visits-county-file.json +0 -402
  87. package/examples/filters/Alabama.json +0 -72
  88. package/examples/filters/Alaska.json +0 -1737
  89. package/examples/filters/Arkansas.json +0 -4713
  90. package/examples/filters/California.json +0 -212
  91. package/examples/filters/Colorado.json +0 -1500
  92. package/examples/filters/Connecticut.json +0 -559
  93. package/examples/filters/Delaware.json +0 -63
  94. package/examples/filters/DistrictofColumbia.json +0 -63
  95. package/examples/filters/Florida.json +0 -4217
  96. package/examples/filters/States.json +0 -146
  97. package/examples/state-level.json +0 -90136
  98. package/examples/state-points.json +0 -10474
  99. package/examples/temp-example-data.json +0 -130
  100. package/examples/test-dashboard-simple.json +0 -503
  101. package/examples/test-example.json +0 -752
  102. package/examples/test-file.json +0 -147
  103. package/examples/test.json +0 -752
  104. package/examples/testing.json +0 -94456
  105. /package/examples/{legend-issue-data.json → __data__/legend-issue-data.json} +0 -0
  106. /package/examples/api-test/{categories.json → __data__/categories.json} +0 -0
  107. /package/examples/api-test/{chart-data.json → __data__/chart-data.json} +0 -0
  108. /package/examples/api-test/{topics.json → __data__/topics.json} +0 -0
  109. /package/examples/api-test/{years.json → __data__/years.json} +0 -0
@@ -7,7 +7,7 @@ const meta: Meta<typeof DashboardFilters> = {
7
7
  component: DashboardFilters,
8
8
  decorators: [
9
9
  Story => (
10
- <div className='cdc-open-viz-module type-dashboard'>
10
+ <div className='cove-visualization type-dashboard'>
11
11
  <Story />
12
12
  </div>
13
13
  )
@@ -4,18 +4,18 @@
4
4
  font-weight: 700;
5
5
  }
6
6
  .btn {
7
+ align-self: flex-end;
7
8
  /* this is the height that is defined for the .form-control class in _forms.scss in bootstrap. */
8
9
  height: calc(1.5em + 0.75rem + 2px);
9
- align-self: flex-end;
10
10
  }
11
11
  .loading-filter {
12
12
  position: relative;
13
13
  .spinner-border {
14
+ height: 1.5rem;
14
15
  position: absolute;
15
- top: 55%;
16
16
  right: 10%;
17
+ top: 55%;
17
18
  width: 1.5rem;
18
- height: 1.5rem;
19
19
  }
20
20
  }
21
21
  :is(select):disabled {
@@ -59,8 +59,8 @@ export const DataDesignerModal: React.FC<DataDesignerModalProps> = ({ vizKey, ro
59
59
  if (dataSetChanged || noCachedData) {
60
60
  setLoadingAPIData(true)
61
61
  try {
62
- newData = await fetchRemoteData(dataUrl)
63
- newData = transform.autoStandardize(newData)
62
+ const result = await fetchRemoteData(dataUrl)
63
+ newData = transform.autoStandardize(result.data)
64
64
  } catch (e) {
65
65
  setErrorMessage('There was an issue loading the data source. Please check the datasource URL and try again.')
66
66
  }
@@ -1,3 +1,5 @@
1
+ import Button from '@cdc/core/components/elements/Button'
2
+
1
3
  type ExpandCollapseButtonsProps = {
2
4
  setAllExpanded: Function
3
5
  }
@@ -6,12 +8,12 @@ const ExpandCollapseButtons: React.FC<ExpandCollapseButtonsProps> = ({ setAllExp
6
8
  return (
7
9
  <div className='d-block '>
8
10
  <div className='d-flex flex-row-reverse mb-2'>
9
- <button className='btn expand-collapse-buttons' onClick={() => setAllExpanded(false)}>
11
+ <Button variant='light' onClick={() => setAllExpanded(false)}>
10
12
  - Collapse All
11
- </button>
12
- <button className='btn expand-collapse-buttons me-2' onClick={() => setAllExpanded(true)}>
13
+ </Button>
14
+ <Button variant='light' className='me-2' onClick={() => setAllExpanded(true)}>
13
15
  + Expand All
14
- </button>
16
+ </Button>
15
17
  </div>
16
18
  </div>
17
19
  )
@@ -1,14 +1,15 @@
1
1
  import React, { useContext } from 'react'
2
2
  import Row from './Row'
3
+ import Button from '@cdc/core/components/elements/Button'
3
4
 
4
5
  import { DashboardContext, DashboardDispatchContext } from '../DashboardContext'
5
6
  import { ConfigRow } from '../types/ConfigRow'
6
7
 
7
8
  const Grid = () => {
8
9
  const { config } = useContext(DashboardContext)
10
+ const dispatch = useContext(DashboardDispatchContext)
9
11
  if (!config) return null
10
12
  const rows = config.rows
11
- const dispatch = useContext(DashboardDispatchContext)
12
13
  const updateConfig = config => dispatch({ type: 'UPDATE_CONFIG', payload: [config] })
13
14
  const addRow = () => {
14
15
  const blankRow: Partial<ConfigRow> = { columns: [{ width: 12 }] }
@@ -24,9 +25,9 @@ const Grid = () => {
24
25
  {(rows || []).map((row, idx) => (
25
26
  <Row row={row} idx={idx} uuid={row.uuid} key={idx} />
26
27
  ))}
27
- <button className='btn btn-primary col' onClick={addRow}>
28
+ <Button variant='primary' className='col' onClick={addRow}>
28
29
  Add Row
29
- </button>
30
+ </Button>
30
31
  </div>
31
32
  )
32
33
  }
@@ -176,7 +176,6 @@ const Header = (props: HeaderProps) => {
176
176
  Show Data Table(s)
177
177
  </label>
178
178
  <br />
179
-
180
179
  <label>
181
180
  <input
182
181
  type='checkbox'
@@ -185,7 +184,6 @@ const Header = (props: HeaderProps) => {
185
184
  />
186
185
  Expanded by Default
187
186
  </label>
188
- <br />
189
187
  </div>
190
188
 
191
189
  <div className='wrap'>
@@ -206,9 +204,6 @@ const Header = (props: HeaderProps) => {
206
204
  onChange={e => changeConfigValue('table', 'height', e.target.value)}
207
205
  />
208
206
  )}
209
- </div>
210
-
211
- <div className='wrap'>
212
207
  <label>
213
208
  <input
214
209
  type='checkbox'
@@ -217,6 +212,17 @@ const Header = (props: HeaderProps) => {
217
212
  />
218
213
  Show Download CSV Link
219
214
  </label>
215
+ {config.table.download && (
216
+ <input
217
+ type='text'
218
+ placeholder='Customize label'
219
+ defaultValue={config.table.downloadDataLabel}
220
+ onChange={e => changeConfigValue('table', 'downloadDataLabel', e.target.value)}
221
+ />
222
+ )}
223
+ </div>
224
+
225
+ <div className='wrap'>
220
226
  <label>
221
227
  <input
222
228
  type='checkbox'
@@ -225,6 +231,22 @@ const Header = (props: HeaderProps) => {
225
231
  />
226
232
  Show URL to Automatically Updated Data
227
233
  </label>
234
+ <label>
235
+ <input
236
+ type='checkbox'
237
+ defaultChecked={config.table.downloadImageButton}
238
+ onChange={e => changeConfigValue('table', 'downloadImageButton', e.target.checked)}
239
+ />
240
+ Show Download Image Button
241
+ </label>
242
+ {config.table.downloadImageButton && (
243
+ <input
244
+ type='text'
245
+ placeholder='Customize label'
246
+ defaultValue={config.table.downloadImageLabel}
247
+ onChange={e => changeConfigValue('table', 'downloadImageLabel', e.target.value)}
248
+ />
249
+ )}
228
250
  </div>
229
251
  </>
230
252
  )}
@@ -1,4 +1,4 @@
1
- .cdc-open-viz-module .shared-filter-modal,
1
+ .cove-visualization .shared-filter-modal,
2
2
  .cove .shared-filter-modal,
3
3
  .shared-filter-modal {
4
4
  &__title {
@@ -1,140 +1,141 @@
1
- import { createRef, useContext, useMemo, useState } from 'react'
2
- import { DashboardContext, DashboardDispatchContext } from '../../DashboardContext'
3
- import Modal from '@cdc/core/components/ui/Modal'
4
- import { useGlobalContext } from '@cdc/core/components/GlobalContext'
5
- import './multiconfigtabs.styles.css'
6
-
7
- const AreYouSure = deleteCallback => {
8
- return (
9
- <Modal>
10
- <Modal.Content>
11
- <p>Are you sure you want to delete this dashboard? </p>
12
- <button className='btn btn-danger' onClick={deleteCallback}>
13
- DELETE
14
- </button>
15
- </Modal.Content>
16
- </Modal>
17
- )
18
- }
19
-
20
- const Tab = ({ name, handleClick, tabs, index, active }) => {
21
- const [editing, setEditing] = useState(false)
22
- const dispatch = useContext(DashboardDispatchContext)
23
- const { overlay } = useGlobalContext()
24
- const inputRef = createRef<HTMLInputElement>()
25
-
26
- const saveName = e => {
27
- e.stopPropagation()
28
- const newVal = inputRef.current.value
29
- const sameName = newVal === name
30
- const blankName = !newVal
31
- const duplicateName = tabs.includes(newVal)
32
- if (!sameName && !blankName && !duplicateName) {
33
- dispatch({ type: 'RENAME_DASHBOARD_TAB', payload: { current: name, new: newVal } })
34
- }
35
- setEditing(false)
36
- }
37
-
38
- const onClick = e => {
39
- // ignore click on delete button
40
- if (e.target.className === 'remove') return
41
- if (active) {
42
- setEditing(true)
43
- } else {
44
- handleClick()
45
- }
46
- }
47
-
48
- const handleRemove = () => {
49
- const deleteCallback = () => {
50
- dispatch({ type: 'REMOVE_MULTIDASHBOARD_AT_INDEX', payload: index })
51
- overlay?.actions.toggleOverlay(false)
52
- }
53
- overlay?.actions.openOverlay(AreYouSure(deleteCallback))
54
- }
55
-
56
- const handleReorder = (index: number, moveTo: -1 | 1) => {
57
- const newIndex = index + moveTo
58
- const inbounds = newIndex > -1 && newIndex <= tabs.length - 1
59
- if (inbounds) {
60
- dispatch({ type: 'REORDER_MULTIDASHBOARDS', payload: { currentIndex: index, newIndex: index + moveTo } })
61
- }
62
- }
63
-
64
- const canMoveLeft = index !== 0
65
- const canMoveRight = index <= tabs.length - 2
66
-
67
- return (
68
- <li className='nav-item d-flex mt-0'>
69
- {canMoveLeft && editing && (
70
- <button className='border-0' onClick={() => handleReorder(index, -1)}>
71
- {'<'}
72
- </button>
73
- )}
74
- <div
75
- className={`edit nav-link${active ? ' active' : ''}`}
76
- aria-current={active ? 'page' : null}
77
- onClick={onClick}
78
- >
79
- {editing ? (
80
- <div className='d-flex'>
81
- <input type='text' defaultValue={name} onBlur={saveName} ref={inputRef} />
82
- <button className='btn btn-link save' onClick={saveName}>
83
- save
84
- </button>
85
- </div>
86
- ) : (
87
- <>
88
- {name}
89
- <button className='btn btn-danger border-0 ms-1' onClick={handleRemove}>
90
- X
91
- </button>
92
- </>
93
- )}
94
- </div>
95
- {canMoveRight && editing && (
96
- <button className='border-0' onClick={() => handleReorder(index, 1)}>
97
- {'>'}
98
- </button>
99
- )}
100
- </li>
101
- )
102
- }
103
-
104
- const MultiConfigTabs = () => {
105
- const { config } = useContext(DashboardContext)
106
- const dispatch = useContext(DashboardDispatchContext)
107
- const tabs = useMemo<string[]>(
108
- () => (config.multiDashboards || []).map(({ label }) => label),
109
- [config.multiDashboards]
110
- )
111
- const activeTab = useMemo<number>(() => config.activeDashboard, [config.activeDashboard])
112
-
113
- const saveAndLoad = (indexToSwitchTo: number) => {
114
- dispatch({ type: 'SAVE_CURRENT_CHANGES' })
115
- dispatch({ type: 'SWITCH_CONFIG', payload: indexToSwitchTo })
116
- }
117
-
118
- if (!config.multiDashboards) return null
119
- return (
120
- <ul className='nav nav-tabs multi-config-tabs mb-4'>
121
- {tabs.map((tab, index) => (
122
- <Tab
123
- key={tab + index}
124
- name={tab}
125
- tabs={tabs}
126
- index={index}
127
- handleClick={() => saveAndLoad(index)}
128
- active={index === activeTab}
129
- />
130
- ))}
131
- <li className='nav-item'>
132
- <button className='nav-link add' onClick={() => dispatch({ type: 'ADD_NEW_DASHBOARD' })}>
133
- +
134
- </button>
135
- </li>
136
- </ul>
137
- )
138
- }
139
-
140
- export default MultiConfigTabs
1
+ import { createRef, useContext, useMemo, useState } from 'react'
2
+ import { DashboardContext, DashboardDispatchContext } from '../../DashboardContext'
3
+ import Modal from '@cdc/core/components/ui/Modal'
4
+ import { useGlobalContext } from '@cdc/core/components/GlobalContext'
5
+ import Button from '@cdc/core/components/elements/Button'
6
+ import './multiconfigtabs.styles.css'
7
+
8
+ const AreYouSure = deleteCallback => {
9
+ return (
10
+ <Modal>
11
+ <Modal.Content>
12
+ <p>Are you sure you want to delete this dashboard? </p>
13
+ <Button variant='danger' onClick={deleteCallback}>
14
+ DELETE
15
+ </Button>
16
+ </Modal.Content>
17
+ </Modal>
18
+ )
19
+ }
20
+
21
+ const Tab = ({ name, handleClick, tabs, index, active }) => {
22
+ const [editing, setEditing] = useState(false)
23
+ const dispatch = useContext(DashboardDispatchContext)
24
+ const { overlay } = useGlobalContext()
25
+ const inputRef = createRef<HTMLInputElement>()
26
+
27
+ const saveName = e => {
28
+ e.stopPropagation()
29
+ const newVal = inputRef.current.value
30
+ const sameName = newVal === name
31
+ const blankName = !newVal
32
+ const duplicateName = tabs.includes(newVal)
33
+ if (!sameName && !blankName && !duplicateName) {
34
+ dispatch({ type: 'RENAME_DASHBOARD_TAB', payload: { current: name, new: newVal } })
35
+ }
36
+ setEditing(false)
37
+ }
38
+
39
+ const onClick = e => {
40
+ // ignore click on delete button
41
+ if (e.target.className === 'remove') return
42
+ if (active) {
43
+ setEditing(true)
44
+ } else {
45
+ handleClick()
46
+ }
47
+ }
48
+
49
+ const handleRemove = () => {
50
+ const deleteCallback = () => {
51
+ dispatch({ type: 'REMOVE_MULTIDASHBOARD_AT_INDEX', payload: index })
52
+ overlay?.actions.toggleOverlay(false)
53
+ }
54
+ overlay?.actions.openOverlay(AreYouSure(deleteCallback))
55
+ }
56
+
57
+ const handleReorder = (index: number, moveTo: -1 | 1) => {
58
+ const newIndex = index + moveTo
59
+ const inbounds = newIndex > -1 && newIndex <= tabs.length - 1
60
+ if (inbounds) {
61
+ dispatch({ type: 'REORDER_MULTIDASHBOARDS', payload: { currentIndex: index, newIndex: index + moveTo } })
62
+ }
63
+ }
64
+
65
+ const canMoveLeft = index !== 0
66
+ const canMoveRight = index <= tabs.length - 2
67
+
68
+ return (
69
+ <li className='nav-item d-flex mt-0'>
70
+ {canMoveLeft && editing && (
71
+ <button className='border-0' onClick={() => handleReorder(index, -1)}>
72
+ {'<'}
73
+ </button>
74
+ )}
75
+ <div
76
+ className={`edit nav-link${active ? ' active' : ''}`}
77
+ aria-current={active ? 'page' : null}
78
+ onClick={onClick}
79
+ >
80
+ {editing ? (
81
+ <div className='d-flex'>
82
+ <input type='text' defaultValue={name} onBlur={saveName} ref={inputRef} />
83
+ <Button variant='link' className='save' onClick={saveName}>
84
+ save
85
+ </Button>
86
+ </div>
87
+ ) : (
88
+ <>
89
+ {name}
90
+ <Button variant='danger' className='border-0 ms-1' onClick={handleRemove}>
91
+ X
92
+ </Button>
93
+ </>
94
+ )}
95
+ </div>
96
+ {canMoveRight && editing && (
97
+ <button className='border-0' onClick={() => handleReorder(index, 1)}>
98
+ {'>'}
99
+ </button>
100
+ )}
101
+ </li>
102
+ )
103
+ }
104
+
105
+ const MultiConfigTabs = () => {
106
+ const { config } = useContext(DashboardContext)
107
+ const dispatch = useContext(DashboardDispatchContext)
108
+ const tabs = useMemo<string[]>(
109
+ () => (config.multiDashboards || []).map(({ label }) => label),
110
+ [config.multiDashboards]
111
+ )
112
+ const activeTab = useMemo<number>(() => config.activeDashboard, [config.activeDashboard])
113
+
114
+ const saveAndLoad = (indexToSwitchTo: number) => {
115
+ dispatch({ type: 'SAVE_CURRENT_CHANGES' })
116
+ dispatch({ type: 'SWITCH_CONFIG', payload: indexToSwitchTo })
117
+ }
118
+
119
+ if (!config.multiDashboards) return null
120
+ return (
121
+ <ul className='nav nav-tabs multi-config-tabs mb-4'>
122
+ {tabs.map((tab, index) => (
123
+ <Tab
124
+ key={tab + index}
125
+ name={tab}
126
+ tabs={tabs}
127
+ index={index}
128
+ handleClick={() => saveAndLoad(index)}
129
+ active={index === activeTab}
130
+ />
131
+ ))}
132
+ <li className='nav-item'>
133
+ <button className='nav-link add' onClick={() => dispatch({ type: 'ADD_NEW_DASHBOARD' })}>
134
+ +
135
+ </button>
136
+ </li>
137
+ </ul>
138
+ )
139
+ }
140
+
141
+ export default MultiConfigTabs
@@ -1,17 +1,17 @@
1
1
  .multi-config-tabs {
2
2
  .nav-link {
3
+ border-color: var(--lightGray);
3
4
  border-radius: 6px 6px 0 0;
4
- font-weight: 400;
5
+ color: var(--primary);
5
6
  display: block;
7
+ font-weight: 400;
6
8
  padding: 0.5rem 1rem;
7
9
  @media (max-width: 480px) {
8
10
  padding: 0.5rem 0.8rem;
9
11
  }
10
- color: var(--primary);
11
- border-color: var(--lightGray);
12
12
  :is(button) {
13
- display: none;
14
13
  background: none;
14
+ display: none;
15
15
  }
16
16
  &:hover {
17
17
  :is(button) {
@@ -31,9 +31,9 @@
31
31
  font-weight: bold;
32
32
  }
33
33
  .btn-danger {
34
- text-decoration: none;
35
- padding: 0px 5px;
36
34
  font-size: inherit;
35
+ padding: 0px 5px;
36
+ text-decoration: none;
37
37
  }
38
38
  }
39
39
  .add {
@@ -15,6 +15,7 @@ import ToggleIcon from '../images/icon-toggle.svg'
15
15
  import { ConfigRow } from '../types/ConfigRow'
16
16
  import { DataDesignerModal } from './DataDesignerModal'
17
17
  import { useGlobalContext } from '@cdc/core/components/GlobalContext'
18
+ import Button from '@cdc/core/components/elements/Button'
18
19
  import { iconHash } from '../helpers/iconHash'
19
20
  import _ from 'lodash'
20
21
  import { Visualization } from '@cdc/core/types/Visualization'
@@ -70,6 +71,12 @@ const RowMenu: React.FC<RowMenuProps> = ({ rowIdx }) => {
70
71
  updateConfig({ ...config, rows: newRows })
71
72
  }
72
73
 
74
+ const toggleEqualHeight = () => {
75
+ const newRows = _.cloneDeep(rows)
76
+ newRows[rowIdx].equalHeight = !newRows[rowIdx].equalHeight
77
+ updateConfig({ ...config, rows: newRows })
78
+ }
79
+
73
80
  const moveRow = (dir = 'down') => {
74
81
  if (rowIdx === rows.length - 1 && dir === 'down') return
75
82
 
@@ -179,34 +186,49 @@ const RowMenu: React.FC<RowMenuProps> = ({ rowIdx }) => {
179
186
  </li>
180
187
  ]
181
188
 
189
+ const isMultiColumn = curr !== '12' && curr !== 'toggle'
190
+
182
191
  return (
183
192
  <nav className='row-menu'>
184
193
  <ul className='row-menu__flyout'>{layoutList}</ul>
194
+ {isMultiColumn && (
195
+ <Button
196
+ className={`btn row-menu__btn border-0${row.equalHeight ? ' btn-primary' : ''}`}
197
+ title={row.equalHeight ? 'Disable Equal Height Rows' : 'Enable Equal Height Rows'}
198
+ onClick={toggleEqualHeight}
199
+ >
200
+ <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='25' height='20' fill='#fff'>
201
+ <rect x='1' y='2' width='9' height='14' rx='1' />
202
+ <rect x='14' y='2' width='9' height='14' rx='1' />
203
+ <line x1='0' y1='19' x2='24' y2='19' stroke='#fff' strokeWidth='2' strokeDasharray='3 2' />
204
+ </svg>
205
+ </Button>
206
+ )}
185
207
  <div className='spacer'></div>
186
- <button
208
+ <Button
187
209
  className={`btn btn-primary row-menu__btn border-0`}
188
210
  title='Move Row Up'
189
211
  onClick={() => moveRow('up')}
190
212
  disabled={rowIdx === 0}
191
213
  >
192
214
  <Icon display='caretUp' color='#fff' size={25} />
193
- </button>
194
- <button
215
+ </Button>
216
+ <Button
195
217
  className={'btn btn-primary row-menu__btn border-0'}
196
218
  title='Move Row Down'
197
219
  onClick={() => moveRow('down')}
198
220
  disabled={rowIdx + 1 === rows.length}
199
221
  >
200
222
  <Icon display='caretDown' color='#fff' size={25} />
201
- </button>
202
- <button
223
+ </Button>
224
+ <Button
203
225
  className={'btn btn-danger row-menu__btn row-menu__btn--remove border-0'}
204
226
  title='Delete Row'
205
227
  onClick={deleteRow}
206
228
  disabled={rowIdx === 0 && rows.length === 1}
207
229
  >
208
230
  <Icon display='close' color='#fff' size={25} />
209
- </button>
231
+ </Button>
210
232
  </nav>
211
233
  )
212
234
  }
@@ -220,7 +242,7 @@ const Row: React.FC<RowProps> = ({ row, idx: rowIdx, uuid }) => {
220
242
  <div className='builder-row' data-row-id={rowIdx}>
221
243
  <RowMenu rowIdx={rowIdx} />
222
244
  <span className='ms-2 mt-n3'>Row - {rowIdx + 1}</span>
223
- <button
245
+ <Button
224
246
  title='Configure Data'
225
247
  className='btn btn-configure-row'
226
248
  onClick={() => {
@@ -228,7 +250,7 @@ const Row: React.FC<RowProps> = ({ row, idx: rowIdx, uuid }) => {
228
250
  }}
229
251
  >
230
252
  {iconHash['gearMulti']}
231
- </button>
253
+ </Button>
232
254
  <div className='column-container'>
233
255
  {row.columns
234
256
  .filter(column => column.width)
@@ -1,10 +1,10 @@
1
- .cdc-open-viz-module {
1
+ .cove-visualization {
2
2
  --border: 1px solid var(--lightGray);
3
3
  .toggle-component {
4
4
  display: flex;
5
5
  justify-content: right;
6
- width: 100%;
7
6
  margin-bottom: 15px;
7
+ width: 100%;
8
8
  :first-child:is(div) {
9
9
  border: var(--border);
10
10
  border-radius: 5px 0 0 5px;
@@ -14,18 +14,18 @@
14
14
  border-radius: 0 5px 5px 0;
15
15
  }
16
16
  :is(div) {
17
- border-top: var(--border);
17
+ background-color: var(--white);
18
18
  border-bottom: var(--border);
19
- padding: 7px 15px;
19
+ border-top: var(--border);
20
+ color: var(--primary);
21
+ cursor: pointer;
20
22
  display: inline;
21
23
  float: right;
22
- cursor: pointer;
24
+ padding: 7px 15px;
23
25
  &.selected {
24
26
  background-color: var(--primary);
25
27
  color: white;
26
28
  }
27
- background-color: var(--white);
28
- color: var(--primary);
29
29
  :is(svg) {
30
30
  height: 25px;
31
31
  }