import React from "react"; import Tooltip from "@beisen-phoenix/tooltip"; import { SelectProps, SelectValue } from "./PropsInterface"; import SwitchArrow from "./SwitchArrow"; import DeleteInputTxt from "./DelnputTxtIcon"; import Tags from "./Tags"; import { Item } from "./PropsInterface"; import utils from "@beisen-phoenix/common-utils"; const classes = utils.BEMClass("select"); import "./index.scss"; export interface SelectState extends SelectValue { inputValue: string; isFocus: boolean; isHasTooltip: boolean; visibleTxt: boolean; hover: boolean; searchWord: string; inputWidth: number; adjustArrow?: boolean; } const IE = /(msie\s|trident.*rv:)([\w.]+)/.test( navigator.userAgent.toLowerCase() ); export default class Select extends React.PureComponent< SelectProps, SelectState > { static defaultProps = { size: "normal", disabled: false, isMultiSelect: false, placeHolder: "", isSearch: false, readOnly: false, showDelete: true, translation: {} }; private inputRef: React.RefObject = React.createRef(); private hiddenSpanRef: React.RefObject = React.createRef(); private ulRef: React.RefObject = React.createRef(); private clickDelet: boolean = false; constructor(props: SelectProps) { super(props); const { value } = this.props; this.state = { value, inputValue: "", isFocus: false, isHasTooltip: false, visibleTxt: true, hover: false, searchWord: "", inputWidth: 10, adjustArrow: false }; } emitPropsChangeMethod = () => { const { onChange } = this.props; const { value, searchWord } = this.state; onChange && onChange({ value, searchWord }); }; handleValue = () => { const { isMultiSelect } = this.props; const { value } = this.state; return Array.isArray(value) && isMultiSelect ? value : ""; }; isShowToolTip = () => { const { hiddenSpanRef, inputRef } = this; const active = this.props.hasOwnProperty("isActive") ? this.props.isActive : this.state.isFocus; if (hiddenSpanRef.current && inputRef.current && !active) { const { current: spanCurrent } = hiddenSpanRef; const { current: inputCurrent } = inputRef; if (inputCurrent.clientWidth < spanCurrent.clientWidth) { this.setState({ isHasTooltip: true }); return; } } this.state.isHasTooltip && this.setState({ isHasTooltip: false }); }; adjustArrow = () => { if (IE && this.props.isMultiSelect) { const { current } = this.ulRef; const clientHeight = current!.clientHeight; const scrollHeight = current!.scrollHeight; if (scrollHeight > clientHeight) { !this.state.adjustArrow && this.setState({ adjustArrow: true }); } else { this.state.adjustArrow && this.setState({ adjustArrow: false }); } return; } this.state.adjustArrow && this.setState({ adjustArrow: false }); }; componentDidMount() { this.isShowToolTip(); this.adjustArrow(); } componentWillReceiveProps(nextProps: SelectProps) { "value" in nextProps && this.props.value !== nextProps.value && this.setState({ value: nextProps.value }); } componentDidUpdate(prevProps: SelectProps) { this.isShowToolTip(); this.adjustArrow(); if ( this.props.isSearch && this.props.hasOwnProperty("isActive") && !this.props.disabled ) { if ( (this.props.hasOwnProperty("exitSearch") && this.props.exitSearch) || !this.props.isActive ) { this.resetStatus(); } } } resetStatus = () => { this.setState({ isFocus: false, visibleTxt: true, inputValue: "", searchWord: "", value: this.props.value }); }; inputing = (evt: any) => { const searchWord = evt.target.value; const { isSearch, onSearch, readOnly } = this.props; if (!isSearch || readOnly) return; this.setState( { searchWord, inputValue: searchWord // value: this.handleValue() }, () => { this.inputRef.current!.style.width = `${this.handleInputWidth()}px`; } ); onSearch && onSearch(searchWord); }; onBlur = (e: any) => { const isActive = !this.props.disabled && this.props.isActive; this.setState( { isFocus: isActive ? true : false, visibleTxt: isActive ? false : true, inputValue: "", searchWord: "", value: this.clickDelet ? "" : this.props.value }, () => { this.clickDelet = false; if (this.props.isMultiSelect) { this.inputRef && this.inputRef.current && (this.inputRef.current.style.width = `10px`); } } ); }; onKeyDown = (e: any) => { const { keyCode, target } = e; if (keyCode === 8 && !target.value) { this.removeItem(-1); } }; onWrapperClick = (e?: any) => { const { disabled, isSearch, isMultiSelect } = this.props; if (disabled) return; this.props.onClick && this.props.onClick(e); this.setState({ visibleTxt: false }); if (this.inputRef && this.inputRef.current && isSearch) { const value = isMultiSelect ? this.state.value : ""; this.setState({ isFocus: true, value }); this.inputRef.current.focus(); } }; onWrapperMouseEnter = () => { this.setState({ hover: true }); }; onWrapperMouseLeave = () => { this.setState({ hover: false }); }; deleteTxt = e => { const { onDelete, isMultiSelect, isSearch, onSearch, isActive } = this.props; if (!isMultiSelect && isSearch && this.state.isFocus) { this.onWrapperClick(e); this.setState({ inputValue: "", searchWord: "" }, () => { onSearch && onSearch(""); }); return; } this.clickDelet = true; this.setState( { inputValue: "", value: this.handleValue() }, this.emitPropsChangeMethod ); onDelete && onDelete(""); }; removeItem = (item: Item | number): void => { const { value } = this.state; const { onDelete } = this.props; if (Array.isArray(value)) { const copied = [...value]; if (typeof item === "number" && !isNaN(item)) { const temp = copied[item] || copied[copied.length - 1]; !temp.disabled && copied.splice(item, 1); } else if ( typeof item === "object" && copied.includes(item) && !item.disabled ) { copied.splice(copied.indexOf(item), 1); } if (copied.length !== value.length) { this.setState({ value: copied }, this.emitPropsChangeMethod); onDelete && onDelete(copied); } } }; renderMutiItems = () => { const { isMultiSelect, disabled, size } = this.props; const { value } = this.state; if (Array.isArray(value) && isMultiSelect) { return value.map((item: Item, index) => ( )); } }; renderTxt = () => { const { size, disabled, isSearch, isActive } = this.props; const { isFocus, value, isHasTooltip, inputValue, visibleTxt, hover } = this.state; if (typeof value === "string" && value.length) { if (inputValue) return null; const editable = !disabled; const active = editable && (this.props.hasOwnProperty("isActive") ? isActive : isFocus); const txtVisible = this.props.hasOwnProperty("isActive") ? !isActive : visibleTxt; const tipWrapperCls = classes({ element: "tipWrapper", modifiers: { visible: txtVisible, large: size === "large", isSearch, disabled, active } }); const tipCls = classes({ element: "tipEle", modifiers: { isSearch } }); const TempComponent = ( {value} ); return value && isHasTooltip ? ( {TempComponent} ) : ( TempComponent ); } }; handleInputWidth = () => { if (this.props.isMultiSelect) { const { hiddenSpanRef } = this; if (hiddenSpanRef.current) { const { current } = hiddenSpanRef; return current.clientWidth || 10; } return 10; } }; switchDropDown = () => { // this.emitPropsChangeMethod(); }; isShowPlaceHolder = () => { const { inputValue, value } = this.state; if (inputValue) return; if (value && typeof value === "string") return; if (Array.isArray(value) && value.length) return; return true; }; getInputValue = () => { const { inputValue, value } = this.state; if (inputValue) return inputValue; if (value && typeof value === "string" && !this.props.disabled) { return value; } return ""; }; getDeleteIconState() { const { inputValue, value } = this.state; const { disabled, readOnly, showDelete, isMultiSelect } = this.props; if (!showDelete || isMultiSelect) return false; if (disabled || readOnly) return false; if (inputValue) return true; if (value && typeof value === "string") return true; } render() { const { placeHolder, size, disabled, isMultiSelect, isSearch, error, isActive, translation = {}, inputRef, extraCls, suffix } = this.props; const { inputValue, value, isFocus } = this.state; const multiValueLength = isMultiSelect && Array.isArray(value) ? value.length : void 0; const isShowDeleteIcon = this.getDeleteIconState(); const editable = !disabled; const borderColorable = !disabled && !error; const active = editable && (this.props.hasOwnProperty("isActive") ? isActive : isFocus); const hideInput = (disabled && isMultiSelect) || (!isSearch && multiValueLength && isMultiSelect); const singleSearch = !isMultiSelect && isSearch; const wrapperCls = classes({ element: "", modifiers: { editable, borderColorable, singleSearch, multi: isMultiSelect, error, active, disabled, small: size === "small", large: size === "large", normal: size === "normal", exsitMultiValue: multiValueLength }, extra: extraCls }); const calcEleCls = classes({ element: "calcEle" }); const placeHolderCls = classes({ element: "placeHolder", modifiers: { active, large: size === "large", show: this.isShowPlaceHolder() } }); const inputWrapperCls = classes({ element: "inputWrapper", modifiers: { emptyMultiValue: !multiValueLength, isSearch } }); const inputCls = classes({ element: "input", modifiers: { disabled, large: size === "large", unText: !isSearch, multiInput: multiValueLength } }); return (
{inputValue || (typeof value === "string" ? value : " ")}
{this.props.value && !isMultiSelect ? this.props.value : placeHolder || translation.placeHolder}
    {this.renderMutiItems()} {!hideInput && (
  • { inputRef && inputRef(ele as HTMLInputElement); this.inputRef = { current: ele }; }} className={inputCls} value={this.getInputValue()} onChange={this.inputing} onKeyDown={this.onKeyDown} />
  • )} {this.renderTxt()}
); } }