fix(SelectModelPopup): 修复键盘事件处理并移除无效的useEffect

将键盘事件监听从window移动到Modal容器,避免事件冒泡问题
移除无效的useEffect并更新键盘事件类型定义
This commit is contained in:
icarus 2025-08-15 14:14:01 +08:00
parent f92edadb61
commit 4211780b95

View File

@ -14,7 +14,6 @@ import React, {
startTransition,
useCallback,
useDeferredValue,
useEffect,
useLayoutEffect,
useMemo,
useRef,
@ -212,10 +211,10 @@ const PopupContainer: React.FC<Props> = ({ model, resolve, modelFilter }) => {
// 处理键盘导航
const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
(e: React.KeyboardEvent<HTMLDivElement>) => {
const modelCount = modelItems.length
if (!open || modelCount === 0 || e.isComposing) return
if (!open || modelCount === 0 || e.nativeEvent.isComposing) return
// 键盘操作时禁用鼠标 hover
if (['ArrowUp', 'ArrowDown', 'PageUp', 'PageDown', 'Enter', 'Escape'].includes(e.key)) {
@ -277,11 +276,6 @@ const PopupContainer: React.FC<Props> = ({ model, resolve, modelFilter }) => {
[modelItems, open, focusedItemKey, resolve, handleItemClick, setFocusedItemKey, listItems]
)
useEffect(() => {
window.addEventListener('keydown', handleKeyDown)
return () => window.removeEventListener('keydown', handleKeyDown)
}, [handleKeyDown])
const onCancel = useCallback(() => {
setOpen(false)
}, [])
@ -340,52 +334,54 @@ const PopupContainer: React.FC<Props> = ({ model, resolve, modelFilter }) => {
)
return (
<Modal
centered
open={open}
onCancel={onCancel}
afterClose={onAfterClose}
width={600}
transitionName="animation-move-down"
styles={{
content: {
borderRadius: 20,
padding: 0,
overflow: 'hidden',
paddingBottom: 16
},
body: {
maxHeight: 'inherit',
padding: 0
}
}}
closeIcon={null}
footer={null}>
{/* 搜索框 */}
<SelectModelSearchBar onSearch={setSearchText} />
<Divider style={{ margin: 0, marginTop: 4, borderBlockStartWidth: 0.5 }} />
<div onKeyDown={handleKeyDown}>
<Modal
centered
open={open}
onCancel={onCancel}
afterClose={onAfterClose}
width={600}
transitionName="animation-move-down"
styles={{
content: {
borderRadius: 20,
padding: 0,
overflow: 'hidden',
paddingBottom: 16
},
body: {
maxHeight: 'inherit',
padding: 0
}
}}
closeIcon={null}
footer={null}>
{/* 搜索框 */}
<SelectModelSearchBar onSearch={setSearchText} />
<Divider style={{ margin: 0, marginTop: 4, borderBlockStartWidth: 0.5 }} />
{listItems.length > 0 ? (
<ListContainer onMouseMove={() => !isMouseOver && setIsMouseOver(true)}>
<DynamicVirtualList
ref={listRef}
list={listItems}
size={listHeight}
getItemKey={getItemKey}
estimateSize={estimateSize}
isSticky={isSticky}
scrollPaddingStart={ITEM_HEIGHT} // 留出 sticky header 高度
overscan={5}
scrollerStyle={{ pointerEvents: isMouseOver ? 'auto' : 'none' }}>
{rowRenderer}
</DynamicVirtualList>
</ListContainer>
) : (
<EmptyState>
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
</EmptyState>
)}
</Modal>
{listItems.length > 0 ? (
<ListContainer onMouseMove={() => !isMouseOver && setIsMouseOver(true)}>
<DynamicVirtualList
ref={listRef}
list={listItems}
size={listHeight}
getItemKey={getItemKey}
estimateSize={estimateSize}
isSticky={isSticky}
scrollPaddingStart={ITEM_HEIGHT} // 留出 sticky header 高度
overscan={5}
scrollerStyle={{ pointerEvents: isMouseOver ? 'auto' : 'none' }}>
{rowRenderer}
</DynamicVirtualList>
</ListContainer>
) : (
<EmptyState>
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
</EmptyState>
)}
</Modal>
</div>
)
}