UNPKG

saagie-ui

Version:

Saagie UI from Saagie Design System

153 lines (137 loc) 5.29 kB
import React, { useRef, useEffect } from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import SVGInline from 'react-svg-inline'; import { Manager, Reference, Popper } from 'react-popper'; import classnames from 'classnames'; import { checkIfElementOrParentHasClass } from '../../helpers'; import { useMapInteractionContext } from '../mapInteraction/MapInteractionContext'; import { useDragContainerContext } from './PipelineDragContainer'; const iconStart = '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="8" viewBox="0 0 18 8"><path fill="#FFF" fill-rule="evenodd" d="M19,20 L12,20 C11.4477153,20 11,19.5522847 11,19 C11,18.4477153 11.4477153,18 12,18 L19,18 L19,16 C19,15.4477153 19.4477153,15 20,15 L28,15 C28.5522847,15 29,15.4477153 29,16 L29,22 C29,22.5522847 28.5522847,23 28,23 L20,23 C19.4477153,23 19,22.5522847 19,22 L19,20 Z" transform="matrix(-1 0 0 1 29 -15)"/></svg>'; const iconInner = '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="8" viewBox="0 0 18 8"><path fill="#FFF" fill-rule="evenodd" d="M24,20 L24,22 C24,22.5522847 23.5522847,23 23,23 L15,23 C14.4477153,23 14,22.5522847 14,22 L14,20 L11,20 C10.4477153,20 10,19.5522847 10,19 C10,18.4477153 10.4477153,18 11,18 L14,18 L14,16 C14,15.4477153 14.4477153,15 15,15 L23,15 C23.5522847,15 24,15.4477153 24,16 L24,18 L27,18 C27.5522847,18 28,18.4477153 28,19 C28,19.5522847 27.5522847,20 27,20 L24,20 Z" transform="translate(-10 -15)"/></svg>'; const iconEnd = '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="8" viewBox="0 0 18 8"><path fill="#FFF" fill-rule="evenodd" d="M18,20 L11,20 C10.4477153,20 10,19.5522847 10,19 C10,18.4477153 10.4477153,18 11,18 L18,18 L18,16 C18,15.4477153 18.4477153,15 19,15 L27,15 C27.5522847,15 28,15.4477153 28,16 L28,22 C28,22.5522847 27.5522847,23 27,23 L19,23 C18.4477153,23 18,22.5522847 18,22 L18,20 Z" transform="translate(-10 -15)"/></svg>'; const propTypes = { /** * The component used for the root node. * Either a string to use a DOM element or a component. */ tag: PropTypes.elementType, children: PropTypes.node, defaultClassName: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]), className: PropTypes.string, isOpen: PropTypes.bool, position: PropTypes.string, addItemDefaultOffset: PropTypes.shape({ top: PropTypes.number, left: PropTypes.number, }), popperClassName: PropTypes.string, onOpen: PropTypes.func, onClose: PropTypes.func, }; const defaultProps = { tag: 'button', children: '', defaultClassName: 'sui-prj-pipeline-action', className: '', isOpen: false, position: 'inner', addItemDefaultOffset: { top: -200, left: 0 }, popperClassName: 'sui-prj-pipeline-add-item__popper', onOpen: () => {}, onClose: () => {}, }; const getIcon = (position) => { if (position === 'start') { return iconStart; } if (position === 'end') { return iconEnd; } return iconInner; }; export const PipelineAddItem = ({ tag: Tag, children, defaultClassName, className, isOpen, position, popperClassName, addItemDefaultOffset, onOpen, onClose, }) => { const pipelineAddItem = useRef(null); const { scale } = useMapInteractionContext(); const { isDragging } = useDragContainerContext(); const icon = getIcon(position); const formattedOffset = { offset: { offset: `${addItemDefaultOffset.left}, ${addItemDefaultOffset.top}` } }; const classes = classnames( defaultClassName, className, ); useEffect(() => { const onClickOutside = (e) => { if ( pipelineAddItem && pipelineAddItem.current && pipelineAddItem.current.contains(e.target) ) { return; } const elementOrParentHasPopperClass = checkIfElementOrParentHasClass( e.target, popperClassName ); if (elementOrParentHasPopperClass) { return; } onClose(); }; if (isOpen) { document.addEventListener('click', onClickOutside, false); } return () => { document.removeEventListener('click', onClickOutside, false); }; }, [isOpen, pipelineAddItem, popperClassName]); useEffect(() => { onClose(); }, [scale]); return ( <div className={`sui-prj-pipeline-add-item ${!isDragging ? 'as--mounted' : ''} as--${position}`} ref={pipelineAddItem}> <Manager> <Reference> {({ ref }) => ( <Tag type={(Tag === 'button') ? 'button' : null} ref={ref} className={classes} onClick={() => { onOpen(); }} > <SVGInline svg={icon} /> </Tag> )} </Reference> {isOpen ? ReactDOM.createPortal( <Popper placement="bottom" modifiers={formattedOffset}> {({ placement, ref, style }) => ( <div ref={ref} style={style} data-placement={placement} className={popperClassName} > {children} </div> )} </Popper>, document.body ) : '' } </Manager> </div> ); }; PipelineAddItem.propTypes = propTypes; PipelineAddItem.defaultProps = defaultProps;