import * as React from "react"; import * as Constants from "~/common/constants"; import * as SVG from "~/common/svg"; import { css } from "@emotion/core"; import { LoaderSpinner } from "~/components/system/components/Loaders"; const STYLES_DROPDOWN_CONTAINER = css` box-sizing: border-box; z-index: ${Constants.zindex.modal}; `; const STYLES_DROPDOWN = css` box-sizing: border-box; position: absolute; display: flex; flex-direction: column; background-color: ${Constants.system.white}; overflow: hidden; width: 100%; scrollbar-width: none; padding-bottom: 24px; height: calc(100% - 16px); overflow-y: scroll; ::-webkit-scrollbar { display: none; } @media (max-width: ${Constants.sizes.mobile}px) { height: calc(100% - 36px); } `; const STYLES_DROPDOWN_ITEM = css` box-sizing: border-box; padding: 8px; font-size: 0.8em; border-radius: 4px; border: 1px solid transparent; cursor: pointer; margin-bottom: -1px; :hover { border-color: ${Constants.system.lightBorder} !important; } `; const STYLES_INPUT = css` font-family: ${Constants.font.text}; -webkit-appearance: none; width: 100%; height: 40px; background: ${Constants.system.foreground}; color: ${Constants.system.black}; display: flex; font-size: 14px; align-items: center; justify-content: flex-start; outline: 0; border: 0; box-sizing: border-box; transition: 200ms ease all; padding: 0 24px 0 48px; text-overflow: ellipsis; white-space: nowrap; border-radius: 4px; margin-bottom: 16px; ::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */ color: ${Constants.system.black}; opacity: 1; /* Firefox */ } :-ms-input-placeholder { /* Internet Explorer 10-11 */ color: ${Constants.system.black}; } ::-ms-input-placeholder { /* Microsoft Edge */ color: ${Constants.system.black}; } `; const STYLES_LOADER = css` width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; `; export class SearchDropdown extends React.Component { _input; _optionRoot; static defaultProps = { defaultResults: [], }; state = { selectedIndex: -1, }; componentDidMount = () => { window.addEventListener("keydown", this._handleDocumentKeydown); this.debounceInstance = this.debounce(() => { if (this.state.selectedIndex !== -1) { this.setState({ selectedIndex: -1 }); } this.props.onSearch(); }, 500); }; componentWillUnmount = () => { window.removeEventListener("keydown", this._handleDocumentKeydown); }; componentDidUpdate = (prevProps) => { if (prevProps.disabled && !this.props.disabled) { this._input.focus(); } }; debounce = (fn, time) => { let timer; return () => { window.clearTimeout(timer); timer = window.setTimeout(() => fn(), time); }; }; _handleChange = (e) => { this.props.onChange(e); this.debounceInstance(e); }; _handleSelect = (index) => { this.props.onSelect(this.props.results[index].value); }; _handleDocumentKeydown = (e) => { if (e.keyCode === 27) { this._handleDelete(); e.preventDefault(); } else if (e.keyCode === 9) { this._handleDelete(); } else if (e.keyCode === 40) { if (this.state.selectedIndex < this.props.results.length - 1) { let listElem = this._optionRoot.children[this.state.selectedIndex + 1]; let elemRect = listElem.getBoundingClientRect(); let rootRect = this._optionRoot.getBoundingClientRect(); if (elemRect.bottom > rootRect.bottom) { this._optionRoot.scrollTop = listElem.offsetTop + listElem.offsetHeight - this._optionRoot.offsetHeight; } this.setState({ selectedIndex: this.state.selectedIndex + 1 }); } e.preventDefault(); } else if (e.keyCode === 38) { if (this.state.selectedIndex > 0) { let listElem = this._optionRoot.children[this.state.selectedIndex - 1]; let elemRect = listElem.getBoundingClientRect(); let rootRect = this._optionRoot.getBoundingClientRect(); if (elemRect.top < rootRect.top) { this._optionRoot.scrollTop = listElem.offsetTop; } this.setState({ selectedIndex: this.state.selectedIndex - 1 }); } e.preventDefault(); } else if (e.keyCode === 13) { if (this.props.results.length > this.state.selectedIndex && this.state.selectedIndex !== -1) { this._handleSelect(this.state.selectedIndex); } e.preventDefault(); } }; render() { return (
{this.props.disabled ? (
) : (
{ this._input = c; }} />
{ this._optionRoot = c; }} css={STYLES_DROPDOWN} style={this.props.style} > {this.props.results.map((each, i) => (
this.props.onSelect(each.value)} > {each.component}
))}
)}
); } }