@cdc/core 1.1.4 → 9.22.9

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 (115) hide show
  1. package/LICENSE +201 -0
  2. package/assets/filtered-text.svg +1 -0
  3. package/assets/icon-caret-down.svg +3 -0
  4. package/assets/icon-caret-filled-down.svg +3 -0
  5. package/assets/icon-caret-filled-up.svg +3 -0
  6. package/assets/icon-caret-up.svg +3 -0
  7. package/assets/icon-chart-bar-paired.svg +15 -0
  8. package/assets/icon-chart-bar-stacked.svg +10 -0
  9. package/assets/icon-chart-bar.svg +3 -0
  10. package/assets/icon-chart-line.svg +3 -0
  11. package/assets/icon-chart-pie.svg +3 -0
  12. package/assets/icon-check.svg +3 -0
  13. package/assets/icon-close.svg +3 -1
  14. package/assets/icon-code.svg +2 -2
  15. package/assets/icon-dashboard.svg +34 -0
  16. package/assets/icon-databite.svg +3 -0
  17. package/assets/icon-edit.svg +3 -0
  18. package/assets/icon-file-upload.svg +3 -0
  19. package/assets/icon-filter-bars.svg +5 -0
  20. package/assets/icon-gear.svg +6 -0
  21. package/assets/icon-grid.svg +2 -3
  22. package/assets/icon-info.svg +1 -1
  23. package/assets/icon-link.svg +3 -0
  24. package/assets/{alabama-graphic.svg → icon-map-alabama.svg} +2 -2
  25. package/assets/icon-map-usa.svg +3 -0
  26. package/assets/icon-map-world.svg +3 -0
  27. package/assets/icon-minus.svg +3 -0
  28. package/assets/icon-move.svg +8 -0
  29. package/assets/icon-plus.svg +3 -0
  30. package/assets/icon-question-circle.svg +3 -0
  31. package/assets/icon-tools.svg +8 -0
  32. package/assets/icon-upload.svg +3 -0
  33. package/assets/icon-warning-circle.svg +3 -0
  34. package/assets/{icon-warning.svg → icon-warning-triangle.svg} +1 -1
  35. package/components/AdvancedEditor.js +1 -1
  36. package/components/{ErrorBoundary.js → ErrorBoundary.jsx} +0 -0
  37. package/components/{LegendCircle.js → LegendCircle.jsx} +0 -0
  38. package/components/{Loading.js → Loading.jsx} +0 -0
  39. package/components/{Waiting.js → Waiting.jsx} +0 -0
  40. package/components/elements/Button.jsx +122 -3
  41. package/components/elements/Card.jsx +13 -0
  42. package/components/inputs/InputCheckbox.jsx +11 -3
  43. package/components/inputs/InputGroup.jsx +50 -0
  44. package/components/inputs/InputSelect.jsx +2 -2
  45. package/components/inputs/InputText.jsx +17 -18
  46. package/components/inputs/InputToggle.jsx +18 -18
  47. package/components/managers/DataDesigner.jsx +171 -0
  48. package/components/ui/Icon.jsx +50 -12
  49. package/components/ui/LoadSpin.jsx +24 -0
  50. package/components/ui/Modal.jsx +7 -2
  51. package/components/ui/Overlay.jsx +3 -1
  52. package/components/ui/Tooltip.jsx +18 -9
  53. package/data/colorPalettes.js +170 -124
  54. package/data/dataDesignerTables.js +148 -0
  55. package/{components → helpers}/DataTransform.js +3 -3
  56. package/helpers/fetchRemoteData.js +43 -0
  57. package/package.json +3 -2
  58. package/styles/_data-table.scss +13 -13
  59. package/styles/_global.scss +14 -0
  60. package/styles/_reset.scss +11 -1
  61. package/styles/base.scss +17 -1
  62. package/styles/v2/base/_file-selector.scss +20 -0
  63. package/styles/v2/base/_general.scss +9 -22
  64. package/styles/v2/base/_heading.scss +20 -0
  65. package/styles/v2/base/_reset.scss +2 -1
  66. package/styles/v2/base/index.scss +5 -1
  67. package/styles/v2/components/button.scss +27 -66
  68. package/styles/v2/components/card.scss +7 -0
  69. package/styles/v2/components/data-designer.scss +100 -0
  70. package/styles/v2/components/editor.scss +2 -1
  71. package/styles/v2/components/guidance-block.scss +74 -0
  72. package/styles/v2/components/icon.scss +0 -4
  73. package/styles/v2/components/input/_input-check-radio.scss +97 -0
  74. package/styles/v2/components/input/_input-group.scss +74 -0
  75. package/styles/v2/components/input/_input-slider.scss +184 -0
  76. package/styles/v2/components/input/_input.scss +66 -0
  77. package/styles/v2/components/input/index.scss +7 -0
  78. package/styles/v2/components/loadspin.scss +100 -0
  79. package/styles/v2/components/modal.scss +13 -6
  80. package/styles/v2/components/overlay.scss +2 -0
  81. package/styles/v2/layout/_alert.scss +11 -10
  82. package/styles/v2/layout/_component.scss +8 -1
  83. package/styles/v2/layout/_data-table.scss +71 -150
  84. package/styles/v2/layout/_progression.scss +4 -2
  85. package/styles/v2/layout/index.scss +0 -2
  86. package/styles/v2/main.scss +52 -2
  87. package/styles/v2/themes/_color-definitions.scss +31 -1
  88. package/styles/v2/utils/_align.scss +17 -0
  89. package/styles/v2/utils/_breakpoints.scss +18 -0
  90. package/styles/v2/utils/_grid.scss +47 -0
  91. package/styles/v2/utils/_mixins.scss +0 -16
  92. package/styles/v2/utils/_spacers.scss +31 -0
  93. package/styles/v2/utils/_variables.scss +7 -0
  94. package/styles/v2/utils/index.scss +7 -2
  95. package/assets/asc.svg +0 -1
  96. package/assets/chart-bar-solid.svg +0 -1
  97. package/assets/chart-line-solid.svg +0 -1
  98. package/assets/chart-pie-solid.svg +0 -1
  99. package/assets/check.svg +0 -3
  100. package/assets/dashboard.svg +0 -11
  101. package/assets/data-bite-graphic.svg +0 -3
  102. package/assets/desc.svg +0 -1
  103. package/assets/file-upload-solid.svg +0 -1
  104. package/assets/horizontal-stacked-bar.svg +0 -1
  105. package/assets/link.svg +0 -1
  106. package/assets/minus.svg +0 -1
  107. package/assets/paired-bar.svg +0 -11
  108. package/assets/plus.svg +0 -1
  109. package/assets/question-circle.svg +0 -1
  110. package/assets/upload-solid.svg +0 -1
  111. package/assets/usa-graphic.svg +0 -3
  112. package/assets/world-graphic.svg +0 -3
  113. package/styles/v2/components/input.scss +0 -372
  114. package/styles/v2/layout/_header.scss +0 -13
  115. package/styles/v2/layout/_link.scss +0 -46
@@ -1,12 +1,131 @@
1
- import React from 'react'
1
+ import React, { useState, useEffect, useRef } from 'react'
2
+ import PropTypes from 'prop-types'
3
+
4
+ import LoadSpin from '../ui/LoadSpin'
2
5
 
3
6
  import '../../styles/v2/components/button.scss'
4
7
 
5
- const Button = ({fluid, children, onClick, className, ...attributes}) => {
8
+ const Button = ({
9
+ style,
10
+ role,
11
+ hoverStyle = {},
12
+ fluid = false,
13
+ loading = false,
14
+ loadingText = "Loading...",
15
+ flexCenter,
16
+ active = false,
17
+ onClick,
18
+ children, ...attributes
19
+ }) => {
20
+
21
+ const buttonRef = useRef(null)
22
+
23
+ const [ buttonState, setButtonState ] = useState('out')
24
+ const [ customStyles, setCustomStyles ] = useState({ ...style })
25
+ const [ childrenWidth, setChildrenWidth ] = useState()
26
+ const [ loadtextWidth, setLoadtextWidth ] = useState()
27
+
28
+ const attributesObj = {
29
+ ...attributes,
30
+ style: customStyles,
31
+ className:
32
+ 'cove-button' +
33
+ (flexCenter || 'loader' === role ? ' cove-button--flex-center' : '') +
34
+ (fluid ? ' fluid' : '') +
35
+ (loading ? ' loading' : '') +
36
+ (attributes.className ? ' ' + attributes.className : ''),
37
+ onMouseOver: () => setButtonState('in'),
38
+ onMouseOut: () => setButtonState('out'),
39
+ onFocus: () => setButtonState('in'),
40
+ onBlur: () => setButtonState('out')
41
+ }
42
+
43
+ useEffect(() => {
44
+ if ('loader' === role && buttonRef.current) {
45
+ //Create ghost object and text nodes for children
46
+ const ghostSpan = document.createElement('span')
47
+ const ghostContent = document.createTextNode(children)
48
+ ghostSpan.style.opacity = '0'
49
+ ghostSpan.style.visibility = 'hidden'
50
+
51
+ //Create ghost object and text nodes for loading value
52
+ const ghostLoaderSpan = document.createElement('span')
53
+ const ghostLoaderContent = document.createTextNode(loadingText)
54
+ ghostLoaderSpan.style.opacity = '0'
55
+ ghostLoaderSpan.style.visibility = 'hidden'
56
+
57
+ //Append data to ghost objects
58
+ ghostSpan.appendChild(ghostContent)
59
+ ghostLoaderSpan.appendChild(ghostLoaderContent)
60
+
61
+ //Append objects to document
62
+ buttonRef.current.parentNode.insertBefore(ghostSpan, buttonRef.current)
63
+ buttonRef.current.parentNode.insertBefore(ghostLoaderSpan, buttonRef.current)
64
+
65
+ //Register ghost width values in state
66
+ setChildrenWidth(ghostSpan.offsetWidth + 2) //Toss in a 2px to account for subpixel offset
67
+ setLoadtextWidth(ghostLoaderSpan.offsetWidth + 2) //Toss in a 2px to account for subpixel offset
68
+
69
+ //Remove ghost objects form document
70
+ buttonRef.current.parentNode.removeChild(ghostSpan)
71
+ buttonRef.current.parentNode.removeChild(ghostLoaderSpan)
72
+ }
73
+ }, [])
74
+
75
+ useEffect(() => {
76
+ //Adjust button styles depending on cursor, focus, and active, states
77
+ return buttonState === 'in'
78
+ ? setCustomStyles(stateStyles => ({ ...stateStyles, ...hoverStyle }))
79
+ : buttonState === 'out'
80
+ ? active //If button state is out, check if its 'active'; we want to keep hover styles applied to 'active' buttons
81
+ ? null //Button is active, so leave the 'hover' styles in place
82
+ : setCustomStyles({ ...style }) //Button is not 'active', so reset display styles back to default
83
+ : false //Button state is neither 'in' nor 'out' - do nothing
84
+ }, [ buttonState, active ])
6
85
 
7
86
  return (
8
- <button className={`cove-button${fluid ? ' fluid' : ''}${className ? className : ''}`} {...attributes} onClick={(e) => {e.preventDefault(); onClick();}}>{children}</button>
87
+ <button {...attributesObj}
88
+ onClick={(e) => {
89
+ e.preventDefault()
90
+ return loading || onClick()
91
+ }}
92
+ disabled={loading || attributesObj.disabled}
93
+ ref={buttonRef}>
94
+ {children &&
95
+ <>
96
+ {'loader' === role &&
97
+ <>
98
+ <span className="cove-button__text" style={loading ? { width: loadtextWidth + 'px' } : { width: childrenWidth + 'px' }}>
99
+ <div className="cove-button__text--loading" style={loading ? { opacity: 1 } : null}>{loadingText}</div>
100
+ <div className="cove-button__text--children" style={loading ? { opacity: 0 } : null}>{children}</div>
101
+ </span>
102
+ <div className="cove-button__load-spin" style={loading ? { width: '28px', opacity: 1 } : null}>
103
+ <LoadSpin className="ml-1" size={20}/>
104
+ </div>
105
+ </>
106
+ }
107
+ {role !== 'loader' && children}
108
+ </>
109
+ }
110
+ </button>
9
111
  )
10
112
  }
11
113
 
114
+ Button.propTypes = {
115
+ /** Specify special role type for button */
116
+ role: PropTypes.oneOf([ 'loader' ]),
117
+ /** Provide object with styles that overwrite base styles when hovered */
118
+ hoverStyle: PropTypes.object,
119
+ /** Enables button to stretch to the full width of the content */
120
+ fluid: PropTypes.bool,
121
+ /** Displays loading spinner on button while condition is true **/
122
+ loading: PropTypes.bool,
123
+ /** Set text to appear during loading animation **/
124
+ loadingText: PropTypes.string,
125
+ /** Displays button as flex and centers all direct children nodes. Useful for aligning icons and text **/
126
+ flexCenter: PropTypes.bool,
127
+ /** When value condition is true, retains any custom, inline `style={}` defined **/
128
+ active: PropTypes.bool
129
+ }
130
+
12
131
  export default Button
@@ -0,0 +1,13 @@
1
+ import React from 'react'
2
+
3
+ import '../../styles/v2/components/card.scss'
4
+
5
+ const Card = ({children, className, ...attributes}) => {
6
+ return (
7
+ <div className={`cove-card${className ? ' ' + className : ''}`} {...attributes}>
8
+ {children}
9
+ </div>
10
+ )
11
+ }
12
+
13
+ export default Card
@@ -1,12 +1,13 @@
1
1
  import React, { useState, useEffect, memo } from 'react'
2
+ import PropTypes from 'prop-types'
2
3
 
3
- import Check from '../../assets/check.svg'
4
- import '../../styles/v2/components/input.scss'
4
+ import Check from '../../assets/icon-check.svg'
5
+ import '../../styles/v2/components/input/index.scss'
5
6
 
6
7
  const InputCheckbox = memo((
7
8
  {
8
9
  label,
9
- size = 'medium',
10
+ size = 'small',
10
11
  activeColor = null,
11
12
  activeCheckColor = null,
12
13
  section = null,
@@ -56,4 +57,11 @@ const InputCheckbox = memo((
56
57
  )
57
58
  })
58
59
 
60
+ InputCheckbox.propTypes = {
61
+ label: PropTypes.string,
62
+ size: PropTypes.oneOf(['small', 'medium', 'large']),
63
+ activeColor: PropTypes.string,
64
+ activeCheckColor: PropTypes.string
65
+ }
66
+
59
67
  export default InputCheckbox
@@ -0,0 +1,50 @@
1
+ import React, { useState, useEffect, useLayoutEffect, useRef } from 'react'
2
+ import PropTypes from 'prop-types'
3
+
4
+ const InputGroup = ({ label, flow, children, clear, className, style, ...attributes }) => {
5
+ const [ styles, setStyles ] = useState({})
6
+ const [ labelWidth, setLabelWidth ] = useState(null)
7
+
8
+ const groupLabelRef = useRef(null)
9
+ const groupLabel = <div className="cove-input-group__label" ref={groupLabelRef}>{label}</div>
10
+
11
+ useLayoutEffect(() => {
12
+ if (!clear) return
13
+ if (!groupLabelRef.current) return
14
+ setLabelWidth(groupLabelRef.current.offsetWidth)
15
+ }, [ clear, groupLabelRef ])
16
+
17
+ useLayoutEffect(() => {
18
+ if (!clear) return
19
+ if ('left' === flow) {
20
+ setStyles(() => ({ paddingLeft: labelWidth + 'px' }))
21
+ }
22
+ if ('right' === flow) {
23
+ setStyles(() => ({ paddingRight: labelWidth + 'px' }))
24
+ }
25
+ }, [ clear, flow, labelWidth ])
26
+
27
+
28
+ return (
29
+ <div className={`cove-input-group${clear ? ' clear' : ''}${className ? ' ' + className : ''}`} flow={flow} {...attributes}>
30
+ {label && flow ? <>
31
+ {'left' === flow && <> {groupLabel}{children} </>}
32
+ {'right' === flow && <> {children}{groupLabel} </>}
33
+ {'center' === flow && children.length > 1 && <> {children[0]}{groupLabel}{children[1]} </>}
34
+ </> :
35
+ children
36
+ }
37
+ </div>
38
+ )
39
+ }
40
+
41
+ InputGroup.propTypes = {
42
+ /* Text to display for the input group */
43
+ label: PropTypes.oneOfType([
44
+ PropTypes.string,
45
+ PropTypes.object
46
+ ]),
47
+ flow: PropTypes.oneOf([ 'left', 'center', 'right' ])
48
+ }
49
+
50
+ export default InputGroup
@@ -1,6 +1,6 @@
1
1
  import React, { memo } from 'react'
2
2
 
3
- import '../../styles/v2/components/input.scss'
3
+ import '../../styles/v2/components/input/index.scss'
4
4
 
5
5
  const InputSelect = memo((
6
6
  {
@@ -36,7 +36,7 @@ const InputSelect = memo((
36
36
 
37
37
  return (
38
38
  <label>
39
- {label && <span className="edit-label">{label}</span>}
39
+ {label && <span className="edit-label cove-input__label">{label}</span>}
40
40
  <select className={required && !value ? 'warning' : ''} name={fieldName} value={value} onChange={(event) => {
41
41
  updateField(section, subsection, fieldName, event.target.value)
42
42
  }} {...attributes}>
@@ -1,7 +1,7 @@
1
1
  import React, { useState, useEffect, memo } from 'react'
2
2
  import { useDebounce } from 'use-debounce'
3
3
 
4
- import '../../styles/v2/components/input.scss'
4
+ import '../../styles/v2/components/input/index.scss'
5
5
 
6
6
  const InputText = memo((
7
7
  {
@@ -13,8 +13,9 @@ const InputText = memo((
13
13
  value: stateValue,
14
14
  type = 'input',
15
15
  tooltip,
16
+ placeholder,
16
17
  i = null, min = null, max = null,
17
- ...attributes
18
+ className, ...attributes
18
19
  }
19
20
  ) => {
20
21
 
@@ -41,27 +42,25 @@ const InputText = memo((
41
42
  }
42
43
  }
43
44
 
44
- let formElement = <input type="text" name={name} onChange={onChange} {...attributes} value={value}/>
45
-
46
- if ('textarea' === type) {
47
- formElement = (
48
- <textarea name={name} onChange={onChange} {...attributes} value={value}/>
49
- )
45
+ let inputAttrs = {
46
+ className: `cove-input${className ? ' ' + className : ''}`,
47
+ type,
48
+ name,
49
+ placeholder,
50
+ onChange,
51
+ value,
52
+ ...attributes
50
53
  }
51
54
 
52
- if ('number' === type) {
53
- formElement = <input type="number" name={name} onChange={onChange} {...attributes} value={value}/>
54
- }
55
+ let formElement = 'textarea' === type
56
+ ? (<textarea {...inputAttrs}/>)
57
+ : (<input {...inputAttrs}/>)
55
58
 
56
59
  return (
57
- <div className="cove-input-group">
58
- {label &&
59
- <>
60
- <label>{label}{tooltip}</label>
61
- </>
62
- }
60
+ <>
61
+ {label && <label className="cove-input__label">{label}</label>}{tooltip}
63
62
  {formElement}
64
- </div>
63
+ </>
65
64
  )
66
65
  })
67
66
 
@@ -1,12 +1,12 @@
1
1
  import React, { useState, useEffect } from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
 
4
- import '../../styles/v2/components/input.scss'
4
+ import '../../styles/v2/components/input/index.scss'
5
5
 
6
- const InputToggle = (
6
+ const InputSlider = (
7
7
  {
8
8
  label,
9
- toggleType = 'flat',
9
+ sliderType = 'flat',
10
10
  size = 'medium',
11
11
  activeColor = null,
12
12
  section = null,
@@ -33,14 +33,14 @@ const InputToggle = (
33
33
  return str
34
34
  }
35
35
 
36
- const toggleTypeClass = () => {
36
+ const sliderTypeClass = () => {
37
37
  const typeArr = {
38
- 'flat': ' toggle--flat',
39
- 'block': ' toggle--block',
40
- 'pill': ' toggle--pill',
41
- '3d': ' toggle--3d'
38
+ 'flat': ' slider--flat',
39
+ 'block': ' slider--block',
40
+ 'pill': ' slider--pill',
41
+ '3d': ' slider--3d'
42
42
  }
43
- return typeArr[toggleType] || ''
43
+ return typeArr[sliderType] || ''
44
44
  }
45
45
 
46
46
  useEffect(() => {
@@ -58,23 +58,23 @@ const InputToggle = (
58
58
  return (
59
59
  <div className="input-group">
60
60
  {label && <label>{label}</label>}
61
- <div className={'cove-input__toggle' + (size === 'small' ? '--small' : size === 'large' ? '--large' : '') + (toggleTypeClass()) + (value ? ' active' : '')} onClick={() => setValue(!value)}>
62
- <div className="cove-input__toggle-button"/>
63
- <div className="cove-input__toggle-track" style={value && activeColor ? { backgroundColor: activeColor } : null }/>
61
+ <div className={'cove-input__slider' + (size === 'small' ? '--small' : size === 'large' ? '--large' : '') + (sliderTypeClass()) + (value ? ' active' : '')} onClick={() => setValue(!value)}>
62
+ <div className="cove-input__slider-button"/>
63
+ <div className="cove-input__slider-track" style={value && activeColor ? { backgroundColor: activeColor } : null }/>
64
64
  <input className="cove-input--hidden" type="checkbox" name={name()} checked={value || false} readOnly/>
65
65
  </div>
66
66
  </div>
67
67
  )
68
68
  }
69
69
 
70
- InputToggle.propTypes = {
70
+ InputSlider.propTypes = {
71
71
  /** Add label to the input field */
72
72
  label: PropTypes.string,
73
- /** Select the preferred display style of the toggle slider */
74
- toggleType: PropTypes.oneOf(['flat', 'block', 'pill', '3d']),
75
- /** Select the preferred size of the toggle slider */
73
+ /** Select the preferred display style of the slider */
74
+ sliderType: PropTypes.oneOf(['flat', 'block', 'pill', '3d']),
75
+ /** Select the preferred size of the slider */
76
76
  size: PropTypes.oneOf(['small', 'medium', 'large']),
77
- /** Select the preferred color for the toggle slider when active */
77
+ /** Select the preferred color for the slider when active */
78
78
  activeColor: PropTypes.string,
79
79
  /** Parent key value of nested target config option
80
80
  *
@@ -92,4 +92,4 @@ InputToggle.propTypes = {
92
92
  stateValue: PropTypes.object
93
93
  }
94
94
 
95
- export default InputToggle
95
+ export default InputSlider
@@ -0,0 +1,171 @@
1
+ import React from 'react'
2
+
3
+ import Button from '../elements/Button'
4
+ import Card from '../elements/Card'
5
+
6
+ import { DATA_TABLE_VERTICAL, DATA_TABLE_HORIZONTAL, DATA_TABLE_SINGLE_ROW, DATA_TABLE_MULTI_ROW } from '../../data/dataDesignerTables'
7
+ import '../../styles/v2/components/data-designer.scss'
8
+
9
+ const DataDesigner = (props) => {
10
+ const { configureData, updateDescriptionProp, visualizationKey, dataKey } = props;
11
+
12
+ return (
13
+ <div className="cove-data-designer__container">
14
+ <div className="mb-2">
15
+ <div className="cove-heading--3 fw-bold mb-1">Describe Data</div>
16
+ <div className="cove-heading--3 fw-normal mb-1">Data Orientation</div>
17
+ <div className="grid grid-gap-2 mb-4">
18
+ <div className="column">
19
+ <button
20
+ className={'cove-data-designer__button' + (configureData.dataDescription && configureData.dataDescription.horizontal === false ? ' active' : '')}
21
+ onClick={() => {
22
+ updateDescriptionProp(visualizationKey, dataKey, 'horizontal', false)
23
+ }}>
24
+ <Card>
25
+ <strong className="cove-heading--3">Vertical</strong>
26
+ <p className="mb-1">Values for map geography or chart date/category axis are contained in a
27
+ single <em>column</em>.
28
+ </p>
29
+ {DATA_TABLE_VERTICAL}
30
+ </Card>
31
+ </button>
32
+ </div>
33
+ <div className="column">
34
+ <button
35
+ className={'cove-data-designer__button' + (configureData.dataDescription && configureData.dataDescription.horizontal === true ? ' active' : '')}
36
+ onClick={() => {
37
+ updateDescriptionProp(visualizationKey, dataKey, 'horizontal', true)
38
+ }}>
39
+ <Card>
40
+ <strong className="cove-heading--3">Horizontal</strong>
41
+ <p className="mb-1">Values for map geography or chart date/category axis are contained in a single <em>row</em>
42
+ </p>
43
+ {DATA_TABLE_HORIZONTAL}
44
+ </Card>
45
+ </button>
46
+ </div>
47
+ </div>
48
+ </div>
49
+ {configureData.dataDescription && (
50
+ <>
51
+ <div className="mb-2">
52
+ <div className="mb-1">Are there multiple series represented in your data?</div>
53
+ <div>
54
+ <Button
55
+ style={{ backgroundColor: '#00345d' }}
56
+ hoverStyle={{ backgroundColor: '#015daa' }}
57
+ className="mr-1"
58
+ onClick={() => {
59
+ updateDescriptionProp(visualizationKey, dataKey, 'series', true)
60
+ }}
61
+ active={configureData.dataDescription.series === true}
62
+ >
63
+ Yes
64
+ </Button>
65
+ <Button
66
+ style={{ backgroundColor: '#00345d' }}
67
+ hoverStyle={{ backgroundColor: '#015daa' }}
68
+ onClick={() => {
69
+ updateDescriptionProp(visualizationKey, dataKey, 'series', false)
70
+ }}
71
+ active={configureData.dataDescription.series === false}
72
+ >
73
+ No
74
+ </Button>
75
+ </div>
76
+ </div>
77
+ {configureData.dataDescription.horizontal === true && configureData.dataDescription.series === true && (
78
+ <div className="mb-2">
79
+ <div className="mb-1">Which property in the dataset represents which series the row is describing?</div>
80
+ <select onChange={(e) => {
81
+ updateDescriptionProp(visualizationKey, dataKey, 'seriesKey', e.target.value)
82
+ }} defaultValue={configureData.dataDescription.seriesKey}>
83
+ <option value="">Choose an option</option>
84
+ {Object.keys(configureData.data[0]).map((value, index) => <option value={value} key={index}>{value}</option>)}
85
+ </select>
86
+ </div>
87
+ )}
88
+ {configureData.dataDescription.horizontal === false && configureData.dataDescription.series === true && (
89
+ <>
90
+ <div className="mb-2">
91
+ <div className="mb-1">Are the series values in your data represented in a
92
+ single row, or across multiple rows?
93
+ </div>
94
+ <div className="grid grid-gap-2 mb-4">
95
+ <div className="column">
96
+ <button
97
+ className={'cove-data-designer__button' + (configureData.dataDescription.singleRow === true ? ' active' : '')}
98
+ onClick={() => {
99
+ updateDescriptionProp(visualizationKey, dataKey, 'singleRow', true)
100
+ }}>
101
+ <Card>
102
+ <strong className="cove-heading--3">Single Row</strong>
103
+ <p className="mb-1">Each row contains the data for an individual series in itself.</p>
104
+ {DATA_TABLE_SINGLE_ROW}
105
+ </Card>
106
+ </button>
107
+ </div>
108
+ <div className="column">
109
+ <button
110
+ className={'cove-data-designer__button' + (configureData.dataDescription.singleRow === false ? ' active' : '')}
111
+ onClick={() => {
112
+ updateDescriptionProp(visualizationKey, dataKey, 'singleRow', false)
113
+ }}>
114
+ <Card>
115
+ <strong className="cove-heading--3">Multiple Rows</strong>
116
+ <p className="mb-1">Each series data is broken out into multiple rows.</p>
117
+ {DATA_TABLE_MULTI_ROW}
118
+ </Card>
119
+ </button>
120
+ </div>
121
+ </div>
122
+ </div>
123
+ {configureData.dataDescription.singleRow === false && (
124
+ <>
125
+ <div className="mb-2">
126
+ <div className="mb-1">Which property in the dataset represents which series the row is describing?</div>
127
+ <select onChange={(e) => {
128
+ updateDescriptionProp(visualizationKey, dataKey, 'seriesKey', e.target.value)
129
+ }} defaultValue={configureData.dataDescription.seriesKey}>
130
+ <option value="">Choose an option</option>
131
+ {Object.keys(configureData.data[0]).map((value, index) => (
132
+ <option value={value} key={index}>{value}</option>
133
+ ))}
134
+ </select>
135
+ </div>
136
+ <div className="mb-2">
137
+ <div className="mb-1">Which property in the dataset represents the values for the category/date axis or map geography?</div>
138
+ <select onChange={(e) => {
139
+ updateDescriptionProp(visualizationKey, dataKey, 'xKey', e.target.value)
140
+ }} defaultValue={configureData.dataDescription.xKey}>
141
+ <option value="">Choose an option</option>
142
+ {Object.keys(configureData.data[0]).map((value, index) => (
143
+ <option value={value} key={index}>{value}</option>
144
+ ))}
145
+ </select>
146
+ </div>
147
+ <div className="mb-2">
148
+ <div className="mb-1">Which property in the dataset represents the numeric value?</div>
149
+ <select onChange={(e) => {
150
+ updateDescriptionProp(visualizationKey, dataKey, 'valueKey', e.target.value)
151
+ }} defaultValue={configureData.dataDescription.valueKey}>
152
+ <option value="">Choose an option</option>
153
+ {Object.keys(configureData.data[0]).map((value, index) => (
154
+ <option value={value} key={index}>{value}</option>
155
+ ))}
156
+ </select>
157
+ </div>
158
+ </>
159
+ )}
160
+ </>
161
+ )}
162
+ </>
163
+ )}
164
+ {configureData.dataDescription && configureData.formattedData && (
165
+ <div>Data configured successfully</div>
166
+ )}
167
+ </div>
168
+ )
169
+ }
170
+
171
+ export default DataDesigner
@@ -1,24 +1,62 @@
1
1
  import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
 
4
+ import iconCaretUp from '../../assets/icon-caret-up.svg'
5
+ import iconCaretDown from '../../assets/icon-caret-down.svg'
6
+ import iconCaretFilledUp from '../../assets/icon-caret-filled-up.svg'
7
+ import iconCaretFilledDown from '../../assets/icon-caret-filled-down.svg'
8
+ import iconChartBar from '../../assets/icon-chart-bar.svg'
9
+ import iconChartLine from '../../assets/icon-chart-line.svg'
10
+ import iconChartPie from '../../assets/icon-chart-pie.svg'
4
11
  import iconClose from '../../assets/icon-close.svg'
5
- import iconQuestion from '../../assets/question-circle.svg'
6
- import iconLink from '../../assets/link.svg'
7
- import iconUpload from '../../assets/upload-solid.svg'
8
- import iconFileUpload from '../../assets/file-upload-solid.svg'
9
- import iconWarning from '../../assets/icon-warning.svg'
12
+ import iconCode from '../../assets/icon-code.svg'
13
+ import iconDataBite from '../../assets/icon-databite.svg'
14
+ import iconEdit from '../../assets/icon-edit.svg'
15
+ import iconFileUpload from '../../assets/icon-file-upload.svg'
16
+ import iconFilterBars from '../../assets/icon-filter-bars.svg'
17
+ import iconGrid from '../../assets/icon-grid.svg'
10
18
  import iconInfo from '../../assets/icon-info.svg'
19
+ import iconLink from '../../assets/icon-link.svg'
20
+ import iconMapAl from '../../assets/icon-map-alabama.svg'
21
+ import iconMapUsa from '../../assets/icon-map-usa.svg'
22
+ import iconMapWorld from '../../assets/icon-map-world.svg'
23
+ import iconMove from '../../assets/icon-move.svg'
24
+ import iconQuestion from '../../assets/icon-question-circle.svg'
25
+ import iconUpload from '../../assets/icon-upload.svg'
26
+ import iconWarningCircle from '../../assets/icon-warning-circle.svg'
27
+ import iconWarningTriangle from '../../assets/icon-warning-triangle.svg'
28
+ import iconGear from '../../assets/icon-gear.svg'
29
+ import iconTools from '../../assets/icon-tools.svg'
11
30
 
12
31
  import '../../styles/v2/components/icon.scss'
13
32
 
14
33
  const iconHash = {
15
- "close": iconClose,
16
- "question": iconQuestion,
17
- "link": iconLink,
18
- "upload": iconUpload,
19
- "fileUpload": iconFileUpload,
20
- "warning": iconWarning,
21
- "info": iconInfo
34
+ 'caretUp': iconCaretUp,
35
+ 'caretDown': iconCaretDown,
36
+ 'caretFilledUp': iconCaretFilledUp,
37
+ 'caretFilledDown': iconCaretFilledDown,
38
+ 'chartBar': iconChartBar,
39
+ 'chartLine': iconChartLine,
40
+ 'chartPie': iconChartPie,
41
+ 'close': iconClose,
42
+ 'code': iconCode,
43
+ 'databite': iconDataBite,
44
+ 'edit': iconEdit,
45
+ 'fileUpload': iconFileUpload,
46
+ 'filterBars': iconFilterBars,
47
+ 'grid': iconGrid,
48
+ 'info': iconInfo,
49
+ 'link': iconLink,
50
+ 'mapAl': iconMapAl,
51
+ 'mapUsa': iconMapUsa,
52
+ 'mapWorld': iconMapWorld,
53
+ 'move': iconMove,
54
+ 'question': iconQuestion,
55
+ 'upload': iconUpload,
56
+ 'warningCircle': iconWarningCircle,
57
+ 'warningTriangle': iconWarningTriangle,
58
+ 'gear': iconGear,
59
+ 'tools': iconTools
22
60
  }
23
61
 
24
62
  const Icon = ({ display = null, base, alt = '', size, color, style, ...attributes }) => {
@@ -0,0 +1,24 @@
1
+ import React from 'react'
2
+ import '../../styles/v2/components/loadspin.scss'
3
+
4
+ const LoadSpin = ({
5
+ color = '#fff',
6
+ opacity = 100,
7
+ size = 100,
8
+ className
9
+ }) => {
10
+ const n = 8
11
+ return (
12
+ <>
13
+ <div className={`cove-loadspin${className ? ' ' + className : ''}`} style={{width: size, height: size}}>
14
+ <div className="cove-loadspin__roller" style={{opacity: opacity / 100, transform: `scale(${size/80})`}}>
15
+ {
16
+ [...Array(n)].map((elem, index) => <div key={index} style={{backgroundColor: color}}/>)
17
+ }
18
+ </div>
19
+ </div>
20
+ </>
21
+ )
22
+ }
23
+
24
+ export default LoadSpin