import React, { useEffect, useRef, useState } from 'react'; import { Input } from 'antd'; import classNames from 'classnames'; import PinyinMatch from 'pinyin-match'; import PropType from 'prop-types'; import { useClickAway } from 'react-use'; import useMergeValue from 'use-merge-value'; import { SearchOutlined } from '@ant-design/icons'; import styles from './index.less'; import SearchPanel from './panel'; const HeaderSearch = props => { const { className, defaultValue, onVisibleChange, placeholder, open, defaultOpen, menu, ...restProps } = props; const inputRef = useRef(null); const wrapperRef = useRef(null); const allawRef = useRef(null); const [keyword, setKeyword] = useState(''); const [willSearch, setWillSearch] = useState([]); const [willMenu, setWillMenu] = useState([]); const [focus, setFocus] = useState(false); const [isShowWidget, setIsShowWidget] = useState(false); const [visiblePanel, setVisiblePanel] = useState(false); const [targetOffset, setTargetOffset] = useState(0); const [value, setValue] = useMergeValue(defaultValue, { value: props.value, onChange: props.onChange, }); const [searchMode, setSearchMode] = useMergeValue(defaultOpen || true, { value: props.open, onChange: onVisibleChange, }); const inputClass = classNames(styles.input, styles.search, { [styles.show]: searchMode, }); const onMouseEnter = () => { // setFocus(true) // setVisiblePanel(true) }; const onMouseLeave = () => { // setVisiblePanel(false) // setFocus(false) }; const onFocusChange = event => { event.persist && event.persist(); event && event.stopPropagation(); setVisiblePanel(true); // inputRef.current.blur(); // setIsShowWidget(true) }; const onEsc = () => { setValue(''); }; const onNavUp = () => { inputRef.current.blur(); }; const onNavDown = () => { // console.log('onNavDown'); }; const onSearch = event => { event.persist && event.persist(); setKeyword(event.target.value); const ret = []; // eslint-disable-next-line no-shadow const menu = []; (props.flatMenu || []).forEach(item => { if (PinyinMatch.match(item.name, event.target.value)) { ret.push(item); } }); setWillSearch(ret); (props.menu || []).forEach(item => { if (PinyinMatch.match(item.name, event.target.value)) { menu.push(item); } }); setWillMenu(menu); }; useEffect(() => { if (wrapperRef) { setTargetOffset(wrapperRef.current.offsetLeft); } window.addEventListener('resize', () => { // eslint-disable-next-line no-unused-expressions wrapperRef.current && setTargetOffset(wrapperRef.current.offsetLeft); }); return () => { window.removeEventListener('resize', () => setTargetOffset(wrapperRef.current.offsetLeft), ); }; }, [wrapperRef]); useClickAway(allawRef, () => { setFocus(false); }); // eslint-disable-next-line no-shadow const onWillSearch = keyword => { // setKeyword(keyword); onSearch({ target: { value: keyword, }, }); }; const onClose = event => { event.persist && event.persist(); event && event.nativeEvent.stopImmediatePropagation(); inputRef.current.blur(); setFocus(false); }; return ( <div className={classNames(className, styles.headerSearch)} ref={allawRef} onTransitionEnd={({ propertyName }) => { if (propertyName === 'width' && !searchMode) { if (onVisibleChange) { onVisibleChange(searchMode); } } }} > <div ref={wrapperRef}> <Input ref={inputRef} value={keyword} aria-label={placeholder} placeholder={placeholder} className={inputClass} allowClear onFocus={() => { setFocus(true); }} onKeyDown={event => { event.key === 'Escape' && (setKeyword(''), setFocus(false), inputRef.current.blur()); wrapperRef.current.focus(); }} onChange={onSearch} prefix={<SearchOutlined className="site-form-item-icon" />} /> </div> <SearchPanel value={keyword} {...props} target={wrapperRef} inputRef={inputRef} test={focus} className={focus ? styles.active : styles.hidden} style={{ left: `${targetOffset}px`, top: isShowWidget ? '42px' : '52px', }} onEsc={onEsc} onNavUp={onNavUp} onNavDown={onNavDown} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} onWillSearch={onWillSearch} onFocusChange={onFocusChange} willSearch={willSearch} onClose={onClose} console={willMenu} /> </div> ); }; HeaderSearch.propTypes = { onSearch: PropType.func, onChange: PropType.func, onSelect: PropType.func, onVisibleChange: PropType.func, className: PropType.string, placeholder: PropType.string, options: PropType.array, defaultOpen: PropType.bool, open: PropType.bool, defaultValue: PropType.string, value: PropType.string, }; export default HeaderSearch;