2023-09-13 15:12:23 +00:00
|
|
|
|
import React, { Component, Fragment } from 'react';
|
|
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
|
import classnames from 'classnames';
|
2025-03-01 02:12:48 +00:00
|
|
|
|
import { Utils } from '../utils/utils';
|
2023-09-13 15:12:23 +00:00
|
|
|
|
|
|
|
|
|
const propTypes = {
|
|
|
|
|
placeholder: PropTypes.string,
|
|
|
|
|
autoFocus: PropTypes.bool,
|
|
|
|
|
className: PropTypes.string,
|
|
|
|
|
onChange: PropTypes.func.isRequired,
|
|
|
|
|
onKeyDown: PropTypes.func,
|
|
|
|
|
wait: PropTypes.number,
|
|
|
|
|
disabled: PropTypes.bool,
|
|
|
|
|
style: PropTypes.object,
|
|
|
|
|
isClearable: PropTypes.bool,
|
|
|
|
|
clearValue: PropTypes.func,
|
|
|
|
|
clearClassName: PropTypes.string,
|
|
|
|
|
components: PropTypes.object,
|
|
|
|
|
value: PropTypes.string,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class SearchInput extends Component {
|
|
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
|
super(props);
|
|
|
|
|
this.state = {
|
2025-03-10 06:27:08 +00:00
|
|
|
|
searchValue: props.value || '',
|
2023-09-13 15:12:23 +00:00
|
|
|
|
};
|
|
|
|
|
this.isInputtingChinese = false;
|
|
|
|
|
this.timer = null;
|
|
|
|
|
this.inputRef = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
|
if (this.props.autoFocus && this.inputRef && this.inputRef !== document.activeElement) {
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
this.inputRef.focus();
|
|
|
|
|
}, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-06 09:24:05 +00:00
|
|
|
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
2023-09-13 15:12:23 +00:00
|
|
|
|
if (nextProps.value !== this.props.value) {
|
2024-07-18 03:58:42 +00:00
|
|
|
|
this.setState({ searchValue: nextProps.value });
|
2023-09-13 15:12:23 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
|
this.timer && clearTimeout(this.timer);
|
|
|
|
|
this.timer = null;
|
|
|
|
|
this.inputRef = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onCompositionStart = () => {
|
|
|
|
|
this.isInputtingChinese = true;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
onChange = (e) => {
|
|
|
|
|
this.timer && clearTimeout(this.timer);
|
2025-03-10 06:27:08 +00:00
|
|
|
|
const { onChange, wait = 100 } = this.props;
|
2023-09-13 15:12:23 +00:00
|
|
|
|
let text = e.target.value;
|
2024-07-18 03:58:42 +00:00
|
|
|
|
this.setState({ searchValue: text || '' }, () => {
|
2023-09-13 15:12:23 +00:00
|
|
|
|
if (this.isInputtingChinese) return;
|
|
|
|
|
this.timer = setTimeout(() => {
|
|
|
|
|
onChange && onChange(this.state.searchValue.trim());
|
|
|
|
|
}, wait);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
onCompositionEnd = (e) => {
|
|
|
|
|
this.isInputtingChinese = false;
|
|
|
|
|
this.onChange(e);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
clearSearch = () => {
|
|
|
|
|
const { clearValue } = this.props;
|
2024-07-18 03:58:42 +00:00
|
|
|
|
this.setState({ searchValue: '' }, () => {
|
2023-09-13 15:12:23 +00:00
|
|
|
|
clearValue && clearValue();
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
setFocus = (isSelectAllText) => {
|
|
|
|
|
if (this.inputRef === document.activeElement) return;
|
|
|
|
|
this.inputRef.focus();
|
|
|
|
|
if (isSelectAllText) {
|
|
|
|
|
const txtLength = this.state.searchValue.length;
|
|
|
|
|
this.inputRef.setSelectionRange(0, txtLength);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
renderClear = () => {
|
|
|
|
|
const { isClearable, clearClassName, components = {} } = this.props;
|
|
|
|
|
const { searchValue } = this.state;
|
|
|
|
|
if (!isClearable || !searchValue) return null;
|
|
|
|
|
const { ClearIndicator } = components;
|
|
|
|
|
if (React.isValidElement(ClearIndicator)) {
|
2024-07-18 03:58:42 +00:00
|
|
|
|
return React.cloneElement(ClearIndicator, { clearValue: this.clearSearch });
|
2024-12-26 07:17:16 +00:00
|
|
|
|
} else if (Utils.isFunction(ClearIndicator)) {
|
2023-09-13 15:12:23 +00:00
|
|
|
|
return <ClearIndicator clearValue={this.clearSearch} />;
|
|
|
|
|
}
|
|
|
|
|
return (
|
|
|
|
|
<i className={classnames('search-text-clear input-icon-addon', clearClassName)} onClick={this.clearSearch}>×</i>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
render() {
|
2025-03-10 06:27:08 +00:00
|
|
|
|
const { placeholder, autoFocus, className, onKeyDown, disabled = false, style } = this.props;
|
2023-09-13 15:12:23 +00:00
|
|
|
|
const { searchValue } = this.state;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Fragment>
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
value={searchValue}
|
|
|
|
|
className={classnames('form-control', className)}
|
|
|
|
|
onChange={this.onChange}
|
|
|
|
|
autoFocus={autoFocus}
|
|
|
|
|
placeholder={placeholder}
|
|
|
|
|
onCompositionStart={this.onCompositionStart}
|
|
|
|
|
onCompositionEnd={this.onCompositionEnd}
|
|
|
|
|
onKeyDown={onKeyDown}
|
|
|
|
|
disabled={disabled}
|
|
|
|
|
style={style}
|
|
|
|
|
ref={ref => this.inputRef = ref}
|
|
|
|
|
/>
|
|
|
|
|
{this.renderClear()}
|
|
|
|
|
</Fragment>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SearchInput.propTypes = propTypes;
|
|
|
|
|
|
|
|
|
|
export default SearchInput;
|