@@ -3,7 +3,7 @@ import Dropdown from '@rc-component/dropdown';
33import Menu , { MenuItem } from '@rc-component/menu' ;
44import { KeyCode } from '@rc-component/util' ;
55import * as React from 'react' ;
6- import { useEffect , useRef , useState } from 'react' ;
6+ import { useEffect , useState } from 'react' ;
77import type { EditableConfig , Tab , TabsLocale , MoreProps } from '../interface' ;
88import { getRemovable } from '../util' ;
99import AddButton from './AddButton' ;
@@ -39,7 +39,6 @@ const OperationNode = React.forwardRef<HTMLDivElement, OperationNodeProps>((prop
3939 tabs,
4040 locale,
4141 mobile,
42- activeKey,
4342 more : moreProps = { } ,
4443 style,
4544 className,
@@ -57,36 +56,8 @@ const OperationNode = React.forwardRef<HTMLDivElement, OperationNodeProps>((prop
5756 // ======================== Dropdown ========================
5857 const [ open , setOpen ] = useState ( false ) ;
5958 const [ selectedKey , setSelectedKey ] = useState < string > ( null ) ;
60- const [ searchValue , setSearchValue ] = useState ( '' ) ;
61- const searchInputRef = useRef < HTMLInputElement > ( null ) ;
6259
63- const { icon : moreIcon = 'More' , showSearch } = moreProps ;
64-
65- const isSearchable = ! ! showSearch ;
66- const showSearchConfig = typeof showSearch === 'object' ? showSearch : { } ;
67- const {
68- placeholder = 'Search' ,
69- onSearch,
70- searchValue : controlledSearchValue ,
71- autoClearSearchValue = true ,
72- filter : filterOption ,
73- } = showSearchConfig ;
74-
75- const mergedSearchValue =
76- controlledSearchValue !== undefined ? controlledSearchValue : searchValue ;
77- const setSearchValueFn = controlledSearchValue !== undefined ? ( ) => { } : setSearchValue ;
78-
79- const filteredTabs = mergedSearchValue
80- ? tabs . filter ( tab => {
81- if ( filterOption ) {
82- return filterOption ( tab , mergedSearchValue ) ;
83- }
84- if ( typeof tab . label === 'string' ) {
85- return tab . label . toLowerCase ( ) . includes ( mergedSearchValue . toLowerCase ( ) ) ;
86- }
87- return false ;
88- } )
89- : tabs ;
60+ const { icon : moreIcon = 'More' } = moreProps ;
9061
9162 const popupId = `${ id } -more-popup` ;
9263 const dropdownPrefix = `${ prefixCls } -dropdown` ;
@@ -114,7 +85,7 @@ const OperationNode = React.forwardRef<HTMLDivElement, OperationNodeProps>((prop
11485 selectedKeys = { [ selectedKey ] }
11586 aria-label = { dropdownAriaLabel !== undefined ? dropdownAriaLabel : 'expanded dropdown' }
11687 >
117- { filteredTabs . map < React . ReactNode > ( tab => {
88+ { tabs . map < React . ReactNode > ( tab => {
11889 const { closable, disabled, closeIcon, key, label } = tab ;
11990 const removable = getRemovable ( closable , closeIcon , editable , disabled ) ;
12091 return (
@@ -148,13 +119,22 @@ const OperationNode = React.forwardRef<HTMLDivElement, OperationNodeProps>((prop
148119 </ Menu >
149120 ) ;
150121
122+ // Handle popupRender to allow custom popup content
123+ const { popupRender } = moreProps ;
124+ const handleClose = ( ) => setOpen ( false ) ;
125+ const overlay = popupRender
126+ ? popupRender ( menu , {
127+ tabs,
128+ activeKey : props . activeKey ,
129+ onClose : handleClose ,
130+ } )
131+ : menu ;
132+
151133 function selectOffset ( offset : - 1 | 1 ) {
152- const enabledTabs = filteredTabs . filter ( tab => ! tab . disabled ) ;
134+ const enabledTabs = tabs . filter ( tab => ! tab . disabled ) ;
153135 let selectedIndex = enabledTabs . findIndex ( tab => tab . key === selectedKey ) || 0 ;
154136 const len = enabledTabs . length ;
155137
156- if ( len === 0 ) return ;
157-
158138 for ( let i = 0 ; i < len ; i += 1 ) {
159139 selectedIndex = ( selectedIndex + offset + len ) % len ;
160140 const tab = enabledTabs [ selectedIndex ] ;
@@ -165,9 +145,17 @@ const OperationNode = React.forwardRef<HTMLDivElement, OperationNodeProps>((prop
165145 }
166146 }
167147
168- function onKeyboardNavigation ( e : React . KeyboardEvent ) {
148+ function onKeyDown ( e : React . KeyboardEvent ) {
169149 const { which } = e ;
170150
151+ if ( ! open ) {
152+ if ( [ KeyCode . DOWN , KeyCode . SPACE , KeyCode . ENTER ] . includes ( which ) ) {
153+ setOpen ( true ) ;
154+ e . preventDefault ( ) ;
155+ }
156+ return ;
157+ }
158+
171159 switch ( which ) {
172160 case KeyCode . UP :
173161 selectOffset ( - 1 ) ;
@@ -182,72 +170,27 @@ const OperationNode = React.forwardRef<HTMLDivElement, OperationNodeProps>((prop
182170 break ;
183171 case KeyCode . SPACE :
184172 case KeyCode . ENTER :
185- if ( selectedKey && filteredTabs . some ( t => t . key === selectedKey ) ) {
173+ if ( selectedKey !== null ) {
186174 onTabClick ( selectedKey , e ) ;
187175 }
188176 break ;
189177 }
190178 }
191179
192- function onKeyDown ( e : React . KeyboardEvent ) {
193- const { which } = e ;
194-
195- if ( ! open ) {
196- if ( [ KeyCode . DOWN , KeyCode . SPACE , KeyCode . ENTER ] . includes ( which ) ) {
197- setOpen ( true ) ;
198- e . preventDefault ( ) ;
199- }
200- return ;
201- }
202-
203- onKeyboardNavigation ( e ) ;
204- }
205-
206- // 搜索框
207- const searchInput = isSearchable ? (
208- < div className = { `${ dropdownPrefix } -search` } >
209- < input
210- ref = { searchInputRef }
211- type = "text"
212- placeholder = { placeholder }
213- value = { mergedSearchValue }
214- onChange = { e => {
215- const value = e . target . value ;
216- setSearchValueFn ( value ) ;
217- onSearch ?.( value ) ;
218- } }
219- onKeyDown = { onKeyboardNavigation }
220- />
221- </ div >
222- ) : null ;
223-
224180 // ========================= Effect =========================
225181 useEffect ( ( ) => {
226182 // We use query element here to avoid React strict warning
227183 const ele = document . getElementById ( selectedItemId ) ;
228184 if ( ele ?. scrollIntoView ) {
229- ele . scrollIntoView ( { block : 'center' , behavior : 'smooth' } ) ;
185+ ele . scrollIntoView ( false ) ;
230186 }
231187 } , [ selectedItemId , selectedKey ] ) ;
232188
233189 useEffect ( ( ) => {
234- if ( open ) {
235- if ( ! selectedKey && activeKey ) {
236- setSelectedKey ( activeKey ) ;
237- }
238-
239- if ( isSearchable ) {
240- requestAnimationFrame ( ( ) => {
241- searchInputRef . current ?. focus ( ) ;
242- } ) ;
243- }
244- } else {
190+ if ( ! open ) {
245191 setSelectedKey ( null ) ;
246- if ( autoClearSearchValue && controlledSearchValue === undefined ) {
247- setSearchValue ( '' ) ;
248- }
249192 }
250- } , [ open , activeKey , isSearchable , autoClearSearchValue , controlledSearchValue ] ) ;
193+ } , [ open ] ) ;
251194
252195 // ========================= Render =========================
253196 const moreStyle : React . CSSProperties = {
@@ -261,29 +204,18 @@ const OperationNode = React.forwardRef<HTMLDivElement, OperationNodeProps>((prop
261204
262205 const overlayClassName = clsx ( popupClassName , { [ `${ dropdownPrefix } -rtl` ] : rtl } ) ;
263206
264- const dropdownContent = isSearchable ? (
265- < div className = { `${ dropdownPrefix } -container` } >
266- { searchInput }
267- { menu }
268- </ div >
269- ) : (
270- menu
271- ) ;
272-
273- const { showSearch : _s , ...dropdownProps } = moreProps ;
274-
275207 const moreNode : React . ReactNode = mobile ? null : (
276208 < Dropdown
277209 prefixCls = { dropdownPrefix }
278- overlay = { dropdownContent }
210+ overlay = { overlay }
279211 visible = { tabs . length ? open : false }
280212 onVisibleChange = { setOpen }
281213 overlayClassName = { overlayClassName }
282214 overlayStyle = { popupStyle }
283215 mouseEnterDelay = { 0.1 }
284216 mouseLeaveDelay = { 0.1 }
285217 getPopupContainer = { getPopupContainer }
286- { ...dropdownProps }
218+ { ...moreProps }
287219 >
288220 < button
289221 type = "button"
0 commit comments