index.tsx 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import { SearchOutlined } from '@ant-design/icons';
  2. import { AutoComplete, Input } from 'antd';
  3. import useMergedState from 'rc-util/es/hooks/useMergedState';
  4. import type { AutoCompleteProps } from 'antd/es/auto-complete';
  5. import React, { useRef } from 'react';
  6. import classNames from 'classnames';
  7. import styles from './index.less';
  8. export type HeaderSearchProps = {
  9. onSearch?: (value?: string) => void;
  10. onChange?: (value?: string) => void;
  11. onVisibleChange?: (b: boolean) => void;
  12. className?: string;
  13. placeholder?: string;
  14. options: AutoCompleteProps['options'];
  15. defaultVisible?: boolean;
  16. visible?: boolean;
  17. defaultValue?: string;
  18. value?: string;
  19. };
  20. const HeaderSearch: React.FC<HeaderSearchProps> = (props) => {
  21. const {
  22. className,
  23. defaultValue,
  24. onVisibleChange,
  25. placeholder,
  26. visible,
  27. defaultVisible,
  28. ...restProps
  29. } = props;
  30. // @ts-ignore
  31. const inputRef = useRef<Input | null>(null);
  32. const [value, setValue] = useMergedState<string | undefined>(defaultValue, {
  33. value: props.value,
  34. onChange: props.onChange,
  35. });
  36. const [searchMode, setSearchMode] = useMergedState(defaultVisible ?? false, {
  37. value: props.visible,
  38. onChange: onVisibleChange,
  39. });
  40. const inputClass = classNames(styles.input, {
  41. [styles.show]: searchMode,
  42. });
  43. // @ts-ignore
  44. return (
  45. <div
  46. className={classNames(className, styles.headerSearch)}
  47. onClick={() => {
  48. setSearchMode(true);
  49. if (searchMode && inputRef.current) {
  50. inputRef.current.focus();
  51. }
  52. }}
  53. onTransitionEnd={({ propertyName }) => {
  54. if (propertyName === 'width' && !searchMode) {
  55. if (onVisibleChange) {
  56. onVisibleChange(searchMode);
  57. }
  58. }
  59. }}
  60. >
  61. <SearchOutlined
  62. key="Icon"
  63. style={{
  64. cursor: 'pointer',
  65. }}
  66. />
  67. <AutoComplete
  68. key="AutoComplete"
  69. className={inputClass}
  70. value={value}
  71. options={restProps.options}
  72. // @ts-ignore
  73. onChange={setValue}
  74. >
  75. <Input
  76. size="small"
  77. ref={inputRef}
  78. defaultValue={defaultValue}
  79. aria-label={placeholder}
  80. placeholder={placeholder}
  81. onKeyDown={(e) => {
  82. if (e.key === 'Enter') {
  83. if (restProps.onSearch) {
  84. restProps.onSearch(value);
  85. }
  86. }
  87. }}
  88. onBlur={() => {
  89. setSearchMode(false);
  90. }}
  91. />
  92. </AutoComplete>
  93. </div>
  94. );
  95. };
  96. export default HeaderSearch;