import React from 'react'; import cx from 'classnames'; // @ts-ignore import matchSorter from 'match-sorter'; import keycode from 'keycode'; import Downshift, {StateChangeOptions} from 'downshift'; import {autobind} from '../../utils/helper'; import {ICONS} from './IconPickerIcons'; import {FormItem, FormControlProps, FormBaseControl} from './Item'; import {Option} from '../../components/Select'; /** * 图标选择器 * 文档:https://baidu.gitee.io/amis/docs/components/form/icon-picker */ export interface IconPickerControlSchema extends FormBaseControl { type: 'icon-picker'; // 这就不应该成为一个 amis 控件。。。 } export interface IconPickerProps extends FormControlProps { placeholder?: string; resetValue?: any; noDataTip?: string; } export interface IconPickerState { isOpen?: boolean; inputValue?: string; isFocused?: boolean; vendorIndex?: number; } export default class IconPickerControl extends React.PureComponent< IconPickerProps, IconPickerState > { input?: HTMLInputElement; state: IconPickerState = { isOpen: false, inputValue: '', isFocused: false, vendorIndex: 0 }; static defaultProps: Pick< IconPickerProps, 'resetValue' | 'placeholder' | 'noDataTip' > = { resetValue: '', placeholder: '', noDataTip: '未找到匹配的图标' }; componentWillReceiveProps(nextProps: IconPickerProps) { const props = this.props; if (props.value !== nextProps.value) { this.setState({ inputValue: '' }); } } @autobind changeVendor(index: number) { this.setState( { vendorIndex: index }, this.formatOptions ); } @autobind formatOptions() { let vendorIndex = this.state.vendorIndex || 0; let {prefix, icons} = ICONS[vendorIndex]; return icons.map((icon: string) => ({ label: prefix + icon, value: prefix + icon })); } @autobind getVendors() { return ICONS.map(icons => icons.name); } @autobind inputRef(ref: any) { this.input = ref; } @autobind focus() { if (!this.input) { return; } this.input.focus(); const len = this.input.value.length; len && this.input.setSelectionRange(len, len); } @autobind handleClick() { if (this.props.disabled) { return; } this.focus(); this.setState({ isOpen: true }); } @autobind handleFocus(e: any) { this.setState({ isOpen: true, isFocused: true }); this.props.onFocus && this.props.onFocus(e); } @autobind handleBlur(e: any) { const {onBlur, trimContents, value, onChange} = this.props; this.setState( { isFocused: false }, () => { if (trimContents && value && typeof value === 'string') { onChange(value.trim()); } } ); onBlur && onBlur(e); } @autobind handleInputChange(evt: React.ChangeEvent) { let value = evt.currentTarget.value; this.setState({ inputValue: value }); } @autobind handleKeyDown(evt: React.KeyboardEvent) { const code = keycode(evt.keyCode); if (code !== 'backspace') { return; } const {onChange} = this.props; if (!this.state.inputValue) { onChange(''); this.setState({ inputValue: '' }); } } @autobind handleChange(value: any) { const {onChange, disabled} = this.props; if (disabled) { return; } onChange(value); this.setState({ isFocused: false, inputValue: '' }); } @autobind handleStateChange(changes: StateChangeOptions) { switch (changes.type) { case Downshift.stateChangeTypes.itemMouseEnter: case Downshift.stateChangeTypes.changeInput: this.setState({ isOpen: true }); break; default: const state: IconPickerState = {}; if (typeof changes.isOpen !== 'undefined') { state.isOpen = changes.isOpen; } if (this.state.isOpen && changes.isOpen === false) { state.inputValue = ''; } this.setState(state); break; } } renderFontIcons() { const { className, inputOnly, placeholder, classnames: cx, name, value, noDataTip, disabled, translate: __ } = this.props; const options = this.formatOptions(); const vendors = this.getVendors(); return ( {({getInputProps, getItemProps, isOpen, inputValue}) => { let filteredOptions = inputValue && isOpen ? matchSorter(options, inputValue, {keys: ['label', 'value']}) : options; return (
{placeholder && !value && !this.state.inputValue ? (
{placeholder}
) : null} {!value || (inputValue && isOpen) ? null : (
{value}
)}
{isOpen ? (
{vendors.length > 1 ? (
{vendors.map((vendor: string, index: number) => (
this.changeVendor(index)} key={index} > {vendor}
))}
) : null} {filteredOptions.length ? (
1 ? 'IconPickerControl-multiVendor' : 'IconPickerControl-singleVendor' )} > {filteredOptions.map((option: Option, index: number) => (
))}
) : (
1 ? 'IconPickerControl-multiVendor' : 'IconPickerControl-singleVendor' )} > {__(noDataTip)}
)}
) : null}
); }}
); } render(): JSX.Element { const {className, classPrefix: ns, inputOnly, disabled} = this.props; let input = this.renderFontIcons(); if (inputOnly) { return input; } return (
{input}
); } } @FormItem({ type: 'icon-picker' }) export class IconPickerControlRenderer extends IconPickerControl {}