2019-08-13 11:44:04 +00:00
|
|
|
import React, { memo } from 'react'
|
2019-06-10 12:28:54 +00:00
|
|
|
import styled, { css } from 'styled-components'
|
|
|
|
import PropTypes from 'prop-types'
|
2019-08-13 12:04:56 +00:00
|
|
|
import CustomScrollbarsVirtualList from '../scrollbar/custom-scrollbars-virtual-list'
|
2019-08-13 11:21:38 +00:00
|
|
|
import DropDownItem from '../drop-down-item'
|
2019-12-17 14:27:06 +00:00
|
|
|
import Backdrop from '../backdrop'
|
2020-04-13 12:56:47 +00:00
|
|
|
import { VariableSizeList } from "react-window"
|
2020-01-09 13:27:49 +00:00
|
|
|
import onClickOutside from "react-onclickoutside";
|
2019-06-10 12:28:54 +00:00
|
|
|
|
|
|
|
const StyledDropdown = styled.div`
|
2019-08-07 09:36:28 +00:00
|
|
|
font-family: 'Open Sans',sans-serif,Arial;
|
2019-06-18 14:07:57 +00:00
|
|
|
font-style: normal;
|
|
|
|
font-weight: 600;
|
|
|
|
font-size: 13px;
|
2019-08-09 07:57:12 +00:00
|
|
|
${props => props.maxHeight && `
|
2019-08-13 11:21:38 +00:00
|
|
|
max-height: ${props.maxHeight}px;
|
2019-08-09 07:57:12 +00:00
|
|
|
overflow-y: auto;
|
|
|
|
`}
|
2020-02-17 13:37:42 +00:00
|
|
|
height: fit-content;
|
2019-06-10 12:28:54 +00:00
|
|
|
position: absolute;
|
2019-07-18 07:43:17 +00:00
|
|
|
${props => props.manualWidth && `width: ${props.manualWidth};`}
|
2020-09-18 07:13:06 +00:00
|
|
|
${props => (props.directionY === 'top' && css`bottom: ${props => props.manualY ? props.manualY : 'auto'};`)}
|
|
|
|
${props => (props.directionY === 'bottom' && css`top: ${props => props.manualY ? props.manualY : 'auto'};`)}
|
2019-08-15 11:08:46 +00:00
|
|
|
${props => (props.directionX === 'right' && css`right: ${props => props.manualX ? props.manualX : '0px'};`)}
|
|
|
|
${props => (props.directionX === 'left' && css`left: ${props => props.manualX ? props.manualX : '0px'};`)}
|
2019-11-25 12:49:38 +00:00
|
|
|
z-index: 150;
|
2019-12-17 14:27:06 +00:00
|
|
|
display: ${props => (props.open ? 'block' : 'none')};
|
2019-07-04 11:43:55 +00:00
|
|
|
background: #FFFFFF;
|
2019-06-18 14:07:57 +00:00
|
|
|
border-radius: 6px;
|
|
|
|
-moz-border-radius: 6px;
|
|
|
|
-webkit-border-radius: 6px;
|
|
|
|
box-shadow: 0px 5px 20px rgba(0, 0, 0, 0.13);
|
|
|
|
-moz-box-shadow: 0px 5px 20px rgba(0, 0, 0, 0.13);
|
|
|
|
-webkit-box-shadow: 0px 5px 20px rgba(0, 0, 0, 0.13);
|
2020-02-05 12:38:45 +00:00
|
|
|
padding: ${props => !props.maxHeight && props.children && props.children.length > 1 && `6px 0px`};
|
2020-03-26 14:10:14 +00:00
|
|
|
${props => props.columnCount && `
|
|
|
|
-webkit-column-count: ${props.columnCount};
|
|
|
|
-moz-column-count: ${props.columnCount};
|
|
|
|
column-count: ${props.columnCount};
|
|
|
|
`}
|
2019-06-10 12:28:54 +00:00
|
|
|
`;
|
|
|
|
|
2020-01-17 10:58:44 +00:00
|
|
|
// eslint-disable-next-line react/display-name, react/prop-types
|
2019-08-13 11:21:38 +00:00
|
|
|
const Row = memo(({ data, index, style }) => {
|
|
|
|
const option = data[index];
|
2020-09-01 13:55:28 +00:00
|
|
|
// eslint-disable-next-line react/prop-types
|
2020-04-13 12:56:47 +00:00
|
|
|
const separator = option.props.isSeparator ? { width: `calc(100% - 32px)`, height: `1px` } : {}
|
|
|
|
const newStyle = {...style, ...separator};
|
2019-08-13 11:21:38 +00:00
|
|
|
|
2019-07-31 11:45:39 +00:00
|
|
|
return (
|
2019-08-13 11:21:38 +00:00
|
|
|
<DropDownItem
|
2020-01-17 10:58:44 +00:00
|
|
|
// eslint-disable-next-line react/prop-types
|
2019-08-13 11:21:38 +00:00
|
|
|
{...option.props}
|
2020-04-13 12:56:47 +00:00
|
|
|
style={newStyle} />
|
2019-07-31 11:45:39 +00:00
|
|
|
);
|
2019-07-24 17:43:18 +00:00
|
|
|
});
|
2019-06-24 13:18:47 +00:00
|
|
|
|
2019-08-13 11:21:38 +00:00
|
|
|
class DropDown extends React.PureComponent {
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
this.state = {
|
2019-12-23 13:14:46 +00:00
|
|
|
width: this.dropDownRef ? this.dropDownRef.current.offsetWidth : 240,
|
2019-11-19 10:35:42 +00:00
|
|
|
directionX: props.directionX,
|
|
|
|
directionY: props.directionY
|
2019-08-13 11:21:38 +00:00
|
|
|
};
|
2019-12-17 14:27:06 +00:00
|
|
|
|
2019-11-19 10:35:42 +00:00
|
|
|
this.dropDownRef = React.createRef();
|
2019-08-13 11:21:38 +00:00
|
|
|
}
|
|
|
|
|
2019-12-17 14:27:06 +00:00
|
|
|
componentDidMount() {
|
2020-01-17 10:58:44 +00:00
|
|
|
if (this.props.open) {
|
2020-01-09 13:27:49 +00:00
|
|
|
this.props.enableOnClickOutside();
|
|
|
|
this.checkPosition();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
this.props.disableOnClickOutside();
|
2019-09-09 13:45:07 +00:00
|
|
|
}
|
2019-08-13 11:21:38 +00:00
|
|
|
|
2019-12-23 13:14:46 +00:00
|
|
|
componentDidUpdate(prevProps) {
|
2019-12-17 14:27:06 +00:00
|
|
|
if (this.props.open !== prevProps.open) {
|
2020-01-17 10:58:44 +00:00
|
|
|
if (this.props.open) {
|
2020-01-09 13:27:49 +00:00
|
|
|
this.props.enableOnClickOutside();
|
|
|
|
this.checkPosition();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.props.disableOnClickOutside();
|
|
|
|
}
|
2019-11-19 10:35:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-09 13:27:49 +00:00
|
|
|
handleClickOutside = e => {
|
|
|
|
this.toggleDropDown(e);
|
|
|
|
};
|
|
|
|
|
|
|
|
toggleDropDown = (e) => {
|
|
|
|
this.props.clickOutsideAction && this.props.clickOutsideAction(e, !this.props.open);
|
2019-12-17 14:27:06 +00:00
|
|
|
}
|
|
|
|
|
2019-11-19 10:35:42 +00:00
|
|
|
checkPosition = () => {
|
2019-12-17 14:27:06 +00:00
|
|
|
if (!this.dropDownRef.current) return;
|
|
|
|
|
|
|
|
const rects = this.dropDownRef.current.getBoundingClientRect();
|
|
|
|
const container = { width: window.innerWidth, height: window.innerHeight };
|
2020-02-11 08:23:30 +00:00
|
|
|
const left = rects.left < 0 && rects.width < container.width;
|
2020-09-11 05:57:03 +00:00
|
|
|
const right = rects.width && rects.left < 250 && rects.left > rects.width && rects.width < container.width;
|
2020-02-17 13:37:42 +00:00
|
|
|
const top = rects.bottom > container.height && rects.top > rects.height;
|
|
|
|
const bottom = rects.top < 0;
|
2020-02-14 09:21:25 +00:00
|
|
|
const x = left ? 'left' : right ? 'right' : this.state.directionX;
|
2020-02-17 13:37:42 +00:00
|
|
|
const y = bottom ? 'bottom' : top ? 'top' : this.state.directionY;
|
2019-12-17 14:27:06 +00:00
|
|
|
|
|
|
|
this.setState({
|
2020-02-11 08:23:30 +00:00
|
|
|
directionX: x,
|
2020-02-14 09:21:25 +00:00
|
|
|
directionY: y,
|
2019-12-17 14:27:06 +00:00
|
|
|
width: rects.width
|
|
|
|
});
|
2019-09-09 13:45:07 +00:00
|
|
|
}
|
2019-08-13 11:21:38 +00:00
|
|
|
|
2020-04-13 12:56:47 +00:00
|
|
|
getItemHeight = (item) => {
|
|
|
|
const isTablet = window.innerWidth < 1024; //TODO: Make some better
|
|
|
|
|
|
|
|
if (item && item.props.isSeparator)
|
|
|
|
return isTablet ? 16 : 12;
|
|
|
|
|
|
|
|
return isTablet ? 36 : 32;
|
|
|
|
}
|
|
|
|
|
2019-08-13 11:21:38 +00:00
|
|
|
render() {
|
2020-01-28 07:01:05 +00:00
|
|
|
const { maxHeight, children } = this.props;
|
2019-12-23 13:14:46 +00:00
|
|
|
const { directionX, directionY, width } = this.state;
|
2020-04-13 12:56:47 +00:00
|
|
|
const rowHeights = React.Children.map(children, child => this.getItemHeight(child));
|
|
|
|
const getItemSize = index => rowHeights[index];
|
|
|
|
const fullHeight = children && rowHeights.reduce((a, b) => a + b, 0);
|
2019-11-05 13:56:30 +00:00
|
|
|
const calculatedHeight = ((fullHeight > 0) && (fullHeight < maxHeight)) ? fullHeight : maxHeight;
|
2019-11-05 13:42:17 +00:00
|
|
|
const dropDownMaxHeightProp = maxHeight ? { height: calculatedHeight + 'px' } : {};
|
2020-02-17 13:37:42 +00:00
|
|
|
//console.log("DropDown render", this.props);
|
2019-08-13 11:21:38 +00:00
|
|
|
return (
|
2020-01-28 07:01:05 +00:00
|
|
|
<StyledDropdown
|
|
|
|
ref={this.dropDownRef}
|
|
|
|
{...this.props}
|
|
|
|
directionX={directionX}
|
|
|
|
directionY={directionY}
|
|
|
|
{...dropDownMaxHeightProp}
|
|
|
|
>
|
|
|
|
{maxHeight
|
2020-04-13 12:56:47 +00:00
|
|
|
? <VariableSizeList
|
2020-01-28 07:01:05 +00:00
|
|
|
height={calculatedHeight}
|
|
|
|
width={width}
|
2020-04-13 12:56:47 +00:00
|
|
|
itemSize={getItemSize}
|
2020-01-28 07:01:05 +00:00
|
|
|
itemCount={children.length}
|
|
|
|
itemData={children}
|
|
|
|
outerElementType={CustomScrollbarsVirtualList}
|
|
|
|
>
|
|
|
|
{Row}
|
2020-04-13 12:56:47 +00:00
|
|
|
</VariableSizeList>
|
2020-01-28 07:01:05 +00:00
|
|
|
: children}
|
|
|
|
</StyledDropdown>
|
2019-08-13 11:21:38 +00:00
|
|
|
);
|
|
|
|
}
|
2019-09-09 13:45:07 +00:00
|
|
|
}
|
2019-08-13 11:21:38 +00:00
|
|
|
|
2019-06-28 11:37:43 +00:00
|
|
|
DropDown.propTypes = {
|
2019-09-09 13:45:07 +00:00
|
|
|
children: PropTypes.any,
|
2019-12-17 14:27:06 +00:00
|
|
|
className: PropTypes.string,
|
2020-02-11 08:23:30 +00:00
|
|
|
clickOutsideAction: PropTypes.func,
|
2020-03-26 14:10:14 +00:00
|
|
|
directionX: PropTypes.oneOf(['left', 'right']), //TODO: make more informative
|
2019-07-31 11:45:39 +00:00
|
|
|
directionY: PropTypes.oneOf(['bottom', 'top']),
|
2020-02-11 08:23:30 +00:00
|
|
|
disableOnClickOutside: PropTypes.func,
|
|
|
|
enableOnClickOutside: PropTypes.func,
|
2019-12-17 14:27:06 +00:00
|
|
|
id: PropTypes.string,
|
2019-07-31 11:45:39 +00:00
|
|
|
manualWidth: PropTypes.string,
|
2019-08-15 11:08:46 +00:00
|
|
|
manualX: PropTypes.string,
|
2019-12-17 14:27:06 +00:00
|
|
|
manualY: PropTypes.string,
|
2019-11-27 13:08:22 +00:00
|
|
|
maxHeight: PropTypes.number,
|
2020-02-11 08:23:30 +00:00
|
|
|
open: PropTypes.bool,
|
2019-12-17 14:27:06 +00:00
|
|
|
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
2020-03-26 14:10:14 +00:00
|
|
|
withBackdrop: PropTypes.bool,
|
|
|
|
columnCount: PropTypes.number
|
2019-06-28 11:37:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
DropDown.defaultProps = {
|
2019-07-31 11:45:39 +00:00
|
|
|
directionX: 'left',
|
|
|
|
directionY: 'bottom',
|
2020-01-28 07:01:05 +00:00
|
|
|
withBackdrop: false
|
2019-06-28 11:37:43 +00:00
|
|
|
};
|
|
|
|
|
2020-01-09 13:27:49 +00:00
|
|
|
const EnhancedComponent = onClickOutside(DropDown);
|
|
|
|
|
|
|
|
class DropDownContainer extends React.Component {
|
|
|
|
render() {
|
2020-01-28 07:01:05 +00:00
|
|
|
const { withBackdrop = false, open } = this.props;
|
|
|
|
const isTablet = window.innerWidth < 1024; //TODO: Make some better
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<EnhancedComponent disableOnClickOutside={true} {...this.props} />
|
|
|
|
{(withBackdrop && open && isTablet) && <Backdrop visible zIndex={149} onClick={this.toggleDropDown} />}
|
|
|
|
</>);
|
2020-01-09 13:27:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-28 07:01:05 +00:00
|
|
|
DropDownContainer.propTypes = {
|
|
|
|
open: PropTypes.bool,
|
|
|
|
withBackdrop: PropTypes.bool
|
|
|
|
}
|
|
|
|
|
2020-01-09 13:27:49 +00:00
|
|
|
export default DropDownContainer;
|