@cdc/core 4.24.12 → 4.25.2-25

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 (77) hide show
  1. package/components/DataTable/DataTable.tsx +58 -45
  2. package/components/DataTable/DataTableStandAlone.tsx +3 -3
  3. package/components/DataTable/components/ChartHeader.tsx +26 -6
  4. package/components/DataTable/components/ExpandCollapse.tsx +1 -4
  5. package/components/DataTable/components/MapHeader.tsx +5 -1
  6. package/components/DataTable/data-table.css +3 -8
  7. package/components/DataTable/helpers/chartCellMatrix.tsx +14 -5
  8. package/components/DataTable/helpers/customSort.ts +2 -2
  9. package/components/DataTable/helpers/mapCellMatrix.tsx +83 -60
  10. package/components/DataTable/types/TableConfig.ts +0 -1
  11. package/components/EditorPanel/FootnotesEditor.tsx +49 -7
  12. package/components/EditorPanel/Inputs.tsx +4 -0
  13. package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +16 -3
  14. package/components/Filters/Filters.tsx +95 -51
  15. package/components/Filters/helpers/filterWrapping.ts +43 -0
  16. package/components/Filters/helpers/handleSorting.ts +6 -0
  17. package/components/Filters/helpers/tests/handleSorting.test.ts +26 -0
  18. package/components/Footnotes/Footnotes.tsx +1 -1
  19. package/components/Layout/components/Visualization/index.tsx +18 -4
  20. package/components/Layout/components/Visualization/visualizations.scss +1 -1
  21. package/components/Legend/Legend.Gradient.tsx +1 -4
  22. package/components/Legend/index.tsx +1 -1
  23. package/components/LegendShape.tsx +2 -3
  24. package/components/MediaControls.jsx +32 -8
  25. package/components/NestedDropdown/NestedDropdown.tsx +25 -17
  26. package/components/NestedDropdown/nesteddropdown.styles.css +13 -7
  27. package/components/Table/Table.tsx +11 -11
  28. package/components/Table/components/Row.tsx +14 -5
  29. package/components/_stories/DataTable.stories.tsx +1 -2
  30. package/components/elements/Button.jsx +38 -19
  31. package/components/elements/Confirm.tsx +45 -0
  32. package/components/elements/Error.tsx +24 -0
  33. package/components/managers/DataDesigner.tsx +198 -143
  34. package/components/ui/Title/Title.scss +12 -5
  35. package/components/ui/Title/index.tsx +1 -1
  36. package/dist/cove-main.css +260 -723
  37. package/dist/cove-main.css.map +1 -1
  38. package/helpers/DataTransform.ts +55 -61
  39. package/helpers/addValuesToFilters.ts +45 -16
  40. package/helpers/cove/accessibility.ts +24 -0
  41. package/helpers/cove/fontSettings.ts +1 -1
  42. package/helpers/cove/number.ts +1 -7
  43. package/helpers/coveUpdateWorker.ts +5 -1
  44. package/helpers/displayDataAsText.ts +64 -0
  45. package/helpers/filterVizData.ts +2 -2
  46. package/helpers/formatConfigBeforeSave.ts +17 -2
  47. package/helpers/isOlderVersion.ts +20 -0
  48. package/helpers/isRightAlignedTableValue.js +14 -0
  49. package/helpers/missingRequiredSections.ts +20 -0
  50. package/helpers/queryStringUtils.ts +7 -0
  51. package/helpers/tests/addValuesToFilters.test.ts +19 -1
  52. package/helpers/useDataVizClasses.ts +8 -4
  53. package/helpers/ver/4.24.10.ts +12 -0
  54. package/helpers/ver/4.24.11.ts +18 -0
  55. package/helpers/ver/4.24.7.ts +19 -1
  56. package/helpers/ver/4.25.1.ts +18 -0
  57. package/package.json +2 -2
  58. package/styles/_button-section.scss +2 -5
  59. package/styles/_global-variables.scss +17 -7
  60. package/styles/_global.scss +8 -12
  61. package/styles/_reset.scss +4 -5
  62. package/styles/_typography.scss +0 -20
  63. package/styles/_variables.scss +0 -3
  64. package/styles/base.scss +44 -5
  65. package/styles/cove-main.scss +1 -1
  66. package/styles/filters.scss +65 -6
  67. package/styles/v2/base/_general.scss +3 -2
  68. package/styles/v2/components/button.scss +0 -1
  69. package/styles/v2/main.scss +3 -4
  70. package/styles/v2/themes/_color-definitions.scss +4 -4
  71. package/styles/v2/utils/index.scss +0 -1
  72. package/types/BoxPlot.ts +1 -0
  73. package/types/Runtime.ts +1 -0
  74. package/types/Table.ts +0 -1
  75. package/types/Version.ts +1 -1
  76. package/types/VizFilter.ts +3 -1
  77. package/styles/v2/utils/_spacers.scss +0 -31
@@ -3,7 +3,12 @@ import { useEffect } from 'react'
3
3
  import Button from '../elements/Button'
4
4
  import Card from '../elements/Card'
5
5
 
6
- import { DATA_TABLE_VERTICAL, DATA_TABLE_HORIZONTAL, DATA_TABLE_SINGLE_ROW, DATA_TABLE_MULTI_ROW } from '../../templates/dataDesignerTables'
6
+ import {
7
+ DATA_TABLE_VERTICAL,
8
+ DATA_TABLE_HORIZONTAL,
9
+ DATA_TABLE_SINGLE_ROW,
10
+ DATA_TABLE_MULTI_ROW
11
+ } from '../../templates/dataDesignerTables'
7
12
  import '../../styles/v2/components/data-designer.scss'
8
13
  import { ConfigureData } from '../../types/ConfigureData'
9
14
 
@@ -45,7 +50,12 @@ const DataDesigner = (props: DataDesignerProps) => {
45
50
  <div className='grid grid-gap-2 mb-4'>
46
51
  <div className='column'>
47
52
  <button
48
- className={'cove-data-designer__button' + (configureData.dataDescription && configureData.dataDescription.horizontal === false ? ' active' : '')}
53
+ className={
54
+ 'cove-data-designer__button' +
55
+ (configureData.dataDescription && configureData.dataDescription.horizontal === false
56
+ ? ' active'
57
+ : '')
58
+ }
49
59
  onClick={() => {
50
60
  updateDescriptionProp('horizontal', false)
51
61
  }}
@@ -61,7 +71,12 @@ const DataDesigner = (props: DataDesignerProps) => {
61
71
  </div>
62
72
  <div className='column'>
63
73
  <button
64
- className={'cove-data-designer__button' + (configureData.dataDescription && configureData.dataDescription.horizontal === true ? ' active' : '')}
74
+ className={
75
+ 'cove-data-designer__button' +
76
+ (configureData.dataDescription && configureData.dataDescription.horizontal === true
77
+ ? ' active'
78
+ : '')
79
+ }
65
80
  onClick={() => {
66
81
  updateDescriptionProp('horizontal', true)
67
82
  }}
@@ -88,7 +103,7 @@ const DataDesigner = (props: DataDesignerProps) => {
88
103
  <Button
89
104
  style={{ backgroundColor: '#00345d' }}
90
105
  hoverStyle={{ backgroundColor: '#015daa' }}
91
- className='mr-1'
106
+ className='me-1'
92
107
  onClick={() => {
93
108
  updateDescriptionProp('series', true)
94
109
  }}
@@ -127,154 +142,194 @@ const DataDesigner = (props: DataDesignerProps) => {
127
142
  </select>
128
143
  </div>
129
144
  )}
130
- {configureData.dataDescription.horizontal === false && configureData.dataDescription.series === true && hasRowSelection && (
131
- <>
132
- <div className='mb-2'>
133
- <div className='mb-1'>Are the series values in your data represented in a single row, or across multiple rows?</div>
134
- <div className='grid grid-gap-2 mb-4'>
135
- <div className='column'>
136
- <button
137
- className={'cove-data-designer__button' + (configureData.dataDescription.singleRow === true ? ' active' : '')}
138
- onClick={() => {
139
- updateDescriptionProp('singleRow', true)
140
- }}
141
- >
142
- <Card>
143
- <strong className='cove-heading--3'>Single Row</strong>
144
- <p className='mb-1'>Each row contains the data for an individual series in itself.</p>
145
- {DATA_TABLE_SINGLE_ROW}
146
- </Card>
147
- </button>
145
+ {configureData.dataDescription.horizontal === false &&
146
+ configureData.dataDescription.series === true &&
147
+ hasRowSelection && (
148
+ <>
149
+ <div className='mb-2'>
150
+ <div className='mb-1'>
151
+ Are the series values in your data represented in a single row, or across multiple rows?
148
152
  </div>
149
- <div className='column'>
150
- <button
151
- className={'cove-data-designer__button' + (configureData.dataDescription.singleRow === false ? ' active' : '')}
152
- onClick={() => {
153
- updateDescriptionProp('singleRow', false)
154
- }}
155
- >
156
- <Card>
157
- <strong className='cove-heading--3'>Multiple Rows</strong>
158
- <p className='mb-1'>Each series data is broken out into multiple rows.</p>
159
- {DATA_TABLE_MULTI_ROW}
160
- </Card>
161
- </button>
153
+ <div className='grid grid-gap-2 mb-4'>
154
+ <div className='column'>
155
+ <button
156
+ className={
157
+ 'cove-data-designer__button' +
158
+ (configureData.dataDescription.singleRow === true ? ' active' : '')
159
+ }
160
+ onClick={() => {
161
+ updateDescriptionProp('singleRow', true)
162
+ }}
163
+ >
164
+ <Card>
165
+ <strong className='cove-heading--3'>Single Row</strong>
166
+ <p className='mb-1'>Each row contains the data for an individual series in itself.</p>
167
+ {DATA_TABLE_SINGLE_ROW}
168
+ </Card>
169
+ </button>
170
+ </div>
171
+ <div className='column'>
172
+ <button
173
+ className={
174
+ 'cove-data-designer__button' +
175
+ (configureData.dataDescription.singleRow === false ? ' active' : '')
176
+ }
177
+ onClick={() => {
178
+ updateDescriptionProp('singleRow', false)
179
+ }}
180
+ >
181
+ <Card>
182
+ <strong className='cove-heading--3'>Multiple Rows</strong>
183
+ <p className='mb-1'>Each series data is broken out into multiple rows.</p>
184
+ {DATA_TABLE_MULTI_ROW}
185
+ </Card>
186
+ </button>
187
+ </div>
162
188
  </div>
163
189
  </div>
164
- </div>
165
- {configureData.dataDescription.singleRow === false && (
166
- <>
167
- <div className='mb-2'>
168
- <div className='mb-1'>Which property in the dataset represents which series the row is describing?</div>
169
- <select
170
- onChange={e => {
171
- updateDescriptionProp('seriesKey', e.target.value)
172
- }}
173
- defaultValue={configureData.dataDescription.seriesKey}
174
- >
175
- <option value=''>Choose an option</option>
176
- {Object.keys(configureData.data[0]).map((value, index) => (
177
- <option value={value} key={index}>
178
- {value}
179
- </option>
180
- ))}
181
- </select>
182
- </div>
183
- <div className='mb-2'>
184
- <div className='mb-1'>Which property in the dataset represents the values for the category/date axis or map geography?</div>
185
- <select
186
- onChange={e => {
187
- updateDescriptionProp('xKey', e.target.value)
188
- }}
189
- defaultValue={configureData.dataDescription.xKey}
190
- >
191
- <option value=''>Choose an option</option>
192
- {Object.keys(configureData.data[0]).map((value, index) => (
193
- <option value={value} key={index}>
194
- {value}
195
- </option>
196
- ))}
197
- </select>
198
- </div>
199
- <div className='mb-2'>
200
- <div className='mb-1'>Which properties in the dataset represent the numeric value? (all remaining properties will be treated as filters)</div>
201
- {configureData.dataDescription.valueKeysTallSupport && configureData.dataDescription.valueKeysTallSupport.length > 0 && (
202
- <ul className='value-list'>
203
- {configureData.dataDescription.valueKeysTallSupport.map((valueKey, index) => (
204
- <li key={`value-keys-list-${index}`}>
205
- {valueKey}
206
- <button
207
- onClick={() => {
208
- let newValueKeys = configureData.dataDescription.valueKeysTallSupport
209
- newValueKeys.splice(index, 1)
210
- updateDescriptionProp('valueKeysTallSupport', newValueKeys)
211
- }}
212
- >
213
- X
214
- </button>
215
- </li>
216
- ))}
217
- </ul>
218
- )}
219
- <select
220
- onChange={e => {
221
- if (e.target.value && (!configureData.dataDescription.valueKeysTallSupport || configureData.dataDescription.valueKeysTallSupport.indexOf(e.target.value) === -1)) {
222
- updateDescriptionProp('valueKeysTallSupport', [...(configureData.dataDescription.valueKeysTallSupport || []), e.target.value])
223
- }
224
- }}
225
- >
226
- <option value=''>Choose an option</option>
227
- {Object.keys(configureData.data[0])
228
- .filter(value => !configureData.dataDescription.valueKeysTallSupport || configureData.dataDescription.valueKeysTallSupport.indexOf(value) === -1)
229
- .map((value, index) => (
230
- <option value={value} key={`value-keys-option-${index}`}>
190
+ {configureData.dataDescription.singleRow === false && (
191
+ <>
192
+ <div className='mb-2'>
193
+ <div className='mb-1'>
194
+ Which property in the dataset represents which series the row is describing?
195
+ </div>
196
+ <select
197
+ onChange={e => {
198
+ updateDescriptionProp('seriesKey', e.target.value)
199
+ }}
200
+ defaultValue={configureData.dataDescription.seriesKey}
201
+ >
202
+ <option value=''>Choose an option</option>
203
+ {Object.keys(configureData.data[0]).map((value, index) => (
204
+ <option value={value} key={index}>
231
205
  {value}
232
206
  </option>
233
207
  ))}
234
- </select>
235
- </div>
236
- <div className='mb-2'>
237
- <div className='mb-1'>(Optional) Which properties in the dataset should be ignored? (will not be used or treated as filters)</div>
238
- {configureData.dataDescription.ignoredKeys && configureData.dataDescription.ignoredKeys.length > 0 && (
239
- <ul className='value-list'>
240
- {configureData.dataDescription.ignoredKeys.map((ignoredKey, index) => (
241
- <li key={`value-keys-list-${index}`}>
242
- {ignoredKey}
243
- <button
244
- onClick={() => {
245
- let newIgnoredKeys = configureData.dataDescription.ignoredKeys
246
- newIgnoredKeys.splice(index, 1)
247
- updateDescriptionProp('ignoredKeys', newIgnoredKeys)
248
- }}
249
- >
250
- X
251
- </button>
252
- </li>
253
- ))}
254
- </ul>
255
- )}
256
- <select
257
- onChange={e => {
258
- if (e.target.value) {
259
- updateDescriptionProp('ignoredKeys', [...(configureData.dataDescription.ignoredKeys || []), e.target.value])
260
- }
261
- e.target.value = ''
262
- }}
263
- >
264
- <option value=''>Choose an option</option>
265
- {Object.keys(configureData.data[0])
266
- .filter(value => !configureData.dataDescription.ignoredKeys || configureData.dataDescription.ignoredKeys.indexOf(value) === -1)
267
- .map((value, index) => (
268
- <option value={value} key={`ignored-keys-option-${index}`}>
208
+ </select>
209
+ </div>
210
+ <div className='mb-2'>
211
+ <div className='mb-1'>
212
+ Which property in the dataset represents the values for the category/date axis or map geography?
213
+ </div>
214
+ <select
215
+ onChange={e => {
216
+ updateDescriptionProp('xKey', e.target.value)
217
+ }}
218
+ defaultValue={configureData.dataDescription.xKey}
219
+ >
220
+ <option value=''>Choose an option</option>
221
+ {Object.keys(configureData.data[0]).map((value, index) => (
222
+ <option value={value} key={index}>
269
223
  {value}
270
224
  </option>
271
225
  ))}
272
- </select>
273
- </div>
274
- </>
275
- )}
276
- </>
277
- )}
226
+ </select>
227
+ </div>
228
+ <div className='mb-2'>
229
+ <div className='mb-1'>
230
+ Which properties in the dataset represent the numeric value? (all remaining properties will be
231
+ treated as filters)
232
+ </div>
233
+ {configureData.dataDescription.valueKeysTallSupport &&
234
+ configureData.dataDescription.valueKeysTallSupport.length > 0 && (
235
+ <ul className='value-list'>
236
+ {configureData.dataDescription.valueKeysTallSupport.map((valueKey, index) => (
237
+ <li key={`value-keys-list-${index}`}>
238
+ {valueKey}
239
+ <button
240
+ onClick={() => {
241
+ let newValueKeys = configureData.dataDescription.valueKeysTallSupport
242
+ newValueKeys.splice(index, 1)
243
+ updateDescriptionProp('valueKeysTallSupport', newValueKeys)
244
+ }}
245
+ >
246
+ X
247
+ </button>
248
+ </li>
249
+ ))}
250
+ </ul>
251
+ )}
252
+ <select
253
+ onChange={e => {
254
+ if (
255
+ e.target.value &&
256
+ (!configureData.dataDescription.valueKeysTallSupport ||
257
+ configureData.dataDescription.valueKeysTallSupport.indexOf(e.target.value) === -1)
258
+ ) {
259
+ updateDescriptionProp('valueKeysTallSupport', [
260
+ ...(configureData.dataDescription.valueKeysTallSupport || []),
261
+ e.target.value
262
+ ])
263
+ }
264
+ }}
265
+ >
266
+ <option value=''>Choose an option</option>
267
+ {Object.keys(configureData.data[0])
268
+ .filter(
269
+ value =>
270
+ !configureData.dataDescription.valueKeysTallSupport ||
271
+ configureData.dataDescription.valueKeysTallSupport.indexOf(value) === -1
272
+ )
273
+ .map((value, index) => (
274
+ <option value={value} key={`value-keys-option-${index}`}>
275
+ {value}
276
+ </option>
277
+ ))}
278
+ </select>
279
+ </div>
280
+ <div className='mb-2'>
281
+ <div className='mb-1'>
282
+ (Optional) Which properties in the dataset should be ignored? (will not be used or treated as
283
+ filters)
284
+ </div>
285
+ {configureData.dataDescription.ignoredKeys &&
286
+ configureData.dataDescription.ignoredKeys.length > 0 && (
287
+ <ul className='value-list'>
288
+ {configureData.dataDescription.ignoredKeys.map((ignoredKey, index) => (
289
+ <li key={`value-keys-list-${index}`}>
290
+ {ignoredKey}
291
+ <button
292
+ onClick={() => {
293
+ let newIgnoredKeys = configureData.dataDescription.ignoredKeys
294
+ newIgnoredKeys.splice(index, 1)
295
+ updateDescriptionProp('ignoredKeys', newIgnoredKeys)
296
+ }}
297
+ >
298
+ X
299
+ </button>
300
+ </li>
301
+ ))}
302
+ </ul>
303
+ )}
304
+ <select
305
+ onChange={e => {
306
+ if (e.target.value) {
307
+ updateDescriptionProp('ignoredKeys', [
308
+ ...(configureData.dataDescription.ignoredKeys || []),
309
+ e.target.value
310
+ ])
311
+ }
312
+ e.target.value = ''
313
+ }}
314
+ >
315
+ <option value=''>Choose an option</option>
316
+ {Object.keys(configureData.data[0])
317
+ .filter(
318
+ value =>
319
+ !configureData.dataDescription.ignoredKeys ||
320
+ configureData.dataDescription.ignoredKeys.indexOf(value) === -1
321
+ )
322
+ .map((value, index) => (
323
+ <option value={value} key={`ignored-keys-option-${index}`}>
324
+ {value}
325
+ </option>
326
+ ))}
327
+ </select>
328
+ </div>
329
+ </>
330
+ )}
331
+ </>
332
+ )}
278
333
 
279
334
  {config?.visualizationType === 'Forest Plot' && (
280
335
  <>
@@ -1,12 +1,20 @@
1
- .cove-component__header {
1
+ .cdc-open-viz-module header.cove-component__header {
2
2
  position: relative;
3
- padding: 0.6em 0.8em;
3
+ padding: 1rem;
4
4
  margin: 0;
5
5
  color: var(--white);
6
- font-size: 1.1em;
6
+
7
+ & > sup {
8
+ font-size: var(--superTitle-font-size);
9
+ font-family: var(--app-font-secondary);
10
+ font-weight: 500;
11
+ text-transform: uppercase;
12
+ top: 0;
13
+ }
7
14
 
8
15
  h2 {
9
- font-size: 1.1rem;
16
+ font-size: var(--title-font-size);
17
+ font-family: var(--app-font-secondary);
10
18
  color: var(--white);
11
19
  margin: 0;
12
20
  }
@@ -27,7 +35,6 @@
27
35
  }
28
36
 
29
37
  &:not(:empty) {
30
- padding: 0.6em 0.8em;
31
38
  border-bottom-width: 4px;
32
39
  border-bottom-style: solid;
33
40
  }
@@ -16,7 +16,7 @@ const Title = (props: HeaderProps) => {
16
16
  const { isDashboard, title, superTitle, classes = [], showTitle = true, ariaLevel = 2 } = props
17
17
 
18
18
  // standard classes every vis should have
19
- const updatedClasses = ['cove-component__header', 'component__header', ...classes]
19
+ const updatedClasses = ['cove-component__header', 'component__header', 'mb-3', ...classes]
20
20
 
21
21
  return (
22
22
  title &&