import React, { Component, MutableRefObject, ReactNode } from 'react'; import { Container } from '@teambit/base-ui.surfaces.abs-container'; import { ClickOutside } from '@teambit/base-ui.hook.use-click-outside'; //@ts-ignore import createRef from 'react-create-ref'; import { DefaultPlaceholder } from './default-placeholder'; export interface DrawerProps extends Omit, 'onChange'> { open?: boolean; placeholderContent?: ReactNode; margin?: string | number; indent?: string | number; clickToggles?: boolean; clickPlaceholderToggles?: boolean; clickOutside?: boolean; hoverToOpen?: boolean; onChange?: (evt: React.MouseEvent | undefined, open: boolean) => void; onContainerToggle?: (e: React.MouseEvent) => void; onPlaceholderToggle?: (e: React.MouseEvent) => void; onContaineeToggle?: (e: React.MouseEvent) => void; onClickOutside?: (e: MouseEvent | TouchEvent) => void; } type DrawerState = { isOpen: boolean; }; export class Drawer extends Component { state: DrawerState = { isOpen: this.props.open || false, }; private ref: MutableRefObject = createRef(); static defaultProps = { clickPlaceholderToggles: true, clickOutside: true, clickToggles: true, }; componentWillReceiveProps(nextProps: DrawerProps) { const prevProps = this.props; if (prevProps.open !== nextProps.open && nextProps.open !== undefined) { this.setState({ isOpen: nextProps.open }); } } private get isControlled() { return this.props.open !== undefined; } toggle = (evt: React.MouseEvent) => { const { isOpen } = this.state; const nextOpen = !isOpen; if (!this.isControlled) { this.setState({ isOpen: nextOpen }); } this.props.onChange && this.props.onChange(evt, nextOpen); }; close = (evt?: React.MouseEvent) => { const { isOpen } = this.state; const nextOpen = false; if (!this.isControlled && isOpen) { this.setState({ isOpen: nextOpen }); } this.props.onChange && this.props.onChange(evt, nextOpen); }; open = (evt: React.MouseEvent) => { const { isOpen } = this.state; const nextOpen = true; if (!this.isControlled && !isOpen) { this.setState({ isOpen: true }); } this.props.onChange && this.props.onChange(evt, nextOpen); }; private handlePlaceholderClick = (e: React.MouseEvent) => { this.props.onPlaceholderToggle && this.props.onPlaceholderToggle(e); if (!e.defaultPrevented) { this.props.clickPlaceholderToggles && this.toggle(e); } }; private handleContainerClick = (e: React.MouseEvent) => { this.props.clickToggles && this.toggle(e); this.props.onClick && this.props.onClick(e); }; private handleClickOutside = (e: MouseEvent | TouchEvent) => { this.props.onClickOutside && this.props.onClickOutside(e); if (!e.defaultPrevented) { this.props.clickOutside && this.close(); } }; private handleLeaveContainer = (e: React.MouseEvent) => { //TODO - add grace period this.props.onMouseLeave && this.props.onMouseLeave(e); if (!e.defaultPrevented) { this.props.hoverToOpen && this.close(e); } }; private handleEnterContainer = (e: React.MouseEvent) => { this.props.onMouseEnter && this.props.onMouseEnter(e); if (!e.defaultPrevented) { this.props.hoverToOpen && this.open(e); } }; render() { const { placeholderContent = '', children, clickOutside, //replaced by handlers: onMouseEnter, onMouseLeave, //virtualProps (should not be included in 'rest') open, hoverToOpen, clickPlaceholderToggles, clickToggles, onChange, onPlaceholderToggle, onContainerToggle, onContaineeToggle, onClickOutside, ...rest } = this.props; const { isOpen } = this.state; return ( {children} {placeholderContent} ); } }