import * as React from 'react'; import classNames from 'classnames'; import { composeRef } from 'rc-util/lib/ref'; import SearchOutlined from '@ant-design/icons/SearchOutlined'; import Input, { InputProps } from './Input'; import Button from '../button'; import SizeContext, { SizeType } from '../config-provider/SizeContext'; import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; import { cloneElement } from '../_util/reactNode'; export interface SearchProps extends InputProps { inputPrefixCls?: string; onSearch?: ( value: string, event?: | React.ChangeEvent | React.MouseEvent | React.KeyboardEvent, ) => void; enterButton?: React.ReactNode; loading?: boolean; } const Search = React.forwardRef((props, ref) => { const inputRef = React.useRef(null); const onChange = (e: React.ChangeEvent) => { const { onChange: customOnChange, onSearch: customOnSearch } = props; if (e && e.target && e.type === 'click' && customOnSearch) { customOnSearch((e as React.ChangeEvent).target.value, e); } if (customOnChange) { customOnChange(e); } }; const onMouseDown: React.MouseEventHandler = e => { if (document.activeElement === inputRef.current?.input) { e.preventDefault(); } }; const onSearch = (e: React.MouseEvent | React.KeyboardEvent) => { const { onSearch: customOnSearch } = props; if (customOnSearch) { customOnSearch(inputRef.current?.input.value!, e); } }; const renderAddonAfter = (prefixCls: string, size: SizeType) => { const { enterButton, disabled, addonAfter, loading } = props; const searchIcon = typeof enterButton === 'boolean' || typeof enterButton === 'undefined' ? ( ) : null; const btnClassName = `${prefixCls}-button`; let button: React.ReactNode; const enterButtonAsElement = enterButton as React.ReactElement; const isAntdButton = enterButtonAsElement.type && (enterButtonAsElement.type as typeof Button).__ANT_BUTTON === true; if (isAntdButton || enterButtonAsElement.type === 'button') { button = cloneElement(enterButtonAsElement, { onMouseDown, onClick: onSearch, key: 'enterButton', ...(isAntdButton ? { className: btnClassName, size, } : {}), }); } else { button = ( ); } if (addonAfter) { return [ button, cloneElement(addonAfter, { key: 'addonAfter', }), ]; } return button; }; const renderSearch = ({ getPrefixCls, direction }: ConfigConsumerProps) => { const { prefixCls: customizePrefixCls, inputPrefixCls: customizeInputPrefixCls, className, size: customizeSize, suffix, enterButton, ...restProps } = props; delete (restProps as any).onSearch; delete (restProps as any).loading; const prefixCls = getPrefixCls('input-search', customizePrefixCls); const inputPrefixCls = getPrefixCls('input', customizeInputPrefixCls); const getClassName = (size: SizeType) => classNames( prefixCls, { [`${prefixCls}-rtl`]: direction === 'rtl', [`${prefixCls}-${size}`]: !!size, [`${prefixCls}-with-button`]: !!enterButton, }, className, ); return ( {size => ( (inputRef, ref)} onPressEnter={onSearch} {...restProps} size={customizeSize || size} prefixCls={inputPrefixCls} addonAfter={renderAddonAfter(prefixCls, customizeSize || size)} suffix={suffix} onChange={onChange} className={getClassName(customizeSize || size)} /> )} ); }; return {renderSearch}; }); Search.defaultProps = { enterButton: false, }; Search.displayName = 'Search'; export default Search;