@@ -76,10 +76,6 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
76
76
( prev , next ) => next [ 0 ] && prev [ 1 ] !== next [ 1 ] ,
77
77
) ;
78
78
79
- // ========================== Active ==========================
80
- const [ activeKey , setActiveKey ] = React . useState < Key > ( null ) ;
81
- const activeEntity = keyEntities [ activeKey as SafeKey ] ;
82
-
83
79
// ========================== Values ==========================
84
80
const mergedCheckedKeys = React . useMemo ( ( ) => {
85
81
if ( ! checkable ) {
@@ -97,18 +93,29 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
97
93
// Single mode should scroll to current key
98
94
if ( open && ! multiple && checkedKeys . length ) {
99
95
treeRef . current ?. scrollTo ( { key : checkedKeys [ 0 ] } ) ;
100
- setActiveKey ( checkedKeys [ 0 ] ) ;
101
96
}
102
97
// eslint-disable-next-line react-hooks/exhaustive-deps
103
98
} , [ open ] ) ;
104
99
105
- // ========================== Search ==========================
106
- const lowerSearchValue = String ( searchValue ) . toLowerCase ( ) ;
107
- const filterTreeNode = ( treeNode : EventDataNode < any > ) => {
108
- if ( ! lowerSearchValue ) {
109
- return false ;
100
+ // ========================== Events ==========================
101
+ const onListMouseDown : React . MouseEventHandler < HTMLDivElement > = event => {
102
+ event . preventDefault ( ) ;
103
+ } ;
104
+
105
+ const onInternalSelect = ( __ : Key [ ] , info : TreeEventInfo ) => {
106
+ const { node } = info ;
107
+
108
+ if ( checkable && isCheckDisabled ( node ) ) {
109
+ return ;
110
+ }
111
+
112
+ onSelect ( node . key , {
113
+ selected : ! checkedKeys . includes ( node . key ) ,
114
+ } ) ;
115
+
116
+ if ( ! multiple ) {
117
+ toggleOpen ( false ) ;
110
118
}
111
- return String ( treeNode [ treeNodeFilterProp ] ) . toLowerCase ( ) . includes ( lowerSearchValue ) ;
112
119
} ;
113
120
114
121
// =========================== Keys ===========================
@@ -122,13 +129,6 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
122
129
return searchValue ? searchExpandedKeys : expandedKeys ;
123
130
} , [ expandedKeys , searchExpandedKeys , treeExpandedKeys , searchValue ] ) ;
124
131
125
- React . useEffect ( ( ) => {
126
- if ( searchValue ) {
127
- setSearchExpandedKeys ( getAllKeys ( treeData , fieldNames ) ) ;
128
- }
129
- // eslint-disable-next-line react-hooks/exhaustive-deps
130
- } , [ searchValue ] ) ;
131
-
132
132
const onInternalExpand = ( keys : Key [ ] ) => {
133
133
setExpandedKeys ( keys ) ;
134
134
setSearchExpandedKeys ( keys ) ;
@@ -138,26 +138,71 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
138
138
}
139
139
} ;
140
140
141
- // ========================== Events ==========================
142
- const onListMouseDown : React . MouseEventHandler < HTMLDivElement > = event => {
143
- event . preventDefault ( ) ;
141
+ // ========================== Search ==========================
142
+ const lowerSearchValue = String ( searchValue ) . toLowerCase ( ) ;
143
+ const filterTreeNode = ( treeNode : EventDataNode < any > ) => {
144
+ if ( ! lowerSearchValue ) {
145
+ return false ;
146
+ }
147
+ return String ( treeNode [ treeNodeFilterProp ] ) . toLowerCase ( ) . includes ( lowerSearchValue ) ;
144
148
} ;
145
149
146
- const onInternalSelect = ( __ : Key [ ] , info : TreeEventInfo ) => {
147
- const { node } = info ;
150
+ React . useEffect ( ( ) => {
151
+ if ( searchValue ) {
152
+ setSearchExpandedKeys ( getAllKeys ( treeData , fieldNames ) ) ;
153
+ }
154
+ // eslint-disable-next-line react-hooks/exhaustive-deps
155
+ } , [ searchValue ] ) ;
148
156
149
- if ( checkable && isCheckDisabled ( node ) ) {
157
+ // ========================== Get First Selectable Node ==========================
158
+ const getFirstMatchingNode = ( nodes : EventDataNode < any > [ ] ) : EventDataNode < any > | null => {
159
+ for ( const node of nodes ) {
160
+ if ( node . disabled || node . selectable === false ) {
161
+ continue ;
162
+ }
163
+
164
+ if ( searchValue ) {
165
+ if ( filterTreeNode ( node ) ) {
166
+ return node ;
167
+ }
168
+ } else {
169
+ return node ;
170
+ }
171
+
172
+ if ( node [ fieldNames . children ] ) {
173
+ const matchInChildren = getFirstMatchingNode ( node [ fieldNames . children ] ) ;
174
+ if ( matchInChildren ) {
175
+ return matchInChildren ;
176
+ }
177
+ }
178
+ }
179
+ return null ;
180
+ } ;
181
+
182
+ // ========================== Active ==========================
183
+ const [ activeKey , setActiveKey ] = React . useState < Key > ( null ) ;
184
+ const activeEntity = keyEntities [ activeKey as SafeKey ] ;
185
+
186
+ React . useEffect ( ( ) => {
187
+ if ( ! open ) {
150
188
return ;
151
189
}
190
+ let nextActiveKey = null ;
152
191
153
- onSelect ( node . key , {
154
- selected : ! checkedKeys . includes ( node . key ) ,
155
- } ) ;
192
+ const getFirstNode = ( ) => {
193
+ const firstNode = getFirstMatchingNode ( memoTreeData ) ;
194
+ return firstNode ? firstNode [ fieldNames . value ] : null ;
195
+ } ;
156
196
157
- if ( ! multiple ) {
158
- toggleOpen ( false ) ;
197
+ // single mode active first checked node
198
+ if ( ! multiple && checkedKeys . length && ! searchValue ) {
199
+ nextActiveKey = checkedKeys [ 0 ] ;
200
+ } else {
201
+ nextActiveKey = getFirstNode ( ) ;
159
202
}
160
- } ;
203
+
204
+ setActiveKey ( nextActiveKey ) ;
205
+ } , [ open , searchValue ] ) ;
161
206
162
207
// ========================= Keyboard =========================
163
208
React . useImperativeHandle ( ref , ( ) => ( {
@@ -176,8 +221,8 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
176
221
// >>> Select item
177
222
case KeyCode . ENTER : {
178
223
if ( activeEntity ) {
179
- const { selectable, value } = activeEntity ?. node || { } ;
180
- if ( selectable !== false ) {
224
+ const { selectable, value, disabled } = activeEntity ?. node || { } ;
225
+ if ( selectable !== false && ! disabled ) {
181
226
onInternalSelect ( null , {
182
227
node : { key : activeKey } ,
183
228
selected : ! checkedKeys . includes ( value ) ,
@@ -197,10 +242,10 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
197
242
} ) ) ;
198
243
199
244
const loadDataFun = useMemo (
200
- ( ) => searchValue ? null : ( loadData as any ) ,
245
+ ( ) => ( searchValue ? null : ( loadData as any ) ) ,
201
246
[ searchValue , treeExpandedKeys || expandedKeys ] ,
202
247
( [ preSearchValue ] , [ nextSearchValue , nextExcludeSearchExpandedKeys ] ) =>
203
- preSearchValue !== nextSearchValue && ! ! ( nextSearchValue || nextExcludeSearchExpandedKeys )
248
+ preSearchValue !== nextSearchValue && ! ! ( nextSearchValue || nextExcludeSearchExpandedKeys ) ,
204
249
) ;
205
250
206
251
// ========================== Render ==========================
0 commit comments