index.tsx 3.69 KB
Newer Older
陈小聪's avatar
陈小聪 committed
1
import React, { Component } from 'react';
2
import { Input, Icon, AutoComplete } from 'antd';
陈小聪's avatar
陈小聪 committed
3 4
import InputProps from 'antd/es/input';

5
import classNames from 'classnames';
6 7
import Debounce from 'lodash-decorators/debounce';
import Bind from 'lodash-decorators/bind';
8 9
import styles from './index.less';

陈小聪's avatar
陈小聪 committed
10 11 12 13 14 15 16 17 18 19 20 21
interface HeaderSearchProps {
  onPressEnter: (value: string) => void;
  onSearch: (value: string) => void;
  onChange: (value: string) => void;
  onVisibleChange: (b: boolean) => void;
  className: string;
  placeholder: string;
  defaultActiveFirstOption: boolean;
  dataSource: any[];
  defaultOpen: boolean;
  open?: boolean;
}
jim's avatar
jim committed
22

陈小聪's avatar
陈小聪 committed
23 24 25 26 27
interface HeaderSearchState {
  value: string;
  searchMode: boolean;
}
export default class HeaderSearch extends Component<HeaderSearchProps, HeaderSearchState> {
jim's avatar
jim committed
28 29 30 31
  static defaultProps = {
    defaultActiveFirstOption: false,
    onPressEnter: () => {},
    onSearch: () => {},
32
    onChange: () => {},
jim's avatar
jim committed
33 34 35 36
    className: '',
    placeholder: '',
    dataSource: [],
    defaultOpen: false,
37
    onVisibleChange: () => {},
jim's avatar
jim committed
38 39
  };

40 41 42 43 44 45 46 47 48
  static getDerivedStateFromProps(props) {
    if ('open' in props) {
      return {
        searchMode: props.open,
      };
    }
    return null;
  }

陈小聪's avatar
陈小聪 committed
49 50
  timeout: NodeJS.Timeout;
  input: InputProps;
陈帅's avatar
陈帅 committed
51 52 53 54 55 56 57 58
  constructor(props) {
    super(props);
    this.state = {
      searchMode: props.defaultOpen,
      value: '',
    };
  }

59 60 61
  componentWillUnmount() {
    clearTimeout(this.timeout);
  }
陈帅's avatar
陈帅 committed
62

jim's avatar
jim committed
63
  onKeyDown = e => {
64
    if (e.key === 'Enter') {
陈帅's avatar
陈帅 committed
65 66
      const { onPressEnter } = this.props;
      const { value } = this.state;
67
      this.timeout = setTimeout(() => {
陈帅's avatar
陈帅 committed
68
        onPressEnter(value); // Fix duplicate onPressEnter
69 70
      }, 0);
    }
jim's avatar
jim committed
71
  };
陈帅's avatar
陈帅 committed
72

jim's avatar
jim committed
73
  onChange = value => {
74
    const { onSearch, onChange } = this.props;
75
    this.setState({ value });
陈帅's avatar
陈帅 committed
76 77
    if (onSearch) {
      onSearch(value);
78
    }
陈帅's avatar
陈帅 committed
79 80
    if (onChange) {
      onChange(value);
81
    }
jim's avatar
jim committed
82
  };
陈帅's avatar
陈帅 committed
83

84
  enterSearchMode = () => {
陈帅's avatar
陈帅 committed
85 86
    const { onVisibleChange } = this.props;
    onVisibleChange(true);
87
    this.setState({ searchMode: true }, () => {
陈帅's avatar
陈帅 committed
88 89
      const { searchMode } = this.state;
      if (searchMode) {
afc163's avatar
afc163 committed
90
        this.input.focus();
91 92
      }
    });
jim's avatar
jim committed
93
  };
陈帅's avatar
陈帅 committed
94

95 96 97 98 99
  leaveSearchMode = () => {
    this.setState({
      searchMode: false,
      value: '',
    });
jim's avatar
jim committed
100
  };
陈帅's avatar
陈帅 committed
101

陈帅's avatar
陈帅 committed
102 103 104 105 106 107 108 109
  // NOTE: 不能小于500,如果长按某键,第一次触发auto repeat的间隔是500ms,小于500会导致触发2次
  @Bind()
  @Debounce(500, {
    leading: true,
    trailing: false,
  })
  debouncePressEnter() {
    const { onPressEnter } = this.props;
Sean Bao's avatar
Sean Bao committed
110
    const { value } = this.state;
陈帅's avatar
陈帅 committed
111 112 113
    onPressEnter(value);
  }

114
  render() {
115
    const { className, placeholder, open, ...restProps } = this.props;
陈帅's avatar
陈帅 committed
116
    const { searchMode, value } = this.state;
117
    delete restProps.defaultOpen; // for rc-select not affected
118
    const inputClass = classNames(styles.input, {
陈帅's avatar
陈帅 committed
119
      [styles.show]: searchMode,
120 121
    });
    return (
122 123 124 125
      <span
        className={classNames(className, styles.headerSearch)}
        onClick={this.enterSearchMode}
        onTransitionEnd={({ propertyName }) => {
陈帅's avatar
陈帅 committed
126 127 128
          if (propertyName === 'width' && !searchMode) {
            const { onVisibleChange } = this.props;
            onVisibleChange(searchMode);
129 130 131
          }
        }}
      >
陈帅's avatar
陈帅 committed
132
        <Icon type="search" key="Icon" />
133
        <AutoComplete
陈帅's avatar
陈帅 committed
134
          key="AutoComplete"
135
          {...restProps}
136
          className={inputClass}
陈帅's avatar
陈帅 committed
137
          value={value}
138 139 140
          onChange={this.onChange}
        >
          <Input
jim's avatar
jim committed
141 142 143
            ref={node => {
              this.input = node;
            }}
jim's avatar
jim committed
144
            aria-label={placeholder}
jim's avatar
jim committed
145
            placeholder={placeholder}
146 147 148 149 150 151 152 153
            onKeyDown={this.onKeyDown}
            onBlur={this.leaveSearchMode}
          />
        </AutoComplete>
      </span>
    );
  }
}