mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-04 11:49:02 +08:00
feat: improve model mention autocomplete behavior under IME
This commit is contained in:
parent
09a347cae4
commit
5a7bcd5997
@ -28,6 +28,8 @@ const MentionModelsButton: FC<Props> = ({ mentionModels, onMentionModel: onSelec
|
|||||||
const menuRef = useRef<HTMLDivElement>(null)
|
const menuRef = useRef<HTMLDivElement>(null)
|
||||||
const [searchText, setSearchText] = useState('')
|
const [searchText, setSearchText] = useState('')
|
||||||
const itemRefs = useRef<Array<HTMLDivElement | null>>([])
|
const itemRefs = useRef<Array<HTMLDivElement | null>>([])
|
||||||
|
// Add a new state to track if menu was dismissed
|
||||||
|
const [menuDismissed, setMenuDismissed] = useState(false)
|
||||||
|
|
||||||
const setItemRef = (index: number, el: HTMLDivElement | null) => {
|
const setItemRef = (index: number, el: HTMLDivElement | null) => {
|
||||||
itemRefs.current[index] = el
|
itemRefs.current[index] = el
|
||||||
@ -186,6 +188,7 @@ const MentionModelsButton: FC<Props> = ({ mentionModels, onMentionModel: onSelec
|
|||||||
setIsOpen(true)
|
setIsOpen(true)
|
||||||
setSelectedIndex(0)
|
setSelectedIndex(0)
|
||||||
setSearchText('')
|
setSearchText('')
|
||||||
|
setMenuDismissed(false) // Reset dismissed flag when manually showing selector
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleKeyDown = (e: KeyboardEvent) => {
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
@ -218,6 +221,7 @@ const MentionModelsButton: FC<Props> = ({ mentionModels, onMentionModel: onSelec
|
|||||||
} else if (e.key === 'Escape') {
|
} else if (e.key === 'Escape') {
|
||||||
setIsOpen(false)
|
setIsOpen(false)
|
||||||
setSearchText('')
|
setSearchText('')
|
||||||
|
setMenuDismissed(true) // Set dismissed flag when Escape is pressed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,10 +234,14 @@ const MentionModelsButton: FC<Props> = ({ mentionModels, onMentionModel: onSelec
|
|||||||
if (lastAtIndex === -1 || textBeforeCursor.slice(lastAtIndex + 1).includes(' ')) {
|
if (lastAtIndex === -1 || textBeforeCursor.slice(lastAtIndex + 1).includes(' ')) {
|
||||||
setIsOpen(false)
|
setIsOpen(false)
|
||||||
setSearchText('')
|
setSearchText('')
|
||||||
} else if (lastAtIndex !== -1) {
|
setMenuDismissed(false) // Reset dismissed flag when @ is removed
|
||||||
// Get the text after @ for search
|
} else {
|
||||||
const searchStr = textBeforeCursor.slice(lastAtIndex + 1)
|
// Only open menu if it wasn't explicitly dismissed
|
||||||
setSearchText(searchStr)
|
if (!menuDismissed) {
|
||||||
|
setIsOpen(true)
|
||||||
|
const searchStr = textBeforeCursor.slice(lastAtIndex + 1)
|
||||||
|
setSearchText(searchStr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,39 +260,42 @@ const MentionModelsButton: FC<Props> = ({ mentionModels, onMentionModel: onSelec
|
|||||||
textArea.removeEventListener('input', handleTextChange)
|
textArea.removeEventListener('input', handleTextChange)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [isOpen, selectedIndex, flatModelItems, mentionModels])
|
}, [isOpen, selectedIndex, flatModelItems, mentionModels, menuDismissed])
|
||||||
|
|
||||||
// Hide dropdown if no models available
|
|
||||||
if (flatModelItems.length === 0) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const menu = (
|
const menu = (
|
||||||
<div ref={menuRef} className="ant-dropdown-menu">
|
<div ref={menuRef} className="ant-dropdown-menu">
|
||||||
{modelMenuItems.map((group, groupIndex) => {
|
{flatModelItems.length > 0 ? (
|
||||||
if (!group) return null
|
modelMenuItems.map((group, groupIndex) => {
|
||||||
|
if (!group) return null
|
||||||
|
|
||||||
// Calculate the starting index for this group's items
|
// Calculate starting index for items in this group
|
||||||
const startIndex = modelMenuItems.slice(0, groupIndex).reduce((acc, g) => acc + (g?.children?.length || 0), 0)
|
const startIndex = modelMenuItems.slice(0, groupIndex).reduce((acc, g) => acc + (g?.children?.length || 0), 0)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={group.key} className="ant-dropdown-menu-item-group">
|
<div key={group.key} className="ant-dropdown-menu-item-group">
|
||||||
<div className="ant-dropdown-menu-item-group-title">{group.label}</div>
|
<div className="ant-dropdown-menu-item-group-title">{group.label}</div>
|
||||||
<div>
|
<div>
|
||||||
{group.children.map((item, idx) => (
|
{group.children.map((item, idx) => (
|
||||||
<div
|
<div
|
||||||
key={item.key}
|
key={item.key}
|
||||||
ref={(el) => setItemRef(startIndex + idx, el)}
|
ref={(el) => setItemRef(startIndex + idx, el)}
|
||||||
className={`ant-dropdown-menu-item ${selectedIndex === startIndex + idx ? 'ant-dropdown-menu-item-selected' : ''}`}
|
className={`ant-dropdown-menu-item ${
|
||||||
onClick={item.onClick}>
|
selectedIndex === startIndex + idx ? 'ant-dropdown-menu-item-selected' : ''
|
||||||
<span className="ant-dropdown-menu-item-icon">{item.icon}</span>
|
}`}
|
||||||
{item.label}
|
onClick={item.onClick}>
|
||||||
</div>
|
<span className="ant-dropdown-menu-item-icon">{item.icon}</span>
|
||||||
))}
|
{item.label}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)
|
||||||
)
|
})
|
||||||
})}
|
) : (
|
||||||
|
<div className="ant-dropdown-menu-item-group">
|
||||||
|
<div className="ant-dropdown-menu-item no-results">{t('models.no_matches')}</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -334,6 +345,17 @@ const DropdownMenuStyle = createGlobalStyle`
|
|||||||
&::-webkit-scrollbar-track {
|
&::-webkit-scrollbar-track {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.no-results {
|
||||||
|
padding: 8px 12px;
|
||||||
|
color: var(--color-text-3);
|
||||||
|
cursor: default;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-dropdown-menu-item-group {
|
.ant-dropdown-menu-item-group {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user