120 lines
3.2 KiB
TypeScript
120 lines
3.2 KiB
TypeScript
|
import React from 'react';
|
|||
|
import {findDOMNode} from 'react-dom';
|
|||
|
import {localeable, LocaleProps} from 'amis-core';
|
|||
|
import {themeable, ThemeProps} from 'amis-core';
|
|||
|
// @ts-ignore
|
|||
|
import {matchSorter} from 'match-sorter';
|
|||
|
import PopOverContainer from './PopOverContainer';
|
|||
|
import SearchBox from './SearchBox';
|
|||
|
import ListSelection from './GroupedSelection';
|
|||
|
import InputBox from './InputBox';
|
|||
|
import {Icon} from './icons';
|
|||
|
|
|||
|
export interface InputBoxWithSuggestionProps extends ThemeProps, LocaleProps {
|
|||
|
options: Array<any>;
|
|||
|
value: any;
|
|||
|
onChange: (value: any) => void;
|
|||
|
disabled?: boolean;
|
|||
|
searchable?: boolean;
|
|||
|
popOverContainer?: any;
|
|||
|
hasError?: boolean;
|
|||
|
placeholder?: string;
|
|||
|
clearable?: boolean;
|
|||
|
}
|
|||
|
|
|||
|
const option2value = (item: any) => item.value;
|
|||
|
|
|||
|
export class InputBoxWithSuggestion extends React.Component<InputBoxWithSuggestionProps> {
|
|||
|
constructor(props: InputBoxWithSuggestionProps) {
|
|||
|
super(props);
|
|||
|
this.state = {
|
|||
|
searchText: ''
|
|||
|
};
|
|||
|
this.onSearch = this.onSearch.bind(this);
|
|||
|
this.filterOptions = this.filterOptions.bind(this);
|
|||
|
}
|
|||
|
|
|||
|
onSearch(text: string) {
|
|||
|
let txt = text.toLowerCase();
|
|||
|
|
|||
|
this.setState({searchText: txt});
|
|||
|
}
|
|||
|
|
|||
|
filterOptions(options: any[]) {
|
|||
|
return this.props.value
|
|||
|
? matchSorter(options, this.props.value, {
|
|||
|
keys: ['label', 'value']
|
|||
|
})
|
|||
|
: options;
|
|||
|
}
|
|||
|
|
|||
|
// 选了值,还原options
|
|||
|
onPopClose(e: React.MouseEvent, onClose: () => void) {
|
|||
|
this.setState({searchText: ''});
|
|||
|
onClose();
|
|||
|
}
|
|||
|
|
|||
|
render() {
|
|||
|
const {
|
|||
|
placeholder,
|
|||
|
onChange,
|
|||
|
value,
|
|||
|
classnames: cx,
|
|||
|
disabled,
|
|||
|
translate: __,
|
|||
|
searchable,
|
|||
|
popOverContainer,
|
|||
|
clearable,
|
|||
|
hasError,
|
|||
|
mobileUI
|
|||
|
} = this.props;
|
|||
|
const options = this.filterOptions(
|
|||
|
Array.isArray(this.props.options) ? this.props.options : []
|
|||
|
);
|
|||
|
|
|||
|
return (
|
|||
|
<PopOverContainer
|
|||
|
popOverContainer={popOverContainer || (() => findDOMNode(this))}
|
|||
|
popOverRender={({onClose}) => (
|
|||
|
<>
|
|||
|
{searchable ? (
|
|||
|
<SearchBox mini={false} onSearch={this.onSearch} />
|
|||
|
) : null}
|
|||
|
<ListSelection
|
|||
|
multiple={false}
|
|||
|
onClick={e => this.onPopClose(e, onClose)}
|
|||
|
options={options}
|
|||
|
value={[value]}
|
|||
|
option2value={option2value}
|
|||
|
onChange={(value: any) => {
|
|||
|
onChange?.(value);
|
|||
|
}}
|
|||
|
/>
|
|||
|
</>
|
|||
|
)}
|
|||
|
>
|
|||
|
{({onClick, ref, isOpened}) => (
|
|||
|
<InputBox
|
|||
|
className={cx('InputBox--sug', isOpened ? 'is-active' : '')}
|
|||
|
ref={ref}
|
|||
|
placeholder={placeholder}
|
|||
|
disabled={disabled}
|
|||
|
value={options.find(o => o.value === value)?.label ?? value}
|
|||
|
onChange={onChange}
|
|||
|
clearable={clearable}
|
|||
|
onClick={onClick}
|
|||
|
hasError={hasError}
|
|||
|
mobileUI={mobileUI}
|
|||
|
>
|
|||
|
<span className={cx('InputBox-caret')}>
|
|||
|
<Icon icon="right-arrow-bold" className="icon" />
|
|||
|
</span>
|
|||
|
</InputBox>
|
|||
|
)}
|
|||
|
</PopOverContainer>
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
export default themeable(localeable(InputBoxWithSuggestion));
|