diff --git a/client/package.json b/client/package.json index 52dc95a581..59e3dd8315 100644 --- a/client/package.json +++ b/client/package.json @@ -29,7 +29,7 @@ "homepage": "https://librechat.ai", "dependencies": { "@ariakit/react": "^0.4.15", - "@ariakit/react-core": "^0.4.15", + "@ariakit/react-core": "^0.4.17", "@codesandbox/sandpack-react": "^2.19.10", "@dicebear/collection": "^9.2.2", "@dicebear/core": "^9.2.2", diff --git a/client/src/components/Conversations/Convo.tsx b/client/src/components/Conversations/Convo.tsx index b31cfb5a55..510a0f407e 100644 --- a/client/src/components/Conversations/Convo.tsx +++ b/client/src/components/Conversations/Convo.tsx @@ -184,11 +184,12 @@ export default function Conversation({ )}
{!renaming && }
diff --git a/client/src/components/Conversations/ConvoOptions/ConvoOptions.tsx b/client/src/components/Conversations/ConvoOptions/ConvoOptions.tsx index d367dd3963..94f99f62db 100644 --- a/client/src/components/Conversations/ConvoOptions/ConvoOptions.tsx +++ b/client/src/components/Conversations/ConvoOptions/ConvoOptions.tsx @@ -50,35 +50,6 @@ function ConvoOptions({ const archiveConvoMutation = useArchiveConvoMutation(); - const archiveHandler = async () => { - const convoId = conversationId ?? ''; - - if (!convoId) { - return; - } - - archiveConvoMutation.mutate( - { conversationId: convoId, isArchived: true }, - { - onSuccess: () => { - if (currentConvoId === convoId || currentConvoId === 'new') { - newConversation(); - navigate('/c/new', { replace: true }); - } - retainView(); - setIsPopoverActive(false); - }, - onError: () => { - showToast({ - message: localize('com_ui_archive_error'), - severity: NotificationSeverity.ERROR, - showIcon: true, - }); - }, - }, - ); - }; - const duplicateConversation = useDuplicateConversationMutation({ onSuccess: (data) => { navigateToConvo(data.conversation); @@ -220,6 +191,10 @@ function ConvoOptions({ return ( <> e.stopPropagation()} + onClick={(e: MouseEvent) => { + e.stopPropagation(); + }} + onKeyDown={(e: React.KeyboardEvent) => { + if (e.key === 'Enter' || e.key === ' ') { + e.stopPropagation(); + } + }} > diff --git a/client/src/components/ui/DropdownPopup.tsx b/client/src/components/ui/DropdownPopup.tsx index 919557eacb..efadae71d8 100644 --- a/client/src/components/ui/DropdownPopup.tsx +++ b/client/src/components/ui/DropdownPopup.tsx @@ -16,84 +16,119 @@ interface DropdownProps { anchor?: { x: string; y: string }; gutter?: number; modal?: boolean; + portal?: boolean; + preserveTabOrder?: boolean; focusLoop?: boolean; menuId: string; + mountByState?: boolean; + unmountOnHide?: boolean; + finalFocus?: React.RefObject; } +type MenuProps = Omit< + DropdownProps, + 'trigger' | 'isOpen' | 'setIsOpen' | 'focusLoop' | 'mountByState' +>; + const DropdownPopup: React.FC = ({ - keyPrefix, trigger, - items, isOpen, setIsOpen, - menuId, - modal, - gutter = 8, - sameWidth, - className, focusLoop, - iconClassName, - itemClassName, + mountByState, + ...props }) => { const menu = Ariakit.useMenuStore({ open: isOpen, setOpen: setIsOpen, focusLoop }); - + if (mountByState) { + return ( + + {trigger} + {isOpen && } + + ); + } return ( {trigger} - - {items - .filter((item) => item.show !== false) - .map((item, index) => { - if (item.separate === true) { - return ; - } - return ( - { - event.preventDefault(); - if (item.onClick) { - item.onClick(event); - } - if (item.hideOnClick === false) { - return; - } - menu.hide(); - }} - > - {item.icon != null && ( - - )} - {item.label} - {item.kbd != null && ( - // eslint-disable-next-line i18next/no-literal-string - - ⌘{item.kbd} - - )} - - ); - })} - + ); }; +const Menu: React.FC = ({ + items, + menuId, + keyPrefix, + className, + iconClassName, + itemClassName, + modal, + portal, + sameWidth, + gutter = 8, + finalFocus, + unmountOnHide, + preserveTabOrder, +}) => { + const menu = Ariakit.useMenuContext(); + return ( + + {items + .filter((item) => item.show !== false) + .map((item, index) => { + if (item.separate === true) { + return ; + } + return ( + { + event.preventDefault(); + if (item.onClick) { + item.onClick(event); + } + if (item.hideOnClick === false) { + return; + } + menu?.hide(); + }} + > + {item.icon != null && ( + + )} + {item.label} + {item.kbd != null && ( + // eslint-disable-next-line i18next/no-literal-string + + ⌘{item.kbd} + + )} + + ); + })} + + ); +}; + export default DropdownPopup; diff --git a/package-lock.json b/package-lock.json index f3a8d6dfa9..fbc5b37b03 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1165,7 +1165,7 @@ "license": "ISC", "dependencies": { "@ariakit/react": "^0.4.15", - "@ariakit/react-core": "^0.4.15", + "@ariakit/react-core": "^0.4.17", "@codesandbox/sandpack-react": "^2.19.10", "@dicebear/collection": "^9.2.2", "@dicebear/core": "^9.2.2", @@ -1299,6 +1299,42 @@ "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "client/node_modules/@ariakit/react-core": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/@ariakit/react-core/-/react-core-0.4.17.tgz", + "integrity": "sha512-kFF6n+gC/5CRQIyaMTFoBPio2xUe0k9rZhMNdUobWRmc/twfeLVkODx+8UVYaNyKilTge8G0JFqwvFKku/jKEw==", + "license": "MIT", + "dependencies": { + "@ariakit/core": "0.4.15", + "@floating-ui/dom": "^1.0.0", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "client/node_modules/@ariakit/react-core/node_modules/@ariakit/core": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/@ariakit/core/-/core-0.4.15.tgz", + "integrity": "sha512-vvxmZvkNhiisKM+Y1TbGMUfVVchV/sWu9F0xw0RYADXcimWPK31dd9JnIZs/OQ5pwAryAHmERHwuGQVESkSjwQ==", + "license": "MIT" + }, + "client/node_modules/@ariakit/react/node_modules/@ariakit/react-core": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/@ariakit/react-core/-/react-core-0.4.15.tgz", + "integrity": "sha512-Up8+U97nAPJdyUh9E8BCEhJYTA+eVztWpHoo1R9zZfHd4cnBWAg5RHxEmMH+MamlvuRxBQA71hFKY/735fDg+A==", + "license": "MIT", + "dependencies": { + "@ariakit/core": "0.4.14", + "@floating-ui/dom": "^1.0.0", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "client/node_modules/@babel/compat-data": { "version": "7.26.8", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", @@ -3417,20 +3453,6 @@ "resolved": "https://registry.npmjs.org/@ariakit/core/-/core-0.4.14.tgz", "integrity": "sha512-hpzZvyYzGhP09S9jW1XGsU/FD5K3BKsH1eG/QJ8rfgEeUdPS7BvHPt5lHbOeJ2cMrRzBEvsEzLi1ivfDifHsVA==" }, - "node_modules/@ariakit/react-core": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/@ariakit/react-core/-/react-core-0.4.15.tgz", - "integrity": "sha512-Up8+U97nAPJdyUh9E8BCEhJYTA+eVztWpHoo1R9zZfHd4cnBWAg5RHxEmMH+MamlvuRxBQA71hFKY/735fDg+A==", - "dependencies": { - "@ariakit/core": "0.4.14", - "@floating-ui/dom": "^1.0.0", - "use-sync-external-store": "^1.2.0" - }, - "peerDependencies": { - "react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, "node_modules/@aws-crypto/crc32": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz",