@cdc/core 1.1.1 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/assets/alabama-graphic.svg +23 -0
  2. package/assets/check.svg +3 -0
  3. package/assets/dashboard.svg +11 -0
  4. package/assets/file-upload-solid.svg +1 -0
  5. package/assets/horizontal-stacked-bar.svg +1 -0
  6. package/assets/icon-code.svg +3 -0
  7. package/assets/icon-grid.svg +4 -0
  8. package/assets/icon-info.svg +3 -0
  9. package/assets/icon-warning.svg +3 -0
  10. package/assets/link.svg +1 -0
  11. package/assets/map-folded.svg +1 -0
  12. package/assets/paired-bar.svg +11 -0
  13. package/assets/upload-solid.svg +1 -0
  14. package/assets/usa-region-graphic.svg +393 -0
  15. package/components/AdvancedEditor.js +74 -0
  16. package/components/GlobalContext.jsx +41 -0
  17. package/components/Loading.js +3 -2
  18. package/components/elements/Button.jsx +12 -0
  19. package/components/inputs/InputCheckbox.jsx +59 -0
  20. package/components/inputs/InputSelect.jsx +49 -0
  21. package/components/inputs/InputText.jsx +68 -0
  22. package/components/inputs/InputToggle.jsx +95 -0
  23. package/components/ui/Accordion.jsx +64 -0
  24. package/components/ui/Icon.jsx +63 -0
  25. package/components/ui/Modal.jsx +87 -0
  26. package/components/ui/Overlay.jsx +84 -0
  27. package/components/ui/OverlayFrame.jsx +16 -0
  28. package/components/ui/Tooltip.jsx +55 -0
  29. package/data/colorPalettes.js +240 -0
  30. package/helpers/events.js +15 -0
  31. package/helpers/numberFromString.js +4 -3
  32. package/helpers/updatePaletteNames.js +18 -0
  33. package/helpers/validateFipsCodeLength.js +67 -0
  34. package/package.json +16 -2
  35. package/styles/_data-table.scss +8 -2
  36. package/styles/_global.scss +5 -3
  37. package/styles/v2/base/_general.scss +46 -0
  38. package/styles/v2/base/_reset.scss +81 -0
  39. package/styles/v2/base/_typography.scss +0 -0
  40. package/styles/v2/base/index.scss +3 -0
  41. package/styles/v2/components/accordion.scss +156 -0
  42. package/styles/v2/components/button.scss +178 -0
  43. package/styles/v2/components/editor.scss +487 -0
  44. package/styles/v2/components/icon.scss +23 -0
  45. package/styles/v2/components/input.scss +372 -0
  46. package/styles/v2/components/modal.scss +64 -0
  47. package/styles/v2/components/overlay.scss +80 -0
  48. package/styles/v2/layout/_alert.scss +36 -0
  49. package/styles/v2/layout/_component.scss +31 -0
  50. package/styles/v2/layout/_data-table.scss +278 -0
  51. package/styles/v2/layout/_header.scss +13 -0
  52. package/styles/v2/layout/_link.scss +46 -0
  53. package/styles/v2/layout/_progression.scss +80 -0
  54. package/styles/v2/layout/_tooltip.scss +132 -0
  55. package/styles/v2/layout/index.scss +7 -0
  56. package/styles/v2/main.scss +15 -0
  57. package/styles/v2/themes/_color-definitions.scss +129 -0
  58. package/styles/v2/themes/index.scss +1 -0
  59. package/styles/v2/utils/_animations.scss +63 -0
  60. package/styles/v2/utils/_functions.scss +0 -0
  61. package/styles/v2/utils/_mixins.scss +29 -0
  62. package/styles/v2/utils/_variables.scss +2 -0
  63. package/styles/v2/utils/index.scss +4 -0
@@ -0,0 +1,41 @@
1
+ import React, { createContext, useContext, useState } from 'react'
2
+
3
+ export const GlobalContext = createContext({})
4
+ export const useGlobalContext = () => useContext(GlobalContext)
5
+
6
+ export const GlobalContextProvider = ({ children }) => {
7
+ const [ globalContextData, setGlobalContextData ] = useState({})
8
+
9
+ const openOverlay = (obj, disableBgClose = false) => {
10
+ let payload = { object: obj, show: true, disableBgClose: disableBgClose }
11
+ setGlobalContextData(context => ({ ...context, overlay: { ...payload } }))
12
+ }
13
+
14
+ const toggleOverlay = (display = false) => {
15
+ setGlobalContextData(context => ({
16
+ ...context,
17
+ overlay: {
18
+ ...context.overlay,
19
+ show: display
20
+ }
21
+ }))
22
+ }
23
+
24
+ const globalSettings = {
25
+ overlay: {
26
+ object: globalContextData.overlay?.object || null,
27
+ show: globalContextData.overlay?.show || false,
28
+ disableBgClose: globalContextData.overlay?.disableBgClose || false,
29
+ actions: {
30
+ openOverlay,
31
+ toggleOverlay
32
+ }
33
+ }
34
+ }
35
+
36
+ return (
37
+ <GlobalContext.Provider value={globalSettings}>
38
+ {children}
39
+ </GlobalContext.Provider>
40
+ )
41
+ }
@@ -3,7 +3,8 @@ import '../styles/loading.scss';
3
3
 
4
4
  export default function Loading({viewport = "lg"}) {
5
5
  return (
6
- <section className="loading" aria-hidden="true">
6
+ <section className="loading" aria-live="assertive">
7
+ <span className="sr-only" style={{display: 'none'}}>Content is loading.</span>
7
8
  <div className={`la-ball-beat la-dark ${viewport}`}>
8
9
  <div />
9
10
  <div />
@@ -11,4 +12,4 @@ export default function Loading({viewport = "lg"}) {
11
12
  </div>
12
13
  </section>
13
14
  )
14
- }
15
+ }
@@ -0,0 +1,12 @@
1
+ import React from 'react'
2
+
3
+ import '../../styles/v2/components/button.scss'
4
+
5
+ const Button = ({fluid, children, onClick, className, ...attributes}) => {
6
+
7
+ return (
8
+ <button className={`cove-button${fluid ? ' fluid' : ''}${className ? className : ''}`} {...attributes} onClick={(e) => {e.preventDefault(); onClick();}}>{children}</button>
9
+ )
10
+ }
11
+
12
+ export default Button
@@ -0,0 +1,59 @@
1
+ import React, { useState, useEffect, memo } from 'react'
2
+
3
+ import Check from '../../assets/check.svg'
4
+ import '../../styles/v2/components/input.scss'
5
+
6
+ const InputCheckbox = memo((
7
+ {
8
+ label,
9
+ size = 'medium',
10
+ activeColor = null,
11
+ activeCheckColor = null,
12
+ section = null,
13
+ subsection = null,
14
+ fieldName,
15
+ updateField,
16
+ value: stateValue,
17
+
18
+ i = null, min = null, max = null,
19
+ ...attributes
20
+ }
21
+ ) => {
22
+
23
+ const [ value, setValue ] = useState(stateValue)
24
+
25
+ let name = subsection ? `${section}-${subsection}-${fieldName}` : `${section}-${subsection}-${fieldName}`
26
+ if(fieldName === 'border') {
27
+ console.table({fieldName, value, stateValue})
28
+
29
+ }
30
+
31
+ useEffect(() => {
32
+ if (stateValue !== undefined && stateValue !== value) {
33
+ setValue(stateValue)
34
+ }
35
+ }, [ stateValue ])
36
+
37
+ useEffect(() => {
38
+ if (stateValue !== undefined && stateValue !== value && updateField) {
39
+ updateField(section, subsection, fieldName, value, i)
40
+ }
41
+ }, [ value ])
42
+
43
+ return (
44
+ <div className="input-group">
45
+ {label && <label>{label}</label>}
46
+ <div
47
+ className={'cove-input__checkbox' + (size === 'small' ? '--small' : size === 'large' ? '--large' : '') + (value ? ' active' : '')}
48
+ onClick={() => setValue(!value)}>
49
+ <div className={`cove-input__checkbox-box${activeColor ? ' custom-color' : ''}`}
50
+ style={value && activeColor ? { backgroundColor: activeColor } : null}>
51
+ <Check className="cove-input__checkbox-check" style={{fill: activeCheckColor || '#025eaa'}}/>
52
+ </div>
53
+ <input className="cove-input--hidden" type="checkbox" name={name} checked={value || false} readOnly/>
54
+ </div>
55
+ </div>
56
+ )
57
+ })
58
+
59
+ export default InputCheckbox
@@ -0,0 +1,49 @@
1
+ import React, { memo } from 'react'
2
+
3
+ import '../../styles/v2/components/input.scss'
4
+
5
+ const InputSelect = memo((
6
+ {
7
+ label,
8
+ value,
9
+ options,
10
+ fieldName,
11
+ section = null,
12
+ subsection = null,
13
+ required = false,
14
+ updateField,
15
+ initial: initialValue,
16
+ ...attributes
17
+ }
18
+ ) => {
19
+
20
+ let optionsJsx = ''
21
+
22
+ if (Array.isArray(options)) {
23
+ //Handle basic array
24
+ optionsJsx = options.map(optionName => <option value={optionName} key={optionName}>{optionName}</option>)
25
+ } else {
26
+ //Handle object with value/name pairs
27
+ optionsJsx = []
28
+ for (const [ optionValue, optionName ] of Object.entries(options)) {
29
+ optionsJsx.push(<option value={optionValue} key={optionValue}>{optionName}</option>)
30
+ }
31
+ }
32
+
33
+ if (initialValue) {
34
+ optionsJsx.unshift(<option value="" key="initial">{initialValue}</option>)
35
+ }
36
+
37
+ return (
38
+ <label>
39
+ {label && <span className="edit-label">{label}</span>}
40
+ <select className={required && !value ? 'warning' : ''} name={fieldName} value={value} onChange={(event) => {
41
+ updateField(section, subsection, fieldName, event.target.value)
42
+ }} {...attributes}>
43
+ {optionsJsx}
44
+ </select>
45
+ </label>
46
+ )
47
+ })
48
+
49
+ export default InputSelect
@@ -0,0 +1,68 @@
1
+ import React, { useState, useEffect, memo } from 'react'
2
+ import { useDebounce } from 'use-debounce'
3
+
4
+ import '../../styles/v2/components/input.scss'
5
+
6
+ const InputText = memo((
7
+ {
8
+ label,
9
+ section = null,
10
+ subsection = null,
11
+ fieldName,
12
+ updateField,
13
+ value: stateValue,
14
+ type = 'input',
15
+ tooltip,
16
+ i = null, min = null, max = null,
17
+ ...attributes
18
+ }
19
+ ) => {
20
+
21
+ const [ value, setValue ] = useState(stateValue)
22
+ const [ debouncedValue ] = useDebounce(value, 500)
23
+
24
+ useEffect(() => {
25
+ if ('string' === typeof debouncedValue && stateValue !== debouncedValue && updateField) {
26
+ updateField(section, subsection, fieldName, debouncedValue, i)
27
+ }
28
+ }, [ debouncedValue, section, subsection, fieldName, i, stateValue, updateField ])
29
+
30
+ let name = subsection ? `${section}-${subsection}-${fieldName}` : `${section}-${subsection}-${fieldName}`
31
+
32
+ const onChange = (e) => {
33
+ if ('number' !== type || min === null) {
34
+ setValue(e.target.value)
35
+ } else {
36
+ if (!e.target.value || (parseFloat(min) <= parseFloat(e.target.value) & parseFloat(max) >= parseFloat(e.target.value))) {
37
+ setValue(e.target.value)
38
+ } else {
39
+ setValue(min.toString())
40
+ }
41
+ }
42
+ }
43
+
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
+ )
50
+ }
51
+
52
+ if ('number' === type) {
53
+ formElement = <input type="number" name={name} onChange={onChange} {...attributes} value={value}/>
54
+ }
55
+
56
+ return (
57
+ <div className="cove-input-group">
58
+ {label &&
59
+ <>
60
+ <label>{label}{tooltip}</label>
61
+ </>
62
+ }
63
+ {formElement}
64
+ </div>
65
+ )
66
+ })
67
+
68
+ export default InputText
@@ -0,0 +1,95 @@
1
+ import React, { useState, useEffect } from 'react'
2
+ import PropTypes from 'prop-types'
3
+
4
+ import '../../styles/v2/components/input.scss'
5
+
6
+ const InputToggle = (
7
+ {
8
+ label,
9
+ toggleType = 'flat',
10
+ size = 'medium',
11
+ activeColor = null,
12
+ section = null,
13
+ subsection = null,
14
+ fieldName,
15
+ updateField,
16
+ value: stateValue,
17
+
18
+ i = null, min = null, max = null,
19
+ ...attributes
20
+ }
21
+ ) => {
22
+
23
+ const [ value, setValue ] = useState(stateValue)
24
+
25
+ let name = () => {
26
+ let str = ''
27
+ if (section)
28
+ str += section + '-'
29
+ if (subsection)
30
+ str += subsection + '-'
31
+ if (fieldName)
32
+ str += fieldName
33
+ return str
34
+ }
35
+
36
+ const toggleTypeClass = () => {
37
+ const typeArr = {
38
+ 'flat': ' toggle--flat',
39
+ 'block': ' toggle--block',
40
+ 'pill': ' toggle--pill',
41
+ '3d': ' toggle--3d'
42
+ }
43
+ return typeArr[toggleType] || ''
44
+ }
45
+
46
+ useEffect(() => {
47
+ if (stateValue !== undefined && stateValue !== value) {
48
+ setValue(stateValue)
49
+ }
50
+ }, [ stateValue ])
51
+
52
+ useEffect(() => {
53
+ if (stateValue !== undefined && stateValue !== value && updateField) {
54
+ updateField(section, subsection, fieldName, value, i)
55
+ }
56
+ }, [ value ])
57
+
58
+ return (
59
+ <div className="input-group">
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 }/>
64
+ <input className="cove-input--hidden" type="checkbox" name={name()} checked={value || false} readOnly/>
65
+ </div>
66
+ </div>
67
+ )
68
+ }
69
+
70
+ InputToggle.propTypes = {
71
+ /** Add label to the input field */
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 */
76
+ size: PropTypes.oneOf(['small', 'medium', 'large']),
77
+ /** Select the preferred color for the toggle slider when active */
78
+ activeColor: PropTypes.string,
79
+ /** Parent key value of nested target config option
80
+ *
81
+ * (optional)*/
82
+ section: PropTypes.string,
83
+ /** Child key value of nested target config option
84
+ *
85
+ * (optional, requires `section` value)*/
86
+ subsection: PropTypes.string,
87
+ /** Key value of targeted config option */
88
+ fieldName: PropTypes.string,
89
+ /** Prop drill down of the updateField function */
90
+ updateField: PropTypes.func,
91
+ /** Current value of the input, usually the current config option value */
92
+ stateValue: PropTypes.object
93
+ }
94
+
95
+ export default InputToggle
@@ -0,0 +1,64 @@
1
+ import React, { Children } from 'react'
2
+ import {
3
+ Accordion as AccordionComponent,
4
+ AccordionItem,
5
+ AccordionItemHeading,
6
+ AccordionItemPanel,
7
+ AccordionItemButton,
8
+ } from 'react-accessible-accordion'
9
+ import PropTypes from 'prop-types'
10
+
11
+ import Icon from './Icon'
12
+ import Tooltip from './Tooltip'
13
+
14
+ import '../../styles/v2/components/accordion.scss'
15
+
16
+ //Define the "slots" to be populated by subcomponents
17
+ const AccordionSection = () => null
18
+
19
+ const Accordion = ({children}) => {
20
+ const childNodes = Children.toArray(children)
21
+ const accordionSections = childNodes.filter(child => child?.type === AccordionSection)
22
+
23
+ return (
24
+ <AccordionComponent allowZeroExpanded={true}>
25
+ {accordionSections && accordionSections.map((section, index) => (
26
+ <AccordionItem className="cove-accordion__item" key={index}>
27
+ <AccordionItemHeading className="cove-accordion__heading">
28
+ <AccordionItemButton className="cove-accordion__button">
29
+ {section.props.title}
30
+ {section.props.tooltipText
31
+ ? (
32
+ <Tooltip position="bottom">
33
+ <Tooltip.Target>
34
+ <Icon display="question" size={14}/>
35
+ </Tooltip.Target>
36
+ <Tooltip.Content>
37
+ {section.props.tooltipText}
38
+ </Tooltip.Content>
39
+ </Tooltip>
40
+ )
41
+ : null
42
+ }
43
+ </AccordionItemButton>
44
+ </AccordionItemHeading>
45
+ <AccordionItemPanel className="cove-accordion__panel">
46
+ {section.props.children}
47
+ </AccordionItemPanel>
48
+ </AccordionItem>
49
+ ))}
50
+ </AccordionComponent>
51
+ )
52
+ }
53
+
54
+ //Create subcomponents as "slots" within component namespace
55
+ Accordion.Section = AccordionSection
56
+
57
+ Accordion.Section.propTypes = {
58
+ /* Title for the accordion label*/
59
+ title: PropTypes.string,
60
+ /* Tooltip for the accordion label*/
61
+ tooltipText: PropTypes.object
62
+ }
63
+
64
+ export default Accordion
@@ -0,0 +1,63 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+
4
+ 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'
10
+ import iconInfo from '../../assets/icon-info.svg'
11
+
12
+ import '../../styles/v2/components/icon.scss'
13
+
14
+ const iconHash = {
15
+ "close": iconClose,
16
+ "question": iconQuestion,
17
+ "link": iconLink,
18
+ "upload": iconUpload,
19
+ "fileUpload": iconFileUpload,
20
+ "warning": iconWarning,
21
+ "info": iconInfo
22
+ }
23
+
24
+ const Icon = ({ display = null, base, alt = '', size, color, style, ...attributes }) => {
25
+ const IconObj = iconHash[display] || null
26
+
27
+ const filteredAttrs = { ...attributes }
28
+ delete filteredAttrs.className
29
+
30
+ const styles = {
31
+ ...style,
32
+ color: color ? color : null,
33
+ width: size ? size + 'px' : null
34
+ }
35
+
36
+ return (
37
+ <>
38
+ {base
39
+ ? <IconObj title={alt}/>
40
+ : (
41
+ <span className={`cove-icon${attributes.className ? ' ' + attributes.className : ''}`} style={styles} {...filteredAttrs}>
42
+ <IconObj title={alt}/>
43
+ </span>
44
+ )
45
+ }
46
+ </>
47
+ )
48
+ }
49
+
50
+ Icon.propTypes = {
51
+ /* Define the icon to display */
52
+ display: PropTypes.oneOf(Object.keys(iconHash)),
53
+ /* Returns icon data as plain svg */
54
+ base: PropTypes.bool,
55
+ /* Sets alt text for the icon */
56
+ alt: PropTypes.string,
57
+ /* Override the width of the icon (scales height proportionally)*/
58
+ size: PropTypes.number,
59
+ /* Override the color of the icon */
60
+ color: PropTypes.string
61
+ }
62
+
63
+ export default Icon
@@ -0,0 +1,87 @@
1
+ import React, { Children } from 'react'
2
+ import PropTypes from 'prop-types'
3
+
4
+ import { useGlobalContext } from '../GlobalContext'
5
+ import Icon from './Icon'
6
+
7
+ import '../../styles/v2/components/modal.scss'
8
+
9
+ //Define the "slots" to be populated by subcomponents
10
+ const ModalHeader = () => null
11
+ const ModalContent = () => null
12
+ const ModalFooter = () => null
13
+
14
+ const Modal = ({
15
+ fontTheme = 'dark',
16
+ headerBgColor = '#fff',
17
+ showDividerTop = true,
18
+ showDividerBottom = true,
19
+ showClose = true,
20
+ children,
21
+ override = null
22
+ }) => {
23
+
24
+ //Access global overlay state
25
+ let { overlay } = useGlobalContext()
26
+
27
+ //Parse, organize, and pull "slotted" children data from subcomponents
28
+ const childNodes = Children.toArray(children)
29
+ const modalHeaderChildren = childNodes.find(child => child?.type === ModalHeader)
30
+ const modalContentChildren = childNodes.find(child => child?.type === ModalContent)
31
+ const modalFooterChildren = childNodes.find(child => child?.type === ModalFooter)
32
+
33
+ //Modal computed style options
34
+ const dividerBorder = (bool) => {
35
+ return !bool ? 'none' : null
36
+ }
37
+
38
+ //Render output
39
+ return (
40
+ <div className={`cove-modal cove-modal__theme--${fontTheme}`}>
41
+ {(showClose || modalHeaderChildren) &&
42
+ <div className="cove-modal__header" style={{
43
+ backgroundColor: headerBgColor,
44
+ boxShadow: dividerBorder(modalHeaderChildren && showDividerTop),
45
+ padding: !modalHeaderChildren ? '0' : null
46
+ }}>
47
+ {modalHeaderChildren && modalHeaderChildren.props.children}
48
+ {showClose &&
49
+ <button className="cove-modal--close"
50
+ onClick={(e) => override ? override.actions.toggleOverlay(false) : overlay ? overlay?.actions.toggleOverlay(false) : e.preventDefault()}>
51
+ <Icon display="close"/>
52
+ </button>
53
+ }
54
+ </div>
55
+ }
56
+
57
+ <div className="cove-modal__content">
58
+ {modalContentChildren && modalContentChildren.props.children}
59
+ </div>
60
+
61
+ {modalFooterChildren &&
62
+ <div className="cove-modal__footer" style={{
63
+ boxShadow: dividerBorder(showDividerBottom),
64
+ paddingTop: showDividerBottom ? '1rem' : null
65
+ }}>
66
+ {modalFooterChildren.props.children}
67
+ </div>
68
+ }
69
+
70
+ </div>
71
+ )
72
+ }
73
+
74
+ //Create subcomponents as "slots" within component namespace
75
+ Modal.Header = ModalHeader
76
+ Modal.Content = ModalContent
77
+ Modal.Footer = ModalFooter
78
+
79
+ Modal.propTypes = {
80
+ fontTheme: PropTypes.oneOf([ 'dark', 'light' ]),
81
+ headerBgColor: PropTypes.string,
82
+ showDividerTop: PropTypes.bool,
83
+ showDividerBottom: PropTypes.bool,
84
+ showClose: PropTypes.bool
85
+ }
86
+
87
+ export default Modal
@@ -0,0 +1,84 @@
1
+ import React, { useEffect, useState } from 'react'
2
+
3
+ import { useGlobalContext } from '../GlobalContext'
4
+
5
+ import '../../styles/v2/components/overlay.scss'
6
+
7
+ const Overlay = ({ disableBgClose, children, override = null }) => {
8
+ //Access global modal state
9
+ let { overlay } = useGlobalContext()
10
+
11
+ //Set local states
12
+ const [ displayOverlay, setDisplayOverlay ] = useState(false)
13
+ const [ overlayAnimationState, setOverlayAnimationState ] = useState(null)
14
+ const [ overlayErrorState, setOverlayErrorState ] = useState(false)
15
+
16
+ const overlayDisplay = overlay?.show || override?.show
17
+
18
+ //Animate In effect
19
+ useEffect(() => {
20
+ if (overlayDisplay === false) return //Reject
21
+
22
+ document.body.style.overflow = 'hidden'
23
+ setDisplayOverlay(true)
24
+ setOverlayAnimationState('animate-in')
25
+
26
+ const timeoutShow = setTimeout(() => {
27
+ setOverlayAnimationState('show')
28
+ }, 750)
29
+
30
+ return () => clearTimeout(timeoutShow)
31
+ }, [ overlayDisplay ])
32
+
33
+ //Animate Out effect
34
+ useEffect(() => {
35
+ if (overlayDisplay === true) return //Reject
36
+
37
+ setOverlayAnimationState('animate-out')
38
+
39
+ const timeoutHide = setTimeout(() => {
40
+ setOverlayAnimationState(null)
41
+ setDisplayOverlay(false)
42
+ document.body.style.overflow = null
43
+ }, 400)
44
+
45
+ return () => clearTimeout(timeoutHide)
46
+ }, [ overlayDisplay ])
47
+
48
+ //Error animate effect
49
+ useEffect(() => {
50
+ if (overlayErrorState === false) return //Reject
51
+
52
+ const timeoutHide = setTimeout(() => {
53
+ setOverlayErrorState(false)
54
+ }, 400)
55
+
56
+ return () => clearTimeout(timeoutHide)
57
+ }, [ overlayErrorState ])
58
+
59
+ //Render output
60
+ return (
61
+ <>
62
+ {displayOverlay &&
63
+ <div
64
+ className={`cove-overlay${overlayAnimationState ? (' ' + overlayAnimationState) : ''}${overlayErrorState ? ' overlay-error' : ''}`}>
65
+ <div className="cove-overlay__bg" style={{ cursor: disableBgClose ? 'default' : null }}
66
+ onClick={(e) =>
67
+ disableBgClose ? setOverlayErrorState(true) :
68
+ overlay ? overlay.actions.toggleOverlay(false) :
69
+ override ? override.actions.toggleOverlay(false) :
70
+ e.preventDefault()
71
+ }
72
+ role="alert"
73
+ />
74
+ <div className="cove-overlay__wrapper">
75
+ <div className="cove-overlay__container">
76
+ {children}
77
+ </div>
78
+ </div>
79
+ </div>
80
+ }
81
+ </>
82
+ )
83
+ }
84
+ export default Overlay
@@ -0,0 +1,16 @@
1
+ import React from 'react'
2
+
3
+ import { useGlobalContext } from '../GlobalContext'
4
+
5
+ import Overlay from './Overlay'
6
+
7
+ const OverlayFrame = () => {
8
+ const { overlay } = useGlobalContext()
9
+ return (
10
+ <Overlay disableBgClose={overlay.disableBgClose}>
11
+ { overlay.object }
12
+ </Overlay>
13
+ )
14
+ }
15
+
16
+ export default OverlayFrame