diff --git a/client/package.json b/client/package.json index befe52b5ed..35cf53795f 100644 --- a/client/package.json +++ b/client/package.json @@ -31,7 +31,7 @@ "@ariakit/react": "^0.4.5", "@dicebear/collection": "^7.0.4", "@dicebear/core": "^7.0.4", - "@headlessui/react": "^1.7.13", + "@headlessui/react": "^2.1.2", "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-alert-dialog": "^1.0.2", "@radix-ui/react-checkbox": "^1.0.3", diff --git a/client/src/components/Chat/Input/PopoverButtons.tsx b/client/src/components/Chat/Input/PopoverButtons.tsx index 6330e72fcd..1417318531 100644 --- a/client/src/components/Chat/Input/PopoverButtons.tsx +++ b/client/src/components/Chat/Input/PopoverButtons.tsx @@ -122,7 +122,7 @@ export default function PopoverButtons({ type="button" className={cn( button.buttonClass, - 'border-2 border-gray-300/50 focus:ring-1 focus:ring-green-500/90 dark:border-gray-500/50 dark:focus:ring-green-500', + 'border border-gray-300/50 focus:ring-1 focus:ring-green-500/90 dark:border-gray-500/50 dark:focus:ring-green-500', 'ml-1 h-full bg-transparent px-2 py-1 text-xs font-medium font-normal text-black hover:bg-gray-100 hover:text-black dark:bg-transparent dark:text-white dark:hover:bg-gray-600 dark:hover:text-white', buttonClass ?? '', )} @@ -141,7 +141,7 @@ export default function PopoverButtons({ type="button" className={cn( button.buttonClass, - 'flex justify-center border-2 border-gray-300/50 focus:ring-1 focus:ring-green-500/90 dark:border-gray-500/50 dark:focus:ring-green-500', + 'flex justify-center border border-gray-300/50 focus:ring-1 focus:ring-green-500/90 dark:border-gray-500/50 dark:focus:ring-green-500', 'h-full w-full bg-transparent px-2 py-1 text-xs font-medium font-normal text-black hover:bg-gray-100 hover:text-black dark:bg-transparent dark:text-white dark:hover:bg-gray-600 dark:hover:text-white', buttonClass ?? '', )} diff --git a/client/src/components/Input/SetKeyDialog/SetKeyDialog.tsx b/client/src/components/Input/SetKeyDialog/SetKeyDialog.tsx index cb5b0fd469..601bbb96bb 100644 --- a/client/src/components/Input/SetKeyDialog/SetKeyDialog.tsx +++ b/client/src/components/Input/SetKeyDialog/SetKeyDialog.tsx @@ -178,7 +178,7 @@ const SetKeyDialog = ({ value={expiresAtLabel} onChange={handleExpirationChange} options={expirationOptions.map((option) => option.display)} - width={185} + sizeClasses="w-[185px]" /> = ({ plugin }) => { {plugin.loading && } - + - + - + = ({ plugin }) => { classProp="max-h-[450px]" /> )} - + ); }} diff --git a/client/src/components/Nav/NavLinks.tsx b/client/src/components/Nav/NavLinks.tsx index 0e74783e7a..6ae3826a60 100644 --- a/client/src/components/Nav/NavLinks.tsx +++ b/client/src/components/Nav/NavLinks.tsx @@ -1,7 +1,7 @@ import { FileText } from 'lucide-react'; import { useRecoilState } from 'recoil'; import { Fragment, useState, memo } from 'react'; -import { Menu, Transition } from '@headlessui/react'; +import { Menu, MenuItem, MenuButton, MenuItems, Transition } from '@headlessui/react'; import { useGetUserBalance, useGetStartupConfig } from 'librechat-data-provider/react-query'; import FilesView from '~/components/Chat/Input/Files/FilesView'; import { useAuthContext } from '~/hooks/AuthContext'; @@ -32,7 +32,7 @@ function NavLinks() { {({ open }) => ( <> - {user?.name || user?.username || localize('com_nav_user')} - + - +
{user?.email || localize('com_nav_user')}
@@ -90,34 +90,34 @@ function NavLinks() {
)} - + } text={localize('com_nav_my_files')} clickHandler={() => setShowFiles(true)} /> - + {startupConfig?.helpAndFaqURL !== '/' && ( - + } text={localize('com_nav_help_faq')} clickHandler={() => window.open(startupConfig?.helpAndFaqURL, '_blank')} /> - + )} - + } text={localize('com_nav_settings')} clickHandler={() => setShowSettings(true)} /> - +
- + - - + + )} diff --git a/client/src/components/Nav/Settings.tsx b/client/src/components/Nav/Settings.tsx index 00ed6c4bca..d582ff5599 100644 --- a/client/src/components/Nav/Settings.tsx +++ b/client/src/components/Nav/Settings.tsx @@ -2,7 +2,14 @@ import * as Tabs from '@radix-ui/react-tabs'; import { MessageSquare } from 'lucide-react'; import { SettingsTabValues } from 'librechat-data-provider'; import type { TDialogProps } from '~/common'; -import { Dialog, DialogContent, DialogHeader, DialogTitle } from '~/components/ui'; +import { + Button, + Dialog, + DialogPanel, + DialogTitle, + Transition, + TransitionChild, +} from '@headlessui/react'; import { GearIcon, DataIcon, SpeechIcon, UserIcon, ExperimentIcon } from '~/components/svg'; import { General, Messages, Speech, Beta, Data, Account } from './SettingsTabs'; import { useMediaQuery, useLocalize } from '~/hooks'; @@ -13,132 +20,183 @@ export default function Settings({ open, onOpenChange }: TDialogProps) { const localize = useLocalize(); return ( - - - - - {localize('com_nav_settings')} - - -
- + + + +

+ {localize('com_nav_settings')} +

+ + +
+ + + + + {localize('com_nav_setting_general')} + + + + {localize('com_endpoint_messages')} + + + + {localize('com_nav_setting_beta')} + + + + {localize('com_nav_setting_speech')} + + + + {localize('com_nav_setting_data')} + + + + {localize('com_nav_setting_account')} + + +
+ + + + + + +
+
+
+ +
+ +
+ ); } diff --git a/client/src/components/Nav/SettingsTabs/General/General.tsx b/client/src/components/Nav/SettingsTabs/General/General.tsx index 9592392da7..e5edfec83e 100644 --- a/client/src/components/Nav/SettingsTabs/General/General.tsx +++ b/client/src/components/Nav/SettingsTabs/General/General.tsx @@ -34,9 +34,8 @@ export const ThemeSelector = ({ value={theme} onChange={onChange} options={themeOptions} - width={180} - position={'left'} - maxHeight="200px" + sizeClasses="w-[220px]" + anchor="bottom start" testId="theme-selector" />
@@ -111,8 +110,8 @@ export const LangSelector = ({
diff --git a/client/src/components/Nav/SettingsTabs/General/LangSelector.spec.tsx b/client/src/components/Nav/SettingsTabs/General/LangSelector.spec.tsx index 5633e7fc62..74469b2fd5 100644 --- a/client/src/components/Nav/SettingsTabs/General/LangSelector.spec.tsx +++ b/client/src/components/Nav/SettingsTabs/General/LangSelector.spec.tsx @@ -13,6 +13,11 @@ describe('LangSelector', () => { }); it('renders correctly', () => { + global.ResizeObserver = class MockedResizeObserver { + observe = jest.fn(); + unobserve = jest.fn(); + disconnect = jest.fn(); + }; const { getByText } = render( @@ -24,6 +29,11 @@ describe('LangSelector', () => { }); it('calls onChange when the select value changes', async () => { + global.ResizeObserver = class MockedResizeObserver { + observe = jest.fn(); + unobserve = jest.fn(); + disconnect = jest.fn(); + }; const { getByText, getByTestId } = render( diff --git a/client/src/components/Nav/SettingsTabs/General/ThemeSelector.spec.tsx b/client/src/components/Nav/SettingsTabs/General/ThemeSelector.spec.tsx index e989e40c36..e8d28c8a39 100644 --- a/client/src/components/Nav/SettingsTabs/General/ThemeSelector.spec.tsx +++ b/client/src/components/Nav/SettingsTabs/General/ThemeSelector.spec.tsx @@ -1,6 +1,8 @@ +// ThemeSelector.spec.tsx import 'test/matchMedia.mock'; + import React from 'react'; -import { render, fireEvent } from '@testing-library/react'; +import { render, fireEvent, waitFor } from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect'; import { ThemeSelector } from './General'; import { RecoilRoot } from 'recoil'; @@ -13,6 +15,11 @@ describe('ThemeSelector', () => { }); it('renders correctly', () => { + global.ResizeObserver = class MockedResizeObserver { + observe = jest.fn(); + unobserve = jest.fn(); + disconnect = jest.fn(); + }; const { getByText } = render( @@ -24,6 +31,11 @@ describe('ThemeSelector', () => { }); it('calls onChange when the select value changes', async () => { + global.ResizeObserver = class MockedResizeObserver { + observe = jest.fn(); + unobserve = jest.fn(); + disconnect = jest.fn(); + }; const { getByText, getByTestId } = render( @@ -42,9 +54,9 @@ describe('ThemeSelector', () => { const darkOption = getByText('Dark'); fireEvent.click(darkOption); - // Ensure that the onChange is called with the expected value after a short delay - await new Promise((resolve) => setTimeout(resolve, 0)); - - expect(mockOnChange).toHaveBeenCalledWith('dark'); + // Ensure that the onChange is called with the expected value + await waitFor(() => { + expect(mockOnChange).toHaveBeenCalledWith('dark'); + }); }); }); diff --git a/client/src/components/Nav/SettingsTabs/Messages/ForkSettings.tsx b/client/src/components/Nav/SettingsTabs/Messages/ForkSettings.tsx index 7ff24950ea..538a844cab 100644 --- a/client/src/components/Nav/SettingsTabs/Messages/ForkSettings.tsx +++ b/client/src/components/Nav/SettingsTabs/Messages/ForkSettings.tsx @@ -29,8 +29,8 @@ export const ForkSettings = () => { value={forkSetting} onChange={setForkSetting} options={forkOptions} - position={'left'} - maxHeight="199px" + sizeClasses="w-[200px]" + anchor="bottom start" testId="fork-setting-dropdown" /> diff --git a/client/src/components/Nav/SettingsTabs/Speech/STT/EngineSTTDropdown.tsx b/client/src/components/Nav/SettingsTabs/Speech/STT/EngineSTTDropdown.tsx index ab27c20e32..01771399b0 100644 --- a/client/src/components/Nav/SettingsTabs/Speech/STT/EngineSTTDropdown.tsx +++ b/client/src/components/Nav/SettingsTabs/Speech/STT/EngineSTTDropdown.tsx @@ -22,8 +22,8 @@ export default function EngineSTTDropdown() { value={engineSTT} onChange={handleSelect} options={endpointOptions} - width={180} - position={'left'} + sizeClasses="w-[180px]" + anchor="bottom start" testId="EngineSTTDropdown" /> diff --git a/client/src/components/Nav/SettingsTabs/Speech/STT/LanguageSTTDropdown.tsx b/client/src/components/Nav/SettingsTabs/Speech/STT/LanguageSTTDropdown.tsx index 8c10fa49d5..0904b1dbf6 100644 --- a/client/src/components/Nav/SettingsTabs/Speech/STT/LanguageSTTDropdown.tsx +++ b/client/src/components/Nav/SettingsTabs/Speech/STT/LanguageSTTDropdown.tsx @@ -98,8 +98,8 @@ export default function LanguageSTTDropdown() { value={languageSTT} onChange={handleSelect} options={languageOptions} - width={220} - position={'left'} + sizeClasses="[--anchor-max-height:256px]" + anchor="bottom start" testId="LanguageSTTDropdown" /> diff --git a/client/src/components/Nav/SettingsTabs/Speech/Speech.tsx b/client/src/components/Nav/SettingsTabs/Speech/Speech.tsx index 06b57cc882..010a7f09f7 100644 --- a/client/src/components/Nav/SettingsTabs/Speech/Speech.tsx +++ b/client/src/components/Nav/SettingsTabs/Speech/Speech.tsx @@ -130,7 +130,7 @@ function Speech() { -
- +
+ setAdvancedMode(false)} className={cn( diff --git a/client/src/components/Nav/SettingsTabs/Speech/TTS/EngineTTSDropdown.tsx b/client/src/components/Nav/SettingsTabs/Speech/TTS/EngineTTSDropdown.tsx index 77bb85dc78..8f0242d749 100644 --- a/client/src/components/Nav/SettingsTabs/Speech/TTS/EngineTTSDropdown.tsx +++ b/client/src/components/Nav/SettingsTabs/Speech/TTS/EngineTTSDropdown.tsx @@ -22,8 +22,8 @@ export default function EngineTTSDropdown() { value={engineTTS} onChange={handleSelect} options={endpointOptions} - width={180} - position={'left'} + sizeClasses="w-[180px]" + anchor="bottom start" testId="EngineTTSDropdown" />
diff --git a/client/src/components/Nav/SettingsTabs/Speech/TTS/VoiceDropdown.tsx b/client/src/components/Nav/SettingsTabs/Speech/TTS/VoiceDropdown.tsx index afe95b5fcf..7d2074debb 100644 --- a/client/src/components/Nav/SettingsTabs/Speech/TTS/VoiceDropdown.tsx +++ b/client/src/components/Nav/SettingsTabs/Speech/TTS/VoiceDropdown.tsx @@ -67,6 +67,8 @@ export default function VoiceDropdown() { value={voice} onChange={setVoice} options={voiceOptions} + sizeClasses="min-w-[200px] !max-w-[400px] [--anchor-max-width:400px]" + anchor="bottom start" position="left" testId="VoiceDropdown" /> diff --git a/client/src/components/Plugins/Store/PluginStoreDialog.tsx b/client/src/components/Plugins/Store/PluginStoreDialog.tsx index 3bc4852163..5c3f55863d 100644 --- a/client/src/components/Plugins/Store/PluginStoreDialog.tsx +++ b/client/src/components/Plugins/Store/PluginStoreDialog.tsx @@ -1,5 +1,5 @@ import { Search, X } from 'lucide-react'; -import { Dialog } from '@headlessui/react'; +import { Dialog, DialogPanel, DialogTitle } from '@headlessui/react'; import { useState, useEffect, useCallback } from 'react'; import { useAvailablePluginsQuery } from 'librechat-data-provider/react-query'; import type { TError, TPlugin, TPluginAction } from 'librechat-data-provider'; @@ -134,16 +134,16 @@ function PluginStoreDialog({ isOpen, setIsOpen }: TPluginStoreDialogProps) {
{/* Full-screen container to center the panel */}
-
- + {localize('com_nav_plugin_store')} - +
@@ -236,7 +236,7 @@ function PluginStoreDialog({ isOpen, setIsOpen }: TPluginStoreDialogProps) {
*/}
- +
); diff --git a/client/src/components/Tools/ToolSelectDialog.tsx b/client/src/components/Tools/ToolSelectDialog.tsx index c6427630a1..685b57009f 100644 --- a/client/src/components/Tools/ToolSelectDialog.tsx +++ b/client/src/components/Tools/ToolSelectDialog.tsx @@ -1,6 +1,6 @@ import { useEffect } from 'react'; import { Search, X } from 'lucide-react'; -import { Dialog } from '@headlessui/react'; +import { Dialog, DialogPanel, DialogTitle, Description } from '@headlessui/react'; import { useFormContext } from 'react-hook-form'; import { useUpdateUserPluginsMutation } from 'librechat-data-provider/react-query'; import type { AssistantsEndpoint, TError, TPluginAction } from 'librechat-data-provider'; @@ -142,19 +142,19 @@ function ToolSelectDialog({
{/* Full-screen container to center the panel */}
-
- + {localize('com_nav_tool_dialog')} - - + + {localize('com_nav_tool_dialog_description')} - +
@@ -232,7 +232,7 @@ function ToolSelectDialog({ )}
-
+
); diff --git a/client/src/components/ui/Dropdown.tsx b/client/src/components/ui/Dropdown.tsx index 0e057e0742..604d30f9af 100644 --- a/client/src/components/ui/Dropdown.tsx +++ b/client/src/components/ui/Dropdown.tsx @@ -1,5 +1,12 @@ -import React, { FC, useState } from 'react'; -import { Listbox } from '@headlessui/react'; +import React, { FC, useContext, useState } from 'react'; +import { + Listbox, + ListboxButton, + ListboxOption, + ListboxOptions, + Transition, +} from '@headlessui/react'; +import { AnchorPropsWithSelection } from '@headlessui/react/dist/internal/floating'; import { cn } from '~/utils/'; type OptionType = { @@ -7,17 +14,14 @@ type OptionType = { display?: string; }; -type DropdownPosition = 'left' | 'right'; - interface DropdownProps { value: string; label?: string; onChange: (value: string) => void; options: (string | OptionType)[]; className?: string; - position?: DropdownPosition; - width?: number; - maxHeight?: string; + anchor?: AnchorPropsWithSelection; + sizeClasses?: string; testId?: string; } @@ -27,18 +31,12 @@ const Dropdown: FC = ({ onChange, options, className = '', - position = 'right', - width, - maxHeight = 'auto', + anchor, + sizeClasses, testId = 'dropdown-menu', }) => { const [selectedValue, setSelectedValue] = useState(initialValue); - const positionClasses = { - right: 'origin-bottom-left left-0', - left: 'origin-bottom-right right-0', - }; - return (
= ({ }} >
- = ({ - - + - {options.map((item, index) => ( - -
- - {typeof item === 'string' ? item : (item as OptionType).display} - - {selectedValue === (typeof item === 'string' ? item : item.value) && ( - - - - - + + {options.map((item, index) => ( + - - ))} - + style={{ width: '100%' }} + data-theme={typeof item === 'string' ? item : (item as OptionType).value} + > +
+ + {typeof item === 'string' ? item : (item as OptionType).display} + + {selectedValue === (typeof item === 'string' ? item : item.value) && ( + + + + + + )} +
+
+ ))} +
+
diff --git a/client/src/components/ui/DropdownNoState.tsx b/client/src/components/ui/DropdownNoState.tsx index 8f05394b0c..11f2301253 100644 --- a/client/src/components/ui/DropdownNoState.tsx +++ b/client/src/components/ui/DropdownNoState.tsx @@ -1,5 +1,12 @@ -import React, { FC } from 'react'; -import { Listbox } from '@headlessui/react'; +import React, { FC, useContext, useState } from 'react'; +import { + Listbox, + ListboxButton, + ListboxOption, + ListboxOptions, + Transition, +} from '@headlessui/react'; +import { AnchorPropsWithSelection } from '@headlessui/react/dist/internal/floating'; import { cn } from '~/utils/'; type OptionType = { @@ -7,17 +14,14 @@ type OptionType = { display?: string; }; -type DropdownPosition = 'left' | 'right'; - interface DropdownProps { value: string; label?: string; onChange: (value: string) => void; options: (string | OptionType)[]; className?: string; - position?: DropdownPosition; - width?: number; - maxHeight?: string; + anchor?: AnchorPropsWithSelection; + sizeClasses?: string; testId?: string; } @@ -27,16 +31,10 @@ const Dropdown: FC = ({ onChange, options, className = '', - position = 'right', - width, - maxHeight = 'auto', + anchor, + sizeClasses, testId = 'dropdown-menu', }) => { - const positionClasses = { - right: 'origin-bottom-left left-0', - left: 'origin-bottom-right right-0', - }; - return (
= ({ }} >
- {label} @@ -67,35 +66,45 @@ const Dropdown: FC = ({ viewBox="0 0 24 24" strokeWidth="2" stroke="currentColor" - className="h-4 w-5 rotate-0 transform text-gray-400 transition-transform duration-300 ease-in-out" + className="h-4 w-5 rotate-0 transform text-black transition-transform duration-300 ease-in-out dark:text-gray-50" > - - + - {options.map((item, index) => ( - - - {typeof item === 'string' ? item : (item as OptionType).display} - - - ))} - + + {options.map((item, index) => ( + +
+ + {typeof item === 'string' ? item : (item as OptionType).display} + +
+
+ ))} +
+
diff --git a/client/src/components/ui/MultiSelectDropDown.tsx b/client/src/components/ui/MultiSelectDropDown.tsx index 300d032486..0e2724dcf8 100644 --- a/client/src/components/ui/MultiSelectDropDown.tsx +++ b/client/src/components/ui/MultiSelectDropDown.tsx @@ -1,5 +1,12 @@ import React, { useState, useRef } from 'react'; -import { Listbox, Transition } from '@headlessui/react'; +import { + Listbox, + ListboxButton, + Label, + ListboxOptions, + ListboxOption, + Transition, +} from '@headlessui/react'; import { Wrench, ArrowRight } from 'lucide-react'; import { CheckMark } from '~/components/svg'; import useOnClickOutside from '~/hooks/useOnClickOutside'; @@ -74,7 +81,7 @@ function MultiSelectDropDown({ {() => ( <> - {' '} {showLabel && ( - {title} - + )} - + - )} - + ); })} - + )} diff --git a/client/src/components/ui/SelectDropDown.tsx b/client/src/components/ui/SelectDropDown.tsx index 9a4b3e929f..3d4246f29c 100644 --- a/client/src/components/ui/SelectDropDown.tsx +++ b/client/src/components/ui/SelectDropDown.tsx @@ -1,5 +1,12 @@ import React from 'react'; -import { Listbox, Transition } from '@headlessui/react'; +import { + Listbox, + ListboxButton, + Label, + ListboxOptions, + ListboxOption, + Transition, +} from '@headlessui/react'; import type { Option, OptionWithIcon } from '~/common'; import CheckMark from '../svg/CheckMark'; import { useLocalize } from '~/hooks'; @@ -84,8 +91,7 @@ function SelectDropDown({ {({ open }) => ( <> - {' '} {showLabel && ( - {title} - + )} - + - {renderOption && ( - {renderOption()} - + )} {searchRender} {options.map((option: string | Option, i: number) => { @@ -181,7 +187,7 @@ function SelectDropDown({ } return ( - @@ -214,10 +220,10 @@ function SelectDropDown({ )} - + ); })} - + )} diff --git a/client/test/setupTests.js b/client/test/setupTests.js index a91868d243..2131c9b13d 100644 --- a/client/test/setupTests.js +++ b/client/test/setupTests.js @@ -16,3 +16,7 @@ import '@testing-library/jest-dom/extend-expect'; // Mock canvas when run unit test cases with jest. // 'react-lottie' uses canvas import 'jest-canvas-mock'; + +beforeEach(() => { + jest.clearAllMocks(); +}); diff --git a/package-lock.json b/package-lock.json index 1bf35d3af2..5074826fdb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1116,7 +1116,7 @@ "@ariakit/react": "^0.4.5", "@dicebear/collection": "^7.0.4", "@dicebear/core": "^7.0.4", - "@headlessui/react": "^1.7.13", + "@headlessui/react": "^2.1.2", "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-alert-dialog": "^1.0.2", "@radix-ui/react-checkbox": "^1.0.3", @@ -5960,12 +5960,28 @@ "@floating-ui/utils": "^0.2.1" } }, - "node_modules/@floating-ui/react-dom": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz", - "integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==", + "node_modules/@floating-ui/react": { + "version": "0.26.19", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.19.tgz", + "integrity": "sha512-Jk6zITdjjIvjO/VdQFvpRaD3qPwOHH6AoDHxjhpy+oK4KFgaSP871HYWUAPdnLmx1gQ+w/pB312co3tVml+BXA==", + "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.6.1" + "@floating-ui/react-dom": "^2.1.1", + "@floating-ui/utils": "^0.2.4", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", + "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.0.0" }, "peerDependencies": { "react": ">=16.8.0", @@ -5973,9 +5989,10 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", - "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.4.tgz", + "integrity": "sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA==", + "license": "MIT" }, "node_modules/@google/generative-ai": { "version": "0.1.3", @@ -6015,19 +6032,22 @@ } }, "node_modules/@headlessui/react": { - "version": "1.7.18", - "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.18.tgz", - "integrity": "sha512-4i5DOrzwN4qSgNsL4Si61VMkUcWbcSKueUV7sFhpHzQcSShdlHENE5+QBntMSRvHt8NyoFO2AGG8si9lq+w4zQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.1.2.tgz", + "integrity": "sha512-Kb3hgk9gRNRcTZktBrKdHhF3xFhYkca1Rk6e1/im2ENf83dgN54orMW0uSKTXFnUpZOUFZ+wcY05LlipwgZIFQ==", + "license": "MIT", "dependencies": { - "@tanstack/react-virtual": "^3.0.0-beta.60", - "client-only": "^0.0.1" + "@floating-ui/react": "^0.26.16", + "@react-aria/focus": "^3.17.1", + "@react-aria/interactions": "^3.21.3", + "@tanstack/react-virtual": "^3.8.1" }, "engines": { "node": ">=10" }, "peerDependencies": { - "react": "^16 || ^17 || ^18", - "react-dom": "^16 || ^17 || ^18" + "react": "^18", + "react-dom": "^18" } }, "node_modules/@humanwhocodes/config-array": { @@ -8531,6 +8551,86 @@ "node": ">=8.x" } }, + "node_modules/@react-aria/focus": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.17.1.tgz", + "integrity": "sha512-FLTySoSNqX++u0nWZJPPN5etXY0WBxaIe/YuL/GTEeuqUIuC/2bJSaw5hlsM6T2yjy6Y/VAxBcKSdAFUlU6njQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.21.3", + "@react-aria/utils": "^3.24.1", + "@react-types/shared": "^3.23.1", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/focus/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@react-aria/interactions": { + "version": "3.21.3", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.21.3.tgz", + "integrity": "sha512-BWIuf4qCs5FreDJ9AguawLVS0lV9UU+sK4CCnbCNNmYqOWY+1+gRXCsnOM32K+oMESBxilAjdHW5n1hsMqYMpA==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.4", + "@react-aria/utils": "^3.24.1", + "@react-types/shared": "^3.23.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/ssr": { + "version": "3.9.4", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.4.tgz", + "integrity": "sha512-4jmAigVq409qcJvQyuorsmBR4+9r3+JEC60wC+Y0MZV0HCtTmm8D9guYXlJMdx0SSkgj0hHAyFm/HvPNFofCoQ==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/utils": { + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/@react-aria/utils/-/utils-3.24.1.tgz", + "integrity": "sha512-O3s9qhPMd6n42x9sKeJ3lhu5V1Tlnzhu6Yk8QOvDuXf7UGuUjXf9mzfHJt1dYzID4l9Fwm8toczBzPM9t0jc8Q==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.4", + "@react-stately/utils": "^3.10.1", + "@react-types/shared": "^3.23.1", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/utils/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/@react-dnd/asap": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz", @@ -8546,6 +8646,27 @@ "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz", "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==" }, + "node_modules/@react-stately/utils": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@react-stately/utils/-/utils-3.10.1.tgz", + "integrity": "sha512-VS/EHRyicef25zDZcM/ClpzYMC5i2YGN6uegOeQawmgfGjb02yaCX0F0zR69Pod9m2Hr3wunTbtpgVXvYbZItg==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/shared": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.23.1.tgz", + "integrity": "sha512-5d+3HbFDxGZjhbMBeFHRQhexMFt4pUce3okyRtUVKbbedQFUrtXSBg9VszgF2RTeQDKDkMCIQDtz5ccP/Lk1gw==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, "node_modules/@remix-run/router": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.0.tgz", @@ -9542,6 +9663,15 @@ "sourcemap-codec": "^1.4.8" } }, + "node_modules/@swc/helpers": { + "version": "0.5.11", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.11.tgz", + "integrity": "sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@tanstack/match-sorter-utils": { "version": "8.11.8", "resolved": "https://registry.npmjs.org/@tanstack/match-sorter-utils/-/match-sorter-utils-8.11.8.tgz", @@ -9633,11 +9763,12 @@ } }, "node_modules/@tanstack/react-virtual": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.0.4.tgz", - "integrity": "sha512-tiqKW/e2MJVCr7/pRUXulpkyxllaOclkHNfhKTo4pmHjJIqnhMfwIjc1Q1R0Un3PI3kQywywu/791c8z9u0qeA==", + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.8.2.tgz", + "integrity": "sha512-g78+DA29K0ByAfDkuibfLQqDshf8Aha/zcyEZ+huAX/yS/TWj/CUiEY4IJfDrFacdxIFmsLm0u4VtsLSKTngRw==", + "license": "MIT", "dependencies": { - "@tanstack/virtual-core": "3.0.0" + "@tanstack/virtual-core": "3.8.2" }, "funding": { "type": "github", @@ -9661,9 +9792,10 @@ } }, "node_modules/@tanstack/virtual-core": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.0.0.tgz", - "integrity": "sha512-SYXOBTjJb05rXa2vl55TTwO40A6wKu0R5i1qQwhJYNDIqaIGF7D0HsLw+pJAyi2OvntlEIVusx3xtbbgSUi6zg==", + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.8.2.tgz", + "integrity": "sha512-ffpN6kTaPGwQPoWMcBAHbdv2ZCpj1SugldoYAcY0C4xH+Pej1KCOEUisNeEgbUnXOp8Y/4q6wGPu2tFHthOIQw==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" @@ -12296,11 +12428,6 @@ "node": ">= 12" } }, - "node_modules/client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" - }, "node_modules/clipboardy": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-3.0.0.tgz", @@ -26431,6 +26558,12 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "devOptional": true }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "license": "MIT" + }, "node_modules/tailwind-merge": { "version": "1.14.0", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.14.0.tgz",