UNPKG

saagie-ui

Version:

Saagie UI from Saagie Design System

205 lines (183 loc) 5.19 kB
import React from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import { Manager, Reference, Popper } from 'react-popper'; import { FormControlSelect } from '../../atoms/formControlSelect/FormControlSelect'; import { FormControlSelectThemeDefault } from '../../atoms/formControlSelect/themes/FormControlSelectThemeDefault'; import { Icon } from '../../atoms/icon/Icon'; import { keyCodes } from '../../../helpers'; const propTypes = { children: PropTypes.node, options: PropTypes.arrayOf(PropTypes.object), onAdd: PropTypes.func, onClose: PropTypes.func, icon: PropTypes.string, title: PropTypes.node, placeholder: PropTypes.string, isOpen: PropTypes.bool, showInline: PropTypes.bool, disableClickOutside: PropTypes.bool, noAutoFocus: PropTypes.bool, }; const defaultProps = { children: null, options: [], onAdd: () => {}, onClose: () => {}, icon: 'plus', title: 'Add', placeholder: 'Search...', isOpen: false, showInline: false, disableClickOutside: false, noAutoFocus: false, }; const theme = { control: (styles, { isDisabled, isFocused }) => ({ ...FormControlSelectThemeDefault.control(styles, { isDisabled, isFocused }), margin: '0 0.8rem 0.8rem 0.8rem', fontSize: '0.9rem', }), dropdownIndicator: () => ({ display: 'none', }), menu: (styles) => ({ ...styles, position: 'relative', boxShadow: 'none', border: 'none', borderTop: '0.0625rem solid rgba(0, 0, 0, 0.05)', borderRadius: 0, marginBottom: 0, }), }; export class AddBox extends React.Component { container = React.createRef(); componentWillUnmount() { this.removeEvents(); } addEvents = () => { ['click', 'touchstart', 'keyup'].forEach( (event) => document.addEventListener(event, this.handleDocumentEvent, true) ); } removeEvents = () => { ['click', 'touchstart', 'keyup'].forEach( (event) => document.removeEventListener(event, this.handleDocumentEvent, true) ); } handleDocumentEvent = (e) => { const { onClose } = this.props; if (e && (e.which === 3 || (e.type === 'keyup' && e.which !== keyCodes.esc))) { return; } if (!this.container) { return; } if (this.container.contains(e.target) && this.container !== e.target && (e.type !== 'keyup' || e.which === keyCodes.tab) ) { return; } onClose(); } handleAdd = (item) => { const { onAdd } = this.props; onAdd(item); } render() { const { children, options, icon, title, placeholder, isOpen, onClose, showInline, disableClickOutside, noAutoFocus, ...otherProps } = this.props; this.removeEvents(); if (isOpen && !disableClickOutside) { this.addEvents(); } // autofocus in react-select and Popper doesn't work well together; it makes the first click on // the close button ineffective const autoFocus = showInline && !noAutoFocus; const { handleAdd } = this; // eslint-disable-next-line react/prop-types const Menu = React.forwardRef(({ scheduleUpdate, ...attrs }, ref) => ( <div ref={ref} className="sui-m-add-box" {...attrs} > <button type="button" className="sui-m-add-box__close" onClick={() => onClose()} > <Icon name="close" size="sm" /> </button> <div className="sui-m-add-box__title"> {!!icon && ( <Icon name={icon} size="sm" position="start" /> )} {title} </div> <div className="sui-m-add-box__select"> <FormControlSelect menuIsOpen autoFocus={autoFocus} placeholder={placeholder} onChange={(item) => handleAdd(item)} onInputChange={scheduleUpdate ? () => scheduleUpdate() : () => {}} noOptionsMessage={({ inputValue }) => { if (!inputValue) return 'No option'; return `No option "${inputValue}"`; }} theme={theme} options={options} isGroupOption {...otherProps} /> </div> </div> )); if (showInline) { return isOpen && ( <div ref={(node) => { this.container = node; }}> {children} <Menu /> </div> ); } return ( <Manager> <Reference>{({ ref }) => <span style={{ display: 'inline-block' }} ref={ref}>{children}</span>}</Reference> {isOpen && ReactDOM.createPortal( <Popper innerRef={(node) => { this.container = node; }} placement="bottom-start" > {({ ref, style, placement, scheduleUpdate, }) => ( <Menu ref={ref} style={style} data-placement={placement} scheduleUpdate={scheduleUpdate} /> )} </Popper>, document.body )} </Manager> ); } } AddBox.propTypes = propTypes; AddBox.defaultProps = defaultProps;