@cdc/core 4.24.10 → 4.24.11

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 (52) hide show
  1. package/components/AdvancedEditor/AdvancedEditor.tsx +17 -13
  2. package/components/Alert/components/Alert.tsx +34 -8
  3. package/components/DataTable/DataTable.tsx +12 -2
  4. package/components/DataTable/data-table.css +4 -22
  5. package/components/DataTable/helpers/boxplotCellMatrix.tsx +14 -13
  6. package/components/DataTable/helpers/getChartCellValue.ts +23 -5
  7. package/components/EditorPanel/ColumnsEditor.tsx +81 -36
  8. package/components/EditorPanel/DataTableEditor.tsx +33 -33
  9. package/components/EditorPanel/FieldSetWrapper.tsx +2 -2
  10. package/components/EditorPanel/Inputs.tsx +26 -16
  11. package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +30 -55
  12. package/components/Filters/Filters.tsx +12 -4
  13. package/components/Layout/components/Sidebar/components/sidebar.styles.scss +0 -4
  14. package/components/Layout/components/Visualization/visualizations.scss +1 -1
  15. package/components/Legend/Legend.Gradient.tsx +49 -34
  16. package/components/MultiSelect/MultiSelect.tsx +85 -62
  17. package/components/MultiSelect/multiselect.styles.css +10 -7
  18. package/components/NestedDropdown/NestedDropdown.tsx +40 -20
  19. package/components/NestedDropdown/nesteddropdown.styles.css +15 -13
  20. package/components/Table/Table.tsx +102 -34
  21. package/components/_stories/DataTable.stories.tsx +14 -0
  22. package/components/_stories/Filters.stories.tsx +57 -0
  23. package/components/_stories/_mocks/DataTable/no-data.json +108 -0
  24. package/components/ui/Icon.tsx +19 -6
  25. package/dist/cove-main.css +20 -54
  26. package/dist/cove-main.css.map +1 -1
  27. package/helpers/DataTransform.ts +2 -1
  28. package/helpers/cove/{number.js → number.ts} +25 -11
  29. package/helpers/fetchRemoteData.js +32 -37
  30. package/helpers/formatConfigBeforeSave.ts +1 -0
  31. package/helpers/queryStringUtils.ts +6 -0
  32. package/helpers/useDataVizClasses.ts +42 -20
  33. package/package.json +2 -2
  34. package/styles/_button-section.scss +1 -1
  35. package/styles/_global-variables.scss +3 -3
  36. package/styles/_global.scss +21 -22
  37. package/styles/_reset.scss +0 -11
  38. package/styles/filters.scss +0 -22
  39. package/styles/v2/base/_reset.scss +0 -7
  40. package/styles/v2/components/editor.scss +0 -4
  41. package/styles/v2/components/icon.scss +1 -1
  42. package/types/Axis.ts +2 -0
  43. package/types/BoxPlot.ts +5 -3
  44. package/types/Color.ts +1 -1
  45. package/types/Legend.ts +1 -2
  46. package/types/MarkupInclude.ts +1 -0
  47. package/types/Runtime.ts +3 -1
  48. package/types/Series.ts +8 -1
  49. package/types/Table.ts +1 -1
  50. package/types/Visualization.ts +7 -8
  51. package/components/ui/Select.jsx +0 -30
  52. package/helpers/getGradientLegendWidth.ts +0 -15
@@ -1,15 +1,16 @@
1
- import { useState, useEffect, useRef, useMemo } from 'react'
1
+ import { useState, useEffect, useRef, useMemo, useId } from 'react'
2
2
  import './nesteddropdown.styles.css'
3
3
  import Icon from '@cdc/core/components/ui/Icon'
4
4
  import { filterSearchTerm, NestedOptions, ValueTextPair } from './nestedDropdownHelpers'
5
5
 
6
6
  const Options: React.FC<{
7
7
  subOptions: ValueTextPair[]
8
+ filterIndex: number
8
9
  label: string
9
10
  handleSubGroupSelect: Function
10
11
  userSelectedLabel: string
11
12
  userSearchTerm: string
12
- }> = ({ subOptions, label, handleSubGroupSelect, userSelectedLabel, userSearchTerm }) => {
13
+ }> = ({ subOptions, filterIndex, label, handleSubGroupSelect, userSelectedLabel, userSearchTerm }) => {
13
14
  const [isTierOneExpanded, setIsTierOneExpanded] = useState(true)
14
15
  const checkMark = <>&#10004;</>
15
16
 
@@ -18,7 +19,7 @@ const Options: React.FC<{
18
19
  }, [userSearchTerm])
19
20
 
20
21
  const handleGroupClick = e => {
21
- const leaveExpanded = e.target.className === 'selectable-item' ? true : !isTierOneExpanded
22
+ const leaveExpanded = e.target.className === `selectable-item-${filterIndex}` ? true : !isTierOneExpanded
22
23
  setIsTierOneExpanded(leaveExpanded)
23
24
  }
24
25
 
@@ -26,10 +27,10 @@ const Options: React.FC<{
26
27
  const currentItem = e.target
27
28
  if (e.key === 'ArrowRight') setIsTierOneExpanded(true)
28
29
  else if (e.key === 'ArrowLeft') {
29
- if (currentItem.className === 'selectable-item') currentItem.parentNode.parentNode.focus()
30
+ if (currentItem.className === `selectable-item-${filterIndex}`) currentItem.parentNode.parentNode.focus()
30
31
  setIsTierOneExpanded(false)
31
32
  } else if (e.key === 'Enter') {
32
- currentItem.className === 'selectable-item'
33
+ currentItem.className === `selectable-item-${filterIndex}`
33
34
  ? handleSubGroupSelect(currentItem.dataset.value)
34
35
  : setIsTierOneExpanded(!isTierOneExpanded)
35
36
  }
@@ -44,7 +45,7 @@ const Options: React.FC<{
44
45
  aria-label={label}
45
46
  onClick={handleGroupClick}
46
47
  onKeyUp={handleKeyUp}
47
- className='nested-dropdown-group'
48
+ className={`nested-dropdown-group-${filterIndex}`}
48
49
  >
49
50
  <span className={'font-weight-bold'}>{label} </span>
50
51
  {
@@ -73,7 +74,7 @@ const Options: React.FC<{
73
74
  return (
74
75
  <li
75
76
  key={regionID}
76
- className='selectable-item'
77
+ className={`selectable-item-${filterIndex}`}
77
78
  tabIndex={0}
78
79
  role='treeitem'
79
80
  aria-label={regionID}
@@ -104,6 +105,7 @@ const Options: React.FC<{
104
105
  type NestedDropdownProps = {
105
106
  activeGroup: string
106
107
  activeSubGroup?: string
108
+ filterIndex: number
107
109
  isEditor?: boolean
108
110
  isUrlFilter?: boolean
109
111
  listLabel: string
@@ -116,9 +118,11 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
116
118
  options,
117
119
  activeGroup,
118
120
  activeSubGroup,
121
+ filterIndex,
119
122
  listLabel,
120
123
  handleSelectedItems
121
124
  }) => {
125
+ const dropdownId = useId()
122
126
  const groupFilterActive = activeGroup
123
127
  const subGroupFilterActive = activeSubGroup || ''
124
128
 
@@ -150,7 +154,7 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
150
154
  setIsListOpened(true)
151
155
  // Move focus from Input to top of dropdown
152
156
  Dropdown.firstChild.focus()
153
- } else if (className === 'selectable-item') {
157
+ } else if (className === `selectable-item-${filterIndex}`) {
154
158
  // Move focus to next item on list: next Tier Two item or the next Tier One or SearchInput
155
159
  const itemToFocusOnAfterKeyUp = nextSibling ?? parentNode.parentNode.nextSibling ?? searchInput.current
156
160
  itemToFocusOnAfterKeyUp.focus()
@@ -175,7 +179,7 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
175
179
  // Move focus to last item of the last collapsed Tier Two in dropdown
176
180
  Dropdown.lastChild.lastChild.lastChild.focus()
177
181
  }
178
- } else if (className === 'selectable-item') {
182
+ } else if (className === `selectable-item-${filterIndex}`) {
179
183
  // Move focus to previous Tier Two or Move focus to current Tier One
180
184
  const itemToFocusOnAfterKeyUp = previousSibling ?? parentNode.parentNode
181
185
  itemToFocusOnAfterKeyUp.focus()
@@ -214,7 +218,7 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
214
218
  }
215
219
  }
216
220
 
217
- const filterOptions: OptionsMemo = useMemo(() => {
221
+ const filterOptions = useMemo(() => {
218
222
  return filterSearchTerm(userSearchTerm, options)
219
223
  }, [userSearchTerm, options])
220
224
 
@@ -225,16 +229,35 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
225
229
  setInputValue(newSearchTerm)
226
230
  }
227
231
 
232
+ const handleOnBlur = e => {
233
+ if (
234
+ e.relatedTarget === null ||
235
+ ![
236
+ `nested-dropdown-${filterIndex}`,
237
+ `nested-dropdown-group-${filterIndex}`,
238
+ `selectable-item-${filterIndex}`
239
+ ].includes(e.relatedTarget.className)
240
+ ) {
241
+ setInputHasFocus(false)
242
+ setIsListOpened(false)
243
+ }
244
+ }
245
+
228
246
  return (
229
247
  <>
230
- {listLabel && <span className='edit-label column-heading'>{listLabel}</span>}
248
+ {listLabel && (
249
+ <label className='text-capitalize font-weight-bold' htmlFor={dropdownId}>
250
+ {listLabel}
251
+ </label>
252
+ )}
231
253
  <div
232
- id='nested-dropdown-container'
233
- className={`nested-dropdown ${isListOpened ? 'open-filter' : ''}`}
254
+ id={dropdownId}
255
+ className={`nested-dropdown nested-dropdown-${filterIndex} ${isListOpened ? 'open-filter' : ''}`}
234
256
  onKeyUp={handleKeyUp}
235
257
  >
236
258
  <div className='nested-dropdown-input-container' aria-label='searchInput' role='textbox'>
237
259
  <input
260
+ id={`nested-dropdown-${filterIndex}`}
238
261
  className='search-input'
239
262
  ref={searchInput}
240
263
  aria-label='searchInput'
@@ -243,19 +266,15 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
243
266
  tabIndex={0}
244
267
  value={inputValue}
245
268
  onChange={handleSearchTermChange}
246
- placeholder={'Select an Option'}
269
+ placeholder={'- Select -'}
247
270
  onClick={() => {
248
271
  if (inputHasFocus) setIsListOpened(!isListOpened)
249
272
  }}
250
273
  onFocus={() => setInputHasFocus(true)}
251
- onBlur={() => setInputHasFocus(false)}
274
+ onBlur={e => handleOnBlur(e)}
252
275
  />
253
276
  <span className='list-arrow' aria-hidden={true}>
254
- {isListOpened ? (
255
- <Icon display='caretFilledUp' alt='arrow pointing up' />
256
- ) : (
257
- <Icon display='caretFilledDown' alt='arrow pointing down' />
258
- )}
277
+ <Icon display='caretDown' />
259
278
  </span>
260
279
  </div>
261
280
  <ul
@@ -275,6 +294,7 @@ const NestedDropdown: React.FC<NestedDropdownProps> = ({
275
294
  <Options
276
295
  key={groupTextValue + '_' + index}
277
296
  subOptions={subgroup}
297
+ filterIndex={filterIndex}
278
298
  label={groupTextValue}
279
299
  handleSubGroupSelect={subGroupValue => {
280
300
  chooseSelectedSubGroup(groupValue, subGroupValue)
@@ -6,7 +6,7 @@
6
6
  }
7
7
 
8
8
  .nested-dropdown {
9
- .nested-dropdown-group {
9
+ [class^='nested-dropdown-group-'] {
10
10
  list-style: none;
11
11
  }
12
12
 
@@ -15,19 +15,19 @@
15
15
  position: relative;
16
16
  display: inline-block;
17
17
  width: 100%;
18
+ padding: 0;
18
19
  }
19
20
 
20
21
  .main-nested-dropdown-container,
21
22
  .nested-dropdown-input-container {
22
- padding: 7px 15px;
23
- background: #fff;
24
23
  border: 1px solid var(--lightGray);
25
- border-radius: 5px;
26
- width: 325px;
24
+ min-width: 200px;
27
25
  cursor: pointer;
26
+ padding: 0.375rem 0.75rem;
27
+ font-size: 1em;
28
28
  }
29
29
 
30
- .selectable-item {
30
+ [class^='selectable-item-'] {
31
31
  list-style: none;
32
32
  padding-left: 20px;
33
33
  position: relative;
@@ -45,15 +45,16 @@
45
45
  }
46
46
 
47
47
  .nested-dropdown-input-container {
48
+ display: block;
49
+ width: 100%;
50
+ border-radius: 0.25rem;
48
51
  position: relative;
49
52
  & > span.list-arrow {
53
+ color: var(--mediumGray);
50
54
  position: absolute;
51
- font-size: 10px;
52
- top: 4px;
53
- right: 12px;
54
- padding: 9px;
55
- background: #fff;
56
- pointer-events: none;
55
+ top: 9px;
56
+ right: 1px;
57
+ float: right;
57
58
  }
58
59
  }
59
60
 
@@ -62,7 +63,8 @@
62
63
  overflow-y: scroll;
63
64
  position: absolute;
64
65
  z-index: 3;
65
- width: 325px;
66
+ min-width: 200px;
67
+ background: white;
66
68
  }
67
69
 
68
70
  .hide {
@@ -4,9 +4,11 @@ import GroupRow from './components/GroupRow'
4
4
  import { CellMatrix, GroupCellMatrix } from './types/CellMatrix'
5
5
  import { RowType } from './types/RowType'
6
6
  import { PreliminaryDataItem } from '@cdc/chart/src/types/ChartConfig'
7
+ import _ from 'lodash'
7
8
 
8
9
  type TableProps = {
9
10
  childrenMatrix: CellMatrix | GroupCellMatrix
11
+ noData?: boolean
10
12
  tableName: string
11
13
  caption: string
12
14
  stickyHeader?: boolean
@@ -27,46 +29,112 @@ type TableProps = {
27
29
 
28
30
  type Position = 'sticky'
29
31
 
30
- const Table = ({ childrenMatrix, tableName, caption, stickyHeader, headContent, tableOptions, wrapColumns, hasRowType, fontSize, viewport, preliminaryData }: TableProps) => {
32
+ const Table = ({
33
+ childrenMatrix,
34
+ noData,
35
+ tableName,
36
+ caption,
37
+ stickyHeader,
38
+ headContent,
39
+ tableOptions,
40
+ wrapColumns,
41
+ hasRowType,
42
+ fontSize,
43
+ viewport,
44
+ preliminaryData
45
+ }: TableProps) => {
31
46
  const headStyle = stickyHeader ? { position: 'sticky' as Position, top: 0, zIndex: 2 } : {}
32
47
  const isGroupedMatrix = !Array.isArray(childrenMatrix)
33
48
 
34
49
  return (
35
50
  <table {...tableOptions}>
36
51
  <caption className='visually-hidden'>{caption}</caption>
37
- <thead style={headStyle}>{headContent}</thead>
38
- <tbody>
39
- {isGroupedMatrix
40
- ? Object.keys(childrenMatrix).flatMap(groupName => {
41
- let colSpan = 0
42
- const rows = childrenMatrix[groupName].map((row, i) => {
43
- colSpan = row.length
44
- const key = `${tableName}-${groupName}-row-${i}`
45
- return <Row preliminaryData={preliminaryData} key={key} rowKey={key} childRow={row} wrapColumns={wrapColumns} cellMinWidth={tableOptions.cellMinWidth} fontSize={fontSize} viewport={viewport} />
46
- })
47
- return [<GroupRow label={groupName} colSpan={colSpan} key={`${tableName}-${groupName}`} />, ...rows]
48
- })
49
- : childrenMatrix.map((childRow, i) => {
50
- let childRowCopy = [...childRow]
51
- let rowType = undefined
52
- if (hasRowType) rowType = childRowCopy.shift()
53
- const key = `${tableName}-row-${i}`
54
- if (rowType === undefined) {
55
- return <Row preliminaryData={preliminaryData} key={key} rowKey={key} childRow={childRow} wrapColumns={wrapColumns} cellMinWidth={tableOptions.cellMinWidth} fontSize={fontSize} viewport={viewport} />
56
- } else {
57
- switch (rowType) {
58
- case RowType.row_group:
59
- return <GroupRow label={childRowCopy[0]} colSpan={childRowCopy.length} key={key} />
60
- case RowType.total:
61
- return <Row preliminaryData={preliminaryData} key={key} rowKey={key} childRow={childRowCopy} isTotal={true} wrapColumns={wrapColumns} cellMinWidth={tableOptions.cellMinWidth} fontSize={fontSize} viewport={viewport} />
62
- case RowType.row_group_total:
63
- return <GroupRow label={childRowCopy[0]} colSpan={1} key={key} data={childRowCopy.slice(1)} />
64
- default:
65
- return <Row preliminaryData={preliminaryData} key={key} rowKey={key} childRow={childRowCopy} wrapColumns={wrapColumns} cellMinWidth={tableOptions.cellMinWidth} fontSize={fontSize} viewport={viewport} />
66
- }
67
- }
68
- })}
69
- </tbody>
52
+ {noData ? (
53
+ <tr>
54
+ <td className='py-5 text-center'>No Data</td>
55
+ </tr>
56
+ ) : (
57
+ <>
58
+ <thead style={headStyle}>{headContent}</thead>
59
+ <tbody>
60
+ {isGroupedMatrix
61
+ ? Object.keys(childrenMatrix).flatMap(groupName => {
62
+ let colSpan = 0
63
+ const rows = childrenMatrix[groupName].map((row, i) => {
64
+ colSpan = row.length
65
+ const key = `${tableName}-${groupName}-row-${i}`
66
+ return (
67
+ <Row
68
+ preliminaryData={preliminaryData}
69
+ key={key}
70
+ rowKey={key}
71
+ childRow={row}
72
+ wrapColumns={wrapColumns}
73
+ cellMinWidth={tableOptions.cellMinWidth}
74
+ fontSize={fontSize}
75
+ viewport={viewport}
76
+ />
77
+ )
78
+ })
79
+ return [<GroupRow label={groupName} colSpan={colSpan} key={`${tableName}-${groupName}`} />, ...rows]
80
+ })
81
+ : childrenMatrix.map((childRow, i) => {
82
+ let childRowCopy = [...childRow]
83
+ let rowType = undefined
84
+ if (hasRowType) rowType = childRowCopy.shift()
85
+ const key = `${tableName}-row-${i}`
86
+ if (rowType === undefined) {
87
+ return (
88
+ <Row
89
+ preliminaryData={preliminaryData}
90
+ key={key}
91
+ rowKey={key}
92
+ childRow={childRow}
93
+ wrapColumns={wrapColumns}
94
+ cellMinWidth={tableOptions.cellMinWidth}
95
+ fontSize={fontSize}
96
+ viewport={viewport}
97
+ />
98
+ )
99
+ } else {
100
+ switch (rowType) {
101
+ case RowType.row_group:
102
+ return <GroupRow label={childRowCopy[0]} colSpan={childRowCopy.length} key={key} />
103
+ case RowType.total:
104
+ return (
105
+ <Row
106
+ preliminaryData={preliminaryData}
107
+ key={key}
108
+ rowKey={key}
109
+ childRow={childRowCopy}
110
+ isTotal={true}
111
+ wrapColumns={wrapColumns}
112
+ cellMinWidth={tableOptions.cellMinWidth}
113
+ fontSize={fontSize}
114
+ viewport={viewport}
115
+ />
116
+ )
117
+ case RowType.row_group_total:
118
+ return <GroupRow label={childRowCopy[0]} colSpan={1} key={key} data={childRowCopy.slice(1)} />
119
+ default:
120
+ return (
121
+ <Row
122
+ preliminaryData={preliminaryData}
123
+ key={key}
124
+ rowKey={key}
125
+ childRow={childRowCopy}
126
+ wrapColumns={wrapColumns}
127
+ cellMinWidth={tableOptions.cellMinWidth}
128
+ fontSize={fontSize}
129
+ viewport={viewport}
130
+ />
131
+ )
132
+ }
133
+ }
134
+ })}
135
+ </tbody>
136
+ </>
137
+ )}
70
138
  </table>
71
139
  )
72
140
  }
@@ -2,6 +2,7 @@ import { Meta, StoryObj } from '@storybook/react'
2
2
 
3
3
  import DataTable from '../DataTable'
4
4
  import './styles.scss'
5
+ import NoDataConfig from './_mocks/DataTable/no-data.json'
5
6
  import Example_1 from './_mocks/dashboard_no_filter.json'
6
7
  import CityStateExample from './_mocks/example-city-state.json'
7
8
  import { displayGeoName } from '@cdc/map/src/helpers/displayGeoName'
@@ -62,6 +63,19 @@ export const Grouped: Story = {
62
63
  }
63
64
  }
64
65
 
66
+ const noDataData = NoDataConfig.datasets['dev-8931-hide-markup-include.csv'].data
67
+ export const NoData: Story = {
68
+ args: {
69
+ config: NoDataConfig,
70
+ dataConfig: { data: noDataData },
71
+ rawData: noDataData,
72
+ runtimeData: noDataData,
73
+ expandDataTable: true,
74
+ tableTitle: 'No Data Table',
75
+ viewport: 'lg',
76
+ tabbingId: '#asdf'
77
+ }
78
+ }
65
79
  export const RowType: Story = {
66
80
  args: {
67
81
  config: {
@@ -0,0 +1,57 @@
1
+ import { Meta, StoryObj } from '@storybook/react'
2
+
3
+ import Filters from '../Filters'
4
+ import { VizFilter } from '../../types/VizFilter'
5
+ import { faker } from '@faker-js/faker'
6
+ import _ from 'lodash'
7
+ import { Visualization } from '../../types/Visualization'
8
+
9
+ const meta: Meta<typeof Filters> = {
10
+ title: 'Components/Molecules/Visualization Filters',
11
+ component: Filters
12
+ }
13
+
14
+ type Story = StoryObj<typeof Filters>
15
+
16
+ faker.seed(123)
17
+
18
+ const animalData = _.times(7, () => ({ bear: faker.animal.bear(), cat: faker.animal.cat(), cow: faker.animal.cow() }))
19
+ const generateFilters = filterStyle => {
20
+ return ['bear', 'cat', 'cow'].map(columnName => {
21
+ return {
22
+ filterStyle,
23
+ label: columnName.toUpperCase(),
24
+ columnName
25
+ } as VizFilter
26
+ })
27
+ }
28
+
29
+ const generateConfig = filterStyle =>
30
+ ({
31
+ args: {
32
+ config: {
33
+ filters: generateFilters(filterStyle),
34
+ data: animalData
35
+ } as Visualization,
36
+ filteredData: animalData,
37
+ setFilteredData: () => {},
38
+ setConfig: () => {},
39
+ exclusions: []
40
+ }
41
+ } as Story)
42
+
43
+ export const Dropdown: Story = generateConfig('dropdown')
44
+
45
+ export const DropdownBar: Story = generateConfig('dropdown bar')
46
+
47
+ export const MultiSelect: Story = generateConfig('multi-select')
48
+
49
+ export const NestedDropdown: Story = generateConfig('nested-dropdown')
50
+
51
+ export const Pill: Story = generateConfig('pill')
52
+
53
+ export const Tab: Story = generateConfig('tab')
54
+
55
+ export const TabBar: Story = generateConfig('tab bar')
56
+
57
+ export default meta
@@ -0,0 +1,108 @@
1
+ {
2
+ "dashboard": {
3
+ "theme": "theme-blue",
4
+ "sharedFilters": []
5
+ },
6
+ "rows": [
7
+ {
8
+ "columns": [
9
+ {
10
+ "width": 12,
11
+ "widget": "table1730380781112"
12
+ }
13
+ ],
14
+ "uuid": 1730380998726
15
+ }
16
+ ],
17
+ "visualizations": {
18
+ "table1730380781112": {
19
+ "filters": [],
20
+ "filterBehavior": "Filter Change",
21
+ "newViz": false,
22
+ "openModal": true,
23
+ "uid": "table1730380781112",
24
+ "type": "table",
25
+ "table": {
26
+ "label": "Data Table",
27
+ "show": true,
28
+ "showDownloadUrl": false,
29
+ "showVertical": true,
30
+ "expanded": true,
31
+ "collapsible": true
32
+ },
33
+ "columns": {
34
+ "additionalColumn1": {
35
+ "label": "New Column",
36
+ "dataTable": true,
37
+ "tooltips": false,
38
+ "prefix": "",
39
+ "suffix": "",
40
+ "forestPlot": false,
41
+ "startingPoint": "0",
42
+ "forestPlotAlignRight": false,
43
+ "roundToPlace": 0,
44
+ "commas": false,
45
+ "showInViz": false,
46
+ "forestPlotStartingPoint": 0
47
+ },
48
+ "Class": {
49
+ "name": "Class",
50
+ "dataTable": false
51
+ },
52
+ "Data_Type": {
53
+ "name": "Data_Type",
54
+ "dataTable": false
55
+ },
56
+ "Question": {
57
+ "name": "Question",
58
+ "dataTable": false
59
+ },
60
+ "Response": {
61
+ "name": "Response",
62
+ "dataTable": false
63
+ },
64
+ "Topic": {
65
+ "name": "Topic",
66
+ "dataTable": false
67
+ }
68
+ },
69
+ "dataFormat": {},
70
+ "visualizationType": "table",
71
+ "dataDescription": {
72
+ "horizontal": false,
73
+ "series": false
74
+ },
75
+ "dataKey": "dev-8931-hide-markup-include.csv"
76
+ }
77
+ },
78
+ "table": {
79
+ "label": "Data Table",
80
+ "show": true,
81
+ "showDownloadUrl": false,
82
+ "showDownloadLinkBelow": true,
83
+ "showVertical": true
84
+ },
85
+ "newViz": true,
86
+ "datasets": {
87
+ "dev-8931-hide-markup-include.csv": {
88
+ "data": [],
89
+ "dataFileSize": 10023,
90
+ "dataFileName": "dev-8931-hide-markup-include.csv",
91
+ "dataFileSourceType": "file",
92
+ "dataFileFormat": "CSV",
93
+ "preview": true
94
+ }
95
+ },
96
+ "isResponsiveTicks": false,
97
+ "type": "dashboard",
98
+ "barThickness": "0.37",
99
+ "xAxis": {
100
+ "type": "categorical",
101
+ "size": 75,
102
+ "maxTickRotation": 45,
103
+ "labelOffset": 0
104
+ },
105
+ "runtime": {},
106
+ "version": "4.24.10",
107
+ "uuid": 1730380778769
108
+ }
@@ -88,15 +88,24 @@ type IconProps = {
88
88
  /* Returns icon data as plain svg */
89
89
  base?: boolean
90
90
  /* Sets alt text for the icon */
91
- alt: string
91
+ alt?: string
92
92
  /* Override the width of the icon (scales height proportionally)*/
93
93
  size?: number
94
94
  /* Override the color of the icon */
95
95
  color?: string
96
- style?: string
96
+ style?: object
97
+ className?: string // className attribute will be ignored.
97
98
  }
98
99
 
99
- const Icon: React.FC<IconProps> = ({ display = '', base = undefined, alt = '', size = undefined, color = undefined, style = undefined, ...attributes }) => {
100
+ const Icon: React.FC<IconProps> = ({
101
+ display = '',
102
+ base = undefined,
103
+ alt = '',
104
+ size = undefined,
105
+ color = undefined,
106
+ style = undefined,
107
+ ...attributes
108
+ }) => {
100
109
  const IconObj = iconHash[display] || null
101
110
 
102
111
  const filteredAttrs = { ...attributes }
@@ -112,10 +121,14 @@ const Icon: React.FC<IconProps> = ({ display = '', base = undefined, alt = '', s
112
121
  return (
113
122
  <>
114
123
  {base ? (
115
- <IconObj title={alt} />
124
+ <IconObj title={alt || display} />
116
125
  ) : (
117
- <span className={`cove-icon${attributes.className ? ' ' + attributes.className : ''}`} style={styles} {...filteredAttrs}>
118
- <IconObj title={alt} />
126
+ <span
127
+ className={`cove-icon${attributes.className ? ' ' + attributes.className : ''}`}
128
+ style={styles}
129
+ {...filteredAttrs}
130
+ >
131
+ <IconObj title={alt || display} />
119
132
  </span>
120
133
  )}
121
134
  </>