predix-ui
Version:
px-* web components as React styled components
297 lines (275 loc) • 7.84 kB
JavaScript
import React from 'react';
import classnames from 'classnames';
import PropTypes from 'prop-types';
import styled, { css } from 'styled-components';
import Icon from '../IconSet/Icon';
import Button from '../Button';
/*
const SearchInput = styled.input`
height: 2em;
width: 100%;
border: none;
border-radius: 0;
border-bottom: 1px solid var(--px-input-border-color--outer,#889aa5);
padding: 0 .33333rem;
color: var(--px-input-text-color,#2c404c);
&:focus{
border-color: var(--px-input-border-color--outer--focused,#007acc);
background-color: var(--px-input-background-color--focused,#eefbff);
color: var(--px-input-text-color--focused,inherit);
}
`;
*/
const DropdownLabel = styled.div`
overflow: hidden;
flex-grow: 1;
text-overflow: ellipsis;
text-align: left;
~ i{
margin-left: .5rem;
}
`;
DropdownLabel.displayName = 'DropdownLabel';
DropdownLabel.defaultProps = {
className: 'px-dropdown__label'
};
const DropdownContent = styled.div`
z-index: 10;
position: absolute;
background-color: var(--px-dropdown-bg-color,#fff);
border: 1px solid var(--px-dropdown-border-color,gray);
max-height: var(--px-dropdown-max-height,300px);
max-width: var(--px-dropdown-max-width,400px);
min-width: var(--px-dropdown-min-width);
min-height: var(--px-dropdown-min-height);
display: flex;
flex-direction: column;
display: none;
${props => props.opened && css`
display: block;
`}
${props => props.width && css`
width: width;
`}
`;
DropdownContent.displayName = 'DropdownContent';
DropdownContent.defaultProps = {
className: 'px-dropdown__content'
};
const DropdownOption = styled.div`
padding-left: var(--px-dropdown-item-padding,.66667rem);
padding-right: var(--px-dropdown-item-padding,.66667rem);
padding-top: var(--px-dropdown-item-padding);
padding-bottom: var(--px-dropdown-item-padding);
height: var(--px-dropdown-item-height,2rem);
cursor: pointer;
display: flex;
align-items: center;
&:hover {
background-color: var(--px-dropdown-bg-color--hover,#d3d3d3);
}
&.selected,
&:active {
background-color: var(--px-dropdown-bg-color--selected,#00f);
color: var(--px-dropdown-text-color--selected,#fff);
}
${props => props.disabled && css`
color: var(--px-dropdown-text-color--disabled,gray);
background-color: var(--px-dropdown-bg-color--disabled,transparent);
cursor: not-allowed;
pointer-events: none;
`}
${props => props.selected && css`
background-color: var(--px-dropdown-bg-color--selected,#00f);
color: var(--px-dropdown-text-color--selected,#fff);
&:hover {
background-color: var(--px-dropdown-bg-color--selected,#00f);
color: var(--px-dropdown-text-color--selected,#fff);
}
`}
`;
DropdownOption.displayName = 'DropdownOption';
DropdownOption.defaultProps = {
className: 'px-dropdown__option'
};
const DropdownTrigger = styled.div`
max-width: inherit;
width: inherit;
display: flex;
justify-content: center;
align-items: center;
outline: 0;
font-weight: var(--px-dropdown-font-weight,normal);
height: auto;
`;
DropdownTrigger.displayName = 'DropdownTrigger';
DropdownTrigger.defaultProps = {
className: 'px-dropdown__trigger'
};
class Dropdown extends React.Component {
constructor(props) {
super(props);
this.displayName = 'Dropdown';
this._handleClear = this._handleClear.bind(this);
this._handleClick = this._handleClick.bind(this);
this.state = {
dropdownContentWidth: props.dropdownContentWidth,
selected: props.selected, /* eslint-disable-line */
selectedItems: props.selectedItems || null, /* eslint-disable-line */
selectedValues: props.selectedValues || null, /* eslint-disable-line */
opened: props.opened || false,
items: props.items || null
};
}
_handleClick(e) {
if (e && e.target && e.target.classList.contains('px-utl-close')) {
this._clearSelected();
this.setState({
selectedItem: null
});
} else {
this.setState({ opened: !this.state.opened });
}
}
_clearSelected() {
const { items } = this.state;
items.forEach((item) => {
const i = item;
i.selected = false;
return i;
});
this.setState({ items });
}
_handleChange(item, index, e) {
if (item.disabled) {
return;
}
this.setState({
selectedItem: item
});
if (!this.props.multi) {
this._clearSelected();
this._handleClick();
}
// const items = this.state.items[index].selected = !this.state.items[index].selected;
if (this.props.onChange) {
this.props.onChange(item, index, e);
}
}
_handleClear() {
this.setState({
selectedItem: null
});
}
_handleDropdownContentRef(el) {
this.dropdownContent = el;
}
render() {
const {
keys = {
key: 'key',
val: 'val'
},
className,
disabled,
disableClear,
icon,
triggerHeight,
hideChevron,
buttonStyle,
displayValue,
children
} = this.props;
const triggerStyle = {
height: triggerHeight
};
const {
opened,
items,
selectedItem,
dropdownContentWidth
} = this.state;
const baseClasses = classnames('px-dropdown', className);
return (
<div className={baseClasses}>
<Button
theme={buttonStyle}
disabled={disabled}
style={triggerStyle}
onClick={this._handleClick}
>
{children && children}
{!children &&
<DropdownTrigger>
{selectedItem && <DropdownLabel>{selectedItem[keys.val]}</DropdownLabel>}
{!selectedItem && <DropdownLabel>{displayValue}</DropdownLabel>}
{(!hideChevron && !opened && !selectedItem) && <Icon icon={icon} size={16} />}
{(!disableClear && selectedItem && opened) && <Icon icon="px-utl:close" size={16} onClick={this._handleClear} />}
</DropdownTrigger>}
</Button>
<DropdownContent opened={opened} width={dropdownContentWidth}>
{items && items.map((item, index) => (
<DropdownOption
key={item[keys.key]}
data-key={item[keys.key]}
data-val={item[keys.val]}
disabled={item.disabled}
selected={item.selected}
onClick={this._handleChange.bind(this, item, index)} /* eslint-disable-line */
>
{item[keys.val]}
</DropdownOption>
))}
</DropdownContent>
</div>
);
}
}
Dropdown.defaultProps = {
keys: {
key: 'key',
val: 'val'
},
className: null,
disabled: null,
disableClear: null,
triggerHeight: null,
selected: null,
hideChevron: null,
buttonStyle: null,
dropdownContentWidth: null,
displayValue: null,
multi: null,
opened: null,
children: null,
items: null,
onChange: null,
selectedItems: null,
selectedValues: null,
icon: 'px-utl:chevron'
};
Dropdown.propTypes = {
keys: PropTypes.shape({
key: PropTypes.string,
val: PropTypes.string
}),
items: PropTypes.arrayOf(PropTypes.any),
selectedItems: PropTypes.arrayOf(PropTypes.any),
selectedValues: PropTypes.arrayOf(PropTypes.any),
selected: PropTypes.string,
className: PropTypes.string,
disabled: PropTypes.bool,
disableClear: PropTypes.bool,
dropdownContentWidth: PropTypes.number,
triggerHeight: PropTypes.number,
hideChevron: PropTypes.bool,
buttonStyle: PropTypes.string,
displayValue: PropTypes.string,
opened: PropTypes.bool,
multi: PropTypes.bool,
children: PropTypes.node,
onChange: PropTypes.func,
icon: PropTypes.string
};
Dropdown.displayName = 'Dropdown';
export default Dropdown;