1- import React , { useRef , MouseEvent } from 'react' ;
2- import { isObject } from 'lodash-es' ;
1+ import React , { useRef } from 'react' ;
2+
33import classNames from 'classnames' ;
4- import { TdSelectInputProps , SelectInputChangeContext , SelectInputKeys , SelectInputValue } from './type' ;
5- import TagInput , { TagInputValue } from '../tag-input' ;
6- import { SelectInputCommonProperties } from './interface' ;
7- import useControlled from '../hooks/useControlled' ;
4+ import { isObject } from 'lodash-es' ;
5+
86import useConfig from '../hooks/useConfig' ;
9- import { InputRef } from '../input' ;
10- import { StyledProps } from '../common' ;
7+ import useControlled from '../hooks/useControlled' ;
8+ import TagInput , { type TagInputValue } from '../tag-input' ;
9+
10+ import type { StyledProps } from '../common' ;
11+ import type { InputRef } from '../input' ;
12+ import type { SelectInputCommonProperties } from './interface' ;
13+ import type { SelectInputChangeContext , SelectInputKeys , SelectInputValue , TdSelectInputProps } from './type' ;
1114
1215export interface RenderSelectMultipleParams {
1316 commonInputProps : SelectInputCommonProperties ;
14- onInnerClear : ( context : { e : MouseEvent < SVGElement > } ) => void ;
1517 popupVisible : boolean ;
1618 allowInput : boolean ;
19+ onInnerClear : ( context : { e : React . MouseEvent < SVGElement > } ) => void ;
20+ onInnerBlur ?: ( context : { e : React . FocusEvent < HTMLInputElement > } ) => void ;
1721}
1822
1923const DEFAULT_KEYS = {
@@ -29,8 +33,12 @@ export interface SelectInputProps extends TdSelectInputProps, StyledProps {
2933export default function useMultiple ( props : SelectInputProps ) {
3034 const { value } = props ;
3135 const { classPrefix } = useConfig ( ) ;
32- const tagInputRef = useRef < InputRef > ( null ) ;
36+
3337 const [ tInputValue , setTInputValue ] = useControlled ( props , 'inputValue' , props . onInputChange ) ;
38+
39+ const tagInputRef = useRef < InputRef > ( null ) ;
40+ const blurTimeoutRef = useRef ( null ) ;
41+
3442 const iKeys : SelectInputKeys = { ...DEFAULT_KEYS , ...props . keys } ;
3543
3644 const getTags = ( ) => {
@@ -51,44 +59,72 @@ export default function useMultiple(props: SelectInputProps) {
5159 props . onTagChange ?.( val , context ) ;
5260 } ;
5361
54- const renderSelectMultiple = ( p : RenderSelectMultipleParams ) => (
55- < TagInput
56- ref = { tagInputRef }
57- { ...p . commonInputProps }
58- autoWidth = { props . autoWidth }
59- readonly = { props . readonly }
60- minCollapsedNum = { props . minCollapsedNum }
61- collapsedItems = { props . collapsedItems }
62- tag = { props . tag }
63- valueDisplay = { props . valueDisplay }
64- placeholder = { tPlaceholder }
65- options = { props . options }
66- value = { tags }
67- inputValue = { p . popupVisible && p . allowInput ? tInputValue : '' }
68- onChange = { onTagInputChange }
69- onInputChange = { ( val , context ) => {
70- // 筛选器统一特性:筛选器按下回车时不清空输入框
71- if ( context ?. trigger === 'enter' || context ?. trigger === 'blur' ) return ;
72- setTInputValue ( val , { trigger : context . trigger , e : context . e } ) ;
73- } }
74- tagProps = { props . tagProps }
75- onClear = { p . onInnerClear }
76- // [Important Info]: SelectInput.blur is not equal to TagInput, example: click popup panel
77- onFocus = { ( val , context ) => {
78- props . onFocus ?.( props . value , { ...context , tagInputValue : val } ) ;
79- } }
80- onBlur = { ! props . panel ? props . onBlur : null }
81- { ...props . tagInputProps }
82- inputProps = { {
83- ...props . inputProps ,
84- readonly : ! props . allowInput || props . readonly ,
85- inputClass : classNames ( props . tagInputProps ?. className , {
86- [ `${ classPrefix } -input--focused` ] : p . popupVisible ,
87- [ `${ classPrefix } -is-focused` ] : p . popupVisible ,
88- } ) ,
89- } }
90- />
91- ) ;
62+ const renderSelectMultiple = ( p : RenderSelectMultipleParams ) => {
63+ const handleBlur = ( value : SelectInputValue , context : { e : React . FocusEvent < HTMLInputElement > } ) => {
64+ if ( blurTimeoutRef . current ) {
65+ clearTimeout ( blurTimeoutRef . current ) ;
66+ }
67+ // 强制把 popupVisible 设置为 false 时,点击 input,会出现 blur -> focus 的情况,因此忽略前面短暂的 blur 事件
68+ blurTimeoutRef . current = setTimeout ( ( ) => {
69+ if ( blurTimeoutRef . current ) {
70+ if ( ! p . popupVisible ) {
71+ p . onInnerBlur ( context ) ;
72+ } else if ( ! props . panel ) {
73+ props . onBlur ?.( value , { e : context . e , inputValue : tInputValue , tagInputValue : tags } ) ;
74+ }
75+ }
76+ blurTimeoutRef . current = null ;
77+ } , 150 ) ;
78+ } ;
79+
80+ const handleFocus = (
81+ val : TagInputValue ,
82+ context : { e : React . FocusEvent < HTMLInputElement > ; inputValue : string } ,
83+ ) => {
84+ if ( blurTimeoutRef . current ) {
85+ clearTimeout ( blurTimeoutRef . current ) ;
86+ blurTimeoutRef . current = null ;
87+ }
88+ props . onFocus ?.( props . value , { ...context , tagInputValue : val } ) ;
89+ } ;
90+
91+ return (
92+ < TagInput
93+ ref = { tagInputRef }
94+ { ...p . commonInputProps }
95+ autoWidth = { props . autoWidth }
96+ readonly = { props . readonly }
97+ minCollapsedNum = { props . minCollapsedNum }
98+ collapsedItems = { props . collapsedItems }
99+ tag = { props . tag }
100+ valueDisplay = { props . valueDisplay }
101+ placeholder = { tPlaceholder }
102+ options = { props . options }
103+ value = { tags }
104+ inputValue = { p . popupVisible && p . allowInput ? tInputValue : '' }
105+ onChange = { onTagInputChange }
106+ onInputChange = { ( val , context ) => {
107+ // 筛选器统一特性:筛选器按下回车时不清空输入框
108+ if ( context ?. trigger === 'enter' || context ?. trigger === 'blur' ) return ;
109+ setTInputValue ( val , { trigger : context . trigger , e : context . e } ) ;
110+ } }
111+ tagProps = { props . tagProps }
112+ onClear = { p . onInnerClear }
113+ // [Important Info]: SelectInput.blur is not equal to TagInput, example: click popup panel
114+ onFocus = { handleFocus }
115+ onBlur = { handleBlur }
116+ { ...props . tagInputProps }
117+ inputProps = { {
118+ ...props . inputProps ,
119+ readonly : ! props . allowInput || props . readonly ,
120+ inputClass : classNames ( props . tagInputProps ?. className , {
121+ [ `${ classPrefix } -input--focused` ] : p . popupVisible ,
122+ [ `${ classPrefix } -is-focused` ] : p . popupVisible ,
123+ } ) ,
124+ } }
125+ />
126+ ) ;
127+ } ;
92128
93129 return {
94130 tags,
0 commit comments