packages/bui-core/src/Input/Input.tsx (119 lines of code) (raw):

import { ErrorCircleFilledIcon } from '@bifrostui/icons'; import { isMini, useValue } from '@bifrostui/utils'; import clsx from 'clsx'; import React, { forwardRef, useState } from 'react'; import { InputProps } from './index'; import './Input.less'; const prefixCls = 'bui-input'; const Input = forwardRef<HTMLDivElement, InputProps>((props, ref) => { const { className, defaultValue, value, inputProps, inputRef, name, type, clearable, startIcon, endIcon, placeholder, disabled, onClear, onChange, onFocus, onBlur, ...others } = props; const [inputValue, triggerChange] = useValue({ value, defaultValue, onChange, }); const [hasFocus, setHasFocus] = useState(false); const handleFocus = (e: React.FocusEvent<HTMLInputElement>) => { setHasFocus(true); onFocus?.(e); inputProps?.onFocus?.(e); }; const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => { // 解决H5/小程序清除按钮先失焦隐藏不到的问题 setTimeout(() => { setHasFocus(false); }, 200); onBlur?.(e); inputProps?.onBlur?.(e); }; const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { // 小程序中input有onChange事件,其他类型一般只有onInput事件 if (isMini) return; triggerChange(e, e.target.value); inputProps?.onChange?.(e); }; const handleInput = (e: React.ChangeEvent<HTMLInputElement>) => { // 小程序中input实际有onChange事件,但文档没有标明,故统一通过onInput模拟 if (isMini) { triggerChange(e, e.target.value); } inputProps?.onInput?.(e); }; const handleClear = (e: React.MouseEvent<HTMLDivElement>) => { triggerChange(e, ''); onClear?.(e); }; let nativeProps: Record<string, any> = {}; if (isMini) { nativeProps = { placeholderClass: 'bui-mini-placeholder', }; } return ( <div ref={ref} className={clsx(prefixCls, className, { [`${prefixCls}-disabled`]: disabled, })} {...others} > {/* 开始图标 */} {startIcon && ( <div className={`${prefixCls}-icon ${prefixCls}-icon-start`}> {startIcon} </div> )} {/* 输入框 */} <input {...nativeProps} name={name} type={type} ref={inputRef} value={inputValue} disabled={disabled} placeholder={placeholder} {...inputProps} onChange={handleChange} onFocus={handleFocus} onBlur={handleBlur} onInput={handleInput} className={clsx(`${prefixCls}-input`, inputProps?.className)} /> {/* 清除按钮 */} {clearable && !!inputValue && hasFocus && ( <div className={`${prefixCls}-clear`} onClick={handleClear}> <ErrorCircleFilledIcon htmlColor="#959aa5" /> </div> )} {/* 结束图标 */} {endIcon && ( <div className={`${prefixCls}-icon ${prefixCls}-icon-end`}> {endIcon} </div> )} </div> ); }); Input.displayName = 'BuiInput'; Input.defaultProps = { defaultValue: '', type: 'text', clearable: false, disabled: false, }; export default Input;